aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Polyakov <johnpol@2ka.mipt.ru>2007-11-10 07:24:18 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2008-01-10 16:16:12 -0500
commita1e6ef2f1e01f2aa9ed930e1089fc85dc745bf7a (patch)
treeb061de93924ff3d4804c04ea7ed85990bb3161b4
parentcd12fb906d2591e80da9edcbd4794b9b916d7489 (diff)
[CRYPTO] hifn: Schedule callback invocation to tasklet.
This patch forces HIFN driver to invoke crypto request callbacks from tasklet (softirq context) instead of hardirq context, since network stack expects it to be called from bottom halves. It is done by simply scheduling callback invocation via dedicated tasklet. Workqueue solution was dropped because of tooo slow rescheduling performance (7 times slower than tasklet, for mode details one can check this link: http://tservice.net.ru/~s0mbre/blog/devel/other/2007_11_09.html). Driver passed all AES and DES tests in tcryt.c module. Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/hifn_795x.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 391c20a3dff8..7b7c85439c33 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -26,6 +26,7 @@
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/mm.h> 27#include <linux/mm.h>
28#include <linux/highmem.h> 28#include <linux/highmem.h>
29#include <linux/interrupt.h>
29#include <linux/crypto.h> 30#include <linux/crypto.h>
30 31
31#include <crypto/algapi.h> 32#include <crypto/algapi.h>
@@ -426,6 +427,8 @@ struct hifn_device
426 427
427 u8 snum; 428 u8 snum;
428 429
430 struct tasklet_struct tasklet;
431
429 struct crypto_queue queue; 432 struct crypto_queue queue;
430 struct list_head alg_list; 433 struct list_head alg_list;
431}; 434};
@@ -1879,7 +1882,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
1879 hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 1882 hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
1880 } 1883 }
1881 1884
1882 hifn_check_for_completion(dev, 0); 1885 tasklet_schedule(&dev->tasklet);
1883 hifn_clear_rings(dev); 1886 hifn_clear_rings(dev);
1884 1887
1885 return IRQ_HANDLED; 1888 return IRQ_HANDLED;
@@ -2408,6 +2411,19 @@ err_out_exit:
2408 return err; 2411 return err;
2409} 2412}
2410 2413
2414static void hifn_tasklet_callback(unsigned long data)
2415{
2416 struct hifn_device *dev = (struct hifn_device *)data;
2417
2418 /*
2419 * This is ok to call this without lock being held,
2420 * althogh it modifies some parameters used in parallel,
2421 * (like dev->success), but they are used in process
2422 * context or update is atomic (like setting dev->sa[i] to NULL).
2423 */
2424 hifn_check_for_completion(dev, 0);
2425}
2426
2411static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) 2427static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2412{ 2428{
2413 int err, i; 2429 int err, i;
@@ -2489,6 +2505,8 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2489 2505
2490 pci_set_drvdata(pdev, dev); 2506 pci_set_drvdata(pdev, dev);
2491 2507
2508 tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
2509
2492 crypto_init_queue(&dev->queue, 1); 2510 crypto_init_queue(&dev->queue, 1);
2493 2511
2494 err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev); 2512 err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
@@ -2524,6 +2542,7 @@ err_out_stop_device:
2524 hifn_stop_device(dev); 2542 hifn_stop_device(dev);
2525err_out_free_irq: 2543err_out_free_irq:
2526 free_irq(dev->irq, dev->name); 2544 free_irq(dev->irq, dev->name);
2545 tasklet_kill(&dev->tasklet);
2527err_out_free_desc: 2546err_out_free_desc:
2528 pci_free_consistent(pdev, sizeof(struct hifn_dma), 2547 pci_free_consistent(pdev, sizeof(struct hifn_dma),
2529 dev->desc_virt, dev->desc_dma); 2548 dev->desc_virt, dev->desc_dma);
@@ -2563,6 +2582,7 @@ static void hifn_remove(struct pci_dev *pdev)
2563 hifn_stop_device(dev); 2582 hifn_stop_device(dev);
2564 2583
2565 free_irq(dev->irq, dev->name); 2584 free_irq(dev->irq, dev->name);
2585 tasklet_kill(&dev->tasklet);
2566 2586
2567 hifn_flush(dev); 2587 hifn_flush(dev);
2568 2588