]> Pileus Git - ~andy/linux/blobdiff - drivers/crypto/nx/nx.c
crypto: nx - fix concurrency issue
[~andy/linux] / drivers / crypto / nx / nx.c
index bbdab6e5ccf08f75fcc23481dbb9d29a1df6cd69..bdf4990f9758a59b6b3f73e1857ca8c91169f2cd 100644 (file)
@@ -61,8 +61,7 @@ int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
 
        do {
                rc = vio_h_cop_sync(viodev, op);
-       } while ((rc == -EBUSY && !may_sleep && retries--) ||
-                (rc == -EBUSY && may_sleep && cond_resched()));
+       } while (rc == -EBUSY && !may_sleep && retries--);
 
        if (rc) {
                dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
@@ -114,13 +113,29 @@ struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
         * have been described (or @sgmax elements have been written), the
         * loop ends. min_t is used to ensure @end_addr falls on the same page
         * as sg_addr, if not, we need to create another nx_sg element for the
-        * data on the next page */
+        * data on the next page.
+        *
+        * Also when using vmalloc'ed data, every time that a system page
+        * boundary is crossed the physical address needs to be re-calculated.
+        */
        for (sg = sg_head; sg_len < len; sg++) {
+               u64 next_page;
+
                sg->addr = sg_addr;
-               sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
-               sg->len = sg_addr - sg->addr;
+               sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE),
+                               end_addr);
+
+               next_page = (sg->addr & PAGE_MASK) + PAGE_SIZE;
+               sg->len = min_t(u64, sg_addr, next_page) - sg->addr;
                sg_len += sg->len;
 
+               if (sg_addr >= next_page &&
+                               is_vmalloc_addr(start_addr + sg_len)) {
+                       sg_addr = page_to_phys(vmalloc_to_page(
+                                               start_addr + sg_len));
+                       end_addr = sg_addr + len - sg_len;
+               }
+
                if ((sg - sg_head) == sgmax) {
                        pr_err("nx: scatter/gather list overflow, pid: %d\n",
                               current->pid);
@@ -235,6 +250,7 @@ int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
  */
 void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
 {
+       spin_lock_init(&nx_ctx->lock);
        memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
        nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;