diff mbox series

[net-next] net: ipa: avoid 64-bit modulus

Message ID 20210323010505.2149882-1-elder@linaro.org
State New
Headers show
Series [net-next] net: ipa: avoid 64-bit modulus | expand

Commit Message

Alex Elder March 23, 2021, 1:05 a.m. UTC
It is possible for a 32 bit x86 build to use a 64 bit DMA address.

There are two remaining spots where the IPA driver does a modulo
operation to check alignment of a DMA address, and under certain
conditions this can lead to a build error on i386 (at least).

The alignment checks we're doing are for power-of-2 values, and this
means the lower 32 bits of the DMA address can be used.  This ensures
both operands to the modulo operator are 32 bits wide.

Reported-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Alex Elder <elder@linaro.org>

---
 drivers/net/ipa/gsi.c       | 11 +++++++----
 drivers/net/ipa/ipa_table.c |  9 ++++++---
 2 files changed, 13 insertions(+), 7 deletions(-)

-- 
2.27.0

Comments

Randy Dunlap March 23, 2021, 2:44 a.m. UTC | #1
On 3/22/21 6:05 PM, Alex Elder wrote:
> It is possible for a 32 bit x86 build to use a 64 bit DMA address.

> 

> There are two remaining spots where the IPA driver does a modulo

> operation to check alignment of a DMA address, and under certain

> conditions this can lead to a build error on i386 (at least).

> 

> The alignment checks we're doing are for power-of-2 values, and this

> means the lower 32 bits of the DMA address can be used.  This ensures

> both operands to the modulo operator are 32 bits wide.

> 

> Reported-by: Randy Dunlap <rdunlap@infradead.org>

> Signed-off-by: Alex Elder <elder@linaro.org>


Acked-by: Randy Dunlap <rdunlap@infradead.org> # build-tested



Thanks.

> ---

>  drivers/net/ipa/gsi.c       | 11 +++++++----

>  drivers/net/ipa/ipa_table.c |  9 ++++++---

>  2 files changed, 13 insertions(+), 7 deletions(-)

> 

> diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c

> index 7f3e338ca7a72..b6355827bf900 100644

> --- a/drivers/net/ipa/gsi.c

> +++ b/drivers/net/ipa/gsi.c

> @@ -1436,15 +1436,18 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)

>  /* Initialize a ring, including allocating DMA memory for its entries */

>  static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)

>  {

> -	size_t size = count * GSI_RING_ELEMENT_SIZE;

> +	u32 size = count * GSI_RING_ELEMENT_SIZE;

>  	struct device *dev = gsi->dev;

>  	dma_addr_t addr;

>  

> -	/* Hardware requires a 2^n ring size, with alignment equal to size */

> +	/* Hardware requires a 2^n ring size, with alignment equal to size.

> +	 * The size is a power of 2, so we can check alignment using just

> +	 * the bottom 32 bits for a DMA address of any size.

> +	 */

>  	ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);

