Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on: [pull_request]

jobs:
ci:
runs-on: ubuntu-latest
name: CI for Pull Request
steps:
- name: Checkout the source code
uses: actions/checkout@v3
with:
path: src/src

- name: CI
uses: tedd-an/bzcafe@main
with:
task: ci
base_folder: src
space: kernel
github_token: ${{ secrets.GITHUB_TOKEN }}
email_token: ${{ secrets.EMAIL_TOKEN }}
patchwork_token: ${{ secrets.PATCHWORK_TOKEN }}
patchwork_user: ${{ secrets.PATCHWORK_USER }}

43 changes: 43 additions & 0 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Sync

on:
schedule:
- cron: "*/30 * * * *"

jobs:
sync_repo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: master

- name: Sync Repo
uses: tedd-an/bzcafe@main
with:
task: sync
upstream_repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git'
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Cleanup PR
uses: tedd-an/bzcafe@main
with:
task: cleanup
github_token: ${{ secrets.ACTION_TOKEN }}

sync_patchwork:
needs: sync_repo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Sync Patchwork
uses: tedd-an/bzcafe@main
with:
task: patchwork
space: kernel
github_token: ${{ secrets.ACTION_TOKEN }}
email_token: ${{ secrets.EMAIL_TOKEN }}
patchwork_token: ${{ secrets.PATCHWORK_TOKEN }}
patchwork_user: ${{ secrets.PATCHWORK_USER }}

6 changes: 4 additions & 2 deletions drivers/bluetooth/btintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ static struct {
u32 fw_build_num;
} coredump_info;

static const guid_t btintel_guid_dsm =
const guid_t btintel_guid_dsm =
GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,
0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);
EXPORT_SYMBOL_GPL(btintel_guid_dsm);

int btintel_check_bdaddr(struct hci_dev *hdev)
{
Expand Down Expand Up @@ -2624,7 +2625,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
kfree_skb(skb);
}

static int btintel_acpi_reset_method(struct hci_dev *hdev)
int btintel_acpi_reset_method(struct hci_dev *hdev)
{
int ret = 0;
acpi_status status;
Expand Down Expand Up @@ -2663,6 +2664,7 @@ static int btintel_acpi_reset_method(struct hci_dev *hdev)
kfree(buffer.pointer);
return ret;
}
EXPORT_SYMBOL_GPL(btintel_acpi_reset_method);

static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
struct intel_version_tlv *ver_tlv)
Expand Down
7 changes: 7 additions & 0 deletions drivers/bluetooth/btintel.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct intel_tlv {
#define BTINTEL_HWID_SCP2 0x20 /* Scorpius Peak2 - Nova Lake */
#define BTINTEL_HWID_BZRIW 0x22 /* BlazarIW - Wildcat Lake */

extern const guid_t btintel_guid_dsm;

struct intel_version_tlv {
u32 cnvi_top;
u32 cnvr_top;
Expand Down Expand Up @@ -289,6 +291,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
int btintel_shutdown_combined(struct hci_dev *hdev);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_print_fseq_info(struct hci_dev *hdev);
int btintel_acpi_reset_method(struct hci_dev *hdev);
#else

static inline int btintel_check_bdaddr(struct hci_dev *hdev)
Expand Down Expand Up @@ -422,4 +425,8 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
{
}
static inline int btintel_acpi_reset_method(struct hci_dev *hdev)
{
return -ENODEV;
}
#endif
163 changes: 154 additions & 9 deletions drivers/bluetooth/btintel_pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/acpi.h>

#include <linux/unaligned.h>
#include <linux/devcoredump.h>
Expand Down Expand Up @@ -100,6 +101,22 @@ enum {
BTINTEL_PCIE_D3
};

enum {
BTINTEL_PCIE_DSM_SET_RESET_TIMING = 1,
BTINTEL_PCIE_DSM_GET_RESET_TIMING = 2,
BTINTEL_PCIE_DSM_BT_PLDR_CONFIG = 3,
BTINTEL_PCIE_DSM_GET_RESET_TYPE = 4,
BTINTEL_PCIE_DSM_DYNAMIC_PLDR = 5,
BTINTEL_PCIE_DSM_GET_RESET_METHOD = 6,
BTINTEL_PCIE_DSM_SET_PLDR_DELAY = 7,
};

enum btintel_dsm_internal_product_reset_mode {
BTINTEL_PCIE_DSM_PLDR_MODE_EN_PROD_RESET = BIT(0),
BTINTEL_PCIE_DSM_PLDR_MODE_EN_WIFI_FLR = BIT(1),
BTINTEL_PCIE_DSM_PLDR_MODE_EN_BT_OFF_ON = BIT(2),
};

/* Structure for dbgc fragment buffer
* @buf_addr_lsb: LSB of the buffer's physical address
* @buf_addr_msb: MSB of the buffer's physical address
Expand All @@ -126,6 +143,11 @@ struct btintel_pcie_dbgc_ctxt {
struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT];
};

/* structure for reset and recovery
* @pdev: The pci_dev for controller
* @work: work struct for reset
* @reset type: Reset can be FLR or PLDR
*/
struct btintel_pcie_removal {
struct pci_dev *pdev;
struct work_struct work;
Expand Down Expand Up @@ -2254,6 +2276,112 @@ static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev,
}

static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data);
static void btintel_pcie_reset(struct hci_dev *hdev);

static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data)
{
union acpi_object *obj, argv4;
acpi_handle handle;
int ret;
struct pldr_mode {
u16 cmd_type;
u16 cmd_payload;
} __packed;

/* set 1 for _PRR mode
* Product Reset (PLDR Abort flow)
*/
static const struct pldr_mode mode = {
.cmd_type = 1,
.cmd_payload = BTINTEL_PCIE_DSM_PLDR_MODE_EN_PROD_RESET |
BTINTEL_PCIE_DSM_PLDR_MODE_EN_WIFI_FLR,
};
struct hci_dev *hdev = data->hdev;

handle = ACPI_HANDLE(GET_HCIDEV_DEV(data->hdev));
if (!handle) {
bt_dev_dbg(data->hdev, "No support for bluetooth device in ACPI firmware");
return -EACCES;
}

if (!acpi_has_method(handle, "_PRR")) {
bt_dev_dbg(data->hdev, "No support for _PRR ACPI method, falling back to FLR");
btintel_pcie_reset(data->hdev);
return -ENODEV;
}

argv4.buffer.type = ACPI_TYPE_BUFFER;
argv4.buffer.length = sizeof(mode);
argv4.buffer.pointer = (void *)&mode;

obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
BTINTEL_PCIE_DSM_DYNAMIC_PLDR, &argv4);
if (!obj) {
bt_dev_err(data->hdev, "Failed to call dsm to set reset method");
return -EIO;
}
ACPI_FREE(obj);

pci_dev_lock(data->pdev);
pci_save_state(data->pdev);
ret = btintel_acpi_reset_method(hdev);
if (ret)
bt_dev_err(data->hdev, "ACPI _PRR reset failed (%d),PLDR incomplete",
ret);
pci_restore_state(data->pdev);
pci_dev_unlock(data->pdev);
return ret;
}

static void btintel_pcie_perform_pldr(struct btintel_pcie_removal *removal)
{
struct pci_dev *pdev = removal->pdev;
struct pci_dev *wifi = NULL;
struct pci_bus *bus;
struct btintel_pcie_data *data;
/* on integrated we have to look up by ID (same bus) */
static const struct pci_device_id wifi_device_ids[] = {
#define WIFI_DEV(_id) { PCI_DEVICE(PCI_VENDOR_ID_INTEL, _id) }
WIFI_DEV(0xA840), /* LNL */
WIFI_DEV(0xE440), /* PTL-P */
WIFI_DEV(0xE340), /* PTL-H */
WIFI_DEV(0xD340), /* NVL-H */
WIFI_DEV(0x6E70), /* NVL-S */
WIFI_DEV(0x4D40), /* WCL */
WIFI_DEV(0xD240), /* RZL-H */
WIFI_DEV(0x6C40), /* RZL-M */
{}
};
struct pci_dev *tmp = NULL;

data = pci_get_drvdata(pdev);

bus = pdev->bus;
if (!bus)
return;

/* If ACPI reset fell back to FLR or failed, skip reprobe to avoid
* racing with the FLR work already scheduled.
*/
if (btintel_pcie_acpi_reset_method(data))
return;

list_for_each_entry(tmp, &bus->devices, bus_list) {
if (pci_match_id(wifi_device_ids, tmp)) {
wifi = pci_dev_get(tmp);
break;
}
}

if (wifi) {
if (device_reprobe(&wifi->dev))
BT_ERR("WiFi reprobe failed for BDF:%s", pci_name(wifi));
pci_dev_put(wifi);
}

if (device_reprobe(&pdev->dev))
BT_ERR("BT reprobe failed for BDF:%s", pci_name(pdev));
}

static void btintel_pcie_removal_work(struct work_struct *wk)
{
Expand All @@ -2266,22 +2394,30 @@ static void btintel_pcie_removal_work(struct work_struct *wk)
pci_lock_rescan_remove();

if (!pdev->bus)
goto error;
goto out;

data = pci_get_drvdata(pdev);
if (!data) {
BT_WARN("PCI driver data is NULL, aborting removal work");
goto out;
}

btintel_pcie_disable_interrupts(data);
btintel_pcie_synchronize_irqs(data);

flush_work(&data->rx_work);

bt_dev_dbg(data->hdev, "Release bluetooth interface");
if (data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR) {
btintel_pcie_perform_pldr(removal);
goto out;
}
btintel_pcie_release_hdev(data);

err = pci_reset_function(pdev);
if (err) {
BT_ERR("Failed resetting the pcie device (%d)", err);
goto error;
goto out;
}

btintel_pcie_enable_interrupts(data);
Expand All @@ -2291,7 +2427,7 @@ static void btintel_pcie_removal_work(struct work_struct *wk)
if (err) {
BT_ERR("Failed to enable bluetooth hardware after reset (%d)",
err);
goto error;
goto out;
}

btintel_pcie_reset_ia(data);
Expand All @@ -2301,9 +2437,9 @@ static void btintel_pcie_removal_work(struct work_struct *wk)
err = btintel_pcie_setup_hdev(data);
if (err) {
BT_ERR("Failed registering hdev (%d)", err);
goto error;
goto out;
}
error:
out:
pci_dev_put(pdev);
pci_unlock_rescan_remove();
kfree(removal);
Expand Down Expand Up @@ -2339,15 +2475,19 @@ static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
struct pci_dev *pdev = dev_data->pdev;
time64_t retry_window;

if (code == 0x13) {
bt_dev_err(hdev, "Encountered top exception");
return;
}
btintel_pcie_dump_debug_registers(hdev);

data = btintel_pcie_get_recovery(pdev, &hdev->dev);
if (!data)
return;

if (code == 0x13)
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR;
else
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;

bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code,
dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
retry_window = ktime_get_boottime_seconds() - data->last_error;

if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
Expand Down Expand Up @@ -2503,6 +2643,10 @@ static int btintel_pcie_probe(struct pci_dev *pdev,

data->boot_stage_cache = 0x00;
data->img_resp_cache = 0x00;
/* FLR can be invoked by echoing to debugfs path, so explicitly
* initialized
*/
data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;

err = btintel_pcie_config_pcie(pdev, data);
if (err)
Expand Down Expand Up @@ -2701,6 +2845,7 @@ static int btintel_pcie_resume(struct device *dev)
if (data->pm_sx_event == PM_EVENT_FREEZE ||
data->pm_sx_event == PM_EVENT_HIBERNATE) {
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
btintel_pcie_reset(data->hdev);
return 0;
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/bluetooth/btintel_pcie.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ enum msix_mbox_int_causes {
BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX4 = BIT(3), /* cause MBOX4 */
};

enum btintel_pcie_reset_type {
BTINTEL_PCIE_IOSF_PRR_FLR = 0,
BTINTEL_PCIE_IOSF_PRR_PLDR = 1,
};

#define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)

/* Minimum and Maximum number of MSI-X Vector
Expand Down Expand Up @@ -514,6 +519,7 @@ struct btintel_pcie_data {
struct txq txq;
struct rxq rxq;
u32 alive_intr_ctxt;
enum btintel_pcie_reset_type reset_type;
struct btintel_pcie_dbgc dbgc;
struct btintel_pcie_dump_header dmp_hdr;
u8 pm_sx_event;
Expand Down
Loading
Loading