Skip to content

Commit b3a8822

Browse files
djbwdavejiang
authored andcommitted
cxl/region: Consolidate cxl_decoder_kill_region() and cxl_region_detach()
Both detach_target() and cxld_unregister() want to tear down a cxl_region when an endpoint decoder is either detached or destroyed. When a region is to be destroyed cxl_region_detach() releases cxl_region_rwsem unbinds the cxl_region driver and re-acquires the rwsem. This "reverse" locking pattern is difficult to reason about, not amenable to scope-based cleanup, and the minor differences in the calling context of detach_target() and cxld_unregister() currently results in the cxl_decoder_kill_region() wrapper. Introduce cxl_decoder_detach() to wrap a core __cxl_decoder_detach() that serves both cases. I.e. either detaching a known position in a region (interruptible), or detaching an endpoint decoder if it is found to be a member of a region (uninterruptible). Cc: Davidlohr Bueso <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Dave Jiang <[email protected]> Cc: Alison Schofield <[email protected]> Cc: Vishal Verma <[email protected]> Cc: Ira Weiny <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Dan Williams <[email protected]> Reviewed-by: Fabio M. De Francesco <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Alison Schofield <[email protected]> Reviewed-by: Davidlohr Bueso <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Dave Jiang <[email protected]>
1 parent 695d945 commit b3a8822

File tree

3 files changed

+75
-52
lines changed

3 files changed

+75
-52
lines changed

drivers/cxl/core/core.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ extern const struct device_type cxl_pmu_type;
1212

1313
extern struct attribute_group cxl_base_attribute_group;
1414

15+
enum cxl_detach_mode {
16+
DETACH_ONLY,
17+
DETACH_INVALIDATE,
18+
};
19+
1520
#ifdef CONFIG_CXL_REGION
1621
extern struct device_attribute dev_attr_create_pmem_region;
1722
extern struct device_attribute dev_attr_create_ram_region;
@@ -20,7 +25,11 @@ extern struct device_attribute dev_attr_region;
2025
extern const struct device_type cxl_pmem_region_type;
2126
extern const struct device_type cxl_dax_region_type;
2227
extern const struct device_type cxl_region_type;
23-
void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
28+
29+
int cxl_decoder_detach(struct cxl_region *cxlr,
30+
struct cxl_endpoint_decoder *cxled, int pos,
31+
enum cxl_detach_mode mode);
32+
2433
#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
2534
#define CXL_REGION_TYPE(x) (&cxl_region_type)
2635
#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
@@ -48,7 +57,9 @@ static inline int cxl_get_poison_by_endpoint(struct cxl_port *port)
4857
{
4958
return 0;
5059
}
51-
static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
60+
static inline int cxl_decoder_detach(struct cxl_region *cxlr,
61+
struct cxl_endpoint_decoder *cxled,
62+
int pos, enum cxl_detach_mode mode)
5263
{
5364
}
5465
static inline int cxl_region_init(void)

drivers/cxl/core/port.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,12 +2001,9 @@ EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, "CXL");
20012001

20022002
static void cxld_unregister(void *dev)
20032003
{
2004-
struct cxl_endpoint_decoder *cxled;
2005-
2006-
if (is_endpoint_decoder(dev)) {
2007-
cxled = to_cxl_endpoint_decoder(dev);
2008-
cxl_decoder_kill_region(cxled);
2009-
}
2004+
if (is_endpoint_decoder(dev))
2005+
cxl_decoder_detach(NULL, to_cxl_endpoint_decoder(dev), -1,
2006+
DETACH_INVALIDATE);
20102007

20112008
device_unregister(dev);
20122009
}

drivers/cxl/core/region.c

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,27 +2135,43 @@ static int cxl_region_attach(struct cxl_region *cxlr,
21352135
return 0;
21362136
}
21372137

