Skip to content

Commit 3ced8d7

Browse files
Christophe Lombardmpe
authored andcommitted
cxl: Export library to support IBM XSL
This patch exports a in-kernel 'library' API which can be called by other drivers to help interacting with an IBM XSL on a POWER9 system. The XSL (Translation Service Layer) is a stripped down version of the PSL (Power Service Layer) used in some cards such as the Mellanox CX5. Like the PSL, it implements the CAIA architecture, but has a number of differences, mostly in it's implementation dependent registers. The XSL also uses a special DMA cxl mode, which uses a slightly different init sequence for the CAPP and PHB. Signed-off-by: Andrew Donnellan <[email protected]> Signed-off-by: Christophe Lombard <[email protected]> Acked-by: Frederic Barrat <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 218ea31 commit 3ced8d7

File tree

9 files changed

+449
-30
lines changed

9 files changed

+449
-30
lines changed

arch/powerpc/include/asm/opal-api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ enum {
948948
OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2,
949949
OPAL_PHB_CAPI_MODE_SNOOP_ON = 3,
950950
OPAL_PHB_CAPI_MODE_DMA = 4,
951+
OPAL_PHB_CAPI_MODE_DMA_TVT1 = 5,
951952
};
952953

953954
/* OPAL I2C request */

drivers/misc/cxl/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ config CXL_AFU_DRIVER_OPS
1111
bool
1212
default n
1313

14+
config CXL_LIB
15+
bool
16+
default n
17+
1418
config CXL
1519
tristate "Support for IBM Coherent Accelerators (CXL)"
1620
depends on PPC_POWERNV && PCI_MSI && EEH
1721
select CXL_BASE
1822
select CXL_AFU_DRIVER_OPS
23+
select CXL_LIB
1924
default m
2025
help
2126
Select this option to enable driver support for IBM Coherent

drivers/misc/cxl/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror
33

44
cxl-y += main.o file.o irq.o fault.o native.o
55
cxl-y += context.o sysfs.o pci.o trace.o
6-
cxl-y += vphb.o phb.o api.o
6+
cxl-y += vphb.o phb.o api.o cxllib.o
77
cxl-$(CONFIG_PPC_PSERIES) += flash.o guest.o of.o hcalls.o
88
cxl-$(CONFIG_DEBUG_FS) += debugfs.o
99
obj-$(CONFIG_CXL) += cxl.o

drivers/misc/cxl/cxl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,7 @@ static inline void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct den
10101010

10111011
void cxl_handle_fault(struct work_struct *work);
10121012
void cxl_prefault(struct cxl_context *ctx, u64 wed);
1013+
int cxl_handle_mm_fault(struct mm_struct *mm, u64 dsisr, u64 dar);
10131014

10141015
struct cxl *get_cxl_adapter(int num);
10151016
int cxl_alloc_sst(struct cxl_context *ctx);
@@ -1061,6 +1062,11 @@ int cxl_afu_slbia(struct cxl_afu *afu);
10611062
int cxl_data_cache_flush(struct cxl *adapter);
10621063
int cxl_afu_disable(struct cxl_afu *afu);
10631064
int cxl_psl_purge(struct cxl_afu *afu);
1065+
int cxl_calc_capp_routing(struct pci_dev *dev, u64 *chipid,
1066+
u32 *phb_index, u64 *capp_unit_id);
1067+
int cxl_slot_is_switched(struct pci_dev *dev);
1068+
int cxl_get_xsl9_dsnctl(u64 capp_unit_id, u64 *reg);
1069+
u64 cxl_calculate_sr(bool master, bool kernel, bool real_mode, bool p9);
10641070

10651071
void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx);
10661072
void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx);