> -	if (ring->virt && addr % size) {

> +	if (ring->virt && lower_32_bits(addr) % size) {

>  		dma_free_coherent(dev, size, ring->virt, addr);

> -		dev_err(dev, "unable to alloc 0x%zx-aligned ring buffer\n",

> +		dev_err(dev, "unable to alloc 0x%x-aligned ring buffer\n",

>  			size);

>  		return -EINVAL;	/* Not a good error value, but distinct */

>  	} else if (!ring->virt) {

> diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c

> index 988f2c2886b95..4236a50ff03ae 100644

> --- a/drivers/net/ipa/ipa_table.c

> +++ b/drivers/net/ipa/ipa_table.c

> @@ -658,10 +658,13 @@ int ipa_table_init(struct ipa *ipa)

>  		return -ENOMEM;

>  

>  	/* We put the "zero rule" at the base of our table area.  The IPA

> -	 * hardware requires rules to be aligned on a 128-byte boundary.

> -	 * Make sure the allocation satisfies this constraint.

> +	 * hardware requires route and filter table rules to be aligned

> +	 * on a 128-byte boundary.  As long as the alignment constraint

> +	 * is a power of 2, we can check alignment using just the bottom

> +	 * 32 bits for a DMA address of any size.

>  	 */

> -	if (addr % IPA_TABLE_ALIGN) {

> +	BUILD_BUG_ON(!is_power_of_2(IPA_TABLE_ALIGN));

> +	if (lower_32_bits(addr) % IPA_TABLE_ALIGN) {

>  		dev_err(dev, "table address %pad not %u-byte aligned\n",

>  			&addr, IPA_TABLE_ALIGN);

>  		dma_free_coherent(dev, size, virt, addr);

> 



-- 
~Randy
patchwork-bot+netdevbpf@kernel.org March 24, 2021, 12:20 a.m. UTC | #2
Hello:

This patch was applied to netdev/net-next.git (refs/heads/master):

On Mon, 22 Mar 2021 20:05:05 -0500 you wrote:
> It is possible for a 32 bit x86 build to use a 64 bit DMA address.

> 

> There are two remaining spots where the IPA driver does a modulo

> operation to check alignment of a DMA address, and under certain

> conditions this can lead to a build error on i386 (at least).

> 

> The alignment checks we're doing are for power-of-2 values, and this

> means the lower 32 bits of the DMA address can be used.  This ensures

> both operands to the modulo operator are 32 bits wide.

> 

> [...]


Here is the summary with links:
  - [net-next] net: ipa: avoid 64-bit modulus
    https://git.kernel.org/netdev/net-next/c/437c78f976f5

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
David Laight March 24, 2021, 4:27 p.m. UTC | #3
From: Alex Elder

> Sent: 23 March 2021 01:05

> It is possible for a 32 bit x86 build to use a 64 bit DMA address.

> 

> There are two remaining spots where the IPA driver does a modulo

> operation to check alignment of a DMA address, and under certain

> conditions this can lead to a build error on i386 (at least).

> 

> The alignment checks we're doing are for power-of-2 values, and this

> means the lower 32 bits of the DMA address can be used.  This ensures

> both operands to the modulo operator are 32 bits wide.

> 

> Reported-by: Randy Dunlap <rdunlap@infradead.org>

> Signed-off-by: Alex Elder <elder@linaro.org>

> ---

>  drivers/net/ipa/gsi.c       | 11 +++++++----

>  drivers/net/ipa/ipa_table.c |  9 ++++++---

>  2 files changed, 13 insertions(+), 7 deletions(-)

> 

> diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c

> index 7f3e338ca7a72..b6355827bf900 100644

> --- a/drivers/net/ipa/gsi.c

> +++ b/drivers/net/ipa/gsi.c

> @@ -1436,15 +1436,18 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)

>  /* Initialize a ring, including allocating DMA memory for its entries */

>  static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)

>  {

> -	size_t size = count * GSI_RING_ELEMENT_SIZE;

> +	u32 size = count * GSI_RING_ELEMENT_SIZE;

>  	struct device *dev = gsi->dev;

>  	dma_addr_t addr;

> 

> -	/* Hardware requires a 2^n ring size, with alignment equal to size */

> +	/* Hardware requires a 2^n ring size, with alignment equal to size.

> +	 * The size is a power of 2, so we can check alignment using just

> +	 * the bottom 32 bits for a DMA address of any size.

> +	 */

>  	ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);


Doesn't dma_alloc_coherent() guarantee that alignment?
I doubt anywhere else checks?

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Alex Elder March 24, 2021, 5:07 p.m. UTC | #4
On 3/24/21 11:27 AM, David Laight wrote:
> From: Alex Elder

>> Sent: 23 March 2021 01:05

>> It is possible for a 32 bit x86 build to use a 64 bit DMA address.

>>

>> There are two remaining spots where the IPA driver does a modulo

>> operation to check alignment of a DMA address, and under certain

>> conditions this can lead to a build error on i386 (at least).

>>

>> The alignment checks we're doing are for power-of-2 values, and this

>> means the lower 32 bits of the DMA address can be used.  This ensures

>> both operands to the modulo operator are 32 bits wide.

>>

>> Reported-by: Randy Dunlap <rdunlap@infradead.org>

>> Signed-off-by: Alex Elder <elder@linaro.org>

>> ---

>>   drivers/net/ipa/gsi.c       | 11 +++++++----

>>   drivers/net/ipa/ipa_table.c |  9 ++++++---

>>   2 files changed, 13 insertions(+), 7 deletions(-)

>>

>> diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c

>> index 7f3e338ca7a72..b6355827bf900 100644

>> --- a/drivers/net/ipa/gsi.c

>> +++ b/drivers/net/ipa/gsi.c

>> @@ -1436,15 +1436,18 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)

>>   /* Initialize a ring, including allocating DMA memory for its entries */

>>   static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)

>>   {

>> -	size_t size = count * GSI_RING_ELEMENT_SIZE;

>> +	u32 size = count * GSI_RING_ELEMENT_SIZE;

>>   	struct device *dev = gsi->dev;

>>   	dma_addr_t addr;

>>

>> -	/* Hardware requires a 2^n ring size, with alignment equal to size */

>> +	/* Hardware requires a 2^n ring size, with alignment equal to size.

>> +	 * The size is a power of 2, so we can check alignment using just

>> +	 * the bottom 32 bits for a DMA address of any size.

>> +	 */

>>   	ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);

> 

> Doesn't dma_alloc_coherent() guarantee that alignment?

> I doubt anywhere else checks?


I normally wouldn't check something like this if it
weren't guaranteed.  I'm not sure why I did it here.

I see it's "guaranteed to be aligned to the smallest
PAGE_SIZE order which is greater than or equal to
the requested size."  So I think the answer to your
question is "yes, it does guarantee that."

I'll make a note to remove this check in a future
patch, and will credit you with the suggestion.

Thanks.

					-Alex

> 

> 	David

> 

> -

> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK

> Registration No: 1397386 (Wales)

>
David Laight March 24, 2021, 5:12 p.m. UTC | #5
From: Alex Elder

> Sent: 24 March 2021 17:07

> 

> On 3/24/21 11:27 AM, David Laight wrote:

> > From: Alex Elder

> >> Sent: 23 March 2021 01:05

> >> It is possible for a 32 bit x86 build to use a 64 bit DMA address.

> >>

> >> There are two remaining spots where the IPA driver does a modulo

> >> operation to check alignment of a DMA address, and under certain

> >> conditions this can lead to a build error on i386 (at least).

> >>

> >> The alignment checks we're doing are for power-of-2 values, and this

> >> means the lower 32 bits of the DMA address can be used.  This ensures

> >> both operands to the modulo operator are 32 bits wide.

> >>

> >> Reported-by: Randy Dunlap <rdunlap@infradead.org>

> >> Signed-off-by: Alex Elder <elder@linaro.org>

> >> ---

> >>   drivers/net/ipa/gsi.c       | 11 +++++++----

> >>   drivers/net/ipa/ipa_table.c |  9 ++++++---

> >>   2 files changed, 13 insertions(+), 7 deletions(-)

> >>

> >> diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c

> >> index 7f3e338ca7a72..b6355827bf900 100644

> >> --- a/drivers/net/ipa/gsi.c

> >> +++ b/drivers/net/ipa/gsi.c

> >> @@ -1436,15 +1436,18 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32

> index)

> >>   /* Initialize a ring, including allocating DMA memory for its entries */

> >>   static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)

> >>   {

> >> -	size_t size = count * GSI_RING_ELEMENT_SIZE;

> >> +	u32 size = count * GSI_RING_ELEMENT_SIZE;

> >>   	struct device *dev = gsi->dev;

> >>   	dma_addr_t addr;

> >>

> >> -	/* Hardware requires a 2^n ring size, with alignment equal to size */

> >> +	/* Hardware requires a 2^n ring size, with alignment equal to size.

> >> +	 * The size is a power of 2, so we can check alignment using just

> >> +	 * the bottom 32 bits for a DMA address of any size.

> >> +	 */

> >>   	ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);

> >

> > Doesn't dma_alloc_coherent() guarantee that alignment?

> > I doubt anywhere else checks?

> 

> I normally wouldn't check something like this if it

> weren't guaranteed.  I'm not sure why I did it here.

> 

> I see it's "guaranteed to be aligned to the smallest

> PAGE_SIZE order which is greater than or equal to

> the requested size."  So I think the answer to your

> question is "yes, it does guarantee that."

> 

> I'll make a note to remove this check in a future

> patch, and will credit you with the suggestion.


I think 'count' is also required to be a power of 2.
so you could have checked 'addr & (size - 1)'.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Alex Elder March 24, 2021, 5:32 p.m. UTC | #6
On 3/24/21 12:12 PM, David Laight wrote:
> I think 'count' is also required to be a power of 2.

