Skip to contentSkip to conversation

Fix find_first_zero_bit() usage

PATCH Superseded Niklas Cassel 3 participants 6 messages Nov 17, 2017 – Nov 21, 2017

Subsystems (2)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover Fix find_first_zero_bit() usage

From: Niklas Cassel <[email protected]>

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

Calling find_first_zero_bit() with the wrong size unit will lead to insidious bugs.

Fix all uses of find_first_zero_bit() called with
sizeof() as size argument in drivers/pci.

Niklas Cassel (2):
PCI: designware-ep: Fix find_first_zero_bit() usage
PCI: endpoint: Fix find_first_zero_bit() usage

 drivers/pci/dwc/pcie-designware-ep.c | 6 ++----
 drivers/pci/endpoint/pci-ep-cfs.c    | 3 +--
 2 files changed, 3 insertions(+), 6 deletions(-)
Signature · 1 line
2.14.2
#1 lore raw

PATCH v2 1/2 PCI: designware-ep: Fix find_first_zero_bit() usage

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

find_first_zero_bit() was called with size in bytes rather than bits, which thus defined a too low upper limit, causing dw_pcie_ep_inbound_atu() to assign iatu index #4 to both bar 4 and bar 5, which made bar 5 overwrite the settings set by bar 4.

Fix this by using replacing find_first_zero_bit() with ffz(), since ffz() only works on a single 'unsigned long' and therefore does not need a size argument.

Fixes f8aed6ec624f ("PCI: dwc: designware: Add EP mode support")
---
 drivers/pci/dwc/pcie-designware-ep.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/pci/dwc/pcie-designware-ep.c +2 -4
index d53d5f168363..ab9a9e160daf 100644
@@ -70,8 +70,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ib_window_map,
-				       sizeof(ep->ib_window_map));
+	free_win = ffz(ep->ib_window_map);
 	if (free_win >= ep->num_ib_windows) {
 		dev_err(pci->dev, "no free inbound window\n");
 		return -EINVAL;
@@ -96,8 +95,7 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ob_window_map,
-				       sizeof(ep->ob_window_map));
+	free_win = ffz(ep->ob_window_map);
 	if (free_win >= ep->num_ob_windows) {
 		dev_err(pci->dev, "no free outbound window\n");
 		return -EINVAL;
Signature · 1 line
2.14.2
#2 lore raw

Re: [PATCH v2 1/2] PCI: designware-ep: Fix find_first_zero_bit() usage

[+Kishon - please CC him next time]

Quoted 23 lines · Niklas Cassel

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

find_first_zero_bit() was called with size in bytes rather than bits, which thus defined a too low upper limit, causing dw_pcie_ep_inbound_atu() to assign iatu index #4 to both bar 4 and bar 5, which made bar 5 overwrite the settings set by bar 4.

Fix this by using replacing find_first_zero_bit() with ffz(), since ffz() only works on a single 'unsigned long' and therefore does not need a size argument.

Fixes f8aed6ec624f ("PCI: dwc: designware: Add EP mode support")
---
 drivers/pci/dwc/pcie-designware-ep.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/pci/dwc/pcie-designware-ep.c +0 -0
index d53d5f168363..ab9a9e160daf 100644

drivers/pci/dwc/pcie-designware-ep.c static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, · line 73

Quoted 6 lines
drivers/pci/dwc/pcie-designware-ep.c +1 -2
@@ -70,8 +70,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ib_window_map,
-				       sizeof(ep->ib_window_map));
+	free_win = ffz(ep->ib_window_map);