drivers/misc/cxl/cxllib.c

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/*
2+
* Copyright 2017 IBM Corp.
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version
7+
* 2 of the License, or (at your option) any later version.
8+
*/
9+
10+
#include <linux/hugetlb.h>
11+
#include <linux/sched/mm.h>
12+
#include <asm/pnv-pci.h>
13+
#include <misc/cxllib.h>
14+
15+
#include "cxl.h"
16+
17+
#define CXL_INVALID_DRA ~0ull
18+
#define CXL_DUMMY_READ_SIZE 128
19+
#define CXL_DUMMY_READ_ALIGN 8
20+
#define CXL_CAPI_WINDOW_START 0x2000000000000ull
21+
#define CXL_CAPI_WINDOW_LOG_SIZE 48
22+
#define CXL_XSL_CONFIG_CURRENT_VERSION CXL_XSL_CONFIG_VERSION1
23+
24+
25+
bool cxllib_slot_is_supported(struct pci_dev *dev, unsigned long flags)
26+
{
27+
int rc;
28+
u32 phb_index;
29+
u64 chip_id, capp_unit_id;
30+
31+
/* No flags currently supported */
32+
if (flags)
33+
return false;
34+
35+
if (!cpu_has_feature(CPU_FTR_HVMODE))
36+
return false;
37+
38+
if (!cxl_is_power9())
39+
return false;
40+
41+
if (cxl_slot_is_switched(dev))
42+
return false;
43+
44+
/* on p9, some pci slots are not connected to a CAPP unit */
45+
rc = cxl_calc_capp_routing(dev, &chip_id, &phb_index, &capp_unit_id);
46+
if (rc)
47+
return false;
48+
49+
return true;
50+
}
51+
EXPORT_SYMBOL_GPL(cxllib_slot_is_supported);
52+
53+
static DEFINE_MUTEX(dra_mutex);
54+
static u64 dummy_read_addr = CXL_INVALID_DRA;
55+
56+
static int allocate_dummy_read_buf(void)
57+
{
58+
u64 buf, vaddr;
59+
size_t buf_size;
60+
61+
/*
62+
* Dummy read buffer is 128-byte long, aligned on a
63+
* 256-byte boundary and we need the physical address.
64+
*/
65+
buf_size = CXL_DUMMY_READ_SIZE + (1ull << CXL_DUMMY_READ_ALIGN);
66+
buf = (u64) kzalloc(buf_size, GFP_KERNEL);
67+
if (!buf)
68+
return -ENOMEM;
69+
70+
vaddr = (buf + (1ull << CXL_DUMMY_READ_ALIGN) - 1) &
71+
(~0ull << CXL_DUMMY_READ_ALIGN);
72+
73+
WARN((vaddr + CXL_DUMMY_READ_SIZE) > (buf + buf_size),
74+
"Dummy read buffer alignment issue");
75+
dummy_read_addr = virt_to_phys((void *) vaddr);
76+
return 0;
77+
}
78+
79+
int cxllib_get_xsl_config(struct pci_dev *dev, struct cxllib_xsl_config *cfg)
80+
{
81+
int rc;
82+
u32 phb_index;
83+
u64 chip_id, capp_unit_id;
84+
85+
if (!cpu_has_feature(CPU_FTR_HVMODE))
86+
return -EINVAL;
87+
88+
mutex_lock(&dra_mutex);
89+
if (dummy_read_addr == CXL_INVALID_DRA) {
90+
rc = allocate_dummy_read_buf();
91+
if (rc) {
92+
mutex_unlock(&dra_mutex);
93+
return rc;
94+
}
95+
}
96+
mutex_unlock(&dra_mutex);
97+
98+
rc = cxl_calc_capp_routing(dev, &chip_id, &phb_index, &capp_unit_id);
99+
if (rc)
100+
return rc;
101+
102+
rc = cxl_get_xsl9_dsnctl(capp_unit_id, &cfg->dsnctl);
103+
if (rc)
104+
return rc;
105+
if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
106+
/* workaround for DD1 - nbwind = capiind */
107+
cfg->dsnctl |= ((u64)0x02 << (63-47));
108+
}
109+
110+
cfg->version = CXL_XSL_CONFIG_CURRENT_VERSION;
111+
cfg->log_bar_size = CXL_CAPI_WINDOW_LOG_SIZE;
112+
cfg->bar_addr = CXL_CAPI_WINDOW_START;
113+
cfg->dra = dummy_read_addr;
114+
return 0;
115+
}
116+
EXPORT_SYMBOL_GPL(cxllib_get_xsl_config);
117+
118+
int cxllib_switch_phb_mode(struct pci_dev *dev, enum cxllib_mode mode,
119+
unsigned long flags)
120+
{
121+
int rc = 0;
122+
123+
if (!cpu_has_feature(CPU_FTR_HVMODE))
124+
return -EINVAL;
125+
126+
switch (mode) {
127+
case CXL_MODE_PCI:
128+
/*
129+
* We currently don't support going back to PCI mode
130+
* However, we'll turn the invalidations off, so that
131+
* the firmware doesn't have to ack them and can do
132+
* things like reset, etc.. with no worries.
133+
* So always return EPERM (can't go back to PCI) or
134+
* EBUSY if we couldn't even turn off snooping
135+
*/
136+
rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_OFF);
137+
if (rc)
138+
rc = -EBUSY;
139+
else
140+
rc = -EPERM;
141+
break;
142+
case CXL_MODE_CXL:
143+
/* DMA only supported on TVT1 for the time being */
144+
if (flags != CXL_MODE_DMA_TVT1)
145+
return -EINVAL;
146+
rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_DMA_TVT1);
147+
if (rc)
148+
return rc;
149+
rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON);
150+
break;
151+
default:
152+
rc = -EINVAL;
153+
}
154+
return rc;
155+
}
156+
EXPORT_SYMBOL_GPL(cxllib_switch_phb_mode);
157+
158+
/*
159+
* When switching the PHB to capi mode, the TVT#1 entry for
160+
* the Partitionable Endpoint is set in bypass mode, like
161+
* in PCI mode.
162+
* Configure the device dma to use TVT#1, which is done
163+
* by calling dma_set_mask() with a mask large enough.
164+
*/
165+
int cxllib_set_device_dma(struct pci_dev *dev, unsigned long flags)
166+
{
167+
int rc;
168+
169+
if (flags)
170+
return -EINVAL;
171+
172+
rc = dma_set_mask(&dev->dev, DMA_BIT_MASK(64));
173+
return rc;
174+
}
175+
EXPORT_SYMBOL_GPL(cxllib_set_device_dma);
176+
177+
int cxllib_get_PE_attributes(struct task_struct *task,
178+
unsigned long translation_mode,
179+
struct cxllib_pe_attributes *attr)
180+
{
181+
struct mm_struct *mm = NULL;
182+
183+
if (translation_mode != CXL_TRANSLATED_MODE &&
184+
translation_mode != CXL_REAL_MODE)
185+
return -EINVAL;
186+
187+
attr->sr = cxl_calculate_sr(false,
188+
task == NULL,
189+
translation_mode == CXL_REAL_MODE,
190+
true);
191+
attr->lpid = mfspr(SPRN_LPID);
192+
if (task) {
193+
mm = get_task_mm(task);
194+
if (mm == NULL)
195+
return -EINVAL;
196+
/*
197+
* Caller is keeping a reference on mm_users for as long
198+
* as XSL uses the memory context
199+
*/
200+
attr->pid = mm->context.id;
201+
mmput(mm);
202+
} else {
203+
attr->pid = 0;
204+
}
205+
attr->tid = 0;
206+
return 0;
207+
}
208+
EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes);
209+
210+
int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags)
211+
{
212+
int rc;
213+
u64 dar;
214+
struct vm_area_struct *vma = NULL;
215+
unsigned long page_size;
216+
217+
if (mm == NULL)
218+
return -EFAULT;
219+
220+
down_read(&mm->mmap_sem);
221+
222+
for (dar = addr; dar < addr + size; dar += page_size) {
223+
if (!vma || dar < vma->vm_start || dar > vma->vm_end) {
224+
vma = find_vma(mm, addr);
225+
if (!vma) {
226+
pr_err("Can't find vma for addr %016llx\n", addr);
227+
rc = -EFAULT;
228+
goto out;
229+
}
230+
/* get the size of the pages allocated */
231+
page_size = vma_kernel_pagesize(vma);
232+
}
233+
234+
rc = cxl_handle_mm_fault(mm, flags, dar);
235+
if (rc) {
236+
pr_err("cxl_handle_mm_fault failed %d", rc);
237+
rc = -EFAULT;
238+
goto out;
239+
}
240+
}
241+
rc = 0;
242+
out:
243+
up_read(&mm->mmap_sem);
244+
return rc;
245+
}
246+
EXPORT_SYMBOL_GPL(cxllib_handle_fault);

