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); |
