Re: [PATCH v1 1/2] Bluetooth: btintel_pcie: Add handshake between driver and firmware

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Kiran,

On Tue, Oct 1, 2024 at 6:29 AM Kiran K <kiran.k@xxxxxxxxx> wrote:
>
> The following handshake mechanism needs be followed after firmware
> download is completed to bring the firmware to running state.
>
> After firmware fragments of Operational image are downloaded and
> secure sends result of the image succeeds,
>
> 1. Driver sends HCI Intel reset with boot option #1 to switch FW image.
> 2. FW sends Alive GP[0] MSIx
> 3. Driver enables data path (doorbell 0x460 for RBDs, etc...)
> 4. Driver gets Bootup event from firmware
> 5. Driver performs D0 entry to device (WRITE to IPC_Sleep_Control =0x0)
> 6. FW sends Alive GP[0] MSIx
> 7. Device host interface is fully set for BT protocol stack operation.
> 8. Driver may optionally get debug event with ID 0x97 which can be dropped

We should probably start versioning the boot sequence from the very
beginning, I also wonder if we should promote the use usage of
something like the hci_init_stage_sync for such use cases so one can
clearly define each step separately as a function which makes it very
simple to reuse them in different init stage (operational vs
intermediate).

> For Intermediate loadger image, all the above steps are applicable
> expcept #5 and #6.
>
> On HCI_OP_RESET, firmware raises alive interrupt. Driver needs to wait
> for it before passing control over to bluetooth stack.
>
> Co-developed-by: Devegowda Chandrashekar <chandrashekar.devegowda@xxxxxxxxx>
> Signed-off-by: Devegowda Chandrashekar <chandrashekar.devegowda@xxxxxxxxx>
> Signed-off-by: Kiran K <kiran.k@xxxxxxxxx>
> ---
>  drivers/bluetooth/btintel.c      |  56 ++++++-
>  drivers/bluetooth/btintel.h      |   7 +
>  drivers/bluetooth/btintel_pcie.c | 262 ++++++++++++++++++++++++++++++-
>  drivers/bluetooth/btintel_pcie.h |  16 +-
>  4 files changed, 329 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 1ccbb5157515..fed1a939aad6 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -1841,6 +1841,37 @@ static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
>         return 0;
>  }
>
> +static int btintel_boot_wait_d0(struct hci_dev *hdev, ktime_t calltime,
> +                               int msec)
> +{
> +       ktime_t delta, rettime;
> +       unsigned long long duration;
> +       int err;
> +
> +       bt_dev_info(hdev, "Waiting for device transition to d0");
> +
> +       err = btintel_wait_on_flag_timeout(hdev, INTEL_WAIT_FOR_D0,
> +                                          TASK_INTERRUPTIBLE,
> +                                          msecs_to_jiffies(msec));
> +       if (err == -EINTR) {
> +               bt_dev_err(hdev, "Device d0 move interrupted");
> +               return -EINTR;
> +       }
> +
> +       if (err) {
> +               bt_dev_err(hdev, "Device d0 move timeout");
> +               return -ETIMEDOUT;
> +       }
> +
> +       rettime = ktime_get();
> +       delta = ktime_sub(rettime, calltime);
> +       duration = (unsigned long long)ktime_to_ns(delta) >> 10;
> +
> +       bt_dev_info(hdev, "Device moved to D0 in %llu usecs", duration);
> +
> +       return 0;
> +}
> +
>  static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
>  {
>         ktime_t calltime;
> @@ -1849,6 +1880,7 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
>         calltime = ktime_get();
>
>         btintel_set_flag(hdev, INTEL_BOOTING);
> +       btintel_set_flag(hdev, INTEL_WAIT_FOR_D0);
>
>         err = btintel_send_intel_reset(hdev, boot_addr);
>         if (err) {
> @@ -1861,13 +1893,28 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
>          * is done by the operational firmware sending bootup notification.
>          *
>          * Booting into operational firmware should not take longer than
> -        * 1 second. However if that happens, then just fail the setup
> +        * 5 second. However if that happens, then just fail the setup
>          * since something went wrong.
>          */
> -       err = btintel_boot_wait(hdev, calltime, 1000);
> -       if (err == -ETIMEDOUT)
> +       err = btintel_boot_wait(hdev, calltime, 5000);
> +       if (err == -ETIMEDOUT) {
>                 btintel_reset_to_bootloader(hdev);
> +               goto exit_error;
> +       }
>
> +       if (hdev->bus == HCI_PCI) {
> +               /* In case of PCIe, after receiving bootup event, driver performs
> +                * D0 entry by writing 0 to sleep control register (check
> +                * btintel_pcie_recv_event())
> +                * Firmware acks with alive interrupt indicating host is full ready to
> +                * perform BT operation. Lets wait here till INTEL_WAIT_FOR_D0
> +                * bit is cleared.
> +                */
> +               calltime = ktime_get();
> +               err = btintel_boot_wait_d0(hdev, calltime, 2000);
> +       }
> +
> +exit_error:
>         return err;
>  }
>
> @@ -3273,7 +3320,7 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
>  }
>  EXPORT_SYMBOL_GPL(btintel_configure_setup);
>
> -static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
> +int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
>  {
>         struct intel_tlv *tlv = (void *)&skb->data[5];
>
> @@ -3302,6 +3349,7 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
>  recv_frame:
>         return hci_recv_frame(hdev, skb);
>  }
> +EXPORT_SYMBOL_GPL(btintel_diagnostics);
>
>  int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
>  {
> diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
> index aa70e4c27416..b448c67e8ed9 100644
> --- a/drivers/bluetooth/btintel.h
> +++ b/drivers/bluetooth/btintel.h
> @@ -178,6 +178,7 @@ enum {
>         INTEL_ROM_LEGACY,
>         INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
>         INTEL_ACPI_RESET_ACTIVE,
> +       INTEL_WAIT_FOR_D0,
>
>         __INTEL_NUM_FLAGS,
>  };
> @@ -249,6 +250,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_diagnostics(struct hci_dev *hdev, struct sk_buff *skb);
>  #else
>
>  static inline int btintel_check_bdaddr(struct hci_dev *hdev)
> @@ -382,4 +384,9 @@ 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_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       return -EOPNOTSUPP;
> +}
>  #endif
> diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
> index fda47948c35d..cff3e7afdff9 100644
> --- a/drivers/bluetooth/btintel_pcie.c
> +++ b/drivers/bluetooth/btintel_pcie.c
> @@ -48,6 +48,17 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
>  #define BTINTEL_PCIE_HCI_EVT_PKT       0x00000004
>  #define BTINTEL_PCIE_HCI_ISO_PKT       0x00000005
>
> +/* Alive interrupt context */
> +enum {
> +       BTINTEL_PCIE_ROM,
> +       BTINTEL_PCIE_FW_DL,
> +       BTINTEL_PCIE_HCI_RESET,
> +       BTINTEL_PCIE_INTEL_HCI_RESET1,
> +       BTINTEL_PCIE_INTEL_HCI_RESET2,
> +       BTINTEL_PCIE_D0,
> +       BTINTEL_PCIE_D3
> +};
> +
>  static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia,
>                                      u16 queue_num)
>  {
> @@ -290,8 +301,9 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
>         /* wait for interrupt from the device after booting up to primary
>          * bootloader.
>          */
> +       data->alive_intr_ctxt = BTINTEL_PCIE_ROM;
>         err = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
> -                                msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT));
> +                                msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
>         if (!err)
>                 return -ETIME;
>
> @@ -302,12 +314,78 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
>         return 0;
>  }
>
> +/* BIT(0) - ROM, BIT(1) - IML and BIT(3) - OP
> + * Sometimes during firmware image switching from ROM to IML or IML to OP image,
> + * the previous image bit is not cleared by firmware when alive interrupt is
> + * received. Driver needs to take care of these sticky bits when deciding the
> + * current image running on controller.
> + * Ex: 0x10 and 0x11 - both represents that controller is running IML
> + */
> +static inline bool btintel_pcie_in_rom(struct btintel_pcie_data *data)
> +{
> +       return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM &&
> +               !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) &&
> +               !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
> +}
> +
> +static inline bool btintel_pcie_in_op(struct btintel_pcie_data *data)
> +{
> +       return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW;
> +}
> +
> +static inline bool btintel_pcie_in_iml(struct btintel_pcie_data *data)
> +{
> +       return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML &&
> +               !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
> +}
> +
> +static inline bool btintel_pcie_in_d3(struct btintel_pcie_data *data)
> +{
> +       return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY;
> +}
> +
> +static inline bool btintel_pcie_in_d0(struct btintel_pcie_data *data)
> +{
> +       return !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY);
> +}
> +
> +static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
> +                                       u32 dxstate)
> +{
> +       bt_dev_dbg(data->hdev, "writing sleep_ctl_reg: 0x%8.8x", dxstate);
> +       btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate);
> +}
> +
> +static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)
> +{
> +       switch (alive_intr_ctxt) {
> +       case BTINTEL_PCIE_ROM:
> +               return "rom";
> +       case BTINTEL_PCIE_FW_DL:
> +               return "fw_dl";
> +       case BTINTEL_PCIE_D0:
> +               return "d0";
> +       case BTINTEL_PCIE_D3:
> +               return "d3";
> +       case BTINTEL_PCIE_HCI_RESET:
> +               return "hci_reset";
> +       case BTINTEL_PCIE_INTEL_HCI_RESET1:
> +               return "intel_reset1";
> +       case BTINTEL_PCIE_INTEL_HCI_RESET2:
> +               return "intel_reset2";
> +       default:
> +               return "unknown";
> +       }
> +       return "null";
> +}
> +
>  /* This function handles the MSI-X interrupt for gp0 cause (bit 0 in
>   * BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES) which is sent for boot stage and image response.
>   */
>  static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
>  {
> -       u32 reg;
> +       bool submit_rx, signal_waitq;
> +       u32 reg, old_ctxt;
>
>         /* This interrupt is for three different causes and it is not easy to
>          * know what causes the interrupt. So, it compares each register value
> @@ -317,20 +395,87 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
>         if (reg != data->boot_stage_cache)
>                 data->boot_stage_cache = reg;
>
> +       bt_dev_dbg(data->hdev, "Alive context: %s old_boot_stage: 0x%8.8x new_boot_stage: 0x%8.8x",
> +                  btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt),
> +                  data->boot_stage_cache, reg);
>         reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IMG_RESPONSE_REG);
>         if (reg != data->img_resp_cache)
>                 data->img_resp_cache = reg;
>
>         data->gp0_received = true;
>
> -       /* If the boot stage is OP or IML, reset IA and start RX again */
> -       if (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW ||
> -           data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) {
> +       old_ctxt = data->alive_intr_ctxt;
> +       submit_rx = false;
> +       signal_waitq = false;
> +
> +       switch (data->alive_intr_ctxt) {
> +       case BTINTEL_PCIE_ROM:
> +               data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
> +               signal_waitq = true;
> +               break;
> +       case BTINTEL_PCIE_FW_DL:
> +               /* Error case is already handled. Ideally control shall not
> +                * reach here
> +                */
> +               break;
> +       case BTINTEL_PCIE_INTEL_HCI_RESET1:
> +               if (btintel_pcie_in_op(data)) {
> +                       submit_rx = true;
> +                       break;
> +               }
> +
> +               if (btintel_pcie_in_iml(data)) {
> +                       submit_rx = true;
> +                       data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
> +                       break;
> +               }
> +               break;
> +       case BTINTEL_PCIE_INTEL_HCI_RESET2:
> +               if (btintel_test_and_clear_flag(data->hdev, INTEL_WAIT_FOR_D0)) {
> +                       btintel_wake_up_flag(data->hdev, INTEL_WAIT_FOR_D0);
> +                       data->alive_intr_ctxt = BTINTEL_PCIE_D0;
> +               }
> +               break;
> +       case BTINTEL_PCIE_D0:
> +               if (btintel_pcie_in_d3(data)) {
> +                       data->alive_intr_ctxt = BTINTEL_PCIE_D3;
> +                       signal_waitq = true;
> +                       break;
> +               }
> +               break;
> +       case BTINTEL_PCIE_D3:
> +               if (btintel_pcie_in_d0(data)) {
> +                       data->alive_intr_ctxt = BTINTEL_PCIE_D0;
> +                       submit_rx = true;
> +                       signal_waitq = true;
> +                       break;
> +               }
> +               break;
> +       case BTINTEL_PCIE_HCI_RESET:
> +               data->alive_intr_ctxt = BTINTEL_PCIE_D0;
> +               submit_rx = true;
> +               signal_waitq = true;
> +               break;
> +       default:
> +               bt_dev_err(data->hdev, "Unknown state: 0x%2.2x",
> +                          data->alive_intr_ctxt);
> +               break;
> +       }
> +
> +       if (submit_rx) {
>                 btintel_pcie_reset_ia(data);
>                 btintel_pcie_start_rx(data);
>         }
>
> -       wake_up(&data->gp0_wait_q);
> +       if (signal_waitq) {
> +               bt_dev_dbg(data->hdev, "wake up gp0 wait_q");
> +               wake_up(&data->gp0_wait_q);
> +       }
> +
> +       if (old_ctxt != data->alive_intr_ctxt)
> +               bt_dev_dbg(data->hdev, "alive context changed: %s  ->  %s",
> +                          btintel_pcie_alivectxt_state2str(old_ctxt),
> +                          btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
>  }
>
>  /* This function handles the MSX-X interrupt for rx queue 0 which is for TX
> @@ -364,6 +509,80 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
>         }
>  }
>
> +static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct hci_event_hdr *hdr = (void *)skb->data;
> +       const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
> +       struct btintel_pcie_data *data = hci_get_drvdata(hdev);
> +
> +       if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
> +           hdr->plen > 0) {
> +               const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
> +               unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
> +
> +               if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
> +                       switch (skb->data[2]) {
> +                       case 0x02:
> +                               /* When switching to the operational firmware
> +                                * the device sends a vendor specific event
> +                                * indicating that the bootup completed.
> +                                */
> +                               btintel_bootup(hdev, ptr, len);
> +
> +                               /* If bootup event is from operational image,
> +                                * driver needs to write sleep control register to
> +                                * move into D0 state
> +                                */
> +                               if (btintel_pcie_in_op(data)) {
> +                                       btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0);
> +                                       data->alive_intr_ctxt = BTINTEL_PCIE_INTEL_HCI_RESET2;
> +                                       break;
> +                               }
> +
> +                               if (btintel_pcie_in_iml(data)) {
> +                                       /* In case of IML, there is no concept
> +                                        * of D0 transition. Just mimic as if
> +                                        * IML moved to D0 by clearing INTEL_WAIT_FOR_D0
> +                                        * bit and waking up the task waiting on
> +                                        * INTEL_WAIT_FOR_D0. This is required
> +                                        * as intel_boot() is common function for
> +                                        * both IML and OP image loading.
> +                                        */
> +                                       if (btintel_test_and_clear_flag(data->hdev,
> +                                                                       INTEL_WAIT_FOR_D0))
> +                                               btintel_wake_up_flag(data->hdev,
> +                                                                    INTEL_WAIT_FOR_D0);
> +                               }
> +                               break;
> +                       case 0x06:
> +                               /* When the firmware loading completes the
> +                                * device sends out a vendor specific event
> +                                * indicating the result of the firmware
> +                                * loading.
> +                                */
> +                               btintel_secure_send_result(hdev, ptr, len);
> +                               break;
> +                       }
> +               }
> +
> +               /* Handle all diagnostics events separately. May still call
> +                * hci_recv_frame.
> +                */
> +               if (len >= sizeof(diagnostics_hdr) &&
> +                   memcmp(&skb->data[2], diagnostics_hdr,
> +                          sizeof(diagnostics_hdr)) == 0) {
> +                       return btintel_diagnostics(hdev, skb);
> +               }
> +
> +               /* This is a debug event that comes from IML and OP image when it
> +                * starts execution. There is no need pass this event to stack.
> +                */
> +               if (skb->data[2] == 0x97)
> +                       return 0;
> +       }
> +
> +       return hci_recv_frame(hdev, skb);
> +}
>  /* Process the received rx data
>   * It check the frame header to identify the data type and create skb
>   * and calling HCI API
> @@ -465,7 +684,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
>         hdev->stat.byte_rx += plen;
>
>         if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT)
> -               ret = btintel_recv_event(hdev, new_skb);
> +               ret = btintel_pcie_recv_event(hdev, new_skb);
>         else
>                 ret = hci_recv_frame(hdev, new_skb);
>
> @@ -1053,8 +1272,11 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
>                                        struct sk_buff *skb)
>  {
>         struct btintel_pcie_data *data = hci_get_drvdata(hdev);
> +       struct hci_command_hdr *cmd;
> +       __u16 opcode = ~0;
>         int ret;
>         u32 type;
> +       u32 old_ctxt;
>
>         /* Due to the fw limitation, the type header of the packet should be
>          * 4 bytes unlike 1 byte for UART. In UART, the firmware can read
> @@ -1073,6 +1295,8 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
>         switch (hci_skb_pkt_type(skb)) {
>         case HCI_COMMAND_PKT:
>                 type = BTINTEL_PCIE_HCI_CMD_PKT;
> +               cmd = (void *)skb->data;
> +               opcode = le16_to_cpu(cmd->opcode);
>                 if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
>                         struct hci_command_hdr *cmd = (void *)skb->data;
>                         __u16 opcode = le16_to_cpu(cmd->opcode);
> @@ -1111,6 +1335,30 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
>                 bt_dev_err(hdev, "Failed to send frame (%d)", ret);
>                 goto exit_error;
>         }
> +
> +       if (type == BTINTEL_PCIE_HCI_CMD_PKT &&
> +           (opcode == HCI_OP_RESET || opcode == 0xfc01)) {
> +               old_ctxt = data->alive_intr_ctxt;
> +               data->alive_intr_ctxt =
> +                       (opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
> +                               BTINTEL_PCIE_HCI_RESET);
> +               bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s  ->  %s",
> +                          opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
> +                          btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
> +               if (opcode == HCI_OP_RESET) {
> +                       data->gp0_received = false;
> +                       ret = wait_event_timeout(data->gp0_wait_q,
> +                                                data->gp0_received,
> +                                                msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
> +                       if (!ret) {
> +                               hdev->stat.err_tx++;
> +                               bt_dev_err(hdev, "No alive interrupt received for %s",
> +                                          btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
> +                               ret = -ETIME;
> +                               goto exit_error;
> +                       }
> +               }
> +       }
>         hdev->stat.byte_tx += skb->len;
>         kfree_skb(skb);
>
> diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
> index baaff70420f5..8b7824ad005a 100644
> --- a/drivers/bluetooth/btintel_pcie.h
> +++ b/drivers/bluetooth/btintel_pcie.h
> @@ -12,6 +12,7 @@
>  #define BTINTEL_PCIE_CSR_HW_REV_REG            (BTINTEL_PCIE_CSR_BASE + 0x028)
>  #define BTINTEL_PCIE_CSR_RF_ID_REG             (BTINTEL_PCIE_CSR_BASE + 0x09C)
>  #define BTINTEL_PCIE_CSR_BOOT_STAGE_REG                (BTINTEL_PCIE_CSR_BASE + 0x108)
> +#define BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG     (BTINTEL_PCIE_CSR_BASE + 0x114)
>  #define BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG       (BTINTEL_PCIE_CSR_BASE + 0x118)
>  #define BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG       (BTINTEL_PCIE_CSR_BASE + 0x11C)
>  #define BTINTEL_PCIE_CSR_IMG_RESPONSE_REG      (BTINTEL_PCIE_CSR_BASE + 0x12C)
> @@ -32,6 +33,7 @@
>  #define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN       (BIT(11))
>  #define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON      (BIT(16))
>  #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE              (BIT(23))
> +#define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY     (BIT(24))
>
>  /* Registers for MSI-X */
>  #define BTINTEL_PCIE_CSR_MSIX_BASE             (0x2000)
> @@ -55,6 +57,16 @@ enum msix_hw_int_causes {
>         BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0     = BIT(0),       /* cause 32 */
>  };
>
> +/* PCIe device states
> + * Host-Device interface is active
> + * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD)
> + * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD)
> + */
> +enum {
> +       BTINTEL_PCIE_STATE_D0 = 0,
> +       BTINTEL_PCIE_STATE_D3_HOT = 2,
> +       BTINTEL_PCIE_STATE_D3_COLD = 3,
> +};
>  #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)
>
>  /* Minimum and Maximum number of MSI-X Vector
> @@ -67,7 +79,7 @@ enum msix_hw_int_causes {
>  #define BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US  200000
>
>  /* Default interrupt timeout in msec */
> -#define BTINTEL_DEFAULT_INTR_TIMEOUT   3000
> +#define BTINTEL_DEFAULT_INTR_TIMEOUT_MS        3000
>
>  /* The number of descriptors in TX/RX queues */
>  #define BTINTEL_DESCS_COUNT    16
> @@ -343,6 +355,7 @@ struct rxq {
>   * @ia: Index Array struct
>   * @txq: TX Queue struct
>   * @rxq: RX Queue struct
> + * @alive_intr_ctxt: Alive interrupt context
>   */
>  struct btintel_pcie_data {
>         struct pci_dev  *pdev;
> @@ -389,6 +402,7 @@ struct btintel_pcie_data {
>         struct ia       ia;
>         struct txq      txq;
>         struct rxq      rxq;
> +       u32     alive_intr_ctxt;
>  };
>
>  static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,
> --
> 2.40.1
>
>


-- 
Luiz Augusto von Dentz





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux