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

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: btintel_pcie: Support Function level reset

The driver supports Function Level Reset (FLR) to recover the controller
upon hardware exceptions or hci command timeouts. FLR is triggered only
when no prior reset has occurred within the retry window, with a maximum
of one FLR allowed within this window.

This patch is tested by,
echo 1 > /sys/class/bluetooth/hciX/reset

Signed-off-by: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Chandrashekar Devegowda and committed by
Luiz Augusto von Dentz
256ab952 65b0dca6

+227 -3
+224 -2
drivers/bluetooth/btintel_pcie.c
··· 41 41 }; 42 42 MODULE_DEVICE_TABLE(pci, btintel_pcie_table); 43 43 44 + struct btintel_pcie_dev_restart_data { 45 + struct list_head list; 46 + u8 restart_count; 47 + time64_t last_error; 48 + char name[]; 49 + }; 50 + 44 51 /* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */ 45 52 #define BTINTEL_PCIE_HCI_TYPE_LEN 4 46 53 #define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001 ··· 68 61 69 62 #define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2 70 63 #define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT 0x1E61 64 + 65 + #define BTINTEL_PCIE_RESET_WINDOW_SECS 5 66 + #define BTINTEL_PCIE_FLR_MAX_RETRY 1 71 67 72 68 /* Alive interrupt context */ 73 69 enum { ··· 108 98 u32 num_buf; 109 99 struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT]; 110 100 }; 101 + 102 + struct btintel_pcie_removal { 103 + struct pci_dev *pdev; 104 + struct work_struct work; 105 + }; 106 + 107 + static LIST_HEAD(btintel_pcie_restart_data_list); 108 + static DEFINE_SPINLOCK(btintel_pcie_restart_data_lock); 111 109 112 110 /* This function initializes the memory for DBGC buffers and formats the 113 111 * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and ··· 1950 1932 u32 type; 1951 1933 u32 old_ctxt; 1952 1934 1935 + if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) 1936 + return -ENODEV; 1937 + 1953 1938 /* Due to the fw limitation, the type header of the packet should be 1954 1939 * 4 bytes unlike 1 byte for UART. In UART, the firmware can read 1955 1940 * the first byte to get the packet type and redirect the rest of data ··· 2213 2192 } 2214 2193 btintel_pcie_start_rx(data); 2215 2194 } 2195 + 2196 + if (!err) 2197 + set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags); 2216 2198 return err; 2199 + } 2200 + 2201 + static struct btintel_pcie_dev_restart_data *btintel_pcie_get_restart_data(struct pci_dev *pdev, 2202 + struct device *dev) 2203 + { 2204 + struct btintel_pcie_dev_restart_data *tmp, *data = NULL; 2205 + const char *name = pci_name(pdev); 2206 + struct hci_dev *hdev = to_hci_dev(dev); 2207 + 2208 + spin_lock(&btintel_pcie_restart_data_lock); 2209 + list_for_each_entry(tmp, &btintel_pcie_restart_data_list, list) { 2210 + if (strcmp(tmp->name, name)) 2211 + continue; 2212 + data = tmp; 2213 + break; 2214 + } 2215 + spin_unlock(&btintel_pcie_restart_data_lock); 2216 + 2217 + if (data) { 2218 + bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name); 2219 + return data; 2220 + } 2221 + 2222 + data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC); 2223 + if (!data) 2224 + return NULL; 2225 + 2226 + strscpy_pad(data->name, name, strlen(name) + 1); 2227 + spin_lock(&btintel_pcie_restart_data_lock); 2228 + list_add_tail(&data->list, &btintel_pcie_restart_data_list); 2229 + spin_unlock(&btintel_pcie_restart_data_lock); 2230 + 2231 + return data; 2232 + } 2233 + 2234 + static void btintel_pcie_free_restart_list(void) 2235 + { 2236 + struct btintel_pcie_dev_restart_data *tmp; 2237 + 2238 + while ((tmp = list_first_entry_or_null(&btintel_pcie_restart_data_list, 2239 + typeof(*tmp), list))) { 2240 + list_del(&tmp->list); 2241 + kfree(tmp); 2242 + } 2243 + } 2244 + 2245 + static void btintel_pcie_inc_restart_count(struct pci_dev *pdev, 2246 + struct device *dev) 2247 + { 2248 + struct btintel_pcie_dev_restart_data *data; 2249 + struct hci_dev *hdev = to_hci_dev(dev); 2250 + time64_t retry_window; 2251 + 2252 + data = btintel_pcie_get_restart_data(pdev, dev); 2253 + if (!data) 2254 + return; 2255 + 2256 + retry_window = ktime_get_boottime_seconds() - data->last_error; 2257 + if (data->restart_count == 0) { 2258 + data->last_error = ktime_get_boottime_seconds(); 2259 + data->restart_count++; 2260 + bt_dev_dbg(hdev, "First iteration initialise. last_error: %lld seconds restart_count: %d", 2261 + data->last_error, data->restart_count); 2262 + } else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && 2263 + data->restart_count <= BTINTEL_PCIE_FLR_MAX_RETRY) { 2264 + data->restart_count++; 2265 + bt_dev_dbg(hdev, "Flr triggered within the max retry time so increment the restart_count: %d", 2266 + data->restart_count); 2267 + } else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) { 2268 + data->last_error = 0; 2269 + data->restart_count = 0; 2270 + bt_dev_dbg(hdev, "Flr triggered out of the retry window, so reset counters"); 2271 + } 2272 + } 2273 + 2274 + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data); 2275 + 2276 + static void btintel_pcie_removal_work(struct work_struct *wk) 2277 + { 2278 + struct btintel_pcie_removal *removal = 2279 + container_of(wk, struct btintel_pcie_removal, work); 2280 + struct pci_dev *pdev = removal->pdev; 2281 + struct btintel_pcie_data *data; 2282 + int err; 2283 + 2284 + pci_lock_rescan_remove(); 2285 + 2286 + if (!pdev->bus) 2287 + goto error; 2288 + 2289 + data = pci_get_drvdata(pdev); 2290 + 2291 + btintel_pcie_disable_interrupts(data); 2292 + btintel_pcie_synchronize_irqs(data); 2293 + 2294 + flush_work(&data->rx_work); 2295 + flush_work(&data->hdev->dump.dump_rx); 2296 + 2297 + bt_dev_dbg(data->hdev, "Release bluetooth interface"); 2298 + btintel_pcie_release_hdev(data); 2299 + 2300 + err = pci_reset_function(pdev); 2301 + if (err) { 2302 + BT_ERR("Failed resetting the pcie device (%d)", err); 2303 + goto error; 2304 + } 2305 + 2306 + btintel_pcie_enable_interrupts(data); 2307 + btintel_pcie_config_msix(data); 2308 + 2309 + err = btintel_pcie_enable_bt(data); 2310 + if (err) { 2311 + BT_ERR("Failed to enable bluetooth hardware after reset (%d)", 2312 + err); 2313 + goto error; 2314 + } 2315 + 2316 + btintel_pcie_reset_ia(data); 2317 + btintel_pcie_start_rx(data); 2318 + data->flags = 0; 2319 + 2320 + err = btintel_pcie_setup_hdev(data); 2321 + if (err) { 2322 + BT_ERR("Failed registering hdev (%d)", err); 2323 + goto error; 2324 + } 2325 + error: 2326 + pci_dev_put(pdev); 2327 + pci_unlock_rescan_remove(); 2328 + kfree(removal); 2329 + } 2330 + 2331 + static void btintel_pcie_reset(struct hci_dev *hdev) 2332 + { 2333 + struct btintel_pcie_removal *removal; 2334 + struct btintel_pcie_data *data; 2335 + 2336 + data = hci_get_drvdata(hdev); 2337 + 2338 + if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags)) 2339 + return; 2340 + 2341 + if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) 2342 + return; 2343 + 2344 + removal = kzalloc(sizeof(*removal), GFP_ATOMIC); 2345 + if (!removal) 2346 + return; 2347 + 2348 + removal->pdev = data->pdev; 2349 + INIT_WORK(&removal->work, btintel_pcie_removal_work); 2350 + pci_dev_get(removal->pdev); 2351 + schedule_work(&removal->work); 2352 + } 2353 + 2354 + static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) 2355 + { 2356 + struct btintel_pcie_dev_restart_data *data; 2357 + struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev); 2358 + struct pci_dev *pdev = dev_data->pdev; 2359 + time64_t retry_window; 2360 + 2361 + if (code == 0x13) { 2362 + bt_dev_err(hdev, "Encountered top exception"); 2363 + return; 2364 + } 2365 + 2366 + data = btintel_pcie_get_restart_data(pdev, &hdev->dev); 2367 + if (!data) 2368 + return; 2369 + 2370 + retry_window = ktime_get_boottime_seconds() - data->last_error; 2371 + 2372 + if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && 2373 + data->restart_count >= BTINTEL_PCIE_FLR_MAX_RETRY) { 2374 + bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d", 2375 + BTINTEL_PCIE_FLR_MAX_RETRY, data->restart_count); 2376 + bt_dev_dbg(hdev, "Boot time: %lld seconds first_flr at: %lld seconds restart_count: %d", 2377 + ktime_get_boottime_seconds(), data->last_error, 2378 + data->restart_count); 2379 + return; 2380 + } 2381 + btintel_pcie_inc_restart_count(pdev, &hdev->dev); 2382 + btintel_pcie_reset(hdev); 2217 2383 } 2218 2384 2219 2385 static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) ··· 2424 2216 hdev->send = btintel_pcie_send_frame; 2425 2217 hdev->setup = btintel_pcie_setup; 2426 2218 hdev->shutdown = btintel_shutdown_combined; 2427 - hdev->hw_error = btintel_hw_error; 2219 + hdev->hw_error = btintel_pcie_hw_error; 2428 2220 hdev->set_diag = btintel_set_diag; 2429 2221 hdev->set_bdaddr = btintel_set_bdaddr; 2222 + hdev->reset = btintel_pcie_reset; 2430 2223 2431 2224 err = hci_register_dev(hdev); 2432 2225 if (err < 0) { ··· 2575 2366 .driver.coredump = btintel_pcie_coredump 2576 2367 #endif 2577 2368 }; 2578 - module_pci_driver(btintel_pcie_driver); 2369 + 2370 + static int __init btintel_pcie_init(void) 2371 + { 2372 + return pci_register_driver(&btintel_pcie_driver); 2373 + } 2374 + 2375 + static void __exit btintel_pcie_exit(void) 2376 + { 2377 + pci_unregister_driver(&btintel_pcie_driver); 2378 + btintel_pcie_free_restart_list(); 2379 + } 2380 + 2381 + module_init(btintel_pcie_init); 2382 + module_exit(btintel_pcie_exit); 2579 2383 2580 2384 MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>"); 2581 2385 MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION);
+3 -1
drivers/bluetooth/btintel_pcie.h
··· 117 117 enum { 118 118 BTINTEL_PCIE_CORE_HALTED, 119 119 BTINTEL_PCIE_HWEXP_INPROGRESS, 120 - BTINTEL_PCIE_COREDUMP_INPROGRESS 120 + BTINTEL_PCIE_COREDUMP_INPROGRESS, 121 + BTINTEL_PCIE_RECOVERY_IN_PROGRESS, 122 + BTINTEL_PCIE_SETUP_DONE 121 123 }; 122 124 123 125 enum btintel_pcie_tlv_type {