diff options
-rw-r--r-- | drivers/misc/cxl/fault.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index cb4f3231b451..c99e896604ee 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c | |||
@@ -21,11 +21,20 @@ | |||
21 | 21 | ||
22 | #include "cxl.h" | 22 | #include "cxl.h" |
23 | 23 | ||
24 | /* This finds a free SSTE for the given SLB */ | 24 | static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb) |
25 | { | ||
26 | return ((sste->vsid_data == cpu_to_be64(slb->vsid)) && | ||
27 | (sste->esid_data == cpu_to_be64(slb->esid))); | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * This finds a free SSTE for the given SLB, or returns NULL if it's already in | ||
32 | * the segment table. | ||
33 | */ | ||
25 | static struct cxl_sste* find_free_sste(struct cxl_context *ctx, | 34 | static struct cxl_sste* find_free_sste(struct cxl_context *ctx, |
26 | struct copro_slb *slb) | 35 | struct copro_slb *slb) |
27 | { | 36 | { |
28 | struct cxl_sste *primary, *sste; | 37 | struct cxl_sste *primary, *sste, *ret = NULL; |
29 | unsigned int mask = (ctx->sst_size >> 7) - 1; /* SSTP0[SegTableSize] */ | 38 | unsigned int mask = (ctx->sst_size >> 7) - 1; /* SSTP0[SegTableSize] */ |
30 | unsigned int entry; | 39 | unsigned int entry; |
31 | unsigned int hash; | 40 | unsigned int hash; |
@@ -38,15 +47,19 @@ static struct cxl_sste* find_free_sste(struct cxl_context *ctx, | |||
38 | primary = ctx->sstp + (hash << 3); | 47 | primary = ctx->sstp + (hash << 3); |
39 | 48 | ||
40 | for (entry = 0, sste = primary; entry < 8; entry++, sste++) { | 49 | for (entry = 0, sste = primary; entry < 8; entry++, sste++) { |
41 | if (!(be64_to_cpu(sste->esid_data) & SLB_ESID_V)) | 50 | if (!ret && !(be64_to_cpu(sste->esid_data) & SLB_ESID_V)) |
42 | return sste; | 51 | ret = sste; |
52 | if (sste_matches(sste, slb)) | ||
53 | return NULL; | ||
43 | } | 54 | } |
55 | if (ret) | ||
56 | return ret; | ||
44 | 57 | ||
45 | /* Nothing free, select an entry to cast out */ | 58 | /* Nothing free, select an entry to cast out */ |
46 | sste = primary + ctx->sst_lru; | 59 | ret = primary + ctx->sst_lru; |
47 | ctx->sst_lru = (ctx->sst_lru + 1) & 0x7; | 60 | ctx->sst_lru = (ctx->sst_lru + 1) & 0x7; |
48 | 61 | ||
49 | return sste; | 62 | return ret; |
50 | } | 63 | } |
51 | 64 | ||
52 | static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb) | 65 | static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb) |
@@ -57,12 +70,15 @@ static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb) | |||
57 | 70 | ||
58 | spin_lock_irqsave(&ctx->sste_lock, flags); | 71 | spin_lock_irqsave(&ctx->sste_lock, flags); |
59 | sste = find_free_sste(ctx, slb); | 72 | sste = find_free_sste(ctx, slb); |
73 | if (!sste) | ||
74 | goto out_unlock; | ||
60 | 75 | ||
61 | pr_devel("CXL Populating SST[%li]: %#llx %#llx\n", | 76 | pr_devel("CXL Populating SST[%li]: %#llx %#llx\n", |
62 | sste - ctx->sstp, slb->vsid, slb->esid); | 77 | sste - ctx->sstp, slb->vsid, slb->esid); |
63 | 78 | ||
64 | sste->vsid_data = cpu_to_be64(slb->vsid); | 79 | sste->vsid_data = cpu_to_be64(slb->vsid); |
65 | sste->esid_data = cpu_to_be64(slb->esid); | 80 | sste->esid_data = cpu_to_be64(slb->esid); |
81 | out_unlock: | ||
66 | spin_unlock_irqrestore(&ctx->sste_lock, flags); | 82 | spin_unlock_irqrestore(&ctx->sste_lock, flags); |
67 | } | 83 | } |
68 | 84 | ||