From: Martin Hicks <hidden> Date: 2015-03-03 13:21:49
I was testing dm-crypt performance with a Freescale P1022 board with
a recent kernel and was getting IO errors while doing testing with LUKS.
Investigation showed that all hardware FIFO slots were filling and
the driver was returning EAGAIN to the block layer, which is not an
expected response for an async crypto implementation.
The following patch series adds a few small fixes, and reworks the
submission path to use the crypto_queue mechanism to handle the
request backlog.
Changes since v1:
- Ran checkpatch.pl
- Split the path for submitting new requests vs. issuing backlogged
requests.
- Avoid enqueuing a submitted request to the crypto queue unnecessarily.
- Fix return paths where CRYPTO_TFM_REQ_MAY_BACKLOG is not set.
Martin Hicks (5):
crypto: talitos: Simplify per-channel initialization
crypto: talitos: Remove MD5_BLOCK_SIZE
crypto: talitos: Fix off-by-one and use all hardware slots
crypto: talitos: Reorganize request submission data structures
crypto: talitos: Add software backlog queue handling
drivers/crypto/talitos.c | 240 +++++++++++++++++++++++++++-------------------
drivers/crypto/talitos.h | 44 +++++++--
2 files changed, 177 insertions(+), 107 deletions(-)
--
1.7.10.4
From: Martin Hicks <hidden> Date: 2015-03-03 13:21:50
There were multiple loops in a row, for each separate step of the
initialization of the channels. Simplify to a single loop.
Signed-off-by: Martin Hicks <redacted>
---
drivers/crypto/talitos.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
From: Martin Hicks <hidden> Date: 2015-03-03 13:21:51
This is properly defined in the md5 header file.
Signed-off-by: Martin Hicks <redacted>
---
drivers/crypto/talitos.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Martin Hicks <hidden> Date: 2015-03-03 13:21:52
The submission count was off by one.
Signed-off-by: Martin Hicks <redacted>
---
drivers/crypto/talitos.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
From: Martin Hicks <hidden> Date: 2015-03-03 13:21:54
This is preparatory work for moving to using the crypto async queue
handling code. A talitos_request structure is buried into each
talitos_edesc so that when talitos_submit() is called, everything required
to defer the submission to the hardware is contained within talitos_edesc.
Signed-off-by: Martin Hicks <redacted>
---
drivers/crypto/talitos.c | 95 +++++++++++++++-------------------------------
drivers/crypto/talitos.h | 41 +++++++++++++++++---
2 files changed, 66 insertions(+), 70 deletions(-)
@@ -186,22 +186,16 @@ static int init_device(struct device *dev)*talitos_submit-submitsadescriptortothedeviceforprocessing*@dev:theSECdevicetobeused*@ch:theSECdevicechanneltobeused-*@desc:thedescriptortobeprocessedbythedevice-*@callback:whomtocallwhenprocessingiscomplete-*@context:ahandleforusebycaller(optional)+*@edesc:thedescriptortobeprocessedbythedevice**descmustcontainvaliddma-mapped(busphysical)addresspointers.*callbackmustcheckerrandfeedbackindescriptorheader*fordeviceprocessingstatus.*/-inttalitos_submit(structdevice*dev,intch,structtalitos_desc*desc,-void(*callback)(structdevice*dev,-structtalitos_desc*desc,-void*context,interror),-void*context)+inttalitos_submit(structdevice*dev,intch,structtalitos_edesc*edesc){structtalitos_private*priv=dev_get_drvdata(dev);-structtalitos_request*request;+structtalitos_request*request=&edesc->req;unsignedlongflags;inthead;
@@ -214,19 +208,15 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,}head=priv->chan[ch].head;-request=&priv->chan[ch].fifo[head];--/* map descriptor and save caller data */-request->dma_desc=dma_map_single(dev,desc,sizeof(*desc),+request->dma_desc=dma_map_single(dev,request->desc,+sizeof(*request->desc),DMA_BIDIRECTIONAL);-request->callback=callback;-request->context=context;/* increment fifo head */priv->chan[ch].head=(priv->chan[ch].head+1)&(priv->fifo_len-1);smp_wmb();-request->desc=desc;+priv->chan[ch].fifo[head]=request;/* GO! */wmb();
@@ -247,15 +237,16 @@ EXPORT_SYMBOL(talitos_submit);staticvoidflush_channel(structdevice*dev,intch,interror,intreset_ch){structtalitos_private*priv=dev_get_drvdata(dev);-structtalitos_request*request,saved_req;+structtalitos_request*request;unsignedlongflags;inttail,status;spin_lock_irqsave(&priv->chan[ch].tail_lock,flags);tail=priv->chan[ch].tail;-while(priv->chan[ch].fifo[tail].desc){-request=&priv->chan[ch].fifo[tail];+while(priv->chan[ch].fifo[tail]){+request=priv->chan[ch].fifo[tail];+status=0;/* descriptors with their done bits set don't get the error */rmb();
@@ -271,14 +262,9 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)sizeof(structtalitos_desc),DMA_BIDIRECTIONAL);-/* copy entries so we can call callback outside lock */-saved_req.desc=request->desc;-saved_req.callback=request->callback;-saved_req.context=request->context;-/* release request entry in fifo */smp_wmb();-request->desc=NULL;+priv->chan[ch].fifo[tail]=NULL;/* increment fifo tail */priv->chan[ch].tail=(tail+1)&(priv->fifo_len-1);
@@ -287,8 +273,8 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)atomic_dec(&priv->chan[ch].submit_count);-saved_req.callback(dev,saved_req.desc,saved_req.context,-status);+request->callback(dev,request->desc,request->context,status);+/* channel may resume processing in single desc error case */if(error&&!reset_ch&&status==error)return;
@@ -352,7 +338,8 @@ static u32 current_desc_hdr(struct device *dev, int ch)tail=priv->chan[ch].tail;iter=tail;-while(priv->chan[ch].fifo[iter].dma_desc!=cur_desc){+while(priv->chan[ch].fifo[iter]&&+priv->chan[ch].fifo[iter]->dma_desc!=cur_desc){iter=(iter+1)&(priv->fifo_len-1);if(iter==tail){dev_err(dev,"couldn't locate current descriptor\n");
From: Martin Hicks <hidden> Date: 2015-03-03 13:21:55
I was running into situations where the hardware FIFO was filling up, and
the code was returning EAGAIN to dm-crypt and just dropping the submitted
crypto request.
This adds support in talitos for a software backlog queue. When requests
can't be queued to the hardware immediately EBUSY is returned. The queued
requests are dispatched to the hardware in received order as hardware FIFO
slots become available.
Signed-off-by: Martin Hicks <redacted>
---
drivers/crypto/talitos.c | 135 ++++++++++++++++++++++++++++++++++++----------
drivers/crypto/talitos.h | 3 ++
2 files changed, 110 insertions(+), 28 deletions(-)
@@ -182,55 +182,118 @@ static int init_device(struct device *dev)return0;}-/**-*talitos_submit-submitsadescriptortothedeviceforprocessing-*@dev:theSECdevicetobeused-*@ch:theSECdevicechanneltobeused-*@edesc:thedescriptortobeprocessedbythedevice-*-*descmustcontainvaliddma-mapped(busphysical)addresspointers.-*callbackmustcheckerrandfeedbackindescriptorheader-*fordeviceprocessingstatus.-*/-inttalitos_submit(structdevice*dev,intch,structtalitos_edesc*edesc)+/* Dispatch 'request' if provided, otherwise a backlogged request */+staticint__talitos_handle_queue(structdevice*dev,intch,+structtalitos_edesc*edesc,+unsignedlong*irq_flags){structtalitos_private*priv=dev_get_drvdata(dev);-structtalitos_request*request=&edesc->req;-unsignedlongflags;+structtalitos_request*request;+structcrypto_async_request*areq;inthead;+intret=-EINPROGRESS;-spin_lock_irqsave(&priv->chan[ch].head_lock,flags);--if(!atomic_inc_not_zero(&priv->chan[ch].submit_count)){+if(!atomic_inc_not_zero(&priv->chan[ch].submit_count))/* h/w fifo is full */-spin_unlock_irqrestore(&priv->chan[ch].head_lock,flags);-return-EAGAIN;+return-EBUSY;++if(!edesc){+/* Dequeue the oldest request */+areq=crypto_dequeue_request(&priv->chan[ch].queue);+request=container_of(areq,structtalitos_request,base);+}else{+request=&edesc->req;}-head=priv->chan[ch].head;request->dma_desc=dma_map_single(dev,request->desc,sizeof(*request->desc),DMA_BIDIRECTIONAL);/* increment fifo head */+head=priv->chan[ch].head;priv->chan[ch].head=(priv->chan[ch].head+1)&(priv->fifo_len-1);-smp_wmb();-priv->chan[ch].fifo[head]=request;+spin_unlock_irqrestore(&priv->chan[ch].head_lock,*irq_flags);++/*+*Markabackloggedrequestasin-progress.+*/+if(!edesc){+areq=request->context;+areq->complete(areq,-EINPROGRESS);+}++spin_lock_irqsave(&priv->chan[ch].head_lock,*irq_flags);/* GO! */+priv->chan[ch].fifo[head]=request;wmb();out_be32(priv->chan[ch].reg+TALITOS_FF,upper_32_bits(request->dma_desc));out_be32(priv->chan[ch].reg+TALITOS_FF_LO,lower_32_bits(request->dma_desc));+returnret;+}++/**+*talitos_submit-performssubmissionsofanewdescriptors+*+*@dev:theSECdevicetobeused+*@ch:theSECdevicechanneltobeused+*@edesc:therequesttobeprocessedbythedevice+*+*edesc->reqmustcontainvaliddma-mapped(busphysical)addresspointers.+*callbackmustcheckerrandfeedbackindescriptorheader+*fordeviceprocessingstatusuponcompletion.+*/+inttalitos_submit(structdevice*dev,intch,structtalitos_edesc*edesc)+{+structtalitos_private*priv=dev_get_drvdata(dev);+structtalitos_request*request=&edesc->req;+unsignedlongflags;+intret=-EINPROGRESS;++spin_lock_irqsave(&priv->chan[ch].head_lock,flags);++if(priv->chan[ch].queue.qlen){+/*+*Therearebackloggedrequests.Justqueuethisnewrequest+*anddispatchtheoldestbackloggedrequesttothehardware.+*/+crypto_enqueue_request(&priv->chan[ch].queue,+&request->base);+__talitos_handle_queue(dev,ch,NULL,&flags);+ret=-EBUSY;+}else{+ret=__talitos_handle_queue(dev,ch,edesc,&flags);+if(ret==-EBUSY)+/* Hardware FIFO is full */+crypto_enqueue_request(&priv->chan[ch].queue,+&request->base);+}+spin_unlock_irqrestore(&priv->chan[ch].head_lock,flags);-return-EINPROGRESS;+returnret;}EXPORT_SYMBOL(talitos_submit);+staticinttalitos_handle_queue(structdevice*dev,intch)+{+structtalitos_private*priv=dev_get_drvdata(dev);+unsignedlongflags;+intret=-EINPROGRESS;++spin_lock_irqsave(&priv->chan[ch].head_lock,flags);+/* Queue backlogged requests as long as the hardware has room */+while(priv->chan[ch].queue.qlen&&ret==-EINPROGRESS)+ret=__talitos_handle_queue(dev,ch,NULL,&flags);+spin_unlock_irqrestore(&priv->chan[ch].head_lock,flags);++return0;+}+/**processwhatwasdone,notifycallbackoferrorifnot*/
@@ -283,6 +346,8 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)}spin_unlock_irqrestore(&priv->chan[ch].tail_lock,flags);++talitos_handle_queue(dev,ch);}/*
@@ -1170,6 +1237,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,edesc->dma_len,DMA_BIDIRECTIONAL);edesc->req.desc=&edesc->desc;+/* A copy of the crypto_async_request to use the crypto_queue backlog */+memcpy(&edesc->req.base,areq,sizeof(structcrypto_async_request));returnedesc;}
@@ -91,6 +92,8 @@ struct talitos_channel {spinlock_ttail_lock____cacheline_aligned;/* index to next in-progress/done descriptor request */inttail;++structcrypto_queuequeue;};structtalitos_private{
From: Kim Phillips <hidden> Date: 2015-03-04 00:28:53
On Tue, 3 Mar 2015 08:21:37 -0500
Martin Hicks [off-list ref] wrote:
quoted hunk
@@ -1170,6 +1237,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc->dma_len, DMA_BIDIRECTIONAL); edesc->req.desc = &edesc->desc;+ /* A copy of the crypto_async_request to use the crypto_queue backlog */+ memcpy(&edesc->req.base, areq, sizeof(struct crypto_async_request));
this seems backward, or, at least can be done more efficiently IMO:
talitos_cra_init should set the tfm's reqsize so the rest of
the driver can wholly embed its talitos_edesc (which should also
wholly encapsulate its talitos_request (i.e., not via a pointer))
into the crypto API's request handle allocation. This
would absorb and eliminate the talitos_edesc kmalloc and frees, the
above memcpy, and replace the container_of after the
crypto_dequeue_request with an offset_of, right?
When scatter-gather buffers are needed, we can assume a slower-path
and make them do their own allocations, since their sizes vary
depending on each request. Of course, a pointer to those
allocations would need to be retained somewhere in the request
handle.
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Kim
From: Kim Phillips <hidden> Date: 2015-03-04 00:40:50
On Tue, 3 Mar 2015 08:21:35 -0500
Martin Hicks [off-list ref] wrote:
The submission count was off by one.
Signed-off-by: Martin Hicks <redacted>
---
sadly, this directly contradicts:
commit 4b24ea971a93f5d0bec34bf7bfd0939f70cfaae6
Author: Vishnu Suresh [off-list ref]
Date: Mon Oct 20 21:06:18 2008 +0800
crypto: talitos - Preempt overflow interrupts off-by-one fix
My guess is your request submission pattern differs from that of
Vishnu's (probably IPSec and/or tcrypt), or later h/w versions have
gotten better about dealing with channel near-overflow conditions.
Either way, I'd prefer we not do this: it might break others, and
I'm guessing doesn't improve performance _that_ much?
If it does, we could risk it and restrict it to SEC versions 3.3 and
above maybe? Not sure what to do here exactly, barring digging up
and old 2.x SEC and testing.
Kim
p.s. I checked, Vishnu isn't with Freescale anymore, so I can't
cc him.
From: Martin Hicks <hidden> Date: 2015-03-04 14:46:20
Ok, I'm fine dropping this patch. I'm sure it doesn't affect
performance in a measurable way.
mh
On Tue, Mar 3, 2015 at 7:35 PM, Kim Phillips [off-list ref] wrote:
On Tue, 3 Mar 2015 08:21:35 -0500
Martin Hicks [off-list ref] wrote:
quoted
The submission count was off by one.
Signed-off-by: Martin Hicks <redacted>
---
sadly, this directly contradicts:
commit 4b24ea971a93f5d0bec34bf7bfd0939f70cfaae6
Author: Vishnu Suresh [off-list ref]
Date: Mon Oct 20 21:06:18 2008 +0800
crypto: talitos - Preempt overflow interrupts off-by-one fix
My guess is your request submission pattern differs from that of
Vishnu's (probably IPSec and/or tcrypt), or later h/w versions have
gotten better about dealing with channel near-overflow conditions.
Either way, I'd prefer we not do this: it might break others, and
I'm guessing doesn't improve performance _that_ much?
If it does, we could risk it and restrict it to SEC versions 3.3 and
above maybe? Not sure what to do here exactly, barring digging up
and old 2.x SEC and testing.
Kim
p.s. I checked, Vishnu isn't with Freescale anymore, so I can't
cc him.
--
Martin Hicks P.Eng. | mort@bork.org
Bork Consulting Inc. | +1 (613) 266-2296
On Tue, 3 Mar 2015 08:21:37 -0500
Martin Hicks [off-list ref] wrote:
quoted
@@ -1170,6 +1237,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc->dma_len, DMA_BIDIRECTIONAL); edesc->req.desc = &edesc->desc;+ /* A copy of the crypto_async_request to use the crypto_queue backlog */+ memcpy(&edesc->req.base, areq, sizeof(struct crypto_async_request));
this seems backward, or, at least can be done more efficiently IMO:
talitos_cra_init should set the tfm's reqsize so the rest of
the driver can wholly embed its talitos_edesc (which should also
wholly encapsulate its talitos_request (i.e., not via a pointer))
into the crypto API's request handle allocation. This
would absorb and eliminate the talitos_edesc kmalloc and frees, the
above memcpy, and replace the container_of after the
crypto_dequeue_request with an offset_of, right?
When scatter-gather buffers are needed, we can assume a slower-path
and make them do their own allocations, since their sizes vary
depending on each request. Of course, a pointer to those
allocations would need to be retained somewhere in the request
handle.
Unfortunately talitos_edesc structure size is most of the times
variable. Its exact size can only be established at "request time", and
not at "tfm init time".
Fixed size would be sizeof(talitos_edesc).
Below are factors that influence the variable part, i.e. link_tbl in
talitos_edesc:
- whether any assoc / src / dst data is scattered
- icv_stashing (case when ICV checking is done in SW)
Still we'd be better with:
-crypto API allocates request + request context (i.e.
sizeof(talitos_edesc) + any alignment required)
-talitos driver allocates variable part of talitos_edesc (if needed)
instead of:
-crypto API allocates request
-talitos driver allocates talitos_edesc (fixed + variable)
-memcopy of the req.base (crypto_async_request) into talitos_edesc
both in terms of performance and readability.
At first look, the driver wouldn't change that much:
-talitos_cra_init() callback would have to set tfm.reqsize to
sizeof(talitos_edesc) + padding and also add the CRYPTO_TFM_REQ_DMA
indication in tfm.crt_flags
-talitos_edesc_alloc() logic would be pretty much the same, but would
allocate memory only for the link_tbl
I'm willing to do these changes if needed.
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Right. And this flag would apply only to request __ctx[].
Herbert, would this be an acceptable addition to crypto API?
Thanks,
Horia
From: Kim Phillips <hidden> Date: 2015-03-06 00:11:59
On Tue, 3 Mar 2015 08:21:33 -0500
Martin Hicks [off-list ref] wrote:
There were multiple loops in a row, for each separate step of the
initialization of the channels. Simplify to a single loop.
Signed-off-by: Martin Hicks <redacted>
---
From: Kim Phillips <hidden> Date: 2015-03-06 00:40:22
On Thu, 5 Mar 2015 11:35:23 +0200
Horia Geantă [off-list ref] wrote:
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
On Tue, 3 Mar 2015 08:21:37 -0500
Martin Hicks [off-list ref] wrote:
quoted
@@ -1170,6 +1237,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc->dma_len, DMA_BIDIRECTIONAL); edesc->req.desc = &edesc->desc;+ /* A copy of the crypto_async_request to use the crypto_queue backlog */+ memcpy(&edesc->req.base, areq, sizeof(struct crypto_async_request));
this seems backward, or, at least can be done more efficiently IMO:
talitos_cra_init should set the tfm's reqsize so the rest of
the driver can wholly embed its talitos_edesc (which should also
wholly encapsulate its talitos_request (i.e., not via a pointer))
into the crypto API's request handle allocation. This
would absorb and eliminate the talitos_edesc kmalloc and frees, the
above memcpy, and replace the container_of after the
crypto_dequeue_request with an offset_of, right?
When scatter-gather buffers are needed, we can assume a slower-path
and make them do their own allocations, since their sizes vary
depending on each request. Of course, a pointer to those
allocations would need to be retained somewhere in the request
handle.
Unfortunately talitos_edesc structure size is most of the times
variable. Its exact size can only be established at "request time", and
not at "tfm init time".
yes, I was suggesting a common minimum should be set in cra_init.
Fixed size would be sizeof(talitos_edesc).
Below are factors that influence the variable part, i.e. link_tbl in
talitos_edesc:
- whether any assoc / src / dst data is scattered
- icv_stashing (case when ICV checking is done in SW)
both being slow(er) paths, IMO.
Still we'd be better with:
-crypto API allocates request + request context (i.e.
sizeof(talitos_edesc) + any alignment required)
-talitos driver allocates variable part of talitos_edesc (if needed)
instead of:
-crypto API allocates request
-talitos driver allocates talitos_edesc (fixed + variable)
-memcopy of the req.base (crypto_async_request) into talitos_edesc
both in terms of performance and readability.
indeed.
At first look, the driver wouldn't change that much:
-talitos_cra_init() callback would have to set tfm.reqsize to
sizeof(talitos_edesc) + padding and also add the CRYPTO_TFM_REQ_DMA
indication in tfm.crt_flags
-talitos_edesc_alloc() logic would be pretty much the same, but would
allocate memory only for the link_tbl
I'm willing to do these changes if needed.
Please coordinate with Martin.
fwiw, caam could use this, too.
Kim
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2015-03-06 04:48:42
On Thu, Mar 05, 2015 at 11:35:23AM +0200, Horia Geantă wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Right. And this flag would apply only to request __ctx[].
Herbert, would this be an acceptable addition to crypto API?
On Thu, Mar 05, 2015 at 11:35:23AM +0200, Horia Geantă wrote:
quoted
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Right. And this flag would apply only to request __ctx[].
Herbert, would this be an acceptable addition to crypto API?
How would such a flag work?
Hm, I thought that GFP_DMA memory could be allocated only for request
private ctx. This is obviously not the case.
*_request_alloc(tfm, gfp) crypto API functions would do:
if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_DMA)
gfp |= GFP_DMA;
Thanks,
Horia
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
Thanks,
Horia
From: Kim Phillips <hidden> Date: 2015-03-17 00:19:35
On Mon, 16 Mar 2015 12:02:51 +0200
Horia Geantă [off-list ref] wrote:
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
why not?
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
would modifying the crypto API to either have a different
*_request_alloc() API, and/or adding calls to negotiate the GFP mask
between crypto users and drivers, e.g., get/set_gfp_mask, work?
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
There's a comment in esp_alloc_tmp(): "Use spare space in skb for
this where possible," which is ideally where we'd want to be (esp.
because that memory could already be DMA-able). Your above
suggestion would be in the opposite direction of that.
Kim
On Mon, 16 Mar 2015 12:02:51 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
why not?
It would imply having 2 memory allocations, one for crypto request and
the other for the rest of the data bundled with the request (for IPsec
that would be ESN + space for IV + sg entries for authenticated-only
data and sk_buff extension, if needed).
Trying to have a single allocation by making ESN, IV etc. part of the
request private context requires modifying tfm.reqsize on the fly.
This won't work without adding some kind of locking for the tfm.
quoted
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
would modifying the crypto API to either have a different
*_request_alloc() API, and/or adding calls to negotiate the GFP mask
between crypto users and drivers, e.g., get/set_gfp_mask, work?
I think what DaveM asked for was the change to be transparent.
Besides converting to *_request_alloc(), seems that all other options
require some extra awareness from the user.
Could you elaborate on the idea above?
quoted
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
There's a comment in esp_alloc_tmp(): "Use spare space in skb for
this where possible," which is ideally where we'd want to be (esp.
Ok, I'll check that. But note the "where possible" - finding room in the
skb to avoid the allocation won't always be the case, and then we're
back to square one.
because that memory could already be DMA-able). Your above
suggestion would be in the opposite direction of that.
The proposal:
-removes dma (un)mapping on the fast path
-avoids requesting dma mappable memory for more than it's actually
needed (CRYPTO_TFM_REQ_DMA forces entire request to be mappable, not
only its private context)
-for caam it has the added benefit of speeding the below search for the
offending descriptor in the SW ring from O(n) to O(1):
for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
sw_idx = (tail + i) & (JOBR_DEPTH - 1);
if (jrp->outring[hw_idx].desc ==
jrp->entinfo[sw_idx].desc_addr_dma)
break; /* found */
}
(drivers/crypto/caam/jr.c - caam_dequeue)
Horia
From: Kim Phillips <hidden> Date: 2015-03-17 22:08:42
On Tue, 17 Mar 2015 19:58:55 +0200
Horia Geantă [off-list ref] wrote:
On 3/17/2015 2:19 AM, Kim Phillips wrote:
quoted
On Mon, 16 Mar 2015 12:02:51 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
why not?
It would imply having 2 memory allocations, one for crypto request and
the other for the rest of the data bundled with the request (for IPsec
that would be ESN + space for IV + sg entries for authenticated-only
data and sk_buff extension, if needed).
Trying to have a single allocation by making ESN, IV etc. part of the
request private context requires modifying tfm.reqsize on the fly.
This won't work without adding some kind of locking for the tfm.
can't a common minimum tfm.reqsize be co-established up front, at
least for the fast path?
quoted
quoted
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
would modifying the crypto API to either have a different
*_request_alloc() API, and/or adding calls to negotiate the GFP mask
between crypto users and drivers, e.g., get/set_gfp_mask, work?
I think what DaveM asked for was the change to be transparent.
Besides converting to *_request_alloc(), seems that all other options
require some extra awareness from the user.
Could you elaborate on the idea above?
was merely suggesting communicating GFP flags anonymously across the
API, i.e., GFP_DMA wouldn't appear in user code.
quoted
quoted
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
There's a comment in esp_alloc_tmp(): "Use spare space in skb for
this where possible," which is ideally where we'd want to be (esp.
Ok, I'll check that. But note the "where possible" - finding room in the
skb to avoid the allocation won't always be the case, and then we're
back to square one.
quoted
because that memory could already be DMA-able). Your above
suggestion would be in the opposite direction of that.
The proposal:
-removes dma (un)mapping on the fast path
sure, but at the expense of additional complexity.
-avoids requesting dma mappable memory for more than it's actually
needed (CRYPTO_TFM_REQ_DMA forces entire request to be mappable, not
only its private context)
compared to the payload? Plus, we have plenty of DMA space these
days.
-for caam it has the added benefit of speeding the below search for the
offending descriptor in the SW ring from O(n) to O(1):
for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
sw_idx = (tail + i) & (JOBR_DEPTH - 1);
if (jrp->outring[hw_idx].desc ==
jrp->entinfo[sw_idx].desc_addr_dma)
break; /* found */
}
(drivers/crypto/caam/jr.c - caam_dequeue)
how? The job ring h/w will still be spitting things out
out-of-order.
Plus, like I said, it's taking the problem in the wrong direction:
we need to strive to merge the allocation and mapping with the upper
layers as much as possible.
Kim
On Tue, 17 Mar 2015 19:58:55 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/17/2015 2:19 AM, Kim Phillips wrote:
quoted
On Mon, 16 Mar 2015 12:02:51 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
why not?
It would imply having 2 memory allocations, one for crypto request and
the other for the rest of the data bundled with the request (for IPsec
that would be ESN + space for IV + sg entries for authenticated-only
data and sk_buff extension, if needed).
Trying to have a single allocation by making ESN, IV etc. part of the
request private context requires modifying tfm.reqsize on the fly.
This won't work without adding some kind of locking for the tfm.
can't a common minimum tfm.reqsize be co-established up front, at
least for the fast path?
Indeed, for IPsec at tfm allocation time - esp_init_state() -
tfm.reqsize could be increased to account for what is known for a given
flow: ESN, IV and asg (S/G entries for authenticated-only data).
The layout would be:
aead request (fixed part)
private ctx of backend algorithm
seq_no_hi (if ESN)
IV
asg
sg <-- S/G table for skb_to_sgvec; how many entries is the question
Do you have a suggestion for how many S/G entries to preallocate for
representing the sk_buff data to be encrypted?
An ancient esp4.c used ESP_NUM_FAST_SG, set to 4.
Btw, currently maximum number of fragments supported by the net stack
(MAX_SKB_FRAGS) is 16 or more.
quoted
quoted
quoted
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
would modifying the crypto API to either have a different
*_request_alloc() API, and/or adding calls to negotiate the GFP mask
between crypto users and drivers, e.g., get/set_gfp_mask, work?
I think what DaveM asked for was the change to be transparent.
Besides converting to *_request_alloc(), seems that all other options
require some extra awareness from the user.
Could you elaborate on the idea above?
was merely suggesting communicating GFP flags anonymously across the
API, i.e., GFP_DMA wouldn't appear in user code.
Meaning user would have to get_gfp_mask before allocating a crypto
request - i.e. instead of kmalloc(..., GFP_ATOMIC) to have
kmalloc(GFP_ATOMIC | get_gfp_mask(aead))?
quoted
quoted
quoted
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
There's a comment in esp_alloc_tmp(): "Use spare space in skb for
this where possible," which is ideally where we'd want to be (esp.
Ok, I'll check that. But note the "where possible" - finding room in the
skb to avoid the allocation won't always be the case, and then we're
back to square one.
So the skb cb is out of the question, being too small (48B).
Any idea what was the intention of the "TODO" - maybe to use the
tailroom in the skb data area?
quoted
quoted
because that memory could already be DMA-able). Your above
suggestion would be in the opposite direction of that.
The proposal:
-removes dma (un)mapping on the fast path
sure, but at the expense of additional complexity.
Right, there's no free lunch. But it's cheaper.
quoted
-avoids requesting dma mappable memory for more than it's actually
needed (CRYPTO_TFM_REQ_DMA forces entire request to be mappable, not
only its private context)
compared to the payload? Plus, we have plenty of DMA space these
days.
quoted
-for caam it has the added benefit of speeding the below search for the
offending descriptor in the SW ring from O(n) to O(1):
for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
sw_idx = (tail + i) & (JOBR_DEPTH - 1);
if (jrp->outring[hw_idx].desc ==
jrp->entinfo[sw_idx].desc_addr_dma)
break; /* found */
}
(drivers/crypto/caam/jr.c - caam_dequeue)
how? The job ring h/w will still be spitting things out
out-of-order.
jrp->outring[hw_idx].desc bus address can be used to find the sw_idx in
O(1):
dma_addr_t desc_base = dma_map_page(alloc_page(GFP_DMA),...);
[...]
sw_idx = (desc_base - jrp->outring[hw_idx].desc) / JD_SIZE;
JD_SIZE would be 16 words (64B) - 13 words used for the h/w job
descriptor, 3 words can be used for smth. else.
Basically all JDs would be filled at a 64B-aligned offset in the memory
page.
Plus, like I said, it's taking the problem in the wrong direction:
we need to strive to merge the allocation and mapping with the upper
layers as much as possible.
IMHO propagating the GFP_DMA from backend crypto implementations to
crypto API users doesn't seem feasable.
It's error-prone to audit all places that allocate crypto requests w/out
using *_request_alloc API.
And even if all these places would be identified:
-in some cases there's some heavy rework involved
-more places might show up in the future and there's no way to detect them
Horia
From: Kim Phillips <hidden> Date: 2015-03-19 18:43:38
On Thu, 19 Mar 2015 17:56:57 +0200
Horia Geantă [off-list ref] wrote:
On 3/18/2015 12:03 AM, Kim Phillips wrote:
quoted
On Tue, 17 Mar 2015 19:58:55 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/17/2015 2:19 AM, Kim Phillips wrote:
quoted
On Mon, 16 Mar 2015 12:02:51 +0200
Horia Geantă [off-list ref] wrote:
quoted
On 3/4/2015 2:23 AM, Kim Phillips wrote:
quoted
Only potential problem is getting the crypto API to set the GFP_DMA
flag in the allocation request, but presumably a
CRYPTO_TFM_REQ_DMA crt_flag can be made to handle that.
Seems there are quite a few places that do not use the
{aead,ablkcipher_ahash}_request_alloc() API to allocate crypto requests.
Among them, IPsec and dm-crypt.
I've looked at the code and I don't think it can be converted to use
crypto API.
why not?
It would imply having 2 memory allocations, one for crypto request and
the other for the rest of the data bundled with the request (for IPsec
that would be ESN + space for IV + sg entries for authenticated-only
data and sk_buff extension, if needed).
Trying to have a single allocation by making ESN, IV etc. part of the
request private context requires modifying tfm.reqsize on the fly.
This won't work without adding some kind of locking for the tfm.
can't a common minimum tfm.reqsize be co-established up front, at
least for the fast path?
Indeed, for IPsec at tfm allocation time - esp_init_state() -
tfm.reqsize could be increased to account for what is known for a given
flow: ESN, IV and asg (S/G entries for authenticated-only data).
The layout would be:
aead request (fixed part)
private ctx of backend algorithm
seq_no_hi (if ESN)
IV
asg
sg <-- S/G table for skb_to_sgvec; how many entries is the question
Do you have a suggestion for how many S/G entries to preallocate for
representing the sk_buff data to be encrypted?
An ancient esp4.c used ESP_NUM_FAST_SG, set to 4.
Btw, currently maximum number of fragments supported by the net stack
(MAX_SKB_FRAGS) is 16 or more.
quoted
quoted
quoted
quoted
This means that the CRYPTO_TFM_REQ_DMA would be visible to all of these
places. Some of the maintainers do not agree, as you've seen.
would modifying the crypto API to either have a different
*_request_alloc() API, and/or adding calls to negotiate the GFP mask
between crypto users and drivers, e.g., get/set_gfp_mask, work?
I think what DaveM asked for was the change to be transparent.
Besides converting to *_request_alloc(), seems that all other options
require some extra awareness from the user.
Could you elaborate on the idea above?
was merely suggesting communicating GFP flags anonymously across the
API, i.e., GFP_DMA wouldn't appear in user code.
Meaning user would have to get_gfp_mask before allocating a crypto
request - i.e. instead of kmalloc(..., GFP_ATOMIC) to have
kmalloc(GFP_ATOMIC | get_gfp_mask(aead))?
quoted
quoted
quoted
quoted
An alternative would be for talitos to use the page allocator to get 1 /
2 pages at probe time (4 channels x 32 entries/channel x 64B/descriptor
= 8 kB), dma_map_page the area and manage it internally for talitos_desc
hw descriptors.
What do you think?
There's a comment in esp_alloc_tmp(): "Use spare space in skb for
this where possible," which is ideally where we'd want to be (esp.
Ok, I'll check that. But note the "where possible" - finding room in the
skb to avoid the allocation won't always be the case, and then we're
back to square one.
So the skb cb is out of the question, being too small (48B).
Any idea what was the intention of the "TODO" - maybe to use the
tailroom in the skb data area?
quoted
quoted
quoted
because that memory could already be DMA-able). Your above
suggestion would be in the opposite direction of that.
The proposal:
-removes dma (un)mapping on the fast path
sure, but at the expense of additional complexity.
Right, there's no free lunch. But it's cheaper.
quoted
quoted
-avoids requesting dma mappable memory for more than it's actually
needed (CRYPTO_TFM_REQ_DMA forces entire request to be mappable, not
only its private context)
compared to the payload? Plus, we have plenty of DMA space these
days.
quoted
-for caam it has the added benefit of speeding the below search for the
offending descriptor in the SW ring from O(n) to O(1):
for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
sw_idx = (tail + i) & (JOBR_DEPTH - 1);
if (jrp->outring[hw_idx].desc ==
jrp->entinfo[sw_idx].desc_addr_dma)
break; /* found */
}
(drivers/crypto/caam/jr.c - caam_dequeue)
how? The job ring h/w will still be spitting things out
out-of-order.
jrp->outring[hw_idx].desc bus address can be used to find the sw_idx in
O(1):
dma_addr_t desc_base = dma_map_page(alloc_page(GFP_DMA),...);
[...]
sw_idx = (desc_base - jrp->outring[hw_idx].desc) / JD_SIZE;
JD_SIZE would be 16 words (64B) - 13 words used for the h/w job
descriptor, 3 words can be used for smth. else.
Basically all JDs would be filled at a 64B-aligned offset in the memory
page.
that assumes a linear mapping, which is a wrong assumption to make.
I also think you don't know how many times that loop above executes
in practice.
quoted
Plus, like I said, it's taking the problem in the wrong direction:
we need to strive to merge the allocation and mapping with the upper
layers as much as possible.
IMHO propagating the GFP_DMA from backend crypto implementations to
crypto API users doesn't seem feasable.
should be.
It's error-prone to audit all places that allocate crypto requests w/out
using *_request_alloc API.
why is it error-prone?
And even if all these places would be identified:
-in some cases there's some heavy rework involved
so?
-more places might show up in the future and there's no way to detect them
let them worry about that.
I leave the rest for netdev.
Kim