aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-11-25 08:06:21 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2013-11-27 09:45:32 -0500
commitfc15ca13a6c95e0d6af682af118c3c8e679a8152 (patch)
treee14205c8a0e0dce4daa3139c5324321d0f0d2e0e /drivers/net
parente539887b1521ed4aefce7387bc3f33814b11442d (diff)
ath10k: split up pci irq code
Hardware waits until host signals whether it has chosen MSI(-X) or shared legacy interrupts. It is not required for the driver to register interrupt handlers immediately. This patch prepares the pci irq code for more changes. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c225
1 files changed, 131 insertions, 94 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 12fb12ea2182..957fc59c2256 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -55,8 +55,10 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
55static void ath10k_pci_stop_ce(struct ath10k *ar); 55static void ath10k_pci_stop_ce(struct ath10k *ar);
56static int ath10k_pci_device_reset(struct ath10k *ar); 56static int ath10k_pci_device_reset(struct ath10k *ar);
57static int ath10k_pci_wait_for_target_init(struct ath10k *ar); 57static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
58static int ath10k_pci_start_intr(struct ath10k *ar); 58static int ath10k_pci_init_irq(struct ath10k *ar);
59static void ath10k_pci_stop_intr(struct ath10k *ar); 59static int ath10k_pci_deinit_irq(struct ath10k *ar);
60static int ath10k_pci_request_irq(struct ath10k *ar);
61static void ath10k_pci_free_irq(struct ath10k *ar);
60 62
61static const struct ce_attr host_ce_config_wlan[] = { 63static const struct ce_attr host_ce_config_wlan[] = {
62 /* CE0: host->target HTC control and raw streams */ 64 /* CE0: host->target HTC control and raw streams */
@@ -1354,7 +1356,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
1354 ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); 1356 ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
1355 1357
1356 /* Irqs are never explicitly re-enabled. They are implicitly re-enabled 1358 /* Irqs are never explicitly re-enabled. They are implicitly re-enabled
1357 * by ath10k_pci_start_intr(). */ 1359 * by upon power_up. */
1358 ath10k_pci_disable_irqs(ar); 1360 ath10k_pci_disable_irqs(ar);
1359 1361
1360 ath10k_pci_stop_ce(ar); 1362 ath10k_pci_stop_ce(ar);
@@ -1900,34 +1902,40 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
1900 goto err_ce; 1902 goto err_ce;
1901 } 1903 }
1902 1904
1903 ret = ath10k_pci_start_intr(ar); 1905 ret = ath10k_pci_init_irq(ar);
1904 if (ret) { 1906 if (ret) {
1905 ath10k_err("failed to start interrupt handling: %d\n", ret); 1907 ath10k_err("failed to init irqs: %d\n", ret);
1906 goto err_ce; 1908 goto err_ce;
1907 } 1909 }
1908 1910
1911 ret = ath10k_pci_request_irq(ar);
1912 if (ret) {
1913 ath10k_err("failed to request irqs: %d\n", ret);
1914 goto err_deinit_irq;
1915 }
1916
1909 ret = ath10k_pci_wait_for_target_init(ar); 1917 ret = ath10k_pci_wait_for_target_init(ar);
1910 if (ret) { 1918 if (ret) {
1911 ath10k_err("failed to wait for target to init: %d\n", ret); 1919 ath10k_err("failed to wait for target to init: %d\n", ret);
1912 goto err_irq; 1920 goto err_free_irq;
1913 } 1921 }
1914 1922
1915 ret = ath10k_ce_enable_err_irq(ar); 1923 ret = ath10k_ce_enable_err_irq(ar);
1916 if (ret) { 1924 if (ret) {
1917 ath10k_err("failed to enable CE error irq: %d\n", ret); 1925 ath10k_err("failed to enable CE error irq: %d\n", ret);
1918 goto err_irq; 1926 goto err_free_irq;
1919 } 1927 }
1920 1928
1921 ret = ath10k_pci_init_config(ar); 1929 ret = ath10k_pci_init_config(ar);
1922 if (ret) { 1930 if (ret) {
1923 ath10k_err("failed to setup init config: %d\n", ret); 1931 ath10k_err("failed to setup init config: %d\n", ret);
1924 goto err_irq; 1932 goto err_free_irq;
1925 } 1933 }
1926 1934
1927 ret = ath10k_pci_wake_target_cpu(ar); 1935 ret = ath10k_pci_wake_target_cpu(ar);
1928 if (ret) { 1936 if (ret) {
1929 ath10k_err("could not wake up target CPU: %d\n", ret); 1937 ath10k_err("could not wake up target CPU: %d\n", ret);
1930 goto err_irq; 1938 goto err_free_irq;
1931 } 1939 }
1932 1940
1933 ath10k_pci_start_bmi(ar); 1941 ath10k_pci_start_bmi(ar);
@@ -1944,11 +1952,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
1944 1952
1945 return 0; 1953 return 0;
1946 1954
1947err_irq: 1955err_free_irq:
1948 ath10k_ce_disable_interrupts(ar); 1956 ath10k_pci_free_irq(ar);
1949 ath10k_pci_stop_intr(ar);
1950 ath10k_pci_kill_tasklet(ar); 1957 ath10k_pci_kill_tasklet(ar);
1951 ath10k_pci_device_reset(ar); 1958 ath10k_pci_device_reset(ar);
1959err_deinit_irq:
1960 ath10k_pci_deinit_irq(ar);
1952err_ce: 1961err_ce:
1953 ath10k_pci_ce_deinit(ar); 1962 ath10k_pci_ce_deinit(ar);
1954err_ps: 1963err_ps:
@@ -1962,7 +1971,8 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
1962{ 1971{
1963 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 1972 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
1964 1973
1965 ath10k_pci_stop_intr(ar); 1974 ath10k_pci_free_irq(ar);
1975 ath10k_pci_deinit_irq(ar);
1966 ath10k_pci_device_reset(ar); 1976 ath10k_pci_device_reset(ar);
1967 1977
1968 ath10k_pci_ce_deinit(ar); 1978 ath10k_pci_ce_deinit(ar);
@@ -2152,24 +2162,17 @@ static void ath10k_pci_tasklet(unsigned long data)
2152 } 2162 }
2153} 2163}
2154 2164
2155static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) 2165static int ath10k_pci_request_irq_msix(struct ath10k *ar)
2156{ 2166{
2157 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2167 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2158 int ret; 2168 int ret, i;
2159 int i;
2160
2161 ret = pci_enable_msi_block(ar_pci->pdev, num);
2162 if (ret)
2163 return ret;
2164 2169
2165 ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, 2170 ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
2166 ath10k_pci_msi_fw_handler, 2171 ath10k_pci_msi_fw_handler,
2167 IRQF_SHARED, "ath10k_pci", ar); 2172 IRQF_SHARED, "ath10k_pci", ar);
2168 if (ret) { 2173 if (ret) {
2169 ath10k_warn("request_irq(%d) failed %d\n", 2174 ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
2170 ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); 2175 ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
2171
2172 pci_disable_msi(ar_pci->pdev);
2173 return ret; 2176 return ret;
2174 } 2177 }
2175 2178
@@ -2178,45 +2181,38 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
2178 ath10k_pci_per_engine_handler, 2181 ath10k_pci_per_engine_handler,
2179 IRQF_SHARED, "ath10k_pci", ar); 2182 IRQF_SHARED, "ath10k_pci", ar);
2180 if (ret) { 2183 if (ret) {
2181 ath10k_warn("request_irq(%d) failed %d\n", 2184 ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
2182 ar_pci->pdev->irq + i, ret); 2185 ar_pci->pdev->irq + i, ret);
2183 2186
2184 for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--) 2187 for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
2185 free_irq(ar_pci->pdev->irq + i, ar); 2188 free_irq(ar_pci->pdev->irq + i, ar);
2186 2189
2187 free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar); 2190 free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
2188 pci_disable_msi(ar_pci->pdev);
2189 return ret; 2191 return ret;
2190 } 2192 }
2191 } 2193 }
2192 2194
2193 ath10k_dbg(ATH10K_DBG_BOOT,
2194 "MSI-X interrupt handling (%d intrs)\n", num);
2195 return 0; 2195 return 0;
2196} 2196}
2197 2197
2198static int ath10k_pci_start_intr_msi(struct ath10k *ar) 2198static int ath10k_pci_request_irq_msi(struct ath10k *ar)
2199{ 2199{
2200 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2200 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2201 int ret; 2201 int ret;
2202 2202
2203 ret = pci_enable_msi(ar_pci->pdev);
2204 if (ret < 0)
2205 return ret;
2206
2207 ret = request_irq(ar_pci->pdev->irq, 2203 ret = request_irq(ar_pci->pdev->irq,
2208 ath10k_pci_interrupt_handler, 2204 ath10k_pci_interrupt_handler,
2209 IRQF_SHARED, "ath10k_pci", ar); 2205 IRQF_SHARED, "ath10k_pci", ar);
2210 if (ret < 0) { 2206 if (ret) {
2211 pci_disable_msi(ar_pci->pdev); 2207 ath10k_warn("failed to request MSI irq %d: %d\n",
2208 ar_pci->pdev->irq, ret);
2212 return ret; 2209 return ret;
2213 } 2210 }
2214 2211
2215 ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n");
2216 return 0; 2212 return 0;
2217} 2213}
2218 2214
2219static int ath10k_pci_start_intr_legacy(struct ath10k *ar) 2215static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
2220{ 2216{
2221 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2217 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2222 int ret; 2218 int ret;
@@ -2224,99 +2220,140 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
2224 ret = request_irq(ar_pci->pdev->irq, 2220 ret = request_irq(ar_pci->pdev->irq,
2225 ath10k_pci_interrupt_handler, 2221 ath10k_pci_interrupt_handler,
2226 IRQF_SHARED, "ath10k_pci", ar); 2222 IRQF_SHARED, "ath10k_pci", ar);
2227 if (ret < 0)
2228 return ret;
2229
2230 ret = ath10k_pci_wake(ar);
2231 if (ret) { 2223 if (ret) {
2232 free_irq(ar_pci->pdev->irq, ar); 2224 ath10k_warn("failed to request legacy irq %d: %d\n",
2233 ath10k_err("failed to wake up target: %d\n", ret); 2225 ar_pci->pdev->irq, ret);
2234 return ret; 2226 return ret;
2235 } 2227 }
2236 2228
2237 /*
2238 * A potential race occurs here: The CORE_BASE write
2239 * depends on target correctly decoding AXI address but
2240 * host won't know when target writes BAR to CORE_CTRL.
2241 * This write might get lost if target has NOT written BAR.
2242 * For now, fix the race by repeating the write in below
2243 * synchronization checking.
2244 */
2245 iowrite32(PCIE_INTR_FIRMWARE_MASK |
2246 PCIE_INTR_CE_MASK_ALL,
2247 ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
2248 PCIE_INTR_ENABLE_ADDRESS));
2249
2250 ath10k_pci_sleep(ar);
2251 ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n");
2252 return 0; 2229 return 0;
2253} 2230}
2254 2231
2255static int ath10k_pci_start_intr(struct ath10k *ar) 2232static int ath10k_pci_request_irq(struct ath10k *ar)
2233{
2234 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2235
2236 switch (ar_pci->num_msi_intrs) {
2237 case 0:
2238 return ath10k_pci_request_irq_legacy(ar);
2239 case 1:
2240 return ath10k_pci_request_irq_msi(ar);
2241 case MSI_NUM_REQUEST:
2242 return ath10k_pci_request_irq_msix(ar);
2243 }
2244
2245 ath10k_warn("unknown irq configuration upon request\n");
2246 return -EINVAL;
2247}
2248
2249static void ath10k_pci_free_irq(struct ath10k *ar)
2256{ 2250{
2257 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2251 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2258 int num = MSI_NUM_REQUEST;
2259 int ret;
2260 int i; 2252 int i;
2261 2253
2262 tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long) ar); 2254 /* There's at least one interrupt irregardless whether its legacy INTR
2255 * or MSI or MSI-X */
2256 for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
2257 free_irq(ar_pci->pdev->irq + i, ar);
2258}
2259
2260static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
2261{
2262 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2263 int i;
2264
2265 tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
2263 tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, 2266 tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
2264 (unsigned long) ar); 2267 (unsigned long)ar);
2265 2268
2266 for (i = 0; i < CE_COUNT; i++) { 2269 for (i = 0; i < CE_COUNT; i++) {
2267 ar_pci->pipe_info[i].ar_pci = ar_pci; 2270 ar_pci->pipe_info[i].ar_pci = ar_pci;
2268 tasklet_init(&ar_pci->pipe_info[i].intr, 2271 tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
2269 ath10k_pci_ce_tasklet,
2270 (unsigned long)&ar_pci->pipe_info[i]); 2272 (unsigned long)&ar_pci->pipe_info[i]);
2271 } 2273 }
2274}
2275
2276static int ath10k_pci_init_irq(struct ath10k *ar)
2277{
2278 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2279 int ret;
2280
2281 ath10k_pci_init_irq_tasklets(ar);
2272 2282
2273 if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features)) 2283 if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features))
2274 num = 1; 2284 goto msi;
2275 2285
2276 if (num > 1) { 2286 /* Try MSI-X */
2277 ret = ath10k_pci_start_intr_msix(ar, num); 2287 ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
2278 if (ret == 0) 2288 ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
2279 goto exit; 2289 if (ret == 0)
2290 return 0;
2291 if (ret > 0)
2292 pci_disable_msi(ar_pci->pdev);
2280 2293
2281 ath10k_dbg(ATH10K_DBG_BOOT, 2294msi:
2282 "MSI-X didn't succeed (%d), trying MSI\n", ret); 2295 /* Try MSI */
2283 num = 1; 2296 ar_pci->num_msi_intrs = 1;
2284 } 2297 ret = pci_enable_msi(ar_pci->pdev);
2298 if (ret == 0)
2299 return 0;
2285 2300
2286 if (num == 1) { 2301 /* Try legacy irq
2287 ret = ath10k_pci_start_intr_msi(ar); 2302 *
2288 if (ret == 0) 2303 * A potential race occurs here: The CORE_BASE write
2289 goto exit; 2304 * depends on target correctly decoding AXI address but
2305 * host won't know when target writes BAR to CORE_CTRL.
2306 * This write might get lost if target has NOT written BAR.
2307 * For now, fix the race by repeating the write in below
2308 * synchronization checking. */
2309 ar_pci->num_msi_intrs = 0;
2290 2310
2291 ath10k_dbg(ATH10K_DBG_BOOT, 2311 ret = ath10k_pci_wake(ar);
2292 "MSI didn't succeed (%d), trying legacy INTR\n", 2312 if (ret) {
2293 ret); 2313 ath10k_warn("failed to wake target: %d\n", ret);
2294 num = 0; 2314 return ret;
2295 } 2315 }
2296 2316
2297 ret = ath10k_pci_start_intr_legacy(ar); 2317 ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
2318 PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
2319 ath10k_pci_sleep(ar);
2320
2321 return 0;
2322}
2323
2324static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
2325{
2326 int ret;
2327
2328 ret = ath10k_pci_wake(ar);
2298 if (ret) { 2329 if (ret) {
2299 ath10k_warn("Failed to start legacy interrupts: %d\n", ret); 2330 ath10k_warn("failed to wake target: %d\n", ret);
2300 return ret; 2331 return ret;
2301 } 2332 }
2302 2333
2303exit: 2334 ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
2304 ar_pci->num_msi_intrs = num; 2335 0);
2305 return ret; 2336 ath10k_pci_sleep(ar);
2337
2338 return 0;
2306} 2339}
2307 2340
2308static void ath10k_pci_stop_intr(struct ath10k *ar) 2341static int ath10k_pci_deinit_irq(struct ath10k *ar)
2309{ 2342{
2310 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2343 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2311 int i;
2312 2344
2313 /* There's at least one interrupt irregardless whether its legacy INTR 2345 switch (ar_pci->num_msi_intrs) {
2314 * or MSI or MSI-X */ 2346 case 0:
2315 for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) 2347 return ath10k_pci_deinit_irq_legacy(ar);
2316 free_irq(ar_pci->pdev->irq + i, ar); 2348 case 1:
2317 2349 /* fall-through */
2318 if (ar_pci->num_msi_intrs > 0) 2350 case MSI_NUM_REQUEST:
2319 pci_disable_msi(ar_pci->pdev); 2351 pci_disable_msi(ar_pci->pdev);
2352 return 0;
2353 }
2354
2355 ath10k_warn("unknown irq configuration upon deinit\n");
2356 return -EINVAL;
2320} 2357}
2321 2358
2322static int ath10k_pci_wait_for_target_init(struct ath10k *ar) 2359static int ath10k_pci_wait_for_target_init(struct ath10k *ar)