Skip to contentSkip to conversation

HIFN: schedule callback invocation to tasklet.

PATCH In review Evgeniy Polyakov 2 participants 3 messages Nov 9, 2007 – Nov 10, 2007 Crypto API

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 HIFN: schedule callback invocation to tasklet.

Hi.

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.

drivers/crypto/hifn_795x.c +19 -1
index e152917..f5aa939 100644
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/interrupt.h>
 #include <linux/crypto.h>
 
 #include <crypto/algapi.h>
@@ -425,6 +426,8 @@ struct hifn_device
 
 	u8			snum;
 
+	struct tasklet_struct	tasklet;
+
 	struct crypto_queue 	queue;
 	struct list_head	alg_list;
 };
@@ -1881,7 +1884,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
 		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
 	}
 
-	hifn_check_for_completion(dev, 0);
+	tasklet_schedule(&dev->tasklet);
 	hifn_clear_rings(dev);
 
 	return IRQ_HANDLED;
@@ -2414,6 +2417,19 @@ err_out_exit:
 	return err;
 }
 
+static void hifn_tasklet_callback(unsigned long data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+
+	/*
+	 * This is ok to call this without lock being held,
+	 * althogh it modifies some parameters used in parallel,
+	 * (like dev->success), but they are used in process
+	 * context or update is atomic (like setting dev->sa[i] to NULL).
+	 */
+	hifn_check_for_completion(dev, 0);
+}
+
 static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	int err, i;
@@ -2495,6 +2511,8 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_drvdata(pdev, dev);
 
+	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+
 	crypto_init_queue(&dev->queue, 1);
 
 	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
Signature · 1 line
	Evgeniy Polyakov
#1 lore raw
Quoted 3 lines · Evgeniy Polyakov

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.

And first patch is obviously wrong, since it does not stop tasklet on exit path, please apply given one.

drivers/crypto/hifn_795x.c +21 -1
index e152917..0a7c07b 100644
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/interrupt.h>
 #include <linux/crypto.h>
 
 #include <crypto/algapi.h>
@@ -425,6 +426,8 @@ struct hifn_device
 
 	u8			snum;
 
+	struct tasklet_struct	tasklet;
+
 	struct crypto_queue 	queue;
 	struct list_head	alg_list;
 };
@@ -1881,7 +1884,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
 		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
 	}
 
-	hifn_check_for_completion(dev, 0);
+	tasklet_schedule(&dev->tasklet);
 	hifn_clear_rings(dev);
 
 	return IRQ_HANDLED;
@@ -2414,6 +2417,19 @@ err_out_exit:
 	return err;
 }
 
+static void hifn_tasklet_callback(unsigned long data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+
+	/*
+	 * This is ok to call this without lock being held,
+	 * althogh it modifies some parameters used in parallel,
+	 * (like dev->success), but they are used in process
+	 * context or update is atomic (like setting dev->sa[i] to NULL).
+	 */
+	hifn_check_for_completion(dev, 0);
+}
+
 static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	int err, i;
@@ -2495,6 +2511,8 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_drvdata(pdev, dev);
 
+	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+
 	crypto_init_queue(&dev->queue, 1);
 
 	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
@@ -2530,6 +2548,7 @@ err_out_stop_device:
 	hifn_stop_device(dev);
 err_out_free_irq:
 	free_irq(dev->irq, dev->name);
+	tasklet_kill(&dev->tasklet);
 err_out_free_desc:
 	pci_free_consistent(pdev, sizeof(struct hifn_dma),
 			dev->desc_virt, dev->desc_dma);
@@ -2569,6 +2588,7 @@ static void hifn_remove(struct pci_dev *pdev)
 		hifn_stop_device(dev);
 
 		free_irq(dev->irq, dev->name);
+		tasklet_kill(&dev->tasklet);
 
 		hifn_flush(dev);
 
Signature · 1 line
	Evgeniy Polyakov
maintainer
#2 lore raw
Quoted 9 lines · Evgeniy Polyakov
Quoted 3 lines · Evgeniy Polyakov

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.

And first patch is obviously wrong, since it does not stop tasklet on exit path, please apply given one.

Patch applied. Thanks Evgeniy!

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt