| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- *
- * Bluetooth support for Intel PCIe devices
- *
- * Copyright (C) 2024 Intel Corporation
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/firmware.h>
- #include <linux/pci.h>
- #include <linux/wait.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
- #include <linux/unaligned.h>
- #include <net/bluetooth/bluetooth.h>
- #include <net/bluetooth/hci_core.h>
- #include "btintel.h"
- #include "btintel_pcie.h"
- #define VERSION "0.1"
- #define BTINTEL_PCI_DEVICE(dev, subdev) \
- .vendor = PCI_VENDOR_ID_INTEL, \
- .device = (dev), \
- .subvendor = PCI_ANY_ID, \
- .subdevice = (subdev), \
- .driver_data = 0
- #define POLL_INTERVAL_US 10
- /* Intel Bluetooth PCIe device id table */
- static const struct pci_device_id btintel_pcie_table[] = {
- { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) },
- { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) },
- { 0 }
- };
- MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
- /* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */
- #define BTINTEL_PCIE_HCI_TYPE_LEN 4
- #define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001
- #define BTINTEL_PCIE_HCI_ACL_PKT 0x00000002
- #define BTINTEL_PCIE_HCI_SCO_PKT 0x00000003
- #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)
- {
- bt_dev_dbg(hdev, "IA: %s: tr-h:%02u tr-t:%02u cr-h:%02u cr-t:%02u",
- queue_num == BTINTEL_PCIE_TXQ_NUM ? "TXQ" : "RXQ",
- ia->tr_hia[queue_num], ia->tr_tia[queue_num],
- ia->cr_hia[queue_num], ia->cr_tia[queue_num]);
- }
- static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1,
- u16 index)
- {
- bt_dev_dbg(hdev, "RXQ:urbd1(%u) frbd_tag:%u status: 0x%x fixed:0x%x",
- index, urbd1->frbd_tag, urbd1->status, urbd1->fixed);
- }
- static int btintel_pcie_poll_bit(struct btintel_pcie_data *data, u32 offset,
- u32 bits, u32 mask, int timeout_us)
- {
- int t = 0;
- u32 reg;
- do {
- reg = btintel_pcie_rd_reg32(data, offset);
- if ((reg & mask) == (bits & mask))
- return t;
- udelay(POLL_INTERVAL_US);
- t += POLL_INTERVAL_US;
- } while (t < timeout_us);
- return -ETIMEDOUT;
- }
- static struct btintel_pcie_data *btintel_pcie_get_data(struct msix_entry *entry)
- {
- u8 queue = entry->entry;
- struct msix_entry *entries = entry - queue;
- return container_of(entries, struct btintel_pcie_data, msix_entries[0]);
- }
- /* Set the doorbell for TXQ to notify the device that @index (actually index-1)
- * of the TFD is updated and ready to transmit.
- */
- static void btintel_pcie_set_tx_db(struct btintel_pcie_data *data, u16 index)
- {
- u32 val;
- val = index;
- val |= (BTINTEL_PCIE_TX_DB_VEC << 16);
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR, val);
- }
- /* Copy the data to next(@tfd_index) data buffer and update the TFD(transfer
- * descriptor) with the data length and the DMA address of the data buffer.
- */
- static void btintel_pcie_prepare_tx(struct txq *txq, u16 tfd_index,
- struct sk_buff *skb)
- {
- struct data_buf *buf;
- struct tfd *tfd;
- tfd = &txq->tfds[tfd_index];
- memset(tfd, 0, sizeof(*tfd));
- buf = &txq->bufs[tfd_index];
- tfd->size = skb->len;
- tfd->addr = buf->data_p_addr;
- /* Copy the outgoing data to DMA buffer */
- memcpy(buf->data, skb->data, tfd->size);
- }
- static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
- struct sk_buff *skb)
- {
- int ret;
- u16 tfd_index;
- struct txq *txq = &data->txq;
- tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];
- if (tfd_index > txq->count)
- return -ERANGE;
- /* Prepare for TX. It updates the TFD with the length of data and
- * address of the DMA buffer, and copy the data to the DMA buffer
- */
- btintel_pcie_prepare_tx(txq, tfd_index, skb);
- tfd_index = (tfd_index + 1) % txq->count;
- data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM] = tfd_index;
- /* Arm wait event condition */
- data->tx_wait_done = false;
- /* Set the doorbell to notify the device */
- btintel_pcie_set_tx_db(data, tfd_index);
- /* Wait for the complete interrupt - URBD0 */
- ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done,
- msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS));
- if (!ret)
- return -ETIME;
- return 0;
- }
- /* Set the doorbell for RXQ to notify the device that @index (actually index-1)
- * is available to receive the data
- */
- static void btintel_pcie_set_rx_db(struct btintel_pcie_data *data, u16 index)
- {
- u32 val;
- val = index;
- val |= (BTINTEL_PCIE_RX_DB_VEC << 16);
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR, val);
- }
- /* Update the FRBD (free buffer descriptor) with the @frbd_index and the
- * DMA address of the free buffer.
- */
- static void btintel_pcie_prepare_rx(struct rxq *rxq, u16 frbd_index)
- {
- struct data_buf *buf;
- struct frbd *frbd;
- /* Get the buffer of the FRBD for DMA */
- buf = &rxq->bufs[frbd_index];
- frbd = &rxq->frbds[frbd_index];
- memset(frbd, 0, sizeof(*frbd));
- /* Update FRBD */
- frbd->tag = frbd_index;
- frbd->addr = buf->data_p_addr;
- }
- static int btintel_pcie_submit_rx(struct btintel_pcie_data *data)
- {
- u16 frbd_index;
- struct rxq *rxq = &data->rxq;
- frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM];
- if (frbd_index > rxq->count)
- return -ERANGE;
- /* Prepare for RX submit. It updates the FRBD with the address of DMA
- * buffer
- */
- btintel_pcie_prepare_rx(rxq, frbd_index);
- frbd_index = (frbd_index + 1) % rxq->count;
- data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM] = frbd_index;
- ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_RXQ_NUM);
- /* Set the doorbell to notify the device */
- btintel_pcie_set_rx_db(data, frbd_index);
- return 0;
- }
- static int btintel_pcie_start_rx(struct btintel_pcie_data *data)
- {
- int i, ret;
- struct rxq *rxq = &data->rxq;
- /* Post (BTINTEL_PCIE_RX_DESCS_COUNT - 3) buffers to overcome the
- * hardware issues leading to race condition at the firmware.
- */
- for (i = 0; i < rxq->count - 3; i++) {
- ret = btintel_pcie_submit_rx(data);
- if (ret)
- return ret;
- }
- return 0;
- }
- static void btintel_pcie_reset_ia(struct btintel_pcie_data *data)
- {
- memset(data->ia.tr_hia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
- memset(data->ia.tr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
- memset(data->ia.cr_hia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
- memset(data->ia.cr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
- }
- static void btintel_pcie_reset_bt(struct btintel_pcie_data *data)
- {
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET);
- }
- /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in
- * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with
- * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0.
- * Then the host reads firmware version from BTINTEL_CSR_F2D_MBX and the boot stage
- * from BTINTEL_PCIE_CSR_BOOT_STAGE_REG.
- */
- static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
- {
- int err;
- data->gp0_received = false;
- /* Update the DMA address of CI struct to CSR */
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG,
- data->ci_p_addr & 0xffffffff);
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG,
- (u64)data->ci_p_addr >> 32);
- /* Reset the cached value of boot stage. it is updated by the MSI-X
- * gp0 interrupt handler.
- */
- data->boot_stage_cache = 0x0;
- /* Set MAC_INIT bit to start primary bootloader */
- btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
- btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT);
- /* Wait until MAC_ACCESS is granted */
- err = btintel_pcie_poll_bit(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS,
- BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US);
- if (err < 0)
- return -ENODEV;
- /* MAC is ready. Enable BT FUNC */
- btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
- BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
- btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
- /* 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_MS));
- if (!err)
- return -ETIME;
- /* Check cached boot stage is BTINTEL_PCIE_CSR_BOOT_STAGE_ROM(BIT(0)) */
- if (~data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM)
- return -ENODEV;
- 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)
- {
- 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
- * with cached value and update it before it wake up the queue.
- */
- reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG);
- 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;
- 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);
- }
- 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
- */
- static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
- {
- u16 cr_tia, cr_hia;
- struct txq *txq;
- struct urbd0 *urbd0;
- cr_tia = data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM];
- cr_hia = data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM];
- if (cr_tia == cr_hia)
- return;
- txq = &data->txq;
- while (cr_tia != cr_hia) {
- data->tx_wait_done = true;
- wake_up(&data->tx_wait_q);
- urbd0 = &txq->urbd0s[cr_tia];
- if (urbd0->tfd_index > txq->count)
- return;
- cr_tia = (cr_tia + 1) % txq->count;
- data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] = cr_tia;
- ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_TXQ_NUM);
- }
- }
- 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;
- kfree_skb(skb);
- return 0;
- }
- 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);
- }
- kfree_skb(skb);
- return 0;
- 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);
- kfree_skb(skb);
- return 0;
- }
- }
- /* 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) {
- hci_recv_diag(hdev, skb);
- 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
- */
- static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
- struct sk_buff *skb)
- {
- int ret;
- u8 pkt_type;
- u16 plen;
- u32 pcie_pkt_type;
- void *pdata;
- struct hci_dev *hdev = data->hdev;
- spin_lock(&data->hci_rx_lock);
- /* The first 4 bytes indicates the Intel PCIe specific packet type */
- pdata = skb_pull_data(skb, BTINTEL_PCIE_HCI_TYPE_LEN);
- if (!pdata) {
- bt_dev_err(hdev, "Corrupted packet received");
- ret = -EILSEQ;
- goto exit_error;
- }
- pcie_pkt_type = get_unaligned_le32(pdata);
- switch (pcie_pkt_type) {
- case BTINTEL_PCIE_HCI_ACL_PKT:
- if (skb->len >= HCI_ACL_HDR_SIZE) {
- plen = HCI_ACL_HDR_SIZE + __le16_to_cpu(hci_acl_hdr(skb)->dlen);
- pkt_type = HCI_ACLDATA_PKT;
- } else {
- bt_dev_err(hdev, "ACL packet is too short");
- ret = -EILSEQ;
- goto exit_error;
- }
- break;
- case BTINTEL_PCIE_HCI_SCO_PKT:
- if (skb->len >= HCI_SCO_HDR_SIZE) {
- plen = HCI_SCO_HDR_SIZE + hci_sco_hdr(skb)->dlen;
- pkt_type = HCI_SCODATA_PKT;
- } else {
- bt_dev_err(hdev, "SCO packet is too short");
- ret = -EILSEQ;
- goto exit_error;
- }
- break;
- case BTINTEL_PCIE_HCI_EVT_PKT:
- if (skb->len >= HCI_EVENT_HDR_SIZE) {
- plen = HCI_EVENT_HDR_SIZE + hci_event_hdr(skb)->plen;
- pkt_type = HCI_EVENT_PKT;
- } else {
- bt_dev_err(hdev, "Event packet is too short");
- ret = -EILSEQ;
- goto exit_error;
- }
- break;
- case BTINTEL_PCIE_HCI_ISO_PKT:
- if (skb->len >= HCI_ISO_HDR_SIZE) {
- plen = HCI_ISO_HDR_SIZE + __le16_to_cpu(hci_iso_hdr(skb)->dlen);
- pkt_type = HCI_ISODATA_PKT;
- } else {
- bt_dev_err(hdev, "ISO packet is too short");
- ret = -EILSEQ;
- goto exit_error;
- }
- break;
- default:
- bt_dev_err(hdev, "Invalid packet type received: 0x%4.4x",
- pcie_pkt_type);
- ret = -EINVAL;
- goto exit_error;
- }
- if (skb->len < plen) {
- bt_dev_err(hdev, "Received corrupted packet. type: 0x%2.2x",
- pkt_type);
- ret = -EILSEQ;
- goto exit_error;
- }
- bt_dev_dbg(hdev, "pkt_type: 0x%2.2x len: %u", pkt_type, plen);
- hci_skb_pkt_type(skb) = pkt_type;
- hdev->stat.byte_rx += plen;
- skb_trim(skb, plen);
- if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT)
- ret = btintel_pcie_recv_event(hdev, skb);
- else
- ret = hci_recv_frame(hdev, skb);
- skb = NULL; /* skb is freed in the callee */
- exit_error:
- if (skb)
- kfree_skb(skb);
- if (ret)
- hdev->stat.err_rx++;
- spin_unlock(&data->hci_rx_lock);
- return ret;
- }
- static void btintel_pcie_rx_work(struct work_struct *work)
- {
- struct btintel_pcie_data *data = container_of(work,
- struct btintel_pcie_data, rx_work);
- struct sk_buff *skb;
- /* Process the sk_buf in queue and send to the HCI layer */
- while ((skb = skb_dequeue(&data->rx_skb_q))) {
- btintel_pcie_recv_frame(data, skb);
- }
- }
- /* create sk_buff with data and save it to queue and start RX work */
- static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status,
- void *buf)
- {
- int ret, len;
- struct rfh_hdr *rfh_hdr;
- struct sk_buff *skb;
- rfh_hdr = buf;
- len = rfh_hdr->packet_len;
- if (len <= 0) {
- ret = -EINVAL;
- goto resubmit;
- }
- /* Remove RFH header */
- buf += sizeof(*rfh_hdr);
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- ret = -ENOMEM;
- goto resubmit;
- }
- skb_put_data(skb, buf, len);
- skb_queue_tail(&data->rx_skb_q, skb);
- queue_work(data->workqueue, &data->rx_work);
- resubmit:
- ret = btintel_pcie_submit_rx(data);
- return ret;
- }
- /* Handles the MSI-X interrupt for rx queue 1 which is for RX */
- static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
- {
- u16 cr_hia, cr_tia;
- struct rxq *rxq;
- struct urbd1 *urbd1;
- struct data_buf *buf;
- int ret;
- struct hci_dev *hdev = data->hdev;
- cr_hia = data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM];
- cr_tia = data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM];
- bt_dev_dbg(hdev, "RXQ: cr_hia: %u cr_tia: %u", cr_hia, cr_tia);
- /* Check CR_TIA and CR_HIA for change */
- if (cr_tia == cr_hia)
- return;
- rxq = &data->rxq;
- /* The firmware sends multiple CD in a single MSI-X and it needs to
- * process all received CDs in this interrupt.
- */
- while (cr_tia != cr_hia) {
- urbd1 = &rxq->urbd1s[cr_tia];
- ipc_print_urbd1(data->hdev, urbd1, cr_tia);
- buf = &rxq->bufs[urbd1->frbd_tag];
- if (!buf) {
- bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d",
- urbd1->frbd_tag);
- return;
- }
- ret = btintel_pcie_submit_rx_work(data, urbd1->status,
- buf->data);
- if (ret) {
- bt_dev_err(hdev, "RXQ: failed to submit rx request");
- return;
- }
- cr_tia = (cr_tia + 1) % rxq->count;
- data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM] = cr_tia;
- ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_RXQ_NUM);
- }
- }
- static irqreturn_t btintel_pcie_msix_isr(int irq, void *data)
- {
- return IRQ_WAKE_THREAD;
- }
- static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data)
- {
- return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM];
- }
- static inline bool btintel_pcie_is_txackq_empty(struct btintel_pcie_data *data)
- {
- return data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] == data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM];
- }
- static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
- {
- struct msix_entry *entry = dev_id;
- struct btintel_pcie_data *data = btintel_pcie_get_data(entry);
- u32 intr_fh, intr_hw;
- spin_lock(&data->irq_lock);
- intr_fh = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES);
- intr_hw = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES);
- /* Clear causes registers to avoid being handling the same cause */
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES, intr_fh);
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, intr_hw);
- spin_unlock(&data->irq_lock);
- if (unlikely(!(intr_fh | intr_hw))) {
- /* Ignore interrupt, inta == 0 */
- return IRQ_NONE;
- }
- /* This interrupt is triggered by the firmware after updating
- * boot_stage register and image_response register
- */
- if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0)
- btintel_pcie_msix_gp0_handler(data);
- /* For TX */
- if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) {
- btintel_pcie_msix_tx_handle(data);
- if (!btintel_pcie_is_rxq_empty(data))
- btintel_pcie_msix_rx_handle(data);
- }
- /* For RX */
- if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1) {
- btintel_pcie_msix_rx_handle(data);
- if (!btintel_pcie_is_txackq_empty(data))
- btintel_pcie_msix_tx_handle(data);
- }
- /*
- * Before sending the interrupt the HW disables it to prevent a nested
- * interrupt. This is done by writing 1 to the corresponding bit in
- * the mask register. After handling the interrupt, it should be
- * re-enabled by clearing this bit. This register is defined as write 1
- * clear (W1C) register, meaning that it's cleared by writing 1
- * to the bit.
- */
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_AUTOMASK_ST,
- BIT(entry->entry));
- return IRQ_HANDLED;
- }
- /* This function requests the irq for MSI-X and registers the handlers per irq.
- * Currently, it requests only 1 irq for all interrupt causes.
- */
- static int btintel_pcie_setup_irq(struct btintel_pcie_data *data)
- {
- int err;
- int num_irqs, i;
- for (i = 0; i < BTINTEL_PCIE_MSIX_VEC_MAX; i++)
- data->msix_entries[i].entry = i;
- num_irqs = pci_alloc_irq_vectors(data->pdev, BTINTEL_PCIE_MSIX_VEC_MIN,
- BTINTEL_PCIE_MSIX_VEC_MAX, PCI_IRQ_MSIX);
- if (num_irqs < 0)
- return num_irqs;
- data->alloc_vecs = num_irqs;
- data->msix_enabled = 1;
- data->def_irq = 0;
- /* setup irq handler */
- for (i = 0; i < data->alloc_vecs; i++) {
- struct msix_entry *msix_entry;
- msix_entry = &data->msix_entries[i];
- msix_entry->vector = pci_irq_vector(data->pdev, i);
- err = devm_request_threaded_irq(&data->pdev->dev,
- msix_entry->vector,
- btintel_pcie_msix_isr,
- btintel_pcie_irq_msix_handler,
- IRQF_SHARED,
- KBUILD_MODNAME,
- msix_entry);
- if (err) {
- pci_free_irq_vectors(data->pdev);
- data->alloc_vecs = 0;
- return err;
- }
- }
- return 0;
- }
- struct btintel_pcie_causes_list {
- u32 cause;
- u32 mask_reg;
- u8 cause_num;
- };
- static struct btintel_pcie_causes_list causes_list[] = {
- { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x00 },
- { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x01 },
- { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 },
- };
- /* This function configures the interrupt masks for both HW_INT_CAUSES and
- * FH_INT_CAUSES which are meaningful to us.
- *
- * After resetting BT function via PCIE FLR or FUNC_CTRL reset, the driver
- * need to call this function again to configure since the masks
- * are reset to 0xFFFFFFFF after reset.
- */
- static void btintel_pcie_config_msix(struct btintel_pcie_data *data)
- {
- int i;
- int val = data->def_irq | BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE;
- /* Set Non Auto Clear Cause */
- for (i = 0; i < ARRAY_SIZE(causes_list); i++) {
- btintel_pcie_wr_reg8(data,
- BTINTEL_PCIE_CSR_MSIX_IVAR(causes_list[i].cause_num),
- val);
- btintel_pcie_clr_reg_bits(data,
- causes_list[i].mask_reg,
- causes_list[i].cause);
- }
- /* Save the initial interrupt mask */
- data->fh_init_mask = ~btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK);
- data->hw_init_mask = ~btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK);
- }
- static int btintel_pcie_config_pcie(struct pci_dev *pdev,
- struct btintel_pcie_data *data)
- {
- int err;
- err = pcim_enable_device(pdev);
- if (err)
- return err;
- pci_set_master(pdev);
- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
- if (err) {
- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- if (err)
- return err;
- }
- err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
- if (err)
- return err;
- data->base_addr = pcim_iomap_table(pdev)[0];
- if (!data->base_addr)
- return -ENODEV;
- err = btintel_pcie_setup_irq(data);
- if (err)
- return err;
- /* Configure MSI-X with causes list */
- btintel_pcie_config_msix(data);
- return 0;
- }
- static void btintel_pcie_init_ci(struct btintel_pcie_data *data,
- struct ctx_info *ci)
- {
- ci->version = 0x1;
- ci->size = sizeof(*ci);
- ci->config = 0x0000;
- ci->addr_cr_hia = data->ia.cr_hia_p_addr;
- ci->addr_tr_tia = data->ia.tr_tia_p_addr;
- ci->addr_cr_tia = data->ia.cr_tia_p_addr;
- ci->addr_tr_hia = data->ia.tr_hia_p_addr;
- ci->num_cr_ia = BTINTEL_PCIE_NUM_QUEUES;
- ci->num_tr_ia = BTINTEL_PCIE_NUM_QUEUES;
- ci->addr_urbdq0 = data->txq.urbd0s_p_addr;
- ci->addr_tfdq = data->txq.tfds_p_addr;
- ci->num_tfdq = data->txq.count;
- ci->num_urbdq0 = data->txq.count;
- ci->tfdq_db_vec = BTINTEL_PCIE_TXQ_NUM;
- ci->urbdq0_db_vec = BTINTEL_PCIE_TXQ_NUM;
- ci->rbd_size = BTINTEL_PCIE_RBD_SIZE_4K;
- ci->addr_frbdq = data->rxq.frbds_p_addr;
- ci->num_frbdq = data->rxq.count;
- ci->frbdq_db_vec = BTINTEL_PCIE_RXQ_NUM;
- ci->addr_urbdq1 = data->rxq.urbd1s_p_addr;
- ci->num_urbdq1 = data->rxq.count;
- ci->urbdq_db_vec = BTINTEL_PCIE_RXQ_NUM;
- }
- static void btintel_pcie_free_txq_bufs(struct btintel_pcie_data *data,
- struct txq *txq)
- {
- /* Free data buffers first */
- dma_free_coherent(&data->pdev->dev, txq->count * BTINTEL_PCIE_BUFFER_SIZE,
- txq->buf_v_addr, txq->buf_p_addr);
- kfree(txq->bufs);
- }
- static int btintel_pcie_setup_txq_bufs(struct btintel_pcie_data *data,
- struct txq *txq)
- {
- int i;
- struct data_buf *buf;
- /* Allocate the same number of buffers as the descriptor */
- txq->bufs = kmalloc_array(txq->count, sizeof(*buf), GFP_KERNEL);
- if (!txq->bufs)
- return -ENOMEM;
- /* Allocate full chunk of data buffer for DMA first and do indexing and
- * initialization next, so it can be freed easily
- */
- txq->buf_v_addr = dma_alloc_coherent(&data->pdev->dev,
- txq->count * BTINTEL_PCIE_BUFFER_SIZE,
- &txq->buf_p_addr,
- GFP_KERNEL | __GFP_NOWARN);
- if (!txq->buf_v_addr) {
- kfree(txq->bufs);
- return -ENOMEM;
- }
- /* Setup the allocated DMA buffer to bufs. Each data_buf should
- * have virtual address and physical address
- */
- for (i = 0; i < txq->count; i++) {
- buf = &txq->bufs[i];
- buf->data_p_addr = txq->buf_p_addr + (i * BTINTEL_PCIE_BUFFER_SIZE);
- buf->data = txq->buf_v_addr + (i * BTINTEL_PCIE_BUFFER_SIZE);
- }
- return 0;
- }
- static void btintel_pcie_free_rxq_bufs(struct btintel_pcie_data *data,
- struct rxq *rxq)
- {
- /* Free data buffers first */
- dma_free_coherent(&data->pdev->dev, rxq->count * BTINTEL_PCIE_BUFFER_SIZE,
- rxq->buf_v_addr, rxq->buf_p_addr);
- kfree(rxq->bufs);
- }
- static int btintel_pcie_setup_rxq_bufs(struct btintel_pcie_data *data,
- struct rxq *rxq)
- {
- int i;
- struct data_buf *buf;
- /* Allocate the same number of buffers as the descriptor */
- rxq->bufs = kmalloc_array(rxq->count, sizeof(*buf), GFP_KERNEL);
- if (!rxq->bufs)
- return -ENOMEM;
- /* Allocate full chunk of data buffer for DMA first and do indexing and
- * initialization next, so it can be freed easily
- */
- rxq->buf_v_addr = dma_alloc_coherent(&data->pdev->dev,
- rxq->count * BTINTEL_PCIE_BUFFER_SIZE,
- &rxq->buf_p_addr,
- GFP_KERNEL | __GFP_NOWARN);
- if (!rxq->buf_v_addr) {
- kfree(rxq->bufs);
- return -ENOMEM;
- }
- /* Setup the allocated DMA buffer to bufs. Each data_buf should
- * have virtual address and physical address
- */
- for (i = 0; i < rxq->count; i++) {
- buf = &rxq->bufs[i];
- buf->data_p_addr = rxq->buf_p_addr + (i * BTINTEL_PCIE_BUFFER_SIZE);
- buf->data = rxq->buf_v_addr + (i * BTINTEL_PCIE_BUFFER_SIZE);
- }
- return 0;
- }
- static void btintel_pcie_setup_ia(struct btintel_pcie_data *data,
- dma_addr_t p_addr, void *v_addr,
- struct ia *ia)
- {
- /* TR Head Index Array */
- ia->tr_hia_p_addr = p_addr;
- ia->tr_hia = v_addr;
- /* TR Tail Index Array */
- ia->tr_tia_p_addr = p_addr + sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES;
- ia->tr_tia = v_addr + sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES;
- /* CR Head index Array */
- ia->cr_hia_p_addr = p_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 2);
- ia->cr_hia = v_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 2);
- /* CR Tail Index Array */
- ia->cr_tia_p_addr = p_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 3);
- ia->cr_tia = v_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 3);
- }
- static void btintel_pcie_free(struct btintel_pcie_data *data)
- {
- btintel_pcie_free_rxq_bufs(data, &data->rxq);
- btintel_pcie_free_txq_bufs(data, &data->txq);
- dma_pool_free(data->dma_pool, data->dma_v_addr, data->dma_p_addr);
- dma_pool_destroy(data->dma_pool);
- }
- /* Allocate tx and rx queues, any related data structures and buffers.
- */
- static int btintel_pcie_alloc(struct btintel_pcie_data *data)
- {
- int err = 0;
- size_t total;
- dma_addr_t p_addr;
- void *v_addr;
- /* Allocate the chunk of DMA memory for descriptors, index array, and
- * context information, instead of allocating individually.
- * The DMA memory for data buffer is allocated while setting up the
- * each queue.
- *
- * Total size is sum of the following
- * + size of TFD * Number of descriptors in queue
- * + size of URBD0 * Number of descriptors in queue
- * + size of FRBD * Number of descriptors in queue
- * + size of URBD1 * Number of descriptors in queue
- * + size of index * Number of queues(2) * type of index array(4)
- * + size of context information
- */
- total = (sizeof(struct tfd) + sizeof(struct urbd0)) * BTINTEL_PCIE_TX_DESCS_COUNT;
- total += (sizeof(struct frbd) + sizeof(struct urbd1)) * BTINTEL_PCIE_RX_DESCS_COUNT;
- /* Add the sum of size of index array and size of ci struct */
- total += (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4) + sizeof(struct ctx_info);
- /* Allocate DMA Pool */
- data->dma_pool = dma_pool_create(KBUILD_MODNAME, &data->pdev->dev,
- total, BTINTEL_PCIE_DMA_POOL_ALIGNMENT, 0);
- if (!data->dma_pool) {
- err = -ENOMEM;
- goto exit_error;
- }
- v_addr = dma_pool_zalloc(data->dma_pool, GFP_KERNEL | __GFP_NOWARN,
- &p_addr);
- if (!v_addr) {
- dma_pool_destroy(data->dma_pool);
- err = -ENOMEM;
- goto exit_error;
- }
- data->dma_p_addr = p_addr;
- data->dma_v_addr = v_addr;
- /* Setup descriptor count */
- data->txq.count = BTINTEL_PCIE_TX_DESCS_COUNT;
- data->rxq.count = BTINTEL_PCIE_RX_DESCS_COUNT;
- /* Setup tfds */
- data->txq.tfds_p_addr = p_addr;
- data->txq.tfds = v_addr;
- p_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT);
- v_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT);
- /* Setup urbd0 */
- data->txq.urbd0s_p_addr = p_addr;
- data->txq.urbd0s = v_addr;
- p_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT);
- v_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT);
- /* Setup FRBD*/
- data->rxq.frbds_p_addr = p_addr;
- data->rxq.frbds = v_addr;
- p_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT);
- v_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT);
- /* Setup urbd1 */
- data->rxq.urbd1s_p_addr = p_addr;
- data->rxq.urbd1s = v_addr;
- p_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT);
- v_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT);
- /* Setup data buffers for txq */
- err = btintel_pcie_setup_txq_bufs(data, &data->txq);
- if (err)
- goto exit_error_pool;
- /* Setup data buffers for rxq */
- err = btintel_pcie_setup_rxq_bufs(data, &data->rxq);
- if (err)
- goto exit_error_txq;
- /* Setup Index Array */
- btintel_pcie_setup_ia(data, p_addr, v_addr, &data->ia);
- /* Setup Context Information */
- p_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4;
- v_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4;
- data->ci = v_addr;
- data->ci_p_addr = p_addr;
- /* Initialize the CI */
- btintel_pcie_init_ci(data, data->ci);
- return 0;
- exit_error_txq:
- btintel_pcie_free_txq_bufs(data, &data->txq);
- exit_error_pool:
- dma_pool_free(data->dma_pool, data->dma_v_addr, data->dma_p_addr);
- dma_pool_destroy(data->dma_pool);
- exit_error:
- return err;
- }
- static int btintel_pcie_open(struct hci_dev *hdev)
- {
- bt_dev_dbg(hdev, "");
- return 0;
- }
- static int btintel_pcie_close(struct hci_dev *hdev)
- {
- bt_dev_dbg(hdev, "");
- return 0;
- }
- static int btintel_pcie_inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
- {
- struct sk_buff *skb;
- struct hci_event_hdr *hdr;
- struct hci_ev_cmd_complete *evt;
- skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
- hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr));
- hdr->evt = HCI_EV_CMD_COMPLETE;
- hdr->plen = sizeof(*evt) + 1;
- evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt));
- evt->ncmd = 0x01;
- evt->opcode = cpu_to_le16(opcode);
- *(u8 *)skb_put(skb, 1) = 0x00;
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
- return hci_recv_frame(hdev, skb);
- }
- 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
- * the first byte to get the packet type and redirect the rest of data
- * packet to the right handler.
- *
- * But for PCIe, THF(Transfer Flow Handler) fetches the 4 bytes of data
- * from DMA memory and by the time it reads the first 4 bytes, it has
- * already consumed some part of packet. Thus the packet type indicator
- * for iBT PCIe is 4 bytes.
- *
- * Luckily, when HCI core creates the skb, it allocates 8 bytes of
- * head room for profile and driver use, and before sending the data
- * to the device, append the iBT PCIe packet type in the front.
- */
- 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);
- /* When the 0xfc01 command is issued to boot into
- * the operational firmware, it will actually not
- * send a command complete event. To keep the flow
- * control working inject that event here.
- */
- if (opcode == 0xfc01)
- btintel_pcie_inject_cmd_complete(hdev, opcode);
- }
- /* Firmware raises alive interrupt on HCI_OP_RESET */
- if (opcode == HCI_OP_RESET)
- data->gp0_received = false;
- hdev->stat.cmd_tx++;
- break;
- case HCI_ACLDATA_PKT:
- type = BTINTEL_PCIE_HCI_ACL_PKT;
- hdev->stat.acl_tx++;
- break;
- case HCI_SCODATA_PKT:
- type = BTINTEL_PCIE_HCI_SCO_PKT;
- hdev->stat.sco_tx++;
- break;
- case HCI_ISODATA_PKT:
- type = BTINTEL_PCIE_HCI_ISO_PKT;
- break;
- default:
- bt_dev_err(hdev, "Unknown HCI packet type");
- return -EILSEQ;
- }
- memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &type,
- BTINTEL_PCIE_HCI_TYPE_LEN);
- ret = btintel_pcie_send_sync(data, skb);
- if (ret) {
- hdev->stat.err_tx++;
- 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) {
- 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);
- exit_error:
- return ret;
- }
- static void btintel_pcie_release_hdev(struct btintel_pcie_data *data)
- {
- struct hci_dev *hdev;
- hdev = data->hdev;
- hci_unregister_dev(hdev);
- hci_free_dev(hdev);
- data->hdev = NULL;
- }
- static int btintel_pcie_setup(struct hci_dev *hdev)
- {
- const u8 param[1] = { 0xFF };
- struct intel_version_tlv ver_tlv;
- struct sk_buff *skb;
- int err;
- BT_DBG("%s", hdev->name);
- skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Reading Intel version command failed (%ld)",
- PTR_ERR(skb));
- return PTR_ERR(skb);
- }
- /* Check the status */
- if (skb->data[0]) {
- bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
- skb->data[0]);
- err = -EIO;
- goto exit_error;
- }
- /* Apply the common HCI quirks for Intel device */
- set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
- set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
- set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
- /* Set up the quality report callback for Intel devices */
- hdev->set_quality_report = btintel_set_quality_report;
- memset(&ver_tlv, 0, sizeof(ver_tlv));
- /* For TLV type device, parse the tlv data */
- err = btintel_parse_version_tlv(hdev, &ver_tlv, skb);
- if (err) {
- bt_dev_err(hdev, "Failed to parse TLV version information");
- goto exit_error;
- }
- switch (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt)) {
- case 0x37:
- break;
- default:
- bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
- INTEL_HW_PLATFORM(ver_tlv.cnvi_bt));
- err = -EINVAL;
- goto exit_error;
- }
- /* Check for supported iBT hardware variants of this firmware
- * loading method.
- *
- * This check has been put in place to ensure correct forward
- * compatibility options when newer hardware variants come
- * along.
- */
- switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) {
- case 0x1e: /* BzrI */
- /* Display version information of TLV type */
- btintel_version_info_tlv(hdev, &ver_tlv);
- /* Apply the device specific HCI quirks for TLV based devices
- *
- * All TLV based devices support WBS
- */
- set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
- /* Setup MSFT Extension support */
- btintel_set_msft_opcode(hdev,
- INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
- err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
- if (err)
- goto exit_error;
- break;
- default:
- bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
- INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
- err = -EINVAL;
- goto exit_error;
- break;
- }
- btintel_print_fseq_info(hdev);
- exit_error:
- kfree_skb(skb);
- return err;
- }
- static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
- {
- int err;
- struct hci_dev *hdev;
- hdev = hci_alloc_dev_priv(sizeof(struct btintel_data));
- if (!hdev)
- return -ENOMEM;
- hdev->bus = HCI_PCI;
- hci_set_drvdata(hdev, data);
- data->hdev = hdev;
- SET_HCIDEV_DEV(hdev, &data->pdev->dev);
- hdev->manufacturer = 2;
- hdev->open = btintel_pcie_open;
- hdev->close = btintel_pcie_close;
- hdev->send = btintel_pcie_send_frame;
- hdev->setup = btintel_pcie_setup;
- hdev->shutdown = btintel_shutdown_combined;
- hdev->hw_error = btintel_hw_error;
- hdev->set_diag = btintel_set_diag;
- hdev->set_bdaddr = btintel_set_bdaddr;
- err = hci_register_dev(hdev);
- if (err < 0) {
- BT_ERR("Failed to register to hdev (%d)", err);
- goto exit_error;
- }
- return 0;
- exit_error:
- hci_free_dev(hdev);
- return err;
- }
- static int btintel_pcie_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
- {
- int err;
- struct btintel_pcie_data *data;
- if (!pdev)
- return -ENODEV;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- data->pdev = pdev;
- spin_lock_init(&data->irq_lock);
- spin_lock_init(&data->hci_rx_lock);
- init_waitqueue_head(&data->gp0_wait_q);
- data->gp0_received = false;
- init_waitqueue_head(&data->tx_wait_q);
- data->tx_wait_done = false;
- data->workqueue = alloc_ordered_workqueue(KBUILD_MODNAME, WQ_HIGHPRI);
- if (!data->workqueue)
- return -ENOMEM;
- skb_queue_head_init(&data->rx_skb_q);
- INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
- data->boot_stage_cache = 0x00;
- data->img_resp_cache = 0x00;
- err = btintel_pcie_config_pcie(pdev, data);
- if (err)
- goto exit_error;
- pci_set_drvdata(pdev, data);
- err = btintel_pcie_alloc(data);
- if (err)
- goto exit_error;
- err = btintel_pcie_enable_bt(data);
- if (err)
- goto exit_error;
- /* CNV information (CNVi and CNVr) is in CSR */
- data->cnvi = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_HW_REV_REG);
- data->cnvr = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_RF_ID_REG);
- err = btintel_pcie_start_rx(data);
- if (err)
- goto exit_error;
- err = btintel_pcie_setup_hdev(data);
- if (err)
- goto exit_error;
- bt_dev_dbg(data->hdev, "cnvi: 0x%8.8x cnvr: 0x%8.8x", data->cnvi,
- data->cnvr);
- return 0;
- exit_error:
- /* reset device before exit */
- btintel_pcie_reset_bt(data);
- pci_clear_master(pdev);
- pci_set_drvdata(pdev, NULL);
- return err;
- }
- static void btintel_pcie_remove(struct pci_dev *pdev)
- {
- struct btintel_pcie_data *data;
- data = pci_get_drvdata(pdev);
- btintel_pcie_reset_bt(data);
- for (int i = 0; i < data->alloc_vecs; i++) {
- struct msix_entry *msix_entry;
- msix_entry = &data->msix_entries[i];
- free_irq(msix_entry->vector, msix_entry);
- }
- pci_free_irq_vectors(pdev);
- btintel_pcie_release_hdev(data);
- flush_work(&data->rx_work);
- destroy_workqueue(data->workqueue);
- btintel_pcie_free(data);
- pci_clear_master(pdev);
- pci_set_drvdata(pdev, NULL);
- }
- static struct pci_driver btintel_pcie_driver = {
- .name = KBUILD_MODNAME,
- .id_table = btintel_pcie_table,
- .probe = btintel_pcie_probe,
- .remove = btintel_pcie_remove,
- };
- module_pci_driver(btintel_pcie_driver);
- MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>");
- MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION);
- MODULE_VERSION(VERSION);
- MODULE_LICENSE("GPL");
|