2138-
static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
2138+
static struct cxl_region *
2139+
__cxl_decoder_detach(struct cxl_region *cxlr,
2140+
struct cxl_endpoint_decoder *cxled, int pos,
2141+
enum cxl_detach_mode mode)
21392142
{
2140-
struct cxl_port *iter, *ep_port = cxled_to_port(cxled);
2141-
struct cxl_region *cxlr = cxled->cxld.region;
21422143
struct cxl_region_params *p;
2143-
int rc = 0;
21442144

21452145
lockdep_assert_held_write(&cxl_region_rwsem);
21462146

2147-
if (!cxlr)
2148-
return 0;
2147+
if (!cxled) {
2148+
p = &cxlr->params;
21492149

2150-
p = &cxlr->params;
2151-
get_device(&cxlr->dev);
2150+
if (pos >= p->interleave_ways) {
2151+
dev_dbg(&cxlr->dev, "position %d out of range %d\n",
2152+
pos, p->interleave_ways);
2153+
return ERR_PTR(-ENXIO);
2154+
}
2155+
2156+
if (!p->targets[pos])
2157+
return NULL;
2158+
cxled = p->targets[pos];
2159+
} else {
2160+
cxlr = cxled->cxld.region;
2161+
if (!cxlr)
2162+
return NULL;
2163+
p = &cxlr->params;
2164+
}
2165+
2166+
if (mode == DETACH_INVALIDATE)
2167+
cxled->part = -1;
21522168

21532169
if (p->state > CXL_CONFIG_ACTIVE) {
21542170
cxl_region_decode_reset(cxlr, p->interleave_ways);
21552171
p->state = CXL_CONFIG_ACTIVE;
21562172
}
21572173

2158-
for (iter = ep_port; !is_cxl_root(iter);
2174+
for (struct cxl_port *iter = cxled_to_port(cxled); !is_cxl_root(iter);
21592175
iter = to_cxl_port(iter->dev.parent))
21602176
cxl_port_detach_region(iter, cxlr, cxled);
21612177

@@ -2166,7 +2182,7 @@ static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
21662182
dev_WARN_ONCE(&cxlr->dev, 1, "expected %s:%s at position %d\n",
21672183
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
21682184
cxled->pos);
2169-
goto out;
2185+
return NULL;
21702186
}
21712187

21722188
if (p->state == CXL_CONFIG_ACTIVE) {
@@ -2180,21 +2196,42 @@ static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
21802196
.end = -1,
21812197
};
21822198

2183-
/* notify the region driver that one of its targets has departed */
2184-
up_write(&cxl_region_rwsem);
2185-
device_release_driver(&cxlr->dev);
2186-
down_write(&cxl_region_rwsem);
2187-
out:
2188-
put_device(&cxlr->dev);
2189-
return rc;
2199+
get_device(&cxlr->dev);
2200+
return cxlr;
21902201
}
21912202

2192-
void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
2203+
/*
2204+
* Cleanup a decoder's interest in a region. There are 2 cases to
2205+
* handle, removing an unknown @cxled from a known position in a region
2206+
* (detach_target()) or removing a known @cxled from an unknown @cxlr
2207+
* (cxld_unregister())
2208+
*
2209+
* When the detachment finds a region release the region driver.
2210+
*/
2211+
int cxl_decoder_detach(struct cxl_region *cxlr,
2212+
struct cxl_endpoint_decoder *cxled, int pos,
2213+
enum cxl_detach_mode mode)
21932214
{
2194-
down_write(&cxl_region_rwsem);
2195-
cxled->part = -1;
2196-
cxl_region_detach(cxled);
2215+
struct cxl_region *detach;
2216+
2217+
/* when the decoder is being destroyed lock unconditionally */
2218+
if (mode == DETACH_INVALIDATE)
2219+
down_write(&cxl_region_rwsem);
2220+
else {
2221+
int rc = down_write_killable(&cxl_region_rwsem);
2222+
2223+
if (rc)
2224+
return rc;
2225+
}
2226+
2227+
detach = __cxl_decoder_detach(cxlr, cxled, pos, mode);
21972228
up_write(&cxl_region_rwsem);
2229+
2230+
if (detach) {
2231+
device_release_driver(&detach->dev);
2232+
put_device(&detach->dev);
2233+
}
2234+
return 0;
21982235
}
21992236

22002237
static int attach_target(struct cxl_region *cxlr,
@@ -2225,29 +2262,7 @@ static int attach_target(struct cxl_region *cxlr,
22252262

22262263
static int detach_target(struct cxl_region *cxlr, int pos)
22272264
{
2228-
struct cxl_region_params *p = &cxlr->params;
2229-
int rc;
2230-
2231-
rc = down_write_killable(&cxl_region_rwsem);
2232-
if (rc)
2233-
return rc;
2234-
2235-
if (pos >= p->interleave_ways) {
2236-
dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
2237-
p->interleave_ways);
2238-
rc = -ENXIO;
2239-
goto out;
2240-
}
2241-
2242-
if (!p->targets[pos]) {
2243-
rc = 0;
2244-
goto out;
2245-
}
2246-
2247-
rc = cxl_region_detach(p->targets[pos]);
2248-
out:
2249-
up_write(&cxl_region_rwsem);
2250-
return rc;
2265+
return cxl_decoder_detach(cxlr, NULL, pos, DETACH_ONLY);
22512266
}
22522267

22532268
static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos,

0 commit comments

Comments
 (0)