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

PCI: Restore PRI and PASID state after Function-Level Reset

After a Function-Level Reset, PCI states need to be restored. Save PASID
features and PRI reqs cached.

[bhelgaas: search for capability only if PRI/PASID were enabled]
Signed-off-by: CQ Tang <cq.tang@intel.com>
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Jean-Phillipe Brucker <jean-philippe.brucker@arm.com>
Cc: David Woodhouse <dwmw2@infradead.org>

authored by

CQ Tang and committed by
Bjorn Helgaas
4ebeb1ec a4f4fa68

+67 -16
+48 -16
drivers/pci/ats.c
··· 160 160 if (!pos) 161 161 return -EINVAL; 162 162 163 - pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); 164 163 pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); 165 - if ((control & PCI_PRI_CTRL_ENABLE) || 166 - !(status & PCI_PRI_STATUS_STOPPED)) 164 + if (!(status & PCI_PRI_STATUS_STOPPED)) 167 165 return -EBUSY; 168 166 169 167 pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests); 170 168 reqs = min(max_requests, reqs); 169 + pdev->pri_reqs_alloc = reqs; 171 170 pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); 172 171 173 - control |= PCI_PRI_CTRL_ENABLE; 172 + control = PCI_PRI_CTRL_ENABLE; 174 173 pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); 175 174 176 175 pdev->pri_enabled = 1; ··· 205 206 EXPORT_SYMBOL_GPL(pci_disable_pri); 206 207 207 208 /** 209 + * pci_restore_pri_state - Restore PRI 210 + * @pdev: PCI device structure 211 + */ 212 + void pci_restore_pri_state(struct pci_dev *pdev) 213 + { 214 + u16 control = PCI_PRI_CTRL_ENABLE; 215 + u32 reqs = pdev->pri_reqs_alloc; 216 + int pos; 217 + 218 + if (!pdev->pri_enabled) 219 + return; 220 + 221 + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); 222 + if (!pos) 223 + return; 224 + 225 + pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); 226 + pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); 227 + } 228 + EXPORT_SYMBOL_GPL(pci_restore_pri_state); 229 + 230 + /** 208 231 * pci_reset_pri - Resets device's PRI state 209 232 * @pdev: PCI device structure 210 233 * ··· 245 224 if (!pos) 246 225 return -EINVAL; 247 226 248 - pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); 249 - if (control & PCI_PRI_CTRL_ENABLE) 250 - return -EBUSY; 251 - 252 - control |= PCI_PRI_CTRL_RESET; 253 - 227 + control = PCI_PRI_CTRL_RESET; 254 228 pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); 255 229 256 230 return 0; ··· 275 259 if (!pos) 276 260 return -EINVAL; 277 261 278 - pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control); 279 262 pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); 280 - 281 - if (control & PCI_PASID_CTRL_ENABLE) 282 - return -EINVAL; 283 - 284 263 supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV; 285 264 286 265 /* User wants to enable anything unsupported? */ ··· 283 272 return -EINVAL; 284 273 285 274 control = PCI_PASID_CTRL_ENABLE | features; 275 + pdev->pasid_features = features; 286 276 287 277 pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); 288 278 ··· 296 284 /** 297 285 * pci_disable_pasid - Disable the PASID capability 298 286 * @pdev: PCI device structure 299 - * 300 287 */ 301 288 void pci_disable_pasid(struct pci_dev *pdev) 302 289 { ··· 314 303 pdev->pasid_enabled = 0; 315 304 } 316 305 EXPORT_SYMBOL_GPL(pci_disable_pasid); 306 + 307 + /** 308 + * pci_restore_pasid_state - Restore PASID capabilities 309 + * @pdev: PCI device structure 310 + */ 311 + void pci_restore_pasid_state(struct pci_dev *pdev) 312 + { 313 + u16 control; 314 + int pos; 315 + 316 + if (!pdev->pasid_enabled) 317 + return; 318 + 319 + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); 320 + if (!pos) 321 + return; 322 + 323 + control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features; 324 + pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); 325 + } 326 + EXPORT_SYMBOL_GPL(pci_restore_pasid_state); 317 327 318 328 /** 319 329 * pci_pasid_features - Check which PASID features are supported
+3
drivers/pci/pci.c
··· 28 28 #include <linux/pm_runtime.h> 29 29 #include <linux/pci_hotplug.h> 30 30 #include <linux/vmalloc.h> 31 + #include <linux/pci-ats.h> 31 32 #include <asm/setup.h> 32 33 #include <asm/dma.h> 33 34 #include <linux/aer.h> ··· 1174 1173 1175 1174 /* PCI Express register must be restored first */ 1176 1175 pci_restore_pcie_state(dev); 1176 + pci_restore_pasid_state(dev); 1177 + pci_restore_pri_state(dev); 1177 1178 pci_restore_ats_state(dev); 1178 1179 pci_restore_vc_state(dev); 1179 1180
+10
include/linux/pci-ats.h
··· 7 7 8 8 int pci_enable_pri(struct pci_dev *pdev, u32 reqs); 9 9 void pci_disable_pri(struct pci_dev *pdev); 10 + void pci_restore_pri_state(struct pci_dev *pdev); 10 11 int pci_reset_pri(struct pci_dev *pdev); 11 12 12 13 #else /* CONFIG_PCI_PRI */ ··· 18 17 } 19 18 20 19 static inline void pci_disable_pri(struct pci_dev *pdev) 20 + { 21 + } 22 + 23 + static inline void pci_restore_pri_state(struct pci_dev *pdev) 21 24 { 22 25 } 23 26 ··· 36 31 37 32 int pci_enable_pasid(struct pci_dev *pdev, int features); 38 33 void pci_disable_pasid(struct pci_dev *pdev); 34 + void pci_restore_pasid_state(struct pci_dev *pdev); 39 35 int pci_pasid_features(struct pci_dev *pdev); 40 36 int pci_max_pasids(struct pci_dev *pdev); 41 37 ··· 48 42 } 49 43 50 44 static inline void pci_disable_pasid(struct pci_dev *pdev) 45 + { 46 + } 47 + 48 + static inline void pci_restore_pasid_state(struct pci_dev *pdev) 51 49 { 52 50 } 53 51
+6
include/linux/pci.h
··· 401 401 u8 ats_stu; /* ATS Smallest Translation Unit */ 402 402 atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */ 403 403 #endif 404 + #ifdef CONFIG_PCI_PRI 405 + u32 pri_reqs_alloc; /* Number of PRI requests allocated */ 406 + #endif 407 + #ifdef CONFIG_PCI_PASID 408 + u16 pasid_features; 409 + #endif 404 410 phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ 405 411 size_t romlen; /* Length of ROM if it's not from the BAR */ 406 412 char *driver_override; /* Driver name to force a match */