> so you could have checked 'addr & (size - 1)'.


It is required to be, and that is checked elsewhere
(in gsi_channel_data_valid()).  And yes, size would
therefore be a power-of-2, and so your clever test
would be a simple test.

I'll take that into account when I implement the
fix.  Thanks for the suggestion.

					-Alex
diff mbox series

Patch

diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
index 7f3e338ca7a72..b6355827bf900 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
@@ -1436,15 +1436,18 @@  static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)
 /* Initialize a ring, including allocating DMA memory for its entries */
 static int gsi_ring_alloc(struct gsi *gsi, struct gsi_ring *ring, u32 count)
 {
-	size_t size = count * GSI_RING_ELEMENT_SIZE;
+	u32 size = count * GSI_RING_ELEMENT_SIZE;
 	struct device *dev = gsi->dev;
 	dma_addr_t addr;
 
-	/* Hardware requires a 2^n ring size, with alignment equal to size */
+	/* Hardware requires a 2^n ring size, with alignment equal to size.
+	 * The size is a power of 2, so we can check alignment using just
+	 * the bottom 32 bits for a DMA address of any size.
+	 */
 	ring->virt = dma_alloc_coherent(dev, size, &addr, GFP_KERNEL);
-	if (ring->virt && addr % size) {
+	if (ring->virt && lower_32_bits(addr) % size) {
 		dma_free_coherent(dev, size, ring->virt, addr);
-		dev_err(dev, "unable to alloc 0x%zx-aligned ring buffer\n",
+		dev_err(dev, "unable to alloc 0x%x-aligned ring buffer\n",
 			size);
 		return -EINVAL;	/* Not a good error value, but distinct */
 	} else if (!ring->virt) {
diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c
index 988f2c2886b95..4236a50ff03ae 100644
--- a/drivers/net/ipa/ipa_table.c
+++ b/drivers/net/ipa/ipa_table.c
@@ -658,10 +658,13 @@  int ipa_table_init(struct ipa *ipa)
 		return -ENOMEM;
 
 	/* We put the "zero rule" at the base of our table area.  The IPA
-	 * hardware requires rules to be aligned on a 128-byte boundary.
-	 * Make sure the allocation satisfies this constraint.
+	 * hardware requires route and filter table rules to be aligned
+	 * on a 128-byte boundary.  As long as the alignment constraint
+	 * is a power of 2, we can check alignment using just the bottom
+	 * 32 bits for a DMA address of any size.
 	 */
-	if (addr % IPA_TABLE_ALIGN) {
+	BUILD_BUG_ON(!is_power_of_2(IPA_TABLE_ALIGN));
+	if (lower_32_bits(addr) % IPA_TABLE_ALIGN) {
 		dev_err(dev, "table address %pad not %u-byte aligned\n",
 			&addr, IPA_TABLE_ALIGN);
 		dma_free_coherent(dev, size, virt, addr);