* [PATCH] PCI/P2PDMA: simplify distance calculation
@ 2021-06-14 5:53 Christoph Hellwig
2021-06-14 16:59 ` Logan Gunthorpe
2021-06-16 21:11 ` Bjorn Helgaas
0 siblings, 2 replies; 3+ messages in thread
From: Christoph Hellwig @ 2021-06-14 5:53 UTC (permalink / raw)
To: logang, helgaas; +Cc: linux-pci
Merge __calc_map_type_and_dist and calc_map_type_and_dist_warn into
calc_map_type_and_dist to simplify the code a bit. This now means
we add the devfn strings to the acs_buf unconditionallity even if
the buffer is not printed, but that is not a lot of overhead and
keeps the code much simpler.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/pci/p2pdma.c | 190 +++++++++++++++++--------------------------
1 file changed, 73 insertions(+), 117 deletions(-)
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index deb097ceaf41..ca2574debb2d 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -388,79 +388,6 @@ static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b,
return false;
}
-static enum pci_p2pdma_map_type
-__calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
- int *dist, bool *acs_redirects, struct seq_buf *acs_list)
-{
- struct pci_dev *a = provider, *b = client, *bb;
- int dist_a = 0;
- int dist_b = 0;
- int acs_cnt = 0;
-
- if (acs_redirects)
- *acs_redirects = false;
-
- /*
- * Note, we don't need to take references to devices returned by
- * pci_upstream_bridge() seeing we hold a reference to a child
- * device which will already hold a reference to the upstream bridge.
- */
-
- while (a) {
- dist_b = 0;
-
- if (pci_bridge_has_acs_redir(a)) {
- seq_buf_print_bus_devfn(acs_list, a);
- acs_cnt++;
- }
-
- bb = b;
-
- while (bb) {
- if (a == bb)
- goto check_b_path_acs;
-
- bb = pci_upstream_bridge(bb);
- dist_b++;
- }
-
- a = pci_upstream_bridge(a);
- dist_a++;
- }
-
- if (dist)
- *dist = dist_a + dist_b;
-
- return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
-
-check_b_path_acs:
- bb = b;
-
- while (bb) {
- if (a == bb)
- break;
-
- if (pci_bridge_has_acs_redir(bb)) {
- seq_buf_print_bus_devfn(acs_list, bb);
- acs_cnt++;
- }
-
- bb = pci_upstream_bridge(bb);
- }
-
- if (dist)
- *dist = dist_a + dist_b;
-
- if (acs_cnt) {
- if (acs_redirects)
- *acs_redirects = true;
-
- return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
- }
-
- return PCI_P2PDMA_MAP_BUS_ADDR;
-}
-
static unsigned long map_types_idx(struct pci_dev *client)
{
return (pci_domain_nr(client->bus) << 16) |
@@ -502,63 +429,96 @@ static unsigned long map_types_idx(struct pci_dev *client)
* PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of
* ports per above. If the device is not in the whitelist, return
* PCI_P2PDMA_MAP_NOT_SUPPORTED.
- *
- * If any ACS redirect bits are set, then acs_redirects boolean will be set
- * to true and their PCI device names will be appended to the acs_list
- * seq_buf. This seq_buf is used to print a warning informing the user how
- * to disable ACS using a command line parameter. (See
- * calc_map_type_and_dist_warn() below)
*/
static enum pci_p2pdma_map_type
calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
- int *dist, bool *acs_redirects, struct seq_buf *acs_list)
+ int *dist, bool verbose)
{
- enum pci_p2pdma_map_type map_type;
+ enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
+ struct pci_dev *a = provider, *b = client, *bb;
+ bool acs_redirects = false;
+ struct seq_buf acs_list;
+ int acs_cnt = 0;
+ int dist_a = 0;
+ int dist_b = 0;
+ char buf[128];
+
+ seq_buf_init(&acs_list, buf, sizeof(buf));
+
+ /*
+ * Note, we don't need to take references to devices returned by
+ * pci_upstream_bridge() seeing we hold a reference to a child
+ * device which will already hold a reference to the upstream bridge.
+ */
+ while (a) {
+ dist_b = 0;
- map_type = __calc_map_type_and_dist(provider, client, dist,
- acs_redirects, acs_list);
+ if (pci_bridge_has_acs_redir(a)) {
+ seq_buf_print_bus_devfn(&acs_list, a);
+ acs_cnt++;
+ }
- if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
- if (!cpu_supports_p2pdma() &&
- !host_bridge_whitelist(provider, client, acs_redirects))
- map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
+ bb = b;
+
+ while (bb) {
+ if (a == bb)
+ goto check_b_path_acs;
+
+ bb = pci_upstream_bridge(bb);
+ dist_b++;
+ }
+
+ a = pci_upstream_bridge(a);
+ dist_a++;
}
- if (provider->p2pdma)
- xa_store(&provider->p2pdma->map_types, map_types_idx(client),
- xa_mk_value(map_type), GFP_KERNEL);
+ *dist = dist_a + dist_b;
+ goto map_through_host_bridge;
- return map_type;
-}
+check_b_path_acs:
+ bb = b;
-static enum pci_p2pdma_map_type
-calc_map_type_and_dist_warn(struct pci_dev *provider, struct pci_dev *client,
- int *dist)
-{
- struct seq_buf acs_list;
- bool acs_redirects;
- char buf[128];
- int ret;
+ while (bb) {
+ if (a == bb)
+ break;
- seq_buf_init(&acs_list, buf, sizeof(buf));
+ if (pci_bridge_has_acs_redir(bb)) {
+ seq_buf_print_bus_devfn(&acs_list, bb);
+ acs_cnt++;
+ }
- ret = calc_map_type_and_dist(provider, client, dist, &acs_redirects,
- &acs_list);
- if (acs_redirects) {
+ bb = pci_upstream_bridge(bb);
+ }
+
+ *dist = dist_a + dist_b;
+
+ if (!acs_cnt) {
+ map_type = PCI_P2PDMA_MAP_BUS_ADDR;
+ goto done;
+ }
+
+ if (verbose) {
+ acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */
pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
pci_name(provider));
- /* Drop final semicolon */
- acs_list.buffer[acs_list.len-1] = 0;
pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
acs_list.buffer);
}
+ acs_redirects = true;
- if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
- pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
- pci_name(provider));
+map_through_host_bridge:
+ if (!cpu_supports_p2pdma() &&
+ !host_bridge_whitelist(provider, client, acs_redirects)) {
+ if (verbose)
+ pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
+ pci_name(provider));
+ map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
}
-
- return ret;
+done:
+ if (provider->p2pdma)
+ xa_store(&provider->p2pdma->map_types, map_types_idx(client),
+ xa_mk_value(map_type), GFP_KERNEL);
+ return map_type;
}
/**
@@ -599,12 +559,8 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
return -1;
}
- if (verbose)
- map = calc_map_type_and_dist_warn(provider, pci_client,
- &distance);
- else
- map = calc_map_type_and_dist(provider, pci_client,
- &distance, NULL, NULL);
+ map = calc_map_type_and_dist(provider, pci_client, &distance,
+ verbose);
pci_dev_put(pci_client);
--
2.30.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] PCI/P2PDMA: simplify distance calculation
2021-06-14 5:53 [PATCH] PCI/P2PDMA: simplify distance calculation Christoph Hellwig
@ 2021-06-14 16:59 ` Logan Gunthorpe
2021-06-16 21:11 ` Bjorn Helgaas
1 sibling, 0 replies; 3+ messages in thread
From: Logan Gunthorpe @ 2021-06-14 16:59 UTC (permalink / raw)
To: Christoph Hellwig, helgaas; +Cc: linux-pci
On 2021-06-13 11:53 p.m., Christoph Hellwig wrote:
> Merge __calc_map_type_and_dist and calc_map_type_and_dist_warn into
> calc_map_type_and_dist to simplify the code a bit. This now means
> we add the devfn strings to the acs_buf unconditionallity even if
> the buffer is not printed, but that is not a lot of overhead and
> keeps the code much simpler.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Looks good to me, Thanks.
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
> ---
> drivers/pci/p2pdma.c | 190 +++++++++++++++++--------------------------
> 1 file changed, 73 insertions(+), 117 deletions(-)
>
> diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
> index deb097ceaf41..ca2574debb2d 100644
> --- a/drivers/pci/p2pdma.c
> +++ b/drivers/pci/p2pdma.c
> @@ -388,79 +388,6 @@ static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b,
> return false;
> }
>
> -static enum pci_p2pdma_map_type
> -__calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> - int *dist, bool *acs_redirects, struct seq_buf *acs_list)
> -{
> - struct pci_dev *a = provider, *b = client, *bb;
> - int dist_a = 0;
> - int dist_b = 0;
> - int acs_cnt = 0;
> -
> - if (acs_redirects)
> - *acs_redirects = false;
> -
> - /*
> - * Note, we don't need to take references to devices returned by
> - * pci_upstream_bridge() seeing we hold a reference to a child
> - * device which will already hold a reference to the upstream bridge.
> - */
> -
> - while (a) {
> - dist_b = 0;
> -
> - if (pci_bridge_has_acs_redir(a)) {
> - seq_buf_print_bus_devfn(acs_list, a);
> - acs_cnt++;
> - }
> -
> - bb = b;
> -
> - while (bb) {
> - if (a == bb)
> - goto check_b_path_acs;
> -
> - bb = pci_upstream_bridge(bb);
> - dist_b++;
> - }
> -
> - a = pci_upstream_bridge(a);
> - dist_a++;
> - }
> -
> - if (dist)
> - *dist = dist_a + dist_b;
> -
> - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> -
> -check_b_path_acs:
> - bb = b;
> -
> - while (bb) {
> - if (a == bb)
> - break;
> -
> - if (pci_bridge_has_acs_redir(bb)) {
> - seq_buf_print_bus_devfn(acs_list, bb);
> - acs_cnt++;
> - }
> -
> - bb = pci_upstream_bridge(bb);
> - }
> -
> - if (dist)
> - *dist = dist_a + dist_b;
> -
> - if (acs_cnt) {
> - if (acs_redirects)
> - *acs_redirects = true;
> -
> - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> - }
> -
> - return PCI_P2PDMA_MAP_BUS_ADDR;
> -}
> -
> static unsigned long map_types_idx(struct pci_dev *client)
> {
> return (pci_domain_nr(client->bus) << 16) |
> @@ -502,63 +429,96 @@ static unsigned long map_types_idx(struct pci_dev *client)
> * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of
> * ports per above. If the device is not in the whitelist, return
> * PCI_P2PDMA_MAP_NOT_SUPPORTED.
> - *
> - * If any ACS redirect bits are set, then acs_redirects boolean will be set
> - * to true and their PCI device names will be appended to the acs_list
> - * seq_buf. This seq_buf is used to print a warning informing the user how
> - * to disable ACS using a command line parameter. (See
> - * calc_map_type_and_dist_warn() below)
> */
> static enum pci_p2pdma_map_type
> calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> - int *dist, bool *acs_redirects, struct seq_buf *acs_list)
> + int *dist, bool verbose)
> {
> - enum pci_p2pdma_map_type map_type;
> + enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> + struct pci_dev *a = provider, *b = client, *bb;
> + bool acs_redirects = false;
> + struct seq_buf acs_list;
> + int acs_cnt = 0;
> + int dist_a = 0;
> + int dist_b = 0;
> + char buf[128];
> +
> + seq_buf_init(&acs_list, buf, sizeof(buf));
> +
> + /*
> + * Note, we don't need to take references to devices returned by
> + * pci_upstream_bridge() seeing we hold a reference to a child
> + * device which will already hold a reference to the upstream bridge.
> + */
> + while (a) {
> + dist_b = 0;
>
> - map_type = __calc_map_type_and_dist(provider, client, dist,
> - acs_redirects, acs_list);
> + if (pci_bridge_has_acs_redir(a)) {
> + seq_buf_print_bus_devfn(&acs_list, a);
> + acs_cnt++;
> + }
>
> - if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
> - if (!cpu_supports_p2pdma() &&
> - !host_bridge_whitelist(provider, client, acs_redirects))
> - map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> + bb = b;
> +
> + while (bb) {
> + if (a == bb)
> + goto check_b_path_acs;
> +
> + bb = pci_upstream_bridge(bb);
> + dist_b++;
> + }
> +
> + a = pci_upstream_bridge(a);
> + dist_a++;
> }
>
> - if (provider->p2pdma)
> - xa_store(&provider->p2pdma->map_types, map_types_idx(client),
> - xa_mk_value(map_type), GFP_KERNEL);
> + *dist = dist_a + dist_b;
> + goto map_through_host_bridge;
>
> - return map_type;
> -}
> +check_b_path_acs:
> + bb = b;
>
> -static enum pci_p2pdma_map_type
> -calc_map_type_and_dist_warn(struct pci_dev *provider, struct pci_dev *client,
> - int *dist)
> -{
> - struct seq_buf acs_list;
> - bool acs_redirects;
> - char buf[128];
> - int ret;
> + while (bb) {
> + if (a == bb)
> + break;
>
> - seq_buf_init(&acs_list, buf, sizeof(buf));
> + if (pci_bridge_has_acs_redir(bb)) {
> + seq_buf_print_bus_devfn(&acs_list, bb);
> + acs_cnt++;
> + }
>
> - ret = calc_map_type_and_dist(provider, client, dist, &acs_redirects,
> - &acs_list);
> - if (acs_redirects) {
> + bb = pci_upstream_bridge(bb);
> + }
> +
> + *dist = dist_a + dist_b;
> +
> + if (!acs_cnt) {
> + map_type = PCI_P2PDMA_MAP_BUS_ADDR;
> + goto done;
> + }
> +
> + if (verbose) {
> + acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */
> pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
> pci_name(provider));
> - /* Drop final semicolon */
> - acs_list.buffer[acs_list.len-1] = 0;
> pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
> acs_list.buffer);
> }
> + acs_redirects = true;
>
> - if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
> - pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
> - pci_name(provider));
> +map_through_host_bridge:
> + if (!cpu_supports_p2pdma() &&
> + !host_bridge_whitelist(provider, client, acs_redirects)) {
> + if (verbose)
> + pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
> + pci_name(provider));
> + map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> }
> -
> - return ret;
> +done:
> + if (provider->p2pdma)
> + xa_store(&provider->p2pdma->map_types, map_types_idx(client),
> + xa_mk_value(map_type), GFP_KERNEL);
> + return map_type;
> }
>
> /**
> @@ -599,12 +559,8 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
> return -1;
> }
>
> - if (verbose)
> - map = calc_map_type_and_dist_warn(provider, pci_client,
> - &distance);
> - else
> - map = calc_map_type_and_dist(provider, pci_client,
> - &distance, NULL, NULL);
> + map = calc_map_type_and_dist(provider, pci_client, &distance,
> + verbose);
>
> pci_dev_put(pci_client);
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] PCI/P2PDMA: simplify distance calculation
2021-06-14 5:53 [PATCH] PCI/P2PDMA: simplify distance calculation Christoph Hellwig
2021-06-14 16:59 ` Logan Gunthorpe
@ 2021-06-16 21:11 ` Bjorn Helgaas
1 sibling, 0 replies; 3+ messages in thread
From: Bjorn Helgaas @ 2021-06-16 21:11 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: logang, linux-pci
On Mon, Jun 14, 2021 at 07:53:10AM +0200, Christoph Hellwig wrote:
> Merge __calc_map_type_and_dist and calc_map_type_and_dist_warn into
> calc_map_type_and_dist to simplify the code a bit. This now means
> we add the devfn strings to the acs_buf unconditionallity even if
> the buffer is not printed, but that is not a lot of overhead and
> keeps the code much simpler.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Applied with Logan's reviewed-by to pci/p2pdma for v5.14, thanks!
> ---
> drivers/pci/p2pdma.c | 190 +++++++++++++++++--------------------------
> 1 file changed, 73 insertions(+), 117 deletions(-)
>
> diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
> index deb097ceaf41..ca2574debb2d 100644
> --- a/drivers/pci/p2pdma.c
> +++ b/drivers/pci/p2pdma.c
> @@ -388,79 +388,6 @@ static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b,
> return false;
> }
>
> -static enum pci_p2pdma_map_type
> -__calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> - int *dist, bool *acs_redirects, struct seq_buf *acs_list)
> -{
> - struct pci_dev *a = provider, *b = client, *bb;
> - int dist_a = 0;
> - int dist_b = 0;
> - int acs_cnt = 0;
> -
> - if (acs_redirects)
> - *acs_redirects = false;
> -
> - /*
> - * Note, we don't need to take references to devices returned by
> - * pci_upstream_bridge() seeing we hold a reference to a child
> - * device which will already hold a reference to the upstream bridge.
> - */
> -
> - while (a) {
> - dist_b = 0;
> -
> - if (pci_bridge_has_acs_redir(a)) {
> - seq_buf_print_bus_devfn(acs_list, a);
> - acs_cnt++;
> - }
> -
> - bb = b;
> -
> - while (bb) {
> - if (a == bb)
> - goto check_b_path_acs;
> -
> - bb = pci_upstream_bridge(bb);
> - dist_b++;
> - }
> -
> - a = pci_upstream_bridge(a);
> - dist_a++;
> - }
> -
> - if (dist)
> - *dist = dist_a + dist_b;
> -
> - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> -
> -check_b_path_acs:
> - bb = b;
> -
> - while (bb) {
> - if (a == bb)
> - break;
> -
> - if (pci_bridge_has_acs_redir(bb)) {
> - seq_buf_print_bus_devfn(acs_list, bb);
> - acs_cnt++;
> - }
> -
> - bb = pci_upstream_bridge(bb);
> - }
> -
> - if (dist)
> - *dist = dist_a + dist_b;
> -
> - if (acs_cnt) {
> - if (acs_redirects)
> - *acs_redirects = true;
> -
> - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> - }
> -
> - return PCI_P2PDMA_MAP_BUS_ADDR;
> -}
> -
> static unsigned long map_types_idx(struct pci_dev *client)
> {
> return (pci_domain_nr(client->bus) << 16) |
> @@ -502,63 +429,96 @@ static unsigned long map_types_idx(struct pci_dev *client)
> * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of
> * ports per above. If the device is not in the whitelist, return
> * PCI_P2PDMA_MAP_NOT_SUPPORTED.
> - *
> - * If any ACS redirect bits are set, then acs_redirects boolean will be set
> - * to true and their PCI device names will be appended to the acs_list
> - * seq_buf. This seq_buf is used to print a warning informing the user how
> - * to disable ACS using a command line parameter. (See
> - * calc_map_type_and_dist_warn() below)
> */
> static enum pci_p2pdma_map_type
> calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> - int *dist, bool *acs_redirects, struct seq_buf *acs_list)
> + int *dist, bool verbose)
> {
> - enum pci_p2pdma_map_type map_type;
> + enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> + struct pci_dev *a = provider, *b = client, *bb;
> + bool acs_redirects = false;
> + struct seq_buf acs_list;
> + int acs_cnt = 0;
> + int dist_a = 0;
> + int dist_b = 0;
> + char buf[128];
> +
> + seq_buf_init(&acs_list, buf, sizeof(buf));
> +
> + /*
> + * Note, we don't need to take references to devices returned by
> + * pci_upstream_bridge() seeing we hold a reference to a child
> + * device which will already hold a reference to the upstream bridge.
> + */
> + while (a) {
> + dist_b = 0;
>
> - map_type = __calc_map_type_and_dist(provider, client, dist,
> - acs_redirects, acs_list);
> + if (pci_bridge_has_acs_redir(a)) {
> + seq_buf_print_bus_devfn(&acs_list, a);
> + acs_cnt++;
> + }
>
> - if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
> - if (!cpu_supports_p2pdma() &&
> - !host_bridge_whitelist(provider, client, acs_redirects))
> - map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> + bb = b;
> +
> + while (bb) {
> + if (a == bb)
> + goto check_b_path_acs;
> +
> + bb = pci_upstream_bridge(bb);
> + dist_b++;
> + }
> +
> + a = pci_upstream_bridge(a);
> + dist_a++;
> }
>
> - if (provider->p2pdma)
> - xa_store(&provider->p2pdma->map_types, map_types_idx(client),
> - xa_mk_value(map_type), GFP_KERNEL);
> + *dist = dist_a + dist_b;
> + goto map_through_host_bridge;
>
> - return map_type;
> -}
> +check_b_path_acs:
> + bb = b;
>
> -static enum pci_p2pdma_map_type
> -calc_map_type_and_dist_warn(struct pci_dev *provider, struct pci_dev *client,
> - int *dist)
> -{
> - struct seq_buf acs_list;
> - bool acs_redirects;
> - char buf[128];
> - int ret;
> + while (bb) {
> + if (a == bb)
> + break;
>
> - seq_buf_init(&acs_list, buf, sizeof(buf));
> + if (pci_bridge_has_acs_redir(bb)) {
> + seq_buf_print_bus_devfn(&acs_list, bb);
> + acs_cnt++;
> + }
>
> - ret = calc_map_type_and_dist(provider, client, dist, &acs_redirects,
> - &acs_list);
> - if (acs_redirects) {
> + bb = pci_upstream_bridge(bb);
> + }
> +
> + *dist = dist_a + dist_b;
> +
> + if (!acs_cnt) {
> + map_type = PCI_P2PDMA_MAP_BUS_ADDR;
> + goto done;
> + }
> +
> + if (verbose) {
> + acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */
> pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
> pci_name(provider));
> - /* Drop final semicolon */
> - acs_list.buffer[acs_list.len-1] = 0;
> pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
> acs_list.buffer);
> }
> + acs_redirects = true;
>
> - if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
> - pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
> - pci_name(provider));
> +map_through_host_bridge:
> + if (!cpu_supports_p2pdma() &&
> + !host_bridge_whitelist(provider, client, acs_redirects)) {
> + if (verbose)
> + pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
> + pci_name(provider));
> + map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> }
> -
> - return ret;
> +done:
> + if (provider->p2pdma)
> + xa_store(&provider->p2pdma->map_types, map_types_idx(client),
> + xa_mk_value(map_type), GFP_KERNEL);
> + return map_type;
> }
>
> /**
> @@ -599,12 +559,8 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
> return -1;
> }
>
> - if (verbose)
> - map = calc_map_type_and_dist_warn(provider, pci_client,
> - &distance);
> - else
> - map = calc_map_type_and_dist(provider, pci_client,
> - &distance, NULL, NULL);
> + map = calc_map_type_and_dist(provider, pci_client, &distance,
> + verbose);
>
> pci_dev_put(pci_client);
>
> --
> 2.30.2
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2021-06-16 21:11 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-14 5:53 [PATCH] PCI/P2PDMA: simplify distance calculation Christoph Hellwig
2021-06-14 16:59 ` Logan Gunthorpe
2021-06-16 21:11 ` Bjorn Helgaas
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.