You fix the bug at hand but code suffers from the same issue since we should be checking the value against ~0UL first ie if size in bits < num_ib_windows (that I think it is unlikely anyway but while at it let's think if we can improve this).

@Kishon: maybe we should add a static upper size and declare a static bitmap accordingly (and still use find_first_zero_bit()) ?

I think the check against ~0UL should be added anyway, let's get Kishon's opinion before a v3 (if any).

Thanks,
Lorenzo

Quoted 16 lines
drivers/pci/dwc/pcie-designware-ep.c +1 -2
 	if (free_win >= ep->num_ib_windows) {
 		dev_err(pci->dev, "no free inbound window\n");
 		return -EINVAL;
@@ -96,8 +95,7 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ob_window_map,
-				       sizeof(ep->ob_window_map));
+	free_win = ffz(ep->ob_window_map);
 	if (free_win >= ep->num_ob_windows) {
 		dev_err(pci->dev, "no free outbound window\n");
 		return -EINVAL;
Signature · 1 line
2.14.2
#3 lore raw

Re: [PATCH v2 1/2] PCI: designware-ep: Fix find_first_zero_bit() usage

Hi Lorenzo,

Quoted 38 lines · Lorenzo Pieralisi

[+Kishon - please CC him next time]

Quoted 23 lines · Niklas Cassel

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

find_first_zero_bit() was called with size in bytes rather than bits, which thus defined a too low upper limit, causing dw_pcie_ep_inbound_atu() to assign iatu index #4 to both bar 4 and bar 5, which made bar 5 overwrite the settings set by bar 4.

Fix this by using replacing find_first_zero_bit() with ffz(), since ffz() only works on a single 'unsigned long' and therefore does not need a size argument.

Fixes f8aed6ec624f ("PCI: dwc: designware: Add EP mode support")
---
 drivers/pci/dwc/pcie-designware-ep.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/pci/dwc/pcie-designware-ep.c +0 -0
index d53d5f168363..ab9a9e160daf 100644

drivers/pci/dwc/pcie-designware-ep.c static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, · line 73

Quoted 6 lines
drivers/pci/dwc/pcie-designware-ep.c +1 -2
@@ -70,8 +70,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ib_window_map,
-				       sizeof(ep->ib_window_map));
+	free_win = ffz(ep->ib_window_map);

You fix the bug at hand but code suffers from the same issue since we should be checking the value against ~0UL first ie if size in bits < num_ib_windows (that I think it is unlikely anyway but while at it let's think if we can improve this).

Quoted 5 lines

@Kishon: maybe we should add a static upper size and declare a static bitmap accordingly (and still use find_first_zero_bit()) ?

I think the check against ~0UL should be added anyway, let's get Kishon's opinion before a v3 (if any).

Yeah, for both ffz and find_first_zero_bit, the results are undefined if no zero exists.

I'm thinking if we should just use find_first_zero_bit(&ep->ib_window_map, ep->num_ib_windows) after checking if there are some '0' bits left.

Thanks
Kishon

#4 lore raw

Re: [PATCH v2 1/2] PCI: designware-ep: Fix find_first_zero_bit() usage

Quoted 47 lines · Kishon Vijay Abraham I

Hi Lorenzo,

Quoted 38 lines · Lorenzo Pieralisi

[+Kishon - please CC him next time]

Quoted 23 lines · Niklas Cassel

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

find_first_zero_bit() was called with size in bytes rather than bits, which thus defined a too low upper limit, causing dw_pcie_ep_inbound_atu() to assign iatu index #4 to both bar 4 and bar 5, which made bar 5 overwrite the settings set by bar 4.

Fix this by using replacing find_first_zero_bit() with ffz(), since ffz() only works on a single 'unsigned long' and therefore does not need a size argument.

Fixes f8aed6ec624f ("PCI: dwc: designware: Add EP mode support")
---
 drivers/pci/dwc/pcie-designware-ep.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/pci/dwc/pcie-designware-ep.c +0 -0
index d53d5f168363..ab9a9e160daf 100644

drivers/pci/dwc/pcie-designware-ep.c static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, · line 73

Quoted 6 lines
drivers/pci/dwc/pcie-designware-ep.c +1 -2
@@ -70,8 +70,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
 	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 
-	free_win = find_first_zero_bit(&ep->ib_window_map,
-				       sizeof(ep->ib_window_map));
+	free_win = ffz(ep->ib_window_map);

You fix the bug at hand but code suffers from the same issue since we should be checking the value against ~0UL first ie if size in bits < num_ib_windows (that I think it is unlikely anyway but while at it let's think if we can improve this).

Quoted 5 lines

@Kishon: maybe we should add a static upper size and declare a static bitmap accordingly (and still use find_first_zero_bit()) ?

I think the check against ~0UL should be added anyway, let's get Kishon's opinion before a v3 (if any).

Quoted 6 lines

Yeah, for both ffz and find_first_zero_bit, the results are undefined if no zero exists.

I'm thinking if we should just use find_first_zero_bit(&ep->ib_window_map, ep->num_ib_windows) after checking if there are some '0' bits left.

Well yes but first the &ep->ib_window_map must be sized accordingly.

Lorenzo

#5 lore raw

PATCH v2 2/2 PCI: endpoint: Fix find_first_zero_bit() usage

In reply to Niklas Cassel

find_first_zero_bit()'s parameter 'size' is defined in bits, not in bytes.

Calling find_first_zero_bit() with the wrong size unit will lead to insidious bugs.

Fix this by using replacing find_first_zero_bit() with ffz(), since ffz() only works on a single 'unsigned long' and therefore does not need a size argument.

Fixes d74679911610 ("PCI: endpoint: Introduce configfs entry for configuring EP functions")
---
 drivers/pci/endpoint/pci-ep-cfs.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/pci/endpoint/pci-ep-cfs.c +1 -2
index 4f74386c1ced..96b984685640 100644
@@ -108,8 +108,7 @@ static int pci_epc_epf_link(struct config_item *epc_item,
 	if (ret)
 		goto err_add_epf;
 
-	func_no = find_first_zero_bit(&epc_group->function_num_map,
-				      sizeof(epc_group->function_num_map));
+	func_no = ffz(epc_group->function_num_map);
 	set_bit(func_no, &epc_group->function_num_map);
 	epf->func_no = func_no;
 
Signature · 1 line
2.14.2