drivers/misc/cxl/fault.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,15 @@ static int cxl_handle_segment_miss(struct cxl_context *ctx,
132132
return IRQ_HANDLED;
133133
}
134134

135-
static void cxl_handle_page_fault(struct cxl_context *ctx,
136-
struct mm_struct *mm, u64 dsisr, u64 dar)
135+
int cxl_handle_mm_fault(struct mm_struct *mm, u64 dsisr, u64 dar)
137136
{
138137
unsigned flt = 0;
139138
int result;
140139
unsigned long access, flags, inv_flags = 0;
141140

142-
trace_cxl_pte_miss(ctx, dsisr, dar);
143-
144141
if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) {
145142
pr_devel("copro_handle_mm_fault failed: %#x\n", result);
146-
return cxl_ack_ae(ctx);
143+
return result;
147144
}
148145

149146
if (!radix_enabled()) {
@@ -155,9 +152,8 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
155152
if (dsisr & CXL_PSL_DSISR_An_S)
156153
access |= _PAGE_WRITE;
157154

158-
access |= _PAGE_PRIVILEGED;
159-
if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID))
160-
access &= ~_PAGE_PRIVILEGED;
155+
if (!mm && (REGION_ID(dar) != USER_REGION_ID))
156+
access |= _PAGE_PRIVILEGED;
161157

162158
if (dsisr & DSISR_NOHPTE)
163159
inv_flags |= HPTE_NOHPTE_UPDATE;
@@ -166,8 +162,21 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
166162
hash_page_mm(mm, dar, access, 0x300, inv_flags);
167163
local_irq_restore(flags);
168164
}
169-
pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe);
170-
cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
165+
return 0;
166+
}
167+
168+
static void cxl_handle_page_fault(struct cxl_context *ctx,
169+
struct mm_struct *mm,
170+
u64 dsisr, u64 dar)
171+
{
172+
trace_cxl_pte_miss(ctx, dsisr, dar);
173+
174+
if (cxl_handle_mm_fault(mm, dsisr, dar)) {
175+
cxl_ack_ae(ctx);
176+
} else {
177+
pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe);
178+
cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
179+
}
171180
}
172181

173182
/*

0 commit comments

Comments
 (0)