Skip to content

Commit 0cf36a8

Browse files
AlisonSchofielddjbw
authored andcommitted
cxl/region: Use cxl_calc_interleave_pos() for auto-discovery
For auto-discovered regions the driver must assign each target to a valid position in the region interleave set based on the decoder topology. The current implementation fails to parse valid decode topologies, as it does not consider the child offset into a parent port. The sort put all targets of one port ahead of another port when an interleave was expected, causing the region assembly to fail. Replace the existing relative sort with cxl_calc_interleave_pos() that finds the exact position in a region interleave for an endpoint based on a walk up the ancestral tree from endpoint to root decoder. cxl_calc_interleave_pos() was introduced in a prior patch, so the work here is to use it in cxl_region_sort_targets(). Remove the obsoleted helper functions from the prior sort. Testing passes on pre-production hardware with BIOS defined regions that natively trigger this autodiscovery path of the region driver. Testing passes a CXL unit test using the dev_dbg() calculation test (see cxl_region_attach()) across an expanded set of region configs: 1, 1, 1+1, 1+1+1, 2, 2+2, 2+2+2, 2+2+2+2, 4, 4+4, where each number represents the count of endpoints per host bridge. Fixes: a32320b ("cxl/region: Add region autodiscovery") Reported-by: Dmytro Adamenko <dmytro.adamenko@intel.com> Signed-off-by: Alison Schofield <alison.schofield@intel.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Jim Harris <jim.harris@samsung.com> Link: https://lore.kernel.org/r/3946cc55ddc19678733eddc9de2c317749f43f3b.1698263080.git.alison.schofield@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent a3e00c9 commit 0cf36a8

File tree

1 file changed

+15
-112
lines changed

1 file changed

+15
-112
lines changed

drivers/cxl/core/region.c

Lines changed: 15 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,14 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
14741474
return 0;
14751475
}
14761476

1477+
static int cmp_interleave_pos(const void *a, const void *b)
1478+
{
1479+
struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a;
1480+
struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b;
1481+
1482+
return cxled_a->pos - cxled_b->pos;
1483+
}
1484+
14771485
static struct cxl_port *next_port(struct cxl_port *port)
14781486
{
14791487
if (!port->parent_dport)
@@ -1604,131 +1612,26 @@ static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled)
16041612
return pos;
16051613
}
16061614

