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

PCI: Add array to track reset method ordering

Add reset_methods[] in struct pci_dev to keep track of reset mechanisms
supported by the device and their ordering.

Refactor probing and reset functions to take advantage of calling
convention of reset functions.

Co-developed-by: Alex Williamson <alex.williamson@redhat.com>
Link: https://lore.kernel.org/r/20210817180500.1253-4-ameynarkhede03@gmail.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Amey Narkhede <ameynarkhede03@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>

authored by

Amey Narkhede and committed by
Bjorn Helgaas
e20afa06 56f107d7

+69 -44
+54 -40
drivers/pci/pci.c
··· 73 73 msleep(delay); 74 74 } 75 75 76 + bool pci_reset_supported(struct pci_dev *dev) 77 + { 78 + return dev->reset_methods[0] != 0; 79 + } 80 + 76 81 #ifdef CONFIG_PCI_DOMAINS 77 82 int pci_domains_supported = 1; 78 83 #endif ··· 5122 5117 err_handler->reset_done(dev); 5123 5118 } 5124 5119 5120 + /* dev->reset_methods[] is a 0-terminated list of indices into this array */ 5121 + static const struct pci_reset_fn_method pci_reset_fn_methods[] = { 5122 + { }, 5123 + { pci_dev_specific_reset, .name = "device_specific" }, 5124 + { pcie_reset_flr, .name = "flr" }, 5125 + { pci_af_flr, .name = "af_flr" }, 5126 + { pci_pm_reset, .name = "pm" }, 5127 + { pci_reset_bus_function, .name = "bus" }, 5128 + }; 5129 + 5125 5130 /** 5126 5131 * __pci_reset_function_locked - reset a PCI device function while holding 5127 5132 * the @dev mutex lock. ··· 5154 5139 */ 5155 5140 int __pci_reset_function_locked(struct pci_dev *dev) 5156 5141 { 5157 - int rc; 5142 + int i, m, rc = -ENOTTY; 5158 5143 5159 5144 might_sleep(); 5160 5145 5161 5146 /* 5162 - * A reset method returns -ENOTTY if it doesn't support this device 5163 - * and we should try the next method. 5147 + * A reset method returns -ENOTTY if it doesn't support this device and 5148 + * we should try the next method. 5164 5149 * 5165 - * If it returns 0 (success), we're finished. If it returns any 5166 - * other error, we're also finished: this indicates that further 5167 - * reset mechanisms might be broken on the device. 5150 + * If it returns 0 (success), we're finished. If it returns any other 5151 + * error, we're also finished: this indicates that further reset 5152 + * mechanisms might be broken on the device. 5168 5153 */ 5169 - rc = pci_dev_specific_reset(dev, 0); 5170 - if (rc != -ENOTTY) 5171 - return rc; 5172 - rc = pcie_reset_flr(dev, 0); 5173 - if (rc != -ENOTTY) 5174 - return rc; 5175 - rc = pci_af_flr(dev, 0); 5176 - if (rc != -ENOTTY) 5177 - return rc; 5178 - rc = pci_pm_reset(dev, 0); 5179 - if (rc != -ENOTTY) 5180 - return rc; 5181 - return pci_reset_bus_function(dev, 0); 5154 + for (i = 0; i < PCI_NUM_RESET_METHODS; i++) { 5155 + m = dev->reset_methods[i]; 5156 + if (!m) 5157 + return -ENOTTY; 5158 + 5159 + rc = pci_reset_fn_methods[m].reset_fn(dev, 0); 5160 + if (!rc) 5161 + return 0; 5162 + if (rc != -ENOTTY) 5163 + return rc; 5164 + } 5165 + 5166 + return -ENOTTY; 5182 5167 } 5183 5168 EXPORT_SYMBOL_GPL(__pci_reset_function_locked); 5184 5169 5185 5170 /** 5186 - * pci_probe_reset_function - check whether the device can be safely reset 5187 - * @dev: PCI device to reset 5171 + * pci_init_reset_methods - check whether device can be safely reset 5172 + * and store supported reset mechanisms. 5173 + * @dev: PCI device to check for reset mechanisms 5188 5174 * 5189 5175 * Some devices allow an individual function to be reset without affecting 5190 - * other functions in the same device. The PCI device must be responsive 5191 - * to PCI config space in order to use this function. 5176 + * other functions in the same device. The PCI device must be in D0-D3hot 5177 + * state. 5192 5178 * 5193 - * Returns 0 if the device function can be reset or negative if the 5194 - * device doesn't support resetting a single function. 5179 + * Stores reset mechanisms supported by device in reset_methods byte array 5180 + * which is a member of struct pci_dev. 5195 5181 */ 5196 - int pci_probe_reset_function(struct pci_dev *dev) 5182 + void pci_init_reset_methods(struct pci_dev *dev) 5197 5183 { 5198 - int rc; 5184 + int m, i, rc; 5185 + 5186 + BUILD_BUG_ON(ARRAY_SIZE(pci_reset_fn_methods) != PCI_NUM_RESET_METHODS); 5199 5187 5200 5188 might_sleep(); 5201 5189 5202 - rc = pci_dev_specific_reset(dev, 1); 5203 - if (rc != -ENOTTY) 5204 - return rc; 5205 - rc = pcie_reset_flr(dev, 1); 5206 - if (rc != -ENOTTY) 5207 - return rc; 5208 - rc = pci_af_flr(dev, 1); 5209 - if (rc != -ENOTTY) 5210 - return rc; 5211 - rc = pci_pm_reset(dev, 1); 5212 - if (rc != -ENOTTY) 5213 - return rc; 5190 + i = 0; 5191 + for (m = 1; m < PCI_NUM_RESET_METHODS; m++) { 5192 + rc = pci_reset_fn_methods[m].reset_fn(dev, 1); 5193 + if (!rc) 5194 + dev->reset_methods[i++] = m; 5195 + else if (rc != -ENOTTY) 5196 + break; 5197 + } 5214 5198 5215 - return pci_reset_bus_function(dev, 1); 5199 + dev->reset_methods[i] = 0; 5216 5200 } 5217 5201 5218 5202 /**
+7 -1
drivers/pci/pci.h
··· 33 33 int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai, 34 34 enum pci_mmap_api mmap_api); 35 35 36 - int pci_probe_reset_function(struct pci_dev *dev); 36 + bool pci_reset_supported(struct pci_dev *dev); 37 + void pci_init_reset_methods(struct pci_dev *dev); 37 38 int pci_bridge_secondary_bus_reset(struct pci_dev *dev); 38 39 int pci_bus_error_reset(struct pci_dev *dev); 39 40 ··· 609 608 u16 vendor; 610 609 u16 device; 611 610 int (*reset)(struct pci_dev *dev, int probe); 611 + }; 612 + 613 + struct pci_reset_fn_method { 614 + int (*reset_fn)(struct pci_dev *pdev, int probe); 615 + char *name; 612 616 }; 613 617 614 618 #ifdef CONFIG_PCI_QUIRKS
+2 -3
drivers/pci/probe.c
··· 2429 2429 pci_rcec_init(dev); /* Root Complex Event Collector */ 2430 2430 2431 2431 pcie_report_downtraining(dev); 2432 - 2433 - if (pci_probe_reset_function(dev) == 0) 2434 - dev->reset_fn = 1; 2432 + pci_init_reset_methods(dev); 2433 + dev->reset_fn = pci_reset_supported(dev); 2435 2434 } 2436 2435 2437 2436 /*
+6
include/linux/pci.h
··· 49 49 PCI_STATUS_SIG_TARGET_ABORT | \ 50 50 PCI_STATUS_PARITY) 51 51 52 + /* Number of reset methods used in pci_reset_fn_methods array in pci.c */ 53 + #define PCI_NUM_RESET_METHODS 6 54 + 52 55 /* 53 56 * The PCI interface treats multi-function devices as independent 54 57 * devices. The slot/function address of each device is encoded ··· 509 506 char *driver_override; /* Driver name to force a match */ 510 507 511 508 unsigned long priv_flags; /* Private flags for the PCI driver */ 509 + 510 + /* These methods index pci_reset_fn_methods[] */ 511 + u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */ 512 512 }; 513 513 514 514 static inline struct pci_dev *pci_physfn(struct pci_dev *dev)