Skip to content

Commit

Permalink
[CRYPTO] hifn: Schedule callback invocation to tasklet.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
Evgeniy Polyakov authored and herbertx committed Jan 10, 2008
1 parent cd12fb9 commit a1e6ef2
Showing 1 changed file with 21 additions and 1 deletion.
22 changes: 21 additions & 1 deletion drivers/crypto/hifn_795x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -426,6 +427,8 @@ struct hifn_device

u8 snum;

struct tasklet_struct tasklet;

struct crypto_queue queue;
struct list_head alg_list;
};
Expand Down Expand Up @@ -1879,7 +1882,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;
Expand Down Expand Up @@ -2408,6 +2411,19 @@ static int hifn_register_alg(struct hifn_device *dev)
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;
Expand Down Expand Up @@ -2489,6 +2505,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);
Expand Down Expand Up @@ -2524,6 +2542,7 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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);
Expand Down Expand Up @@ -2563,6 +2582,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);

Expand Down

0 comments on commit a1e6ef2

Please sign in to comment.