1607-
static void find_positions(const struct cxl_switch_decoder *cxlsd,
1608-
const struct cxl_port *iter_a,
1609-
const struct cxl_port *iter_b, int *a_pos,
1610-
int *b_pos)
1611-
{
1612-
int i;
1613-
1614-
for (i = 0, *a_pos = -1, *b_pos = -1; i < cxlsd->nr_targets; i++) {
1615-
if (cxlsd->target[i] == iter_a->parent_dport)
1616-
*a_pos = i;
1617-
else if (cxlsd->target[i] == iter_b->parent_dport)
1618-
*b_pos = i;
1619-
if (*a_pos >= 0 && *b_pos >= 0)
1620-
break;
1621-
}
1622-
}
1623-
1624-
static int cmp_decode_pos(const void *a, const void *b)
1625-
{
1626-
struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a;
1627-
struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b;
1628-
struct cxl_memdev *cxlmd_a = cxled_to_memdev(cxled_a);
1629-
struct cxl_memdev *cxlmd_b = cxled_to_memdev(cxled_b);
1630-
struct cxl_port *port_a = cxled_to_port(cxled_a);
1631-
struct cxl_port *port_b = cxled_to_port(cxled_b);
1632-
struct cxl_port *iter_a, *iter_b, *port = NULL;
1633-
struct cxl_switch_decoder *cxlsd;
1634-
struct device *dev;
1635-
int a_pos, b_pos;
1636-
unsigned int seq;
1637-
1638-
/* Exit early if any prior sorting failed */
1639-
if (cxled_a->pos < 0 || cxled_b->pos < 0)
1640-
return 0;
1641-
1642-
/*
1643-
* Walk up the hierarchy to find a shared port, find the decoder that
1644-
* maps the range, compare the relative position of those dport
1645-
* mappings.
1646-
*/
1647-
for (iter_a = port_a; iter_a; iter_a = next_port(iter_a)) {
1648-
struct cxl_port *next_a, *next_b;
1649-
1650-
next_a = next_port(iter_a);
1651-
if (!next_a)
1652-
break;
1653-
1654-
for (iter_b = port_b; iter_b; iter_b = next_port(iter_b)) {
1655-
next_b = next_port(iter_b);
1656-
if (next_a != next_b)
1657-
continue;
1658-
port = next_a;
1659-
break;
1660-
}
1661-
1662-
if (port)
1663-
break;
1664-
}
1665-
1666-
if (!port) {
1667-
dev_err(cxlmd_a->dev.parent,
1668-
"failed to find shared port with %s\n",
1669-
dev_name(cxlmd_b->dev.parent));
1670-
goto err;
1671-
}
1672-
1673-
dev = device_find_child(&port->dev, &cxled_a->cxld.hpa_range,
1674-
match_switch_decoder_by_range);
1675-
if (!dev) {
1676-
struct range *range = &cxled_a->cxld.hpa_range;
1677-
1678-
dev_err(port->uport_dev,
1679-
"failed to find decoder that maps %#llx-%#llx\n",
1680-
range->start, range->end);
1681-
goto err;
1682-
}
1683-
1684-
cxlsd = to_cxl_switch_decoder(dev);
1685-
do {
1686-
seq = read_seqbegin(&cxlsd->target_lock);
1687-
find_positions(cxlsd, iter_a, iter_b, &a_pos, &b_pos);
1688-
} while (read_seqretry(&cxlsd->target_lock, seq));
1689-
1690-
put_device(dev);
1691-
1692-
if (a_pos < 0 || b_pos < 0) {
1693-
dev_err(port->uport_dev,
1694-
"failed to find shared decoder for %s and %s\n",
1695-
dev_name(cxlmd_a->dev.parent),
1696-
dev_name(cxlmd_b->dev.parent));
1697-
goto err;
1698-
}
1699-
1700-
dev_dbg(port->uport_dev, "%s comes %s %s\n",
1701-
dev_name(cxlmd_a->dev.parent),
1702-
a_pos - b_pos < 0 ? "before" : "after",
1703-
dev_name(cxlmd_b->dev.parent));
1704-
1705-
return a_pos - b_pos;
1706-
err:
1707-
cxled_a->pos = -1;
1708-
return 0;
1709-
}
1710-
17111615
static int cxl_region_sort_targets(struct cxl_region *cxlr)
17121616
{
17131617
struct cxl_region_params *p = &cxlr->params;
17141618
int i, rc = 0;
17151619

1716-
sort(p->targets, p->nr_targets, sizeof(p->targets[0]), cmp_decode_pos,
1717-
NULL);
1718-
17191620
for (i = 0; i < p->nr_targets; i++) {
17201621
struct cxl_endpoint_decoder *cxled = p->targets[i];
17211622

1623+
cxled->pos = cxl_calc_interleave_pos(cxled);
17221624
/*
1723-
* Record that sorting failed, but still continue to restore
1724-
* cxled->pos with its ->targets[] position so that follow-on
1725-
* code paths can reliably do p->targets[cxled->pos] to
1726-
* self-reference their entry.
1625+
* Record that sorting failed, but still continue to calc
1626+
* cxled->pos so that follow-on code paths can reliably
1627+
* do p->targets[cxled->pos] to self-reference their entry.
17271628
*/
17281629
if (cxled->pos < 0)
17291630
rc = -ENXIO;
1730-
cxled->pos = i;
17311631
}
1632+
/* Keep the cxlr target list in interleave position order */
1633+
sort(p->targets, p->nr_targets, sizeof(p->targets[0]),
1634+
cmp_interleave_pos, NULL);
17321635

17331636
dev_dbg(&cxlr->dev, "region sort %s\n", rc ? "failed" : "successful");
17341637
return rc;

0 commit comments

Comments
 (0)