media: staging/ipu7: avoid division by 64-bit value
Subsystems (3)
PATCH 1/1 media: staging/ipu7: avoid division by 64-bit value
From: Arnd Bergmann <[email protected]>
On 32-bit targets, this causes a link failure:
x86_64-linux-ld: drivers/staging/media/ipu7/ipu7-isys-csi-phy.o: in function `ipu7_isys_phy_config':
ipu7-isys-csi-phy.c:(.text+0x1509): undefined reference to `__udivdi3'
Note that this does not divide a 64-bit number by a 32-bit one as usual, but the other way round, which is something that the compiler should really be able to figure out but does not (as of gcc-15).
A few lines higher, a similar division is done using the incorrect div_u64() that truncates the 64-bit divisor to 32 bits.
Change both to use the safe but slow div64_u64() helper.
--- drivers/staging/media/ipu7/ipu7-isys-csi-phy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +4 -4
@@ -734,6 +734,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,u16 reg;u16 val;u32 i; +u64 r64;u32 r;if (is_ipu7p5 (isys->adev->isp->hw_ver))
@@ -806,8 +807,8 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg,2 ,0 ,2 ); } - deass_thresh = (u16 )div_u64_rem (7 *1000 *6 , mbps *5U , &r) +1 ; -if (r !=0 ) + deass_thresh = (u16 )div64_u64_rem (7 *1000 *6 , mbps *5U , &r64) +1 ; +if (r64 !=0 ) deass_thresh++; reg =CORE_DIG_RW_TRIO0_2 ;
@@ -815,8 +816,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg +0x400 * i, deass_thresh,0 ,7 ); - delay_thresh = - ((224U - (9U *7U )) *1000U ) / (5U * mbps) -7U ; + delay_thresh =div64_u64 ((224U - (9U *7U )) *1000U ,5U * mbps) -7u ;if (delay_thresh <1 ) delay_thresh =1 ;
Signature · 1 line
2.39.5
Quoted 47 lines · Arnd Bergmann
From: Arnd Bergmann <[email protected]>
On 32-bit targets, this causes a link failure:
x86_64-linux-ld:
drivers/staging/media/ipu7/ipu7-isys-csi-phy.o: in function `ipu7_isys_phy_config':
ipu7-isys-csi-phy.c:(.text+0x1509): undefined reference to `__udivdi3'Note that this does not divide a 64-bit number by a 32-bit one as usual, but the other way round, which is something that the compiler should really be able to figure out but does not (as of gcc-15).
A few lines higher, a similar division is done using the incorrect
div_u64()that truncates the 64-bit divisor to 32 bits.Change both to use the safe but slow
div64_u64()helper.Fixes a516d36bdc3d ("media: staging/ipu7: add IPU7 input system device driver")Signed-off-by Arnd Bergmann <[email protected]>--- drivers/staging/media/ipu7/ipu7-isys-csi-phy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +3
-2@@ -734,6 +734,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,u16 reg;u16 val;u32 i; +u64 r64;u32 r;if (is_ipu7p5 (isys->adev->isp->hw_ver))@@ -806,8 +807,8 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg,2 ,0 ,2 ); } - deass_thresh = (u16 )div_u64_rem (7 *1000 *6 , mbps *5U , &r) +1 ; -if (r !=0 ) + deass_thresh = (u16 )div64_u64_rem (7 *1000 *6 , mbps *5U , &r64) +1 ; +if (r64 !=0 ) deass_thresh++; reg =CORE_DIG_RW_TRIO0_2 ;
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, · line 822
Quoted 9 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +1
-2@@ -815,8 +816,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg +0x400 * i, deass_thresh,0 ,7 ); - delay_thresh = - ((224U - (9U *7U )) *1000U ) / (5U * mbps) -7U ; + delay_thresh =div64_u64 ((224U - (9U *7U )) *1000U ,5U * mbps) -7u ;if (delay_thresh <1 ) delay_thresh =1 ;
Signature · 2 lines
Best regards, Bingbu Cao
Quoted 35 lines · On Wed, 9 Jul 2025 16:56:56 +0200 Arnd Bergmann <[email protected]> wrote:
From: Arnd Bergmann <[email protected]>
On 32-bit targets, this causes a link failure:
x86_64-linux-ld:
drivers/staging/media/ipu7/ipu7-isys-csi-phy.o: in function `ipu7_isys_phy_config':
ipu7-isys-csi-phy.c:(.text+0x1509): undefined reference to `__udivdi3'Note that this does not divide a 64-bit number by a 32-bit one as usual, but the other way round, which is something that the compiler should really be able to figure out but does not (as of gcc-15).
A few lines higher, a similar division is done using the incorrect
div_u64()that truncates the 64-bit divisor to 32 bits.Change both to use the safe but slow
div64_u64()helper.Fixes a516d36bdc3d ("media: staging/ipu7: add IPU7 input system device driver")Signed-off-by Arnd Bergmann <[email protected]>--- drivers/staging/media/ipu7/ipu7-isys-csi-phy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +1
-0@@ -734,6 +734,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,u16 reg;u16 val;u32 i; +u64 r64;u32 r;if (is_ipu7p5 (isys->adev->isp->hw_ver))
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, · line 812
Quoted 8 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +2
-2@@ -806,8 +807,8 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg,2 ,0 ,2 ); } - deass_thresh = (u16 )div_u64_rem (7 *1000 *6 , mbps *5U , &r) +1 ; -if (r !=0 ) + deass_thresh = (u16 )div64_u64_rem (7 *1000 *6 , mbps *5U , &r64) +1 ; +if (r64 !=0 ) deass_thresh++;
While 'mbps' is presumably u64, it can't be big.
So this can just be:
deass_threas = roundup(7 * 1000 * 6 / 5, (u32)mbps) + 1;
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, · line 819
Quoted 9 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +1
-2reg =CORE_DIG_RW_TRIO0_2 ;@@ -815,8 +816,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg +0x400 * i, deass_thresh,0 ,7 ); - delay_thresh = - ((224U - (9U *7U )) *1000U ) / (5U * mbps) -7U ; + delay_thresh =div64_u64 ((224U - (9U *7U )) *1000U ,5U * mbps) -7u ;
That one just needs a (u32) cast, although the 5 can be moved.
David
Quoted 3 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +0
-0if (delay_thresh <1 ) delay_thresh =1 ;
Sakari Ailus
maintainerHi David,
Quoted 58 lines · David Laight
Quoted 35 lines · On Wed, 9 Jul 2025 16:56:56 +0200 Arnd Bergmann <[email protected]> wrote:
From: Arnd Bergmann <[email protected]>
On 32-bit targets, this causes a link failure:
x86_64-linux-ld:
drivers/staging/media/ipu7/ipu7-isys-csi-phy.o: in function `ipu7_isys_phy_config':
ipu7-isys-csi-phy.c:(.text+0x1509): undefined reference to `__udivdi3'Note that this does not divide a 64-bit number by a 32-bit one as usual, but the other way round, which is something that the compiler should really be able to figure out but does not (as of gcc-15).
A few lines higher, a similar division is done using the incorrect
div_u64()that truncates the 64-bit divisor to 32 bits.Change both to use the safe but slow
div64_u64()helper.Fixes a516d36bdc3d ("media: staging/ipu7: add IPU7 input system device driver")Signed-off-by Arnd Bergmann <[email protected]>--- drivers/staging/media/ipu7/ipu7-isys-csi-phy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +1
-0@@ -734,6 +734,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,u16 reg;u16 val;u32 i; +u64 r64;u32 r;if (is_ipu7p5 (isys->adev->isp->hw_ver))drivers/staging/media/ipu7/ipu7-isys-csi-phy.c static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, · line 812
Quoted 8 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +2
-2@@ -806,8 +807,8 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg,2 ,0 ,2 ); } - deass_thresh = (u16 )div_u64_rem (7 *1000 *6 , mbps *5U , &r) +1 ; -if (r !=0 ) + deass_thresh = (u16 )div64_u64_rem (7 *1000 *6 , mbps *5U , &r64) +1 ; +if (r64 !=0 ) deass_thresh++;While 'mbps' is presumably u64, it can't be big.
So this can just be:deass_threas = roundup(7 * 1000 * 6 / 5, (u32)mbps) + 1;Quoted 6 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +0
-0reg =CORE_DIG_RW_TRIO0_2 ;@@ -815,8 +816,7 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,dwc_phy_write_mask (isys, id, reg +0x400 * i, deass_thresh,0 ,7 );
Quoted 5 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, · line 819
Quoted 3 lines
drivers/staging/media/ipu7/ipu7-isys-csi-phy.c +1
-2- delay_thresh = - ((224U - (9U *7U )) *1000U ) / (5U * mbps) -7U ; + delay_thresh =div64_u64 ((224U - (9U *7U )) *1000U ,5U * mbps) -7u ;That one just needs a (u32) cast, although the 5 can be moved.
I agree in principle but this should be done separately from fixing the bug which is what this patch does. mbps is u64 elsewhere, too, and there doesn't seem to be a need for that.
Signature · 3 lines
Regards, Sakari Ailus