]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more .27 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 29 Apr 2009 20:40:09 +0000 (13:40 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 29 Apr 2009 20:40:09 +0000 (13:40 -0700)
queue-2.6.27/acpi-ec-add-some-basic-check-for-ecdt-data.patch [new file with mode: 0644]
queue-2.6.27/acpi-ec-fix-compilation-warning.patch [new file with mode: 0644]
queue-2.6.27/b44-use-kernel-dma-addresses-for-the-kernel-dma-api.patch [new file with mode: 0644]
queue-2.6.27/crypto-ixp4xx-fix-handling-of-chained-sg-buffers.patch [new file with mode: 0644]
queue-2.6.27/exit_notify-kill-the-wrong-capable-check.patch [new file with mode: 0644]
queue-2.6.27/fix-ptrace-slowness.patch [new file with mode: 0644]
queue-2.6.27/fs-core-fixes.patch [new file with mode: 0644]
queue-2.6.27/pci-fix-incorrect-mask-of-pm-no_soft_reset-bit.patch [new file with mode: 0644]
queue-2.6.27/series
queue-2.6.27/thinkpad-acpi-fix-led-blinking-through-timer-trigger.patch [new file with mode: 0644]

diff --git a/queue-2.6.27/acpi-ec-add-some-basic-check-for-ecdt-data.patch b/queue-2.6.27/acpi-ec-add-some-basic-check-for-ecdt-data.patch
new file mode 100644 (file)
index 0000000..e11358f
--- /dev/null
@@ -0,0 +1,84 @@
+From c5279dee26c0e8d7c4200993bfc4b540d2469598 Mon Sep 17 00:00:00 2001
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+Date: Wed, 26 Nov 2008 17:11:53 -0500
+Subject: ACPI: EC: Add some basic check for ECDT data
+
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+
+commit c5279dee26c0e8d7c4200993bfc4b540d2469598 upstream.
+
+One more ASUS comes with empty ECDT, add a guard for it...
+
+http://bugzilla.kernel.org/show_bug.cgi?id=11880
+
+Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/ec.c |   43 ++++++++++++++++++++++---------------------
+ 1 file changed, 22 insertions(+), 21 deletions(-)
+
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -968,7 +968,6 @@ static const struct acpi_device_id ec_de
+ int __init acpi_ec_ecdt_probe(void)
+ {
+-      int ret;
+       acpi_status status;
+       struct acpi_table_ecdt *ecdt_ptr;
+@@ -996,30 +995,32 @@ int __init acpi_ec_ecdt_probe(void)
+               boot_ec->gpe = ecdt_ptr->gpe;
+               boot_ec->handle = ACPI_ROOT_OBJECT;
+               acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
+-      } else {
+-              /* This workaround is needed only on some broken machines,
+-               * which require early EC, but fail to provide ECDT */
+-              acpi_handle x;
+-              printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
+-              status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
+-                                              boot_ec, NULL);
+-              /* Check that acpi_get_devices actually find something */
+-              if (ACPI_FAILURE(status) || !boot_ec->handle)
+-                      goto error;
+-              /* We really need to limit this workaround, the only ASUS,
+-               * which needs it, has fake EC._INI method, so use it as flag.
+-               * Keep boot_ec struct as it will be needed soon.
+-               */
+-              if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
+-                      return -ENODEV;
++              /* Add some basic check against completely broken table */
++              if (boot_ec->data_addr != boot_ec->command_addr)
++                      goto install;
++      /* fall through */
+       }
+-
+-      ret = ec_install_handlers(boot_ec);
+-      if (!ret) {
++      /* This workaround is needed only on some broken machines,
++       * which require early EC, but fail to provide ECDT */
++      acpi_handle x;
++      printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
++      status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
++                                      boot_ec, NULL);
++      /* Check that acpi_get_devices actually find something */
++      if (ACPI_FAILURE(status) || !boot_ec->handle)
++              goto error;
++      /* We really need to limit this workaround, the only ASUS,
++       * which needs it, has fake EC._INI method, so use it as flag.
++       * Keep boot_ec struct as it will be needed soon.
++       */
++      if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
++              return -ENODEV;
++install:
++      if (!ec_install_handlers(boot_ec)) {
+               first_ec = boot_ec;
+               return 0;
+       }
+-      error:
++error:
+       kfree(boot_ec);
+       boot_ec = NULL;
+       return -ENODEV;
diff --git a/queue-2.6.27/acpi-ec-fix-compilation-warning.patch b/queue-2.6.27/acpi-ec-fix-compilation-warning.patch
new file mode 100644 (file)
index 0000000..bf571e0
--- /dev/null
@@ -0,0 +1,51 @@
+From 3e54048691bce3f323fd5460695273be379803b9 Mon Sep 17 00:00:00 2001
+From: Hannes Eder <hannes@hanneseder.net>
+Date: Sat, 29 Nov 2008 07:21:29 +0100
+Subject: ACPI: EC: fix compilation warning
+
+From: Hannes Eder <hannes@hanneseder.net>
+
+commit 3e54048691bce3f323fd5460695273be379803b9 upstream.
+
+Fix the warning introduced in commit c5279dee26c0e8d7c4200993bfc4b540d2469598,
+and give the dummy variable a more verbose name.
+
+  drivers/acpi/ec.c: In function 'acpi_ec_ecdt_probe':
+  drivers/acpi/ec.c:1015: warning: ISO C90 forbids mixed declarations and code
+
+Signed-off-by: Hannes Eder <hannes@hanneseder.net>
+Acked-by: Alexey Starikovskiy <astarikovskiy@suse.de>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/ec.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -970,6 +970,7 @@ int __init acpi_ec_ecdt_probe(void)
+ {
+       acpi_status status;
+       struct acpi_table_ecdt *ecdt_ptr;
++      acpi_handle dummy;
+       boot_ec = make_acpi_ec();
+       if (!boot_ec)
+@@ -1002,7 +1003,6 @@ int __init acpi_ec_ecdt_probe(void)
+       }
+       /* This workaround is needed only on some broken machines,
+        * which require early EC, but fail to provide ECDT */
+-      acpi_handle x;
+       printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
+       status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
+                                       boot_ec, NULL);
+@@ -1013,7 +1013,7 @@ int __init acpi_ec_ecdt_probe(void)
+        * which needs it, has fake EC._INI method, so use it as flag.
+        * Keep boot_ec struct as it will be needed soon.
+        */
+-      if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
++      if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy)))
+               return -ENODEV;
+ install:
+       if (!ec_install_handlers(boot_ec)) {
diff --git a/queue-2.6.27/b44-use-kernel-dma-addresses-for-the-kernel-dma-api.patch b/queue-2.6.27/b44-use-kernel-dma-addresses-for-the-kernel-dma-api.patch
new file mode 100644 (file)
index 0000000..0aceff2
--- /dev/null
@@ -0,0 +1,34 @@
+From 37efa239901493694a48f1d6f59f8de17c2c4509 Mon Sep 17 00:00:00 2001
+From: Michael Buesch <mb@bu3sch.de>
+Date: Mon, 6 Apr 2009 09:52:27 +0000
+Subject: b44: Use kernel DMA addresses for the kernel DMA API
+
+From: Michael Buesch <mb@bu3sch.de>
+
+commit 37efa239901493694a48f1d6f59f8de17c2c4509 upstream.
+
+We must not use the device DMA addresses for the kernel DMA API, because
+device DMA addresses have an additional offset added for the SSB translation.
+
+Use the original dma_addr_t for the sync operation.
+
+Cc: stable@kernel.org
+Signed-off-by: Michael Buesch <mb@bu3sch.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/b44.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/b44.c
++++ b/drivers/net/b44.c
+@@ -750,7 +750,7 @@ static void b44_recycle_rx(struct b44 *b
+                                            dest_idx * sizeof(dest_desc),
+                                            DMA_BIDIRECTIONAL);
+-      ssb_dma_sync_single_for_device(bp->sdev, le32_to_cpu(src_desc->addr),
++      ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping,
+                                      RX_PKT_BUF_SZ,
+                                      DMA_FROM_DEVICE);
+ }
diff --git a/queue-2.6.27/crypto-ixp4xx-fix-handling-of-chained-sg-buffers.patch b/queue-2.6.27/crypto-ixp4xx-fix-handling-of-chained-sg-buffers.patch
new file mode 100644 (file)
index 0000000..5c0c108
--- /dev/null
@@ -0,0 +1,390 @@
+From 0d44dc59b2b434b29aafeae581d06f81efac7c83 Mon Sep 17 00:00:00 2001
+From: Christian Hohnstaedt <chohnstaedt@innominate.com>
+Date: Fri, 27 Mar 2009 15:09:05 +0800
+Subject: crypto: ixp4xx - Fix handling of chained sg buffers
+
+From: Christian Hohnstaedt <chohnstaedt@innominate.com>
+
+commit 0d44dc59b2b434b29aafeae581d06f81efac7c83 upstream.
+
+ - keep dma functions away from chained scatterlists.
+   Use the existing scatterlist iteration inside the driver
+   to call dma_map_single() for each chunk and avoid dma_map_sg().
+
+Signed-off-by: Christian Hohnstaedt <chohnstaedt@innominate.com>
+Tested-By:  Karl Hiramoto <karl@hiramoto.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/crypto/ixp4xx_crypto.c |  184 ++++++++++++++---------------------------
+ 1 file changed, 64 insertions(+), 120 deletions(-)
+
+--- a/drivers/crypto/ixp4xx_crypto.c
++++ b/drivers/crypto/ixp4xx_crypto.c
+@@ -101,6 +101,7 @@ struct buffer_desc {
+       u32 phys_addr;
+       u32 __reserved[4];
+       struct buffer_desc *next;
++      enum dma_data_direction dir;
+ };
+ struct crypt_ctl {
+@@ -132,14 +133,10 @@ struct crypt_ctl {
+ struct ablk_ctx {
+       struct buffer_desc *src;
+       struct buffer_desc *dst;
+-      unsigned src_nents;
+-      unsigned dst_nents;
+ };
+ struct aead_ctx {
+       struct buffer_desc *buffer;
+-      unsigned short assoc_nents;
+-      unsigned short src_nents;
+       struct scatterlist ivlist;
+       /* used when the hmac is not on one sg entry */
+       u8 *hmac_virt;
+@@ -312,7 +309,7 @@ static struct crypt_ctl *get_crypt_desc_
+       }
+ }
+-static void free_buf_chain(struct buffer_desc *buf, u32 phys)
++static void free_buf_chain(struct device *dev, struct buffer_desc *buf,u32 phys)
+ {
+       while (buf) {
+               struct buffer_desc *buf1;
+@@ -320,6 +317,7 @@ static void free_buf_chain(struct buffer
+               buf1 = buf->next;
+               phys1 = buf->phys_next;
++              dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir);
+               dma_pool_free(buffer_pool, buf, phys);
+               buf = buf1;
+               phys = phys1;
+@@ -348,7 +346,6 @@ static void one_packet(dma_addr_t phys)
+       struct crypt_ctl *crypt;
+       struct ixp_ctx *ctx;
+       int failed;
+-      enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
+       failed = phys & 0x1 ? -EBADMSG : 0;
+       phys &= ~0x3;
+@@ -358,13 +355,8 @@ static void one_packet(dma_addr_t phys)
+       case CTL_FLAG_PERFORM_AEAD: {
+               struct aead_request *req = crypt->data.aead_req;
+               struct aead_ctx *req_ctx = aead_request_ctx(req);
+-              dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents,
+-                              DMA_TO_DEVICE);
+-              dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+-              dma_unmap_sg(dev, req->src, req_ctx->src_nents,
+-                              DMA_BIDIRECTIONAL);
+-              free_buf_chain(req_ctx->buffer, crypt->src_buf);
++              free_buf_chain(dev, req_ctx->buffer, crypt->src_buf);
+               if (req_ctx->hmac_virt) {
+                       finish_scattered_hmac(crypt);
+               }
+@@ -374,16 +366,11 @@ static void one_packet(dma_addr_t phys)
+       case CTL_FLAG_PERFORM_ABLK: {
+               struct ablkcipher_request *req = crypt->data.ablk_req;
+               struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
+-              int nents;
++
+               if (req_ctx->dst) {
+-                      nents = req_ctx->dst_nents;
+-                      dma_unmap_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
+-                      free_buf_chain(req_ctx->dst, crypt->dst_buf);
+-                      src_direction = DMA_TO_DEVICE;
+-              }
+-              nents = req_ctx->src_nents;
+-              dma_unmap_sg(dev, req->src, nents, src_direction);
+-              free_buf_chain(req_ctx->src, crypt->src_buf);
++                      free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
++              }
++              free_buf_chain(dev, req_ctx->src, crypt->src_buf);
+               req->base.complete(&req->base, failed);
+               break;
+       }
+@@ -748,56 +735,35 @@ static int setup_cipher(struct crypto_tf
+       return 0;
+ }
+-static int count_sg(struct scatterlist *sg, int nbytes)
+-{
+-      int i;
+-      for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
+-              nbytes -= sg->length;
+-      return i;
+-}
+-
+-static struct buffer_desc *chainup_buffers(struct scatterlist *sg,
+-                      unsigned nbytes, struct buffer_desc *buf, gfp_t flags)
++static struct buffer_desc *chainup_buffers(struct device *dev,
++              struct scatterlist *sg, unsigned nbytes,
++              struct buffer_desc *buf, gfp_t flags,
++              enum dma_data_direction dir)
+ {
+-      int nents = 0;
+-
+-      while (nbytes > 0) {
++      for (;nbytes > 0; sg = scatterwalk_sg_next(sg)) {
++              unsigned len = min(nbytes, sg->length);
+               struct buffer_desc *next_buf;
+               u32 next_buf_phys;
+-              unsigned len = min(nbytes, sg_dma_len(sg));
++              void *ptr;
+-              nents++;
+               nbytes -= len;
+-              if (!buf->phys_addr) {
+-                      buf->phys_addr = sg_dma_address(sg);
+-                      buf->buf_len = len;
+-                      buf->next = NULL;
+-                      buf->phys_next = 0;
+-                      goto next;
+-              }
+-              /* Two consecutive chunks on one page may be handled by the old
+-               * buffer descriptor, increased by the length of the new one
+-               */
+-              if (sg_dma_address(sg) == buf->phys_addr + buf->buf_len) {
+-                      buf->buf_len += len;
+-                      goto next;
+-              }
++              ptr = page_address(sg_page(sg)) + sg->offset;
+               next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys);
+-              if (!next_buf)
+-                      return NULL;
++              if (!next_buf) {
++                      buf = NULL;
++                      break;
++              }
++              sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir);
+               buf->next = next_buf;
+               buf->phys_next = next_buf_phys;
+-
+               buf = next_buf;
+-              buf->next = NULL;
+-              buf->phys_next = 0;
++
+               buf->phys_addr = sg_dma_address(sg);
+               buf->buf_len = len;
+-next:
+-              if (nbytes > 0) {
+-                      sg = sg_next(sg);
+-              }
++              buf->dir = dir;
+       }
++      buf->next = NULL;
++      buf->phys_next = 0;
+       return buf;
+ }
+@@ -858,12 +824,12 @@ static int ablk_perform(struct ablkciphe
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
+-      int ret = -ENOMEM;
+       struct ix_sa_dir *dir;
+       struct crypt_ctl *crypt;
+-      unsigned int nbytes = req->nbytes, nents;
++      unsigned int nbytes = req->nbytes;
+       enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
+       struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
++      struct buffer_desc src_hook;
+       gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+                               GFP_KERNEL : GFP_ATOMIC;
+@@ -876,7 +842,7 @@ static int ablk_perform(struct ablkciphe
+       crypt = get_crypt_desc();
+       if (!crypt)
+-              return ret;
++              return -ENOMEM;
+       crypt->data.ablk_req = req;
+       crypt->crypto_ctx = dir->npe_ctx_phys;
+@@ -889,53 +855,41 @@ static int ablk_perform(struct ablkciphe
+       BUG_ON(ivsize && !req->info);
+       memcpy(crypt->iv, req->info, ivsize);
+       if (req->src != req->dst) {
++              struct buffer_desc dst_hook;
+               crypt->mode |= NPE_OP_NOT_IN_PLACE;
+-              nents = count_sg(req->dst, nbytes);
+               /* This was never tested by Intel
+                * for more than one dst buffer, I think. */
+-              BUG_ON(nents != 1);
+-              req_ctx->dst_nents = nents;
+-              dma_map_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
+-              req_ctx->dst = dma_pool_alloc(buffer_pool, flags,&crypt->dst_buf);
+-              if (!req_ctx->dst)
+-                      goto unmap_sg_dest;
+-              req_ctx->dst->phys_addr = 0;
+-              if (!chainup_buffers(req->dst, nbytes, req_ctx->dst, flags))
++              BUG_ON(req->dst->length < nbytes);
++              req_ctx->dst = NULL;
++              if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
++                                      flags, DMA_FROM_DEVICE))
+                       goto free_buf_dest;
+               src_direction = DMA_TO_DEVICE;
++              req_ctx->dst = dst_hook.next;
++              crypt->dst_buf = dst_hook.phys_next;
+       } else {
+               req_ctx->dst = NULL;
+-              req_ctx->dst_nents = 0;
+       }
+-      nents = count_sg(req->src, nbytes);
+-      req_ctx->src_nents = nents;
+-      dma_map_sg(dev, req->src, nents, src_direction);
+-
+-      req_ctx->src = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
+-      if (!req_ctx->src)
+-              goto unmap_sg_src;
+-      req_ctx->src->phys_addr = 0;
+-      if (!chainup_buffers(req->src, nbytes, req_ctx->src, flags))
++      req_ctx->src = NULL;
++      if (!chainup_buffers(dev, req->src, nbytes, &src_hook,
++                              flags, src_direction))
+               goto free_buf_src;
++      req_ctx->src = src_hook.next;
++      crypt->src_buf = src_hook.phys_next;
+       crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK;
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return -EINPROGRESS;
+ free_buf_src:
+-      free_buf_chain(req_ctx->src, crypt->src_buf);
+-unmap_sg_src:
+-      dma_unmap_sg(dev, req->src, req_ctx->src_nents, src_direction);
++      free_buf_chain(dev, req_ctx->src, crypt->src_buf);
+ free_buf_dest:
+       if (req->src != req->dst) {
+-              free_buf_chain(req_ctx->dst, crypt->dst_buf);
+-unmap_sg_dest:
+-              dma_unmap_sg(dev, req->src, req_ctx->dst_nents,
+-                      DMA_FROM_DEVICE);
++              free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
+       }
+       crypt->ctl_flags = CTL_FLAG_UNUSED;
+-      return ret;
++      return -ENOMEM;
+ }
+ static int ablk_encrypt(struct ablkcipher_request *req)
+@@ -983,7 +937,7 @@ static int hmac_inconsistent(struct scat
+                       break;
+               offset += sg->length;
+-              sg = sg_next(sg);
++              sg = scatterwalk_sg_next(sg);
+       }
+       return (start + nbytes > offset + sg->length);
+ }
+@@ -995,11 +949,10 @@ static int aead_perform(struct aead_requ
+       struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned ivsize = crypto_aead_ivsize(tfm);
+       unsigned authsize = crypto_aead_authsize(tfm);
+-      int ret = -ENOMEM;
+       struct ix_sa_dir *dir;
+       struct crypt_ctl *crypt;
+-      unsigned int cryptlen, nents;
+-      struct buffer_desc *buf;
++      unsigned int cryptlen;
++      struct buffer_desc *buf, src_hook;
+       struct aead_ctx *req_ctx = aead_request_ctx(req);
+       gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+                               GFP_KERNEL : GFP_ATOMIC;
+@@ -1020,7 +973,7 @@ static int aead_perform(struct aead_requ
+       }
+       crypt = get_crypt_desc();
+       if (!crypt)
+-              return ret;
++              return -ENOMEM;
+       crypt->data.aead_req = req;
+       crypt->crypto_ctx = dir->npe_ctx_phys;
+@@ -1039,31 +992,27 @@ static int aead_perform(struct aead_requ
+               BUG(); /* -ENOTSUP because of my lazyness */
+       }
+-      req_ctx->buffer = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
+-      if (!req_ctx->buffer)
+-              goto out;
+-      req_ctx->buffer->phys_addr = 0;
+       /* ASSOC data */
+-      nents = count_sg(req->assoc, req->assoclen);
+-      req_ctx->assoc_nents = nents;
+-      dma_map_sg(dev, req->assoc, nents, DMA_TO_DEVICE);
+-      buf = chainup_buffers(req->assoc, req->assoclen, req_ctx->buffer,flags);
++      buf = chainup_buffers(dev, req->assoc, req->assoclen, &src_hook,
++              flags, DMA_TO_DEVICE);
++      req_ctx->buffer = src_hook.next;
++      crypt->src_buf = src_hook.phys_next;
+       if (!buf)
+-              goto unmap_sg_assoc;
++              goto out;
+       /* IV */
+       sg_init_table(&req_ctx->ivlist, 1);
+       sg_set_buf(&req_ctx->ivlist, iv, ivsize);
+-      dma_map_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+-      buf = chainup_buffers(&req_ctx->ivlist, ivsize, buf, flags);
++      buf = chainup_buffers(dev, &req_ctx->ivlist, ivsize, buf, flags,
++                      DMA_BIDIRECTIONAL);
+       if (!buf)
+-              goto unmap_sg_iv;
++              goto free_chain;
+       if (unlikely(hmac_inconsistent(req->src, cryptlen, authsize))) {
+               /* The 12 hmac bytes are scattered,
+                * we need to copy them into a safe buffer */
+               req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
+                               &crypt->icv_rev_aes);
+               if (unlikely(!req_ctx->hmac_virt))
+-                      goto unmap_sg_iv;
++                      goto free_chain;
+               if (!encrypt) {
+                       scatterwalk_map_and_copy(req_ctx->hmac_virt,
+                               req->src, cryptlen, authsize, 0);
+@@ -1073,33 +1022,28 @@ static int aead_perform(struct aead_requ
+               req_ctx->hmac_virt = NULL;
+       }
+       /* Crypt */
+-      nents = count_sg(req->src, cryptlen + authsize);
+-      req_ctx->src_nents = nents;
+-      dma_map_sg(dev, req->src, nents, DMA_BIDIRECTIONAL);
+-      buf = chainup_buffers(req->src, cryptlen + authsize, buf, flags);
++      buf = chainup_buffers(dev, req->src, cryptlen + authsize, buf, flags,
++                      DMA_BIDIRECTIONAL);
+       if (!buf)
+-              goto unmap_sg_src;
++              goto free_hmac_virt;
+       if (!req_ctx->hmac_virt) {
+               crypt->icv_rev_aes = buf->phys_addr + buf->buf_len - authsize;
+       }
++
+       crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD;
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return -EINPROGRESS;
+-unmap_sg_src:
+-      dma_unmap_sg(dev, req->src, req_ctx->src_nents, DMA_BIDIRECTIONAL);
++free_hmac_virt:
+       if (req_ctx->hmac_virt) {
+               dma_pool_free(buffer_pool, req_ctx->hmac_virt,
+                               crypt->icv_rev_aes);
+       }
+-unmap_sg_iv:
+-      dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+-unmap_sg_assoc:
+-      dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents, DMA_TO_DEVICE);
+-      free_buf_chain(req_ctx->buffer, crypt->src_buf);
++free_chain:
++      free_buf_chain(dev, req_ctx->buffer, crypt->src_buf);
+ out:
+       crypt->ctl_flags = CTL_FLAG_UNUSED;
+-      return ret;
++      return -ENOMEM;
+ }
+ static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
diff --git a/queue-2.6.27/exit_notify-kill-the-wrong-capable-check.patch b/queue-2.6.27/exit_notify-kill-the-wrong-capable-check.patch
new file mode 100644 (file)
index 0000000..36f556d
--- /dev/null
@@ -0,0 +1,38 @@
+From 432870dab85a2f69dc417022646cb9a70acf7f94 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Mon, 6 Apr 2009 16:16:02 +0200
+Subject: exit_notify: kill the wrong capable(CAP_KILL) check (CVE-2009-1337)
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+CVE-2009-1337
+
+commit 432870dab85a2f69dc417022646cb9a70acf7f94 upstream.
+
+The CAP_KILL check in exit_notify() looks just wrong, kill it.
+
+Whatever logic we have to reset ->exit_signal, the malicious user
+can bypass it if it execs the setuid application before exiting.
+
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Acked-by: Serge Hallyn <serue@us.ibm.com>
+Acked-by: Roland McGrath <roland@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/exit.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -938,8 +938,7 @@ static void exit_notify(struct task_stru
+        */
+       if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) &&
+           (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||
+-           tsk->self_exec_id != tsk->parent_exec_id) &&
+-          !capable(CAP_KILL))
++           tsk->self_exec_id != tsk->parent_exec_id))
+               tsk->exit_signal = SIGCHLD;
+       signal = tracehook_notify_death(tsk, &cookie, group_dead);
diff --git a/queue-2.6.27/fix-ptrace-slowness.patch b/queue-2.6.27/fix-ptrace-slowness.patch
new file mode 100644 (file)
index 0000000..23a7752
--- /dev/null
@@ -0,0 +1,63 @@
+From 53da1d9456fe7f87a920a78fdbdcf1225d197cb7 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@suse.cz>
+Date: Mon, 23 Mar 2009 16:07:24 +0100
+Subject: fix ptrace slowness
+
+From: Miklos Szeredi <mszeredi@suse.cz>
+
+commit 53da1d9456fe7f87a920a78fdbdcf1225d197cb7 upstream.
+
+This patch fixes bug #12208:
+
+  Bug-Entry       : http://bugzilla.kernel.org/show_bug.cgi?id=12208
+  Subject         : uml is very slow on 2.6.28 host
+
+This turned out to be not a scheduler regression, but an already
+existing problem in ptrace being triggered by subtle scheduler
+changes.
+
+The problem is this:
+
+ - task A is ptracing task B
+ - task B stops on a trace event
+ - task A is woken up and preempts task B
+ - task A calls ptrace on task B, which does ptrace_check_attach()
+ - this calls wait_task_inactive(), which sees that task B is still on the runq
+ - task A goes to sleep for a jiffy
+ - ...
+
+Since UML does lots of the above sequences, those jiffies quickly add
+up to make it slow as hell.
+
+This patch solves this by not rescheduling in read_unlock() after
+ptrace_stop() has woken up the tracer.
+
+Thanks to Oleg Nesterov and Ingo Molnar for the feedback.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+CC: stable@kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/signal.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -1549,7 +1549,15 @@ static void ptrace_stop(int exit_code, i
+       read_lock(&tasklist_lock);
+       if (may_ptrace_stop()) {
+               do_notify_parent_cldstop(current, CLD_TRAPPED);
++              /*
++               * Don't want to allow preemption here, because
++               * sys_ptrace() needs this task to be inactive.
++               *
++               * XXX: implement read_unlock_no_resched().
++               */
++              preempt_disable();
+               read_unlock(&tasklist_lock);
++              preempt_enable_no_resched();
+               schedule();
+       } else {
+               /*
diff --git a/queue-2.6.27/fs-core-fixes.patch b/queue-2.6.27/fs-core-fixes.patch
new file mode 100644 (file)
index 0000000..4a130b8
--- /dev/null
@@ -0,0 +1,210 @@
+From hugh@veritas.com  Wed Apr 29 12:45:48 2009
+From: Hugh Dickins <hugh@veritas.com>
+Date: Sat, 25 Apr 2009 17:52:56 +0100 (BST)
+Subject: fs core fixes
+To: Chris Wright <chrisw@sous-sol.org>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>, Oleg Nesterov <oleg@redhat.com>, Joe Malicki <jmalicki@metatcarta.com>, stable@kernel.org, David Howells <dhowells@redhat.com>, Al Viro <viro@zeniv.linux.org.uk>, Andrew Morton <akpm@linux-foundation.org>, Linus Torvalds <torvalds@linux-foundation.org>, Alexey Dobriyan <adobriyan@gmail.com>, Roland McGrath <roland@redhat.com>
+Message-ID: <Pine.LNX.4.64.0904251751200.2298@blonde.anvils>
+
+From: Hugh Dickins <hugh@veritas.com>
+
+Please add the following 4 commits to 2.6.27-stable and 2.6.28-stable.
+However, there has been a lot of change here between 2.6.28 and 2.6.29:
+in particular, fs/exec.c's unsafe_exec() grew into the more complicated
+check_unsafe_exec().  So applying the original patches gives too many
+rejects: at the bottom is the diffstat and the combined patch required.
+
+1
+Commit: 53e9309e01277ec99c38e84e0ca16921287cf470
+Author: Hugh Dickins <hugh@veritas.com>
+Date: Sat, 28 Mar 2009 23:16:03 +0000 (+0000)
+Subject: compat_do_execve should unshare_files
+
+2
+Commit: e426b64c412aaa3e9eb3e4b261dc5be0d5a83e78
+Author: Hugh Dickins <hugh@veritas.com>
+Date: Sat, 28 Mar 2009 23:20:19 +0000 (+0000)
+Subject: fix setuid sometimes doesn't
+
+3
+Commit: 7c2c7d993044cddc5010f6f429b100c63bc7dffb
+Author: Hugh Dickins <hugh@veritas.com>
+Date: Sat, 28 Mar 2009 23:21:27 +0000 (+0000)
+Subject: fix setuid sometimes wouldn't
+
+4
+Commit: f1191b50ec11c8e2ca766d6d99eb5bb9d2c084a3
+Author: Al Viro <viro@zeniv.linux.org.uk>
+Date: Mon, 30 Mar 2009 11:35:18 +0000 (-0400)
+Subject: check_unsafe_exec() doesn't care about signal handlers sharing
+
+Signed-off-by: Hugh Dickins <hugh@veritas.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/compat.c    |   12 +++++++++++-
+ fs/exec.c      |    4 +---
+ fs/proc/base.c |   50 ++++++++++++++++----------------------------------
+ 3 files changed, 28 insertions(+), 38 deletions(-)
+
+--- a/fs/compat.c
++++ b/fs/compat.c
+@@ -1353,12 +1353,17 @@ int compat_do_execve(char * filename,
+ {
+       struct linux_binprm *bprm;
+       struct file *file;
++      struct files_struct *displaced;
+       int retval;
++      retval = unshare_files(&displaced);
++      if (retval)
++              goto out_ret;
++
+       retval = -ENOMEM;
+       bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
+       if (!bprm)
+-              goto out_ret;
++              goto out_files;
+       file = open_exec(filename);
+       retval = PTR_ERR(file);
+@@ -1410,6 +1415,8 @@ int compat_do_execve(char * filename,
+               security_bprm_free(bprm);
+               acct_update_integrals(current);
+               free_bprm(bprm);
++              if (displaced)
++                      put_files_struct(displaced);
+               return retval;
+       }
+@@ -1430,6 +1437,9 @@ out_file:
+ out_kfree:
+       free_bprm(bprm);
++out_files:
++      if (displaced)
++              reset_files_struct(displaced);
+ out_ret:
+       return retval;
+ }
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1089,9 +1089,7 @@ static int unsafe_exec(struct task_struc
+ {
+       int unsafe = tracehook_unsafe_exec(p);
+-      if (atomic_read(&p->fs->count) > 1 ||
+-          atomic_read(&p->files->count) > 1 ||
+-          atomic_read(&p->sighand->count) > 1)
++      if (atomic_read(&p->fs->count) > 1)
+               unsafe |= LSM_UNSAFE_SHARE;
+       return unsafe;
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -151,15 +151,22 @@ static unsigned int pid_entry_count_dirs
+ int maps_protect;
+ EXPORT_SYMBOL(maps_protect);
+-static struct fs_struct *get_fs_struct(struct task_struct *task)
++static int get_fs_path(struct task_struct *task, struct path *path, bool root)
+ {
+       struct fs_struct *fs;
++      int result = -ENOENT;
++
+       task_lock(task);
+       fs = task->fs;
+-      if(fs)
+-              atomic_inc(&fs->count);
++      if (fs) {
++              read_lock(&fs->lock);
++              *path = root ? fs->root : fs->pwd;
++              path_get(path);
++              read_unlock(&fs->lock);
++              result = 0;
++      }
+       task_unlock(task);
+-      return fs;
++      return result;
+ }
+ static int get_nr_threads(struct task_struct *tsk)
+@@ -178,42 +185,24 @@ static int get_nr_threads(struct task_st
+ static int proc_cwd_link(struct inode *inode, struct path *path)
+ {
+       struct task_struct *task = get_proc_task(inode);
+-      struct fs_struct *fs = NULL;
+       int result = -ENOENT;
+       if (task) {
+-              fs = get_fs_struct(task);
++              result = get_fs_path(task, path, 0);
+               put_task_struct(task);
+       }
+-      if (fs) {
+-              read_lock(&fs->lock);
+-              *path = fs->pwd;
+-              path_get(&fs->pwd);
+-              read_unlock(&fs->lock);
+-              result = 0;
+-              put_fs_struct(fs);
+-      }
+       return result;
+ }
+ static int proc_root_link(struct inode *inode, struct path *path)
+ {
+       struct task_struct *task = get_proc_task(inode);
+-      struct fs_struct *fs = NULL;
+       int result = -ENOENT;
+       if (task) {
+-              fs = get_fs_struct(task);
++              result = get_fs_path(task, path, 1);
+               put_task_struct(task);
+       }
+-      if (fs) {
+-              read_lock(&fs->lock);
+-              *path = fs->root;
+-              path_get(&fs->root);
+-              read_unlock(&fs->lock);
+-              result = 0;
+-              put_fs_struct(fs);
+-      }
+       return result;
+ }
+@@ -575,7 +564,6 @@ static int mounts_open_common(struct ino
+       struct task_struct *task = get_proc_task(inode);
+       struct nsproxy *nsp;
+       struct mnt_namespace *ns = NULL;
+-      struct fs_struct *fs = NULL;
+       struct path root;
+       struct proc_mounts *p;
+       int ret = -EINVAL;
+@@ -589,22 +577,16 @@ static int mounts_open_common(struct ino
+                               get_mnt_ns(ns);
+               }
+               rcu_read_unlock();
+-              if (ns)
+-                      fs = get_fs_struct(task);
++              if (ns && get_fs_path(task, &root, 1) == 0)
++                      ret = 0;
+               put_task_struct(task);
+       }
+       if (!ns)
+               goto err;
+-      if (!fs)
++      if (ret)
+               goto err_put_ns;
+-      read_lock(&fs->lock);
+-      root = fs->root;
+-      path_get(&root);
+-      read_unlock(&fs->lock);
+-      put_fs_struct(fs);
+-
+       ret = -ENOMEM;
+       p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
+       if (!p)
diff --git a/queue-2.6.27/pci-fix-incorrect-mask-of-pm-no_soft_reset-bit.patch b/queue-2.6.27/pci-fix-incorrect-mask-of-pm-no_soft_reset-bit.patch
new file mode 100644 (file)
index 0000000..5016a48
--- /dev/null
@@ -0,0 +1,29 @@
+From 998dd7c719f62dcfa91d7bf7f4eb9c160e03d817 Mon Sep 17 00:00:00 2001
+From: Yu Zhao <yu.zhao@intel.com>
+Date: Wed, 25 Feb 2009 13:15:52 +0800
+Subject: PCI: fix incorrect mask of PM No_Soft_Reset bit
+
+From: Yu Zhao <yu.zhao@intel.com>
+
+commit 998dd7c719f62dcfa91d7bf7f4eb9c160e03d817 upstream.
+
+Reviewed-by: Matthew Wilcox <matthew@wil.cx>
+Signed-off-by: Yu Zhao <yu.zhao@intel.com>
+Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/pci_regs.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/pci_regs.h
++++ b/include/linux/pci_regs.h
+@@ -234,7 +234,7 @@
+ #define  PCI_PM_CAP_PME_SHIFT 11      /* Start of the PME Mask in PMC */
+ #define PCI_PM_CTRL           4       /* PM control and status register */
+ #define  PCI_PM_CTRL_STATE_MASK       0x0003  /* Current power state (D0 to D3) */
+-#define  PCI_PM_CTRL_NO_SOFT_RESET    0x0004  /* No reset for D3hot->D0 */
++#define  PCI_PM_CTRL_NO_SOFT_RESET    0x0008  /* No reset for D3hot->D0 */
+ #define  PCI_PM_CTRL_PME_ENABLE       0x0100  /* PME pin enable */
+ #define  PCI_PM_CTRL_DATA_SEL_MASK    0x1e00  /* Data select (??) */
+ #define  PCI_PM_CTRL_DATA_SCALE_MASK  0x6000  /* Data scale (??) */
index dc9521a13676a19d6743f78012fdb65b7e0fa16a..bd10a4c8ce5467f388000987cb89632e77895f02 100644 (file)
@@ -47,3 +47,12 @@ mm-check-for-no-mmaps-in-exit_mmap.patch
 powerpc-sanitize-stack-pointer-in-signal-handling-code.patch
 ath9k-implement-io-serialization.patch
 ath9k-ar9280-pci-devices-must-serialize-io-as-well.patch
+b44-use-kernel-dma-addresses-for-the-kernel-dma-api.patch
+crypto-ixp4xx-fix-handling-of-chained-sg-buffers.patch
+exit_notify-kill-the-wrong-capable-check.patch
+fix-ptrace-slowness.patch
+fs-core-fixes.patch
+pci-fix-incorrect-mask-of-pm-no_soft_reset-bit.patch
+thinkpad-acpi-fix-led-blinking-through-timer-trigger.patch
+acpi-ec-add-some-basic-check-for-ecdt-data.patch
+acpi-ec-fix-compilation-warning.patch
diff --git a/queue-2.6.27/thinkpad-acpi-fix-led-blinking-through-timer-trigger.patch b/queue-2.6.27/thinkpad-acpi-fix-led-blinking-through-timer-trigger.patch
new file mode 100644 (file)
index 0000000..2ecab40
--- /dev/null
@@ -0,0 +1,132 @@
+From 75bd3bf2ade9d548be0d2bde60b5ee0fdce0b127 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 14 Apr 2009 02:44:11 +0000
+Subject: thinkpad-acpi: fix LED blinking through timer trigger
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 75bd3bf2ade9d548be0d2bde60b5ee0fdce0b127 upstream.
+
+The set_blink hook code in the LED subdriver would never manage to get
+a LED to blink, and instead it would just turn it on.  The consequence
+of this is that the "timer" trigger would not cause the LED to blink
+if given default parameters.
+
+This problem exists since 2.6.26-rc1.
+
+To fix it, switch the deferred LED work handling to use the
+thinkpad-acpi-specific LED status (off/on/blink) directly.
+
+This also makes the code easier to read, and to extend later.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: stable@kernel.org
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/misc/thinkpad_acpi.c |   41 +++++++++++++++++++----------------------
+ 1 file changed, 19 insertions(+), 22 deletions(-)
+
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -282,11 +282,17 @@ static u32 dbg_level;
+ static struct workqueue_struct *tpacpi_wq;
++enum led_status_t {
++      TPACPI_LED_OFF = 0,
++      TPACPI_LED_ON,
++      TPACPI_LED_BLINK,
++};
++
+ /* Special LED class that can defer work */
+ struct tpacpi_led_classdev {
+       struct led_classdev led_classdev;
+       struct work_struct work;
+-      enum led_brightness new_brightness;
++      enum led_status_t new_state;
+       unsigned int led;
+ };
+@@ -3478,7 +3484,7 @@ static void light_set_status_worker(stru
+                       container_of(work, struct tpacpi_led_classdev, work);
+       if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+-              light_set_status((data->new_brightness != LED_OFF));
++              light_set_status((data->new_state != TPACPI_LED_OFF));
+ }
+ static void light_sysfs_set(struct led_classdev *led_cdev,
+@@ -3488,7 +3494,8 @@ static void light_sysfs_set(struct led_c
+               container_of(led_cdev,
+                            struct tpacpi_led_classdev,
+                            led_classdev);
+-      data->new_brightness = brightness;
++      data->new_state = (brightness != LED_OFF) ?
++                              TPACPI_LED_ON : TPACPI_LED_OFF;
+       queue_work(tpacpi_wq, &data->work);
+ }
+@@ -3995,12 +4002,6 @@ enum {  /* For TPACPI_LED_OLD */
+       TPACPI_LED_EC_HLMS = 0x0e,      /* EC reg to select led to command */
+ };
+-enum led_status_t {
+-      TPACPI_LED_OFF = 0,
+-      TPACPI_LED_ON,
+-      TPACPI_LED_BLINK,
+-};
+-
+ static enum led_access_mode led_supported;
+ TPACPI_HANDLE(led, ec, "SLED",        /* 570 */
+@@ -4094,23 +4095,13 @@ static int led_set_status(const unsigned
+       return rc;
+ }
+-static void led_sysfs_set_status(unsigned int led,
+-                               enum led_brightness brightness)
+-{
+-      led_set_status(led,
+-                      (brightness == LED_OFF) ?
+-                      TPACPI_LED_OFF :
+-                      (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
+-                              TPACPI_LED_BLINK : TPACPI_LED_ON);
+-}
+-
+ static void led_set_status_worker(struct work_struct *work)
+ {
+       struct tpacpi_led_classdev *data =
+               container_of(work, struct tpacpi_led_classdev, work);
+       if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+-              led_sysfs_set_status(data->led, data->new_brightness);
++              led_set_status(data->led, data->new_state);
+ }
+ static void led_sysfs_set(struct led_classdev *led_cdev,
+@@ -4119,7 +4110,13 @@ static void led_sysfs_set(struct led_cla
+       struct tpacpi_led_classdev *data = container_of(led_cdev,
+                            struct tpacpi_led_classdev, led_classdev);
+-      data->new_brightness = brightness;
++      if (brightness == LED_OFF)
++              data->new_state = TPACPI_LED_OFF;
++      else if (tpacpi_led_state_cache[data->led] != TPACPI_LED_BLINK)
++              data->new_state = TPACPI_LED_ON;
++      else
++              data->new_state = TPACPI_LED_BLINK;
++
+       queue_work(tpacpi_wq, &data->work);
+ }
+@@ -4137,7 +4134,7 @@ static int led_sysfs_blink_set(struct le
+       } else if ((*delay_on != 500) || (*delay_off != 500))
+               return -EINVAL;
+-      data->new_brightness = TPACPI_LED_BLINK;
++      data->new_state = TPACPI_LED_BLINK;
+       queue_work(tpacpi_wq, &data->work);
+       return 0;