Skip to content

Commit 87db757

Browse files
philippe56mpe
authored andcommitted
ocxl: control via sysfs whether the FPGA is reloaded on a link reset
Some opencapi FPGA images allow to control if the FPGA should be reloaded on the next adapter reset. If it is supported, the image specifies it through a Vendor Specific DVSEC in the config space of function 0. Signed-off-by: Philippe Bergheaud <felix@linux.ibm.com> Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200619140439.153962-1-fbarrat@linux.ibm.com
1 parent acccc98 commit 87db757

File tree

5 files changed

+129
-5
lines changed

5 files changed

+129
-5
lines changed

Documentation/ABI/testing/sysfs-class-ocxl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,14 @@ Date: January 2018
3333
Contact: linuxppc-dev@lists.ozlabs.org
3434
Description: read/write
3535
Give access the global mmio area for the AFU
36+
37+
What: /sys/class/ocxl/<afu name>/reload_on_reset
38+
Date: February 2020
39+
Contact: linuxppc-dev@lists.ozlabs.org
40+
Description: read/write
41+
Control whether the FPGA is reloaded on a link reset. Enabled
42+
through a vendor-specific logic block on the FPGA.
43+
0 Do not reload FPGA image from flash
44+
1 Reload FPGA image from flash
45+
unavailable
46+
The device does not support this capability

drivers/misc/ocxl/config.c

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ static int find_dvsec_afu_ctrl(struct pci_dev *dev, u8 afu_idx)
7171
return 0;
7272
}
7373

74+
/**
75+
* get_function_0() - Find a related PCI device (function 0)
76+
* @device: PCI device to match
77+
*
78+
* Returns a pointer to the related device, or null if not found
79+
*/
80+
static struct pci_dev *get_function_0(struct pci_dev *dev)
81+
{
82+
unsigned int devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
83+
84+
return pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
85+
dev->bus->number, devfn);
86+
}
87+
7488
static void read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn)
7589
{
7690
u16 val;
@@ -159,14 +173,15 @@ static int read_dvsec_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn)
159173
static int read_dvsec_vendor(struct pci_dev *dev)
160174
{
161175
int pos;
162-
u32 cfg, tlx, dlx;
176+
u32 cfg, tlx, dlx, reset_reload;
163177

164178
/*
165-
* vendor specific DVSEC is optional
179+
* vendor specific DVSEC, for IBM images only. Some older
180+
* images may not have it
166181
*
167-
* It's currently only used on function 0 to specify the
168-
* version of some logic blocks. Some older images may not
169-
* even have it so we ignore any errors
182+
* It's only used on function 0 to specify the version of some
183+
* logic blocks and to give access to special registers to
184+
* enable host-based flashing.
170185
*/
171186
if (PCI_FUNC(dev->devfn) != 0)
172187
return 0;
@@ -178,11 +193,67 @@ static int read_dvsec_vendor(struct pci_dev *dev)
178193
pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_CFG_VERS, &cfg);
179194
pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_TLX_VERS, &tlx);
180195
pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_DLX_VERS, &dlx);
196+
pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
197+
&reset_reload);
181198

182199
dev_dbg(&dev->dev, "Vendor specific DVSEC:\n");
183200
dev_dbg(&dev->dev, " CFG version = 0x%x\n", cfg);
184201
dev_dbg(&dev->dev, " TLX version = 0x%x\n", tlx);
185202
dev_dbg(&dev->dev, " DLX version = 0x%x\n", dlx);
203+
dev_dbg(&dev->dev, " ResetReload = 0x%x\n", reset_reload);
204+
return 0;
205+
}
206+
207+
static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
208+
int *out_pos)
209+
{
210+
int pos;
211+
212+
if (PCI_FUNC(dev->devfn) != 0) {
213+
dev = get_function_0(dev);
214+
if (!dev)
215+
return -1;
216+
}
217+
pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
218+
if (!pos)
219+
return -1;
220+
*dev0 = dev;
221+
*out_pos = pos;
222+
return 0;
223+
}
224+
225+
int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val)
226+
{
227+
struct pci_dev *dev0;
228+
u32 reset_reload;
229+
int pos;
230+
231+
if (get_dvsec_vendor0(dev, &dev0, &pos))
232+
return -1;
233+
234+
pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
235+
&reset_reload);
236+
*val = !!(reset_reload & BIT(0));
237+
return 0;
238+
}
239+
240+
int ocxl_config_set_reset_reload(struct pci_dev *dev, int val)
241+
{
242+
struct pci_dev *dev0;
243+
u32 reset_reload;
244+
int pos;
245+
246+
if (get_dvsec_vendor0(dev, &dev0, &pos))
247+
return -1;
248+
249+
pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
250+
&reset_reload);
251+
if (val)
252+
reset_reload |= BIT(0);
253+
else
254+
reset_reload &= ~BIT(0);
255+
pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
256+
reset_reload);
186257
return 0;
187258
}
188259

drivers/misc/ocxl/ocxl_internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ void ocxl_actag_afu_free(struct ocxl_fn *fn, u32 start, u32 size);
112112
*/
113113
int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count);
114114

115+
/*
116+
* Control whether the FPGA is reloaded on a link reset
117+
*/
118+
int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val);
119+
int ocxl_config_set_reset_reload(struct pci_dev *dev, int val);
120+
115121
/*
116122
* Check if an AFU index is valid for the given function.
117123
*

drivers/misc/ocxl/sysfs.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,46 @@ static ssize_t contexts_show(struct device *device,
5151
afu->pasid_count, afu->pasid_max);
5252
}
5353

54+
static ssize_t reload_on_reset_show(struct device *device,
55+
struct device_attribute *attr,
56+
char *buf)
57+
{
58+
struct ocxl_afu *afu = to_afu(device);
59+
struct ocxl_fn *fn = afu->fn;
60+
struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
61+
int val;
62+
63+
if (ocxl_config_get_reset_reload(pci_dev, &val))
64+
return scnprintf(buf, PAGE_SIZE, "unavailable\n");
65+
66+
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
67+
}
68+
69+
static ssize_t reload_on_reset_store(struct device *device,
70+
struct device_attribute *attr,
71+
const char *buf, size_t count)
72+
{
73+
struct ocxl_afu *afu = to_afu(device);
74+
struct ocxl_fn *fn = afu->fn;
75+
struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
76+
int rc, val;
77+
78+
rc = kstrtoint(buf, 0, &val);
79+
if (rc || (val != 0 && val != 1))
80+
return -EINVAL;
81+
82+
if (ocxl_config_set_reset_reload(pci_dev, val))
83+
return -ENODEV;
84+
85+
return count;
86+
}
87+
5488
static struct device_attribute afu_attrs[] = {
5589
__ATTR_RO(global_mmio_size),
5690
__ATTR_RO(pp_mmio_size),
5791
__ATTR_RO(afu_version),
5892
__ATTR_RO(contexts),
93+
__ATTR_RW(reload_on_reset),
5994
};
6095

6196
static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj,

include/misc/ocxl-config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@
4141
#define OCXL_DVSEC_VENDOR_CFG_VERS 0x0C
4242
#define OCXL_DVSEC_VENDOR_TLX_VERS 0x10
4343
#define OCXL_DVSEC_VENDOR_DLX_VERS 0x20
44+
#define OCXL_DVSEC_VENDOR_RESET_RELOAD 0x38
4445

4546
#endif /* _OCXL_CONFIG_H_ */

0 commit comments

Comments
 (0)