Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Philippe Bergheaud and committed by
Michael Ellerman
87db7579 acccc984

+129 -5
+11
Documentation/ABI/testing/sysfs-class-ocxl
··· 33 33 Contact: linuxppc-dev@lists.ozlabs.org 34 34 Description: read/write 35 35 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
+76 -5
drivers/misc/ocxl/config.c
··· 71 71 return 0; 72 72 } 73 73 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 + 74 88 static void read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn) 75 89 { 76 90 u16 val; ··· 173 159 static int read_dvsec_vendor(struct pci_dev *dev) 174 160 { 175 161 int pos; 176 - u32 cfg, tlx, dlx; 162 + u32 cfg, tlx, dlx, reset_reload; 177 163 178 164 /* 179 - * vendor specific DVSEC is optional 165 + * vendor specific DVSEC, for IBM images only. Some older 166 + * images may not have it 180 167 * 181 - * It's currently only used on function 0 to specify the 182 - * version of some logic blocks. Some older images may not 183 - * even have it so we ignore any errors 168 + * It's only used on function 0 to specify the version of some 169 + * logic blocks and to give access to special registers to 170 + * enable host-based flashing. 184 171 */ 185 172 if (PCI_FUNC(dev->devfn) != 0) 186 173 return 0; ··· 193 178 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_CFG_VERS, &cfg); 194 179 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_TLX_VERS, &tlx); 195 180 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_DLX_VERS, &dlx); 181 + pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD, 182 + &reset_reload); 196 183 197 184 dev_dbg(&dev->dev, "Vendor specific DVSEC:\n"); 198 185 dev_dbg(&dev->dev, " CFG version = 0x%x\n", cfg); 199 186 dev_dbg(&dev->dev, " TLX version = 0x%x\n", tlx); 200 187 dev_dbg(&dev->dev, " DLX version = 0x%x\n", dlx); 188 + dev_dbg(&dev->dev, " ResetReload = 0x%x\n", reset_reload); 189 + return 0; 190 + } 191 + 192 + static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0, 193 + int *out_pos) 194 + { 195 + int pos; 196 + 197 + if (PCI_FUNC(dev->devfn) != 0) { 198 + dev = get_function_0(dev); 199 + if (!dev) 200 + return -1; 201 + } 202 + pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID); 203 + if (!pos) 204 + return -1; 205 + *dev0 = dev; 206 + *out_pos = pos; 207 + return 0; 208 + } 209 + 210 + int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val) 211 + { 212 + struct pci_dev *dev0; 213 + u32 reset_reload; 214 + int pos; 215 + 216 + if (get_dvsec_vendor0(dev, &dev0, &pos)) 217 + return -1; 218 + 219 + pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD, 220 + &reset_reload); 221 + *val = !!(reset_reload & BIT(0)); 222 + return 0; 223 + } 224 + 225 + int ocxl_config_set_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 + if (val) 237 + reset_reload |= BIT(0); 238 + else 239 + reset_reload &= ~BIT(0); 240 + pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD, 241 + reset_reload); 201 242 return 0; 202 243 } 203 244
+6
drivers/misc/ocxl/ocxl_internal.h
··· 113 113 int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count); 114 114 115 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 + 121 + /* 116 122 * Check if an AFU index is valid for the given function. 117 123 * 118 124 * AFU indexes can be sparse, so a driver should check all indexes up
+35
drivers/misc/ocxl/sysfs.c
··· 51 51 afu->pasid_count, afu->pasid_max); 52 52 } 53 53 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 + 54 88 static struct device_attribute afu_attrs[] = { 55 89 __ATTR_RO(global_mmio_size), 56 90 __ATTR_RO(pp_mmio_size), 57 91 __ATTR_RO(afu_version), 58 92 __ATTR_RO(contexts), 93 + __ATTR_RW(reload_on_reset), 59 94 }; 60 95 61 96 static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj,
+1
include/misc/ocxl-config.h
··· 41 41 #define OCXL_DVSEC_VENDOR_CFG_VERS 0x0C 42 42 #define OCXL_DVSEC_VENDOR_TLX_VERS 0x10 43 43 #define OCXL_DVSEC_VENDOR_DLX_VERS 0x20 44 + #define OCXL_DVSEC_VENDOR_RESET_RELOAD 0x38 44 45 45 46 #endif /* _OCXL_CONFIG_H_ */