diff options
author | Kim Phillips <kim.phillips@freescale.com> | 2009-08-12 21:50:38 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2009-08-12 21:50:38 -0400 |
commit | 4b992628812137e30cda3510510cf3c052345b30 (patch) | |
tree | 97797e65fc0c3e1b7ed51a5b250d9c44213b3ecb /drivers/crypto | |
parent | e41256f139b9148cfa12d2d057fec39e3d181ff0 (diff) |
crypto: talitos - align locks on cache lines
align channel access locks onto separate cache lines (for performance
reasons). This is done by placing per-channel variables into their own
private struct, and using the cacheline_aligned attribute within that
struct.
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/talitos.c | 141 |
1 files changed, 58 insertions, 83 deletions
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index b1a651c61829..5013a2dd47ed 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c | |||
@@ -86,6 +86,25 @@ struct talitos_request { | |||
86 | void *context; | 86 | void *context; |
87 | }; | 87 | }; |
88 | 88 | ||
89 | /* per-channel fifo management */ | ||
90 | struct talitos_channel { | ||
91 | /* request fifo */ | ||
92 | struct talitos_request *fifo; | ||
93 | |||
94 | /* number of requests pending in channel h/w fifo */ | ||
95 | atomic_t submit_count ____cacheline_aligned; | ||
96 | |||
97 | /* request submission (head) lock */ | ||
98 | spinlock_t head_lock ____cacheline_aligned; | ||
99 | /* index to next free descriptor request */ | ||
100 | int head; | ||
101 | |||
102 | /* request release (tail) lock */ | ||
103 | spinlock_t tail_lock ____cacheline_aligned; | ||
104 | /* index to next in-progress/done descriptor request */ | ||
105 | int tail; | ||
106 | }; | ||
107 | |||
89 | struct talitos_private { | 108 | struct talitos_private { |
90 | struct device *dev; | 109 | struct device *dev; |
91 | struct of_device *ofdev; | 110 | struct of_device *ofdev; |
@@ -101,15 +120,6 @@ struct talitos_private { | |||
101 | /* SEC Compatibility info */ | 120 | /* SEC Compatibility info */ |
102 | unsigned long features; | 121 | unsigned long features; |
103 | 122 | ||
104 | /* next channel to be assigned next incoming descriptor */ | ||
105 | atomic_t last_chan; | ||
106 | |||
107 | /* per-channel number of requests pending in channel h/w fifo */ | ||
108 | atomic_t *submit_count; | ||
109 | |||
110 | /* per-channel request fifo */ | ||
111 | struct talitos_request **fifo; | ||
112 | |||
113 | /* | 123 | /* |
114 | * length of the request fifo | 124 | * length of the request fifo |
115 | * fifo_len is chfifo_len rounded up to next power of 2 | 125 | * fifo_len is chfifo_len rounded up to next power of 2 |
@@ -117,15 +127,10 @@ struct talitos_private { | |||
117 | */ | 127 | */ |
118 | unsigned int fifo_len; | 128 | unsigned int fifo_len; |
119 | 129 | ||
120 | /* per-channel index to next free descriptor request */ | 130 | struct talitos_channel *chan; |
121 | int *head; | ||
122 | |||
123 | /* per-channel index to next in-progress/done descriptor request */ | ||
124 | int *tail; | ||
125 | 131 | ||
126 | /* per-channel request submission (head) and release (tail) locks */ | 132 | /* next channel to be assigned next incoming descriptor */ |
127 | spinlock_t *head_lock; | 133 | atomic_t last_chan ____cacheline_aligned; |
128 | spinlock_t *tail_lock; | ||
129 | 134 | ||
130 | /* request callback tasklet */ | 135 | /* request callback tasklet */ |
131 | struct tasklet_struct done_task; | 136 | struct tasklet_struct done_task; |
@@ -282,16 +287,16 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, | |||
282 | /* emulate SEC's round-robin channel fifo polling scheme */ | 287 | /* emulate SEC's round-robin channel fifo polling scheme */ |
283 | ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); | 288 | ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); |
284 | 289 | ||
285 | spin_lock_irqsave(&priv->head_lock[ch], flags); | 290 | spin_lock_irqsave(&priv->chan[ch].head_lock, flags); |
286 | 291 | ||
287 | if (!atomic_inc_not_zero(&priv->submit_count[ch])) { | 292 | if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { |
288 | /* h/w fifo is full */ | 293 | /* h/w fifo is full */ |
289 | spin_unlock_irqrestore(&priv->head_lock[ch], flags); | 294 | spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); |
290 | return -EAGAIN; | 295 | return -EAGAIN; |
291 | } | 296 | } |
292 | 297 | ||
293 | head = priv->head[ch]; | 298 | head = priv->chan[ch].head; |
294 | request = &priv->fifo[ch][head]; | 299 | request = &priv->chan[ch].fifo[head]; |
295 | 300 | ||
296 | /* map descriptor and save caller data */ | 301 | /* map descriptor and save caller data */ |
297 | request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), | 302 | request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), |
@@ -300,7 +305,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, | |||
300 | request->context = context; | 305 | request->context = context; |
301 | 306 | ||
302 | /* increment fifo head */ | 307 | /* increment fifo head */ |
303 | priv->head[ch] = (priv->head[ch] + 1) & (priv->fifo_len - 1); | 308 | priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1); |
304 | 309 | ||
305 | smp_wmb(); | 310 | smp_wmb(); |
306 | request->desc = desc; | 311 | request->desc = desc; |
@@ -309,7 +314,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, | |||
309 | wmb(); | 314 | wmb(); |
310 | out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); | 315 | out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); |
311 | 316 | ||
312 | spin_unlock_irqrestore(&priv->head_lock[ch], flags); | 317 | spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); |
313 | 318 | ||
314 | return -EINPROGRESS; | 319 | return -EINPROGRESS; |
315 | } | 320 | } |
@@ -324,11 +329,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) | |||
324 | unsigned long flags; | 329 | unsigned long flags; |
325 | int tail, status; | 330 | int tail, status; |
326 | 331 | ||
327 | spin_lock_irqsave(&priv->tail_lock[ch], flags); | 332 | spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); |
328 | 333 | ||
329 | tail = priv->tail[ch]; | 334 | tail = priv->chan[ch].tail; |
330 | while (priv->fifo[ch][tail].desc) { | 335 | while (priv->chan[ch].fifo[tail].desc) { |
331 | request = &priv->fifo[ch][tail]; | 336 | request = &priv->chan[ch].fifo[tail]; |
332 | 337 | ||
333 | /* descriptors with their done bits set don't get the error */ | 338 | /* descriptors with their done bits set don't get the error */ |
334 | rmb(); | 339 | rmb(); |
@@ -354,22 +359,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) | |||
354 | request->desc = NULL; | 359 | request->desc = NULL; |
355 | 360 | ||
356 | /* increment fifo tail */ | 361 | /* increment fifo tail */ |
357 | priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); | 362 | priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1); |
358 | 363 | ||
359 | spin_unlock_irqrestore(&priv->tail_lock[ch], flags); | 364 | spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); |
360 | 365 | ||
361 | atomic_dec(&priv->submit_count[ch]); | 366 | atomic_dec(&priv->chan[ch].submit_count); |
362 | 367 | ||
363 | saved_req.callback(dev, saved_req.desc, saved_req.context, | 368 | saved_req.callback(dev, saved_req.desc, saved_req.context, |
364 | status); | 369 | status); |
365 | /* channel may resume processing in single desc error case */ | 370 | /* channel may resume processing in single desc error case */ |
366 | if (error && !reset_ch && status == error) | 371 | if (error && !reset_ch && status == error) |
367 | return; | 372 | return; |
368 | spin_lock_irqsave(&priv->tail_lock[ch], flags); | 373 | spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); |
369 | tail = priv->tail[ch]; | 374 | tail = priv->chan[ch].tail; |
370 | } | 375 | } |
371 | 376 | ||
372 | spin_unlock_irqrestore(&priv->tail_lock[ch], flags); | 377 | spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); |
373 | } | 378 | } |
374 | 379 | ||
375 | /* | 380 | /* |
@@ -397,20 +402,20 @@ static void talitos_done(unsigned long data) | |||
397 | static struct talitos_desc *current_desc(struct device *dev, int ch) | 402 | static struct talitos_desc *current_desc(struct device *dev, int ch) |
398 | { | 403 | { |
399 | struct talitos_private *priv = dev_get_drvdata(dev); | 404 | struct talitos_private *priv = dev_get_drvdata(dev); |
400 | int tail = priv->tail[ch]; | 405 | int tail = priv->chan[ch].tail; |
401 | dma_addr_t cur_desc; | 406 | dma_addr_t cur_desc; |
402 | 407 | ||
403 | cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); | 408 | cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); |
404 | 409 | ||
405 | while (priv->fifo[ch][tail].dma_desc != cur_desc) { | 410 | while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) { |
406 | tail = (tail + 1) & (priv->fifo_len - 1); | 411 | tail = (tail + 1) & (priv->fifo_len - 1); |
407 | if (tail == priv->tail[ch]) { | 412 | if (tail == priv->chan[ch].tail) { |
408 | dev_err(dev, "couldn't locate current descriptor\n"); | 413 | dev_err(dev, "couldn't locate current descriptor\n"); |
409 | return NULL; | 414 | return NULL; |
410 | } | 415 | } |
411 | } | 416 | } |
412 | 417 | ||
413 | return priv->fifo[ch][tail].desc; | 418 | return priv->chan[ch].fifo[tail].desc; |
414 | } | 419 | } |
415 | 420 | ||
416 | /* | 421 | /* |
@@ -1740,17 +1745,11 @@ static int talitos_remove(struct of_device *ofdev) | |||
1740 | if (hw_supports(dev, DESC_HDR_SEL0_RNG)) | 1745 | if (hw_supports(dev, DESC_HDR_SEL0_RNG)) |
1741 | talitos_unregister_rng(dev); | 1746 | talitos_unregister_rng(dev); |
1742 | 1747 | ||
1743 | kfree(priv->submit_count); | 1748 | for (i = 0; i < priv->num_channels; i++) |
1744 | kfree(priv->tail); | 1749 | if (priv->chan[i].fifo) |
1745 | kfree(priv->head); | 1750 | kfree(priv->chan[i].fifo); |
1746 | |||
1747 | if (priv->fifo) | ||
1748 | for (i = 0; i < priv->num_channels; i++) | ||
1749 | kfree(priv->fifo[i]); | ||
1750 | 1751 | ||
1751 | kfree(priv->fifo); | 1752 | kfree(priv->chan); |
1752 | kfree(priv->head_lock); | ||
1753 | kfree(priv->tail_lock); | ||
1754 | 1753 | ||
1755 | if (priv->irq != NO_IRQ) { | 1754 | if (priv->irq != NO_IRQ) { |
1756 | free_irq(priv->irq, dev); | 1755 | free_irq(priv->irq, dev); |
@@ -1870,58 +1869,34 @@ static int talitos_probe(struct of_device *ofdev, | |||
1870 | if (of_device_is_compatible(np, "fsl,sec2.1")) | 1869 | if (of_device_is_compatible(np, "fsl,sec2.1")) |
1871 | priv->features |= TALITOS_FTR_HW_AUTH_CHECK; | 1870 | priv->features |= TALITOS_FTR_HW_AUTH_CHECK; |
1872 | 1871 | ||
1873 | priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1872 | priv->chan = kzalloc(sizeof(struct talitos_channel) * |
1874 | GFP_KERNEL); | 1873 | priv->num_channels, GFP_KERNEL); |
1875 | priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1874 | if (!priv->chan) { |
1876 | GFP_KERNEL); | 1875 | dev_err(dev, "failed to allocate channel management space\n"); |
1877 | if (!priv->head_lock || !priv->tail_lock) { | ||
1878 | dev_err(dev, "failed to allocate fifo locks\n"); | ||
1879 | err = -ENOMEM; | 1876 | err = -ENOMEM; |
1880 | goto err_out; | 1877 | goto err_out; |
1881 | } | 1878 | } |
1882 | 1879 | ||
1883 | for (i = 0; i < priv->num_channels; i++) { | 1880 | for (i = 0; i < priv->num_channels; i++) { |
1884 | spin_lock_init(&priv->head_lock[i]); | 1881 | spin_lock_init(&priv->chan[i].head_lock); |
1885 | spin_lock_init(&priv->tail_lock[i]); | 1882 | spin_lock_init(&priv->chan[i].tail_lock); |
1886 | } | ||
1887 | |||
1888 | priv->fifo = kmalloc(sizeof(struct talitos_request *) * | ||
1889 | priv->num_channels, GFP_KERNEL); | ||
1890 | if (!priv->fifo) { | ||
1891 | dev_err(dev, "failed to allocate request fifo\n"); | ||
1892 | err = -ENOMEM; | ||
1893 | goto err_out; | ||
1894 | } | 1883 | } |
1895 | 1884 | ||
1896 | priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); | 1885 | priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); |
1897 | 1886 | ||
1898 | for (i = 0; i < priv->num_channels; i++) { | 1887 | for (i = 0; i < priv->num_channels; i++) { |
1899 | priv->fifo[i] = kzalloc(sizeof(struct talitos_request) * | 1888 | priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) * |
1900 | priv->fifo_len, GFP_KERNEL); | 1889 | priv->fifo_len, GFP_KERNEL); |
1901 | if (!priv->fifo[i]) { | 1890 | if (!priv->chan[i].fifo) { |
1902 | dev_err(dev, "failed to allocate request fifo %d\n", i); | 1891 | dev_err(dev, "failed to allocate request fifo %d\n", i); |
1903 | err = -ENOMEM; | 1892 | err = -ENOMEM; |
1904 | goto err_out; | 1893 | goto err_out; |
1905 | } | 1894 | } |
1906 | } | 1895 | } |
1907 | 1896 | ||
1908 | priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels, | ||
1909 | GFP_KERNEL); | ||
1910 | if (!priv->submit_count) { | ||
1911 | dev_err(dev, "failed to allocate fifo submit count space\n"); | ||
1912 | err = -ENOMEM; | ||
1913 | goto err_out; | ||
1914 | } | ||
1915 | for (i = 0; i < priv->num_channels; i++) | 1897 | for (i = 0; i < priv->num_channels; i++) |
1916 | atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1)); | 1898 | atomic_set(&priv->chan[i].submit_count, |
1917 | 1899 | -(priv->chfifo_len - 1)); | |
1918 | priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); | ||
1919 | priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); | ||
1920 | if (!priv->head || !priv->tail) { | ||
1921 | dev_err(dev, "failed to allocate request index space\n"); | ||
1922 | err = -ENOMEM; | ||
1923 | goto err_out; | ||
1924 | } | ||
1925 | 1900 | ||
1926 | /* reset and initialize the h/w */ | 1901 | /* reset and initialize the h/w */ |
1927 | err = init_device(dev); | 1902 | err = init_device(dev); |