diff options
author | Yu Zhao <yu.zhao@intel.com> | 2009-06-13 03:52:13 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-06-16 17:30:15 -0400 |
commit | 8c1c699fec9e9021bf6ff0285dee086bb27aec90 (patch) | |
tree | 4af7bd96c1b651633ff7b6721959aeacd120e4ee /drivers/pci/pci.c | |
parent | c465def6bfe834b62623caa9b98f2d4f4739875a (diff) |
PCI: cleanup Function Level Reset
This patch enhances the FLR functions:
1) remove disable_irq() so the shared IRQ won't be disabled.
2) replace the 1s wait with 100, 200 and 400ms wait intervals
for the Pending Transaction.
3) replace mdelay() with msleep().
4) add might_sleep().
5) lock the device to prevent PM suspend from accessing the CSRs
during the reset.
6) coding style fixes.
Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 166 |
1 files changed, 84 insertions, 82 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8ea911e55722..6a052ada3fe8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -2055,111 +2055,112 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) | |||
2055 | EXPORT_SYMBOL(pci_set_dma_seg_boundary); | 2055 | EXPORT_SYMBOL(pci_set_dma_seg_boundary); |
2056 | #endif | 2056 | #endif |
2057 | 2057 | ||
2058 | static int __pcie_flr(struct pci_dev *dev, int probe) | 2058 | static int pcie_flr(struct pci_dev *dev, int probe) |
2059 | { | 2059 | { |
2060 | u16 status; | 2060 | int i; |
2061 | int pos; | ||
2061 | u32 cap; | 2062 | u32 cap; |
2062 | int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 2063 | u16 status; |
2063 | 2064 | ||
2064 | if (!exppos) | 2065 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); |
2066 | if (!pos) | ||
2065 | return -ENOTTY; | 2067 | return -ENOTTY; |
2066 | pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); | 2068 | |
2069 | pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); | ||
2067 | if (!(cap & PCI_EXP_DEVCAP_FLR)) | 2070 | if (!(cap & PCI_EXP_DEVCAP_FLR)) |
2068 | return -ENOTTY; | 2071 | return -ENOTTY; |
2069 | 2072 | ||
2070 | if (probe) | 2073 | if (probe) |
2071 | return 0; | 2074 | return 0; |
2072 | 2075 | ||
2073 | pci_block_user_cfg_access(dev); | ||
2074 | |||
2075 | /* Wait for Transaction Pending bit clean */ | 2076 | /* Wait for Transaction Pending bit clean */ |
2076 | pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); | 2077 | for (i = 0; i < 4; i++) { |
2077 | if (!(status & PCI_EXP_DEVSTA_TRPND)) | 2078 | if (i) |
2078 | goto transaction_done; | 2079 | msleep((1 << (i - 1)) * 100); |
2079 | 2080 | ||
2080 | msleep(100); | 2081 | pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status); |
2081 | pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); | 2082 | if (!(status & PCI_EXP_DEVSTA_TRPND)) |
2082 | if (!(status & PCI_EXP_DEVSTA_TRPND)) | 2083 | goto clear; |
2083 | goto transaction_done; | 2084 | } |
2084 | 2085 | ||
2085 | dev_info(&dev->dev, "Busy after 100ms while trying to reset; " | 2086 | dev_err(&dev->dev, "transaction is not cleared; " |
2086 | "sleeping for 1 second\n"); | 2087 | "proceeding with reset anyway\n"); |
2087 | ssleep(1); | 2088 | |
2088 | pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); | 2089 | clear: |
2089 | if (status & PCI_EXP_DEVSTA_TRPND) | 2090 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, |
2090 | dev_info(&dev->dev, "Still busy after 1s; " | ||
2091 | "proceeding with reset anyway\n"); | ||
2092 | |||
2093 | transaction_done: | ||
2094 | pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, | ||
2095 | PCI_EXP_DEVCTL_BCR_FLR); | 2091 | PCI_EXP_DEVCTL_BCR_FLR); |
2096 | mdelay(100); | 2092 | msleep(100); |
2097 | 2093 | ||
2098 | pci_unblock_user_cfg_access(dev); | ||
2099 | return 0; | 2094 | return 0; |
2100 | } | 2095 | } |
2101 | 2096 | ||
2102 | static int __pci_af_flr(struct pci_dev *dev, int probe) | 2097 | static int pci_af_flr(struct pci_dev *dev, int probe) |
2103 | { | 2098 | { |
2104 | int cappos = pci_find_capability(dev, PCI_CAP_ID_AF); | 2099 | int i; |
2105 | u8 status; | 2100 | int pos; |
2106 | u8 cap; | 2101 | u8 cap; |
2102 | u8 status; | ||
2107 | 2103 | ||
2108 | if (!cappos) | 2104 | pos = pci_find_capability(dev, PCI_CAP_ID_AF); |
2105 | if (!pos) | ||
2109 | return -ENOTTY; | 2106 | return -ENOTTY; |
2110 | pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap); | 2107 | |
2108 | pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap); | ||
2111 | if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) | 2109 | if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) |
2112 | return -ENOTTY; | 2110 | return -ENOTTY; |
2113 | 2111 | ||
2114 | if (probe) | 2112 | if (probe) |
2115 | return 0; | 2113 | return 0; |
2116 | 2114 | ||
2117 | pci_block_user_cfg_access(dev); | ||
2118 | |||
2119 | /* Wait for Transaction Pending bit clean */ | 2115 | /* Wait for Transaction Pending bit clean */ |
2120 | pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); | 2116 | for (i = 0; i < 4; i++) { |
2121 | if (!(status & PCI_AF_STATUS_TP)) | 2117 | if (i) |
2122 | goto transaction_done; | 2118 | msleep((1 << (i - 1)) * 100); |
2119 | |||
2120 | pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status); | ||
2121 | if (!(status & PCI_AF_STATUS_TP)) | ||
2122 | goto clear; | ||
2123 | } | ||
2124 | |||
2125 | dev_err(&dev->dev, "transaction is not cleared; " | ||
2126 | "proceeding with reset anyway\n"); | ||
2123 | 2127 | ||
2128 | clear: | ||
2129 | pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); | ||
2124 | msleep(100); | 2130 | msleep(100); |
2125 | pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); | 2131 | |
2126 | if (!(status & PCI_AF_STATUS_TP)) | ||
2127 | goto transaction_done; | ||
2128 | |||
2129 | dev_info(&dev->dev, "Busy after 100ms while trying to" | ||
2130 | " reset; sleeping for 1 second\n"); | ||
2131 | ssleep(1); | ||
2132 | pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); | ||
2133 | if (status & PCI_AF_STATUS_TP) | ||
2134 | dev_info(&dev->dev, "Still busy after 1s; " | ||
2135 | "proceeding with reset anyway\n"); | ||
2136 | |||
2137 | transaction_done: | ||
2138 | pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); | ||
2139 | mdelay(100); | ||
2140 | |||
2141 | pci_unblock_user_cfg_access(dev); | ||
2142 | return 0; | 2132 | return 0; |
2143 | } | 2133 | } |
2144 | 2134 | ||
2145 | static int __pci_reset_function(struct pci_dev *pdev, int probe) | 2135 | static int pci_dev_reset(struct pci_dev *dev, int probe) |
2146 | { | 2136 | { |
2147 | int res; | 2137 | int rc; |
2138 | |||
2139 | might_sleep(); | ||
2140 | |||
2141 | if (!probe) { | ||
2142 | pci_block_user_cfg_access(dev); | ||
2143 | /* block PM suspend, driver probe, etc. */ | ||
2144 | down(&dev->dev.sem); | ||
2145 | } | ||
2148 | 2146 | ||
2149 | res = __pcie_flr(pdev, probe); | 2147 | rc = pcie_flr(dev, probe); |
2150 | if (res != -ENOTTY) | 2148 | if (rc != -ENOTTY) |
2151 | return res; | 2149 | goto done; |
2152 | 2150 | ||
2153 | res = __pci_af_flr(pdev, probe); | 2151 | rc = pci_af_flr(dev, probe); |
2154 | if (res != -ENOTTY) | 2152 | done: |
2155 | return res; | 2153 | if (!probe) { |
2154 | up(&dev->dev.sem); | ||
2155 | pci_unblock_user_cfg_access(dev); | ||
2156 | } | ||
2156 | 2157 | ||
2157 | return res; | 2158 | return rc; |
2158 | } | 2159 | } |
2159 | 2160 | ||
2160 | /** | 2161 | /** |
2161 | * pci_execute_reset_function() - Reset a PCI device function | 2162 | * __pci_reset_function - reset a PCI device function |
2162 | * @dev: Device function to reset | 2163 | * @dev: PCI device to reset |
2163 | * | 2164 | * |
2164 | * Some devices allow an individual function to be reset without affecting | 2165 | * Some devices allow an individual function to be reset without affecting |
2165 | * other functions in the same device. The PCI device must be responsive | 2166 | * other functions in the same device. The PCI device must be responsive |
@@ -2171,18 +2172,18 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe) | |||
2171 | * device including MSI, bus mastering, BARs, decoding IO and memory spaces, | 2172 | * device including MSI, bus mastering, BARs, decoding IO and memory spaces, |
2172 | * etc. | 2173 | * etc. |
2173 | * | 2174 | * |
2174 | * Returns 0 if the device function was successfully reset or -ENOTTY if the | 2175 | * Returns 0 if the device function was successfully reset or negative if the |
2175 | * device doesn't support resetting a single function. | 2176 | * device doesn't support resetting a single function. |
2176 | */ | 2177 | */ |
2177 | int pci_execute_reset_function(struct pci_dev *dev) | 2178 | int __pci_reset_function(struct pci_dev *dev) |
2178 | { | 2179 | { |
2179 | return __pci_reset_function(dev, 0); | 2180 | return pci_dev_reset(dev, 0); |
2180 | } | 2181 | } |
2181 | EXPORT_SYMBOL_GPL(pci_execute_reset_function); | 2182 | EXPORT_SYMBOL_GPL(__pci_reset_function); |
2182 | 2183 | ||
2183 | /** | 2184 | /** |
2184 | * pci_reset_function() - quiesce and reset a PCI device function | 2185 | * pci_reset_function - quiesce and reset a PCI device function |
2185 | * @dev: Device function to reset | 2186 | * @dev: PCI device to reset |
2186 | * | 2187 | * |
2187 | * Some devices allow an individual function to be reset without affecting | 2188 | * Some devices allow an individual function to be reset without affecting |
2188 | * other functions in the same device. The PCI device must be responsive | 2189 | * other functions in the same device. The PCI device must be responsive |
@@ -2190,32 +2191,33 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function); | |||
2190 | * | 2191 | * |
2191 | * This function does not just reset the PCI portion of a device, but | 2192 | * This function does not just reset the PCI portion of a device, but |
2192 | * clears all the state associated with the device. This function differs | 2193 | * clears all the state associated with the device. This function differs |
2193 | * from pci_execute_reset_function in that it saves and restores device state | 2194 | * from __pci_reset_function in that it saves and restores device state |
2194 | * over the reset. | 2195 | * over the reset. |
2195 | * | 2196 | * |
2196 | * Returns 0 if the device function was successfully reset or -ENOTTY if the | 2197 | * Returns 0 if the device function was successfully reset or negative if the |
2197 | * device doesn't support resetting a single function. | 2198 | * device doesn't support resetting a single function. |
2198 | */ | 2199 | */ |
2199 | int pci_reset_function(struct pci_dev *dev) | 2200 | int pci_reset_function(struct pci_dev *dev) |
2200 | { | 2201 | { |
2201 | int r = __pci_reset_function(dev, 1); | 2202 | int rc; |
2202 | 2203 | ||
2203 | if (r < 0) | 2204 | rc = pci_dev_reset(dev, 1); |
2204 | return r; | 2205 | if (rc) |
2206 | return rc; | ||
2205 | 2207 | ||
2206 | if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) | ||
2207 | disable_irq(dev->irq); | ||
2208 | pci_save_state(dev); | 2208 | pci_save_state(dev); |
2209 | 2209 | ||
2210 | /* | ||
2211 | * both INTx and MSI are disabled after the Interrupt Disable bit | ||
2212 | * is set and the Bus Master bit is cleared. | ||
2213 | */ | ||
2210 | pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); | 2214 | pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); |
2211 | 2215 | ||
2212 | r = pci_execute_reset_function(dev); | 2216 | rc = pci_dev_reset(dev, 0); |
2213 | 2217 | ||
2214 | pci_restore_state(dev); | 2218 | pci_restore_state(dev); |
2215 | if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) | ||
2216 | enable_irq(dev->irq); | ||
2217 | 2219 | ||
2218 | return r; | 2220 | return rc; |
2219 | } | 2221 | } |
2220 | EXPORT_SYMBOL_GPL(pci_reset_function); | 2222 | EXPORT_SYMBOL_GPL(pci_reset_function); |
2221 | 2223 | ||