summaryrefslogtreecommitdiff
path: root/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'pci.c')
-rw-r--r--pci.c255
1 files changed, 104 insertions, 151 deletions
diff --git a/pci.c b/pci.c
index a12c8379cb46..375277ca2b89 100644
--- a/pci.c
+++ b/pci.c
@@ -15,6 +15,7 @@
#include "hif.h"
#include "mhi.h"
#include "debug.h"
+#include "hal.h"
#define ATH12K_PCI_BAR_NUM 0
#define ATH12K_PCI_DMA_MASK 36
@@ -22,50 +23,18 @@
#define ATH12K_PCI_IRQ_CE0_OFFSET 3
#define WINDOW_ENABLE_BIT 0x40000000
-#define WINDOW_REG_ADDRESS 0x310c
#define WINDOW_VALUE_MASK GENMASK(24, 19)
#define WINDOW_START 0x80000
#define WINDOW_RANGE_MASK GENMASK(18, 0)
#define WINDOW_STATIC_MASK GENMASK(31, 6)
-#define TCSR_SOC_HW_VERSION 0x1B00000
-#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)
-#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 4)
-
/* BAR0 + 4k is always accessible, and no
* need to force wakeup.
* 4K - 32 = 0xFE0
*/
#define ACCESS_ALWAYS_OFF 0xFE0
-#define QCN9274_DEVICE_ID 0x1109
-#define WCN7850_DEVICE_ID 0x1107
-
-#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164
-#define DOMAIN_NUMBER_MASK GENMASK(7, 4)
-#define BUS_NUMBER_MASK GENMASK(3, 0)
-
-static const struct pci_device_id ath12k_pci_id_table[] = {
- { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) },
- { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) },
- {}
-};
-
-MODULE_DEVICE_TABLE(pci, ath12k_pci_id_table);
-
-/* TODO: revisit IRQ mapping for new SRNG's */
-static const struct ath12k_msi_config ath12k_msi_config[] = {
- {
- .total_vectors = 16,
- .total_users = 3,
- .users = (struct ath12k_msi_user[]) {
- { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
- { .name = "CE", .num_vectors = 5, .base_vector = 3 },
- { .name = "DP", .num_vectors = 8, .base_vector = 8 },
- },
- },
-};
-
+static struct ath12k_pci_driver *ath12k_pci_family_drivers[ATH12K_DEVICE_FAMILY_MAX];
static const struct ath12k_msi_config msi_config_one_msi = {
.total_vectors = 1,
.total_users = 4,
@@ -136,30 +105,6 @@ static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"tcl2host-status-ring",
};
-static int ath12k_pci_bus_wake_up(struct ath12k_base *ab)
-{
- struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
-
- return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
-}
-
-static void ath12k_pci_bus_release(struct ath12k_base *ab)
-{
- struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
-
- mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
-}
-
-static const struct ath12k_pci_ops ath12k_pci_ops_qcn9274 = {
- .wakeup = NULL,
- .release = NULL,
-};
-
-static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = {
- .wakeup = ath12k_pci_bus_wake_up,
- .release = ath12k_pci_bus_release,
-};
-
static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)
{
struct ath12k_base *ab = ab_pci->ab;
@@ -175,37 +120,40 @@ static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)
if (window != ab_pci->register_window) {
iowrite32(WINDOW_ENABLE_BIT | window,
- ab->mem + WINDOW_REG_ADDRESS);
- ioread32(ab->mem + WINDOW_REG_ADDRESS);
+ ab->mem + ab_pci->window_reg_addr);
+ ioread32(ab->mem + ab_pci->window_reg_addr);
ab_pci->register_window = window;
}
}
static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci)
{
- u32 umac_window = u32_get_bits(HAL_SEQ_WCSS_UMAC_OFFSET, WINDOW_VALUE_MASK);
- u32 ce_window = u32_get_bits(HAL_CE_WFSS_CE_REG_BASE, WINDOW_VALUE_MASK);
+ u32 umac_window;
+ u32 ce_window;
u32 window;
+ umac_window = u32_get_bits(ab_pci->reg_base->umac_base, WINDOW_VALUE_MASK);
+ ce_window = u32_get_bits(ab_pci->reg_base->ce_reg_base, WINDOW_VALUE_MASK);
window = (umac_window << 12) | (ce_window << 6);
spin_lock_bh(&ab_pci->window_lock);
ab_pci->register_window = window;
spin_unlock_bh(&ab_pci->window_lock);
- iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
+ iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + ab_pci->window_reg_addr);
}
static u32 ath12k_pci_get_window_start(struct ath12k_base *ab,
u32 offset)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 window_start;
/* If offset lies within DP register range, use 3rd window */
- if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
+ if ((offset ^ ab_pci->reg_base->umac_base) < WINDOW_RANGE_MASK)
window_start = 3 * WINDOW_START;
/* If offset lies within CE register range, use 2nd window */
- else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
+ else if ((offset ^ ab_pci->reg_base->ce_reg_base) < WINDOW_RANGE_MASK)
window_start = 2 * WINDOW_START;
else
window_start = WINDOW_START;
@@ -225,8 +173,8 @@ static void ath12k_pci_restore_window(struct ath12k_base *ab)
spin_lock_bh(&ab_pci->window_lock);
iowrite32(WINDOW_ENABLE_BIT | ab_pci->register_window,
- ab->mem + WINDOW_REG_ADDRESS);
- ioread32(ab->mem + WINDOW_REG_ADDRESS);
+ ab->mem + ab_pci->window_reg_addr);
+ ioread32(ab->mem + ab_pci->window_reg_addr);
spin_unlock_bh(&ab_pci->window_lock);
}
@@ -544,10 +492,11 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
struct ath12k_ext_irq_grp,
napi);
struct ath12k_base *ab = irq_grp->ab;
+ struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int work_done;
int i;
- work_done = ath12k_dp_service_srng(ab, irq_grp, budget);
+ work_done = ath12k_dp_service_srng(dp, irq_grp, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
for (i = 0; i < irq_grp->num_irq; i++)
@@ -965,7 +914,7 @@ static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab)
* writes to the given register, it is available for firmware when the QMI service
* is spawned.
*/
- reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK;
+ reg = PCIE_LOCAL_REG_QRTR_NODE_ID(ab) & WINDOW_RANGE_MASK;
ath12k_pci_write32(ab, reg, ab_pci->qmi_instance);
ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n",
@@ -1244,6 +1193,7 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset)
ab_pci->pci_ops->release(ab);
return val;
}
+EXPORT_SYMBOL(ath12k_pci_read32);
void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)
{
@@ -1549,28 +1499,34 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
#endif
};
-static
-void ath12k_pci_read_hw_version(struct ath12k_base *ab, u32 *major, u32 *minor)
+static enum ath12k_device_family
+ath12k_get_device_family(const struct pci_device_id *pci_dev)
{
- u32 soc_hw_version;
+ enum ath12k_device_family device_family_id;
+ const struct pci_device_id *id;
+
+ for (device_family_id = ATH12K_DEVICE_FAMILY_START;
+ device_family_id < ATH12K_DEVICE_FAMILY_MAX; device_family_id++) {
+ if (!ath12k_pci_family_drivers[device_family_id])
+ continue;
- soc_hw_version = ath12k_pci_read32(ab, TCSR_SOC_HW_VERSION);
- *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
- soc_hw_version);
- *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
- soc_hw_version);
+ id = ath12k_pci_family_drivers[device_family_id]->id_table;
+ while (id->device) {
+ if (id->device == pci_dev->device)
+ return device_family_id;
+ id += 1;
+ }
+ }
- ath12k_dbg(ab, ATH12K_DBG_PCI,
- "pci tcsr_soc_hw_version major %d minor %d\n",
- *major, *minor);
+ return ATH12K_DEVICE_FAMILY_MAX;
}
static int ath12k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev)
{
- struct ath12k_base *ab;
+ enum ath12k_device_family device_id;
struct ath12k_pci *ab_pci;
- u32 soc_hw_version_major, soc_hw_version_minor;
+ struct ath12k_base *ab;
int ret;
ab = ath12k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH12K_BUS_PCI);
@@ -1580,7 +1536,6 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
}
ab->dev = &pdev->dev;
- pci_set_drvdata(pdev, ab);
ab_pci = ath12k_pci_priv(ab);
ab_pci->dev_id = pci_dev->device;
ab_pci->ab = ab;
@@ -1605,56 +1560,25 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
ab->id.subsystem_vendor = pdev->subsystem_vendor;
ab->id.subsystem_device = pdev->subsystem_device;
- switch (pci_dev->device) {
- case QCN9274_DEVICE_ID:
- ab_pci->msi_config = &ath12k_msi_config[0];
- ab->static_window_map = true;
- ab_pci->pci_ops = &ath12k_pci_ops_qcn9274;
- ab->hal_rx_ops = &hal_rx_qcn9274_ops;
- ath12k_pci_read_hw_version(ab, &soc_hw_version_major,
- &soc_hw_version_minor);
- ab->target_mem_mode = ath12k_core_get_memory_mode(ab);
- switch (soc_hw_version_major) {
- case ATH12K_PCI_SOC_HW_VERSION_2:
- ab->hw_rev = ATH12K_HW_QCN9274_HW20;
- break;
- case ATH12K_PCI_SOC_HW_VERSION_1:
- ab->hw_rev = ATH12K_HW_QCN9274_HW10;
- break;
- default:
- dev_err(&pdev->dev,
- "Unknown hardware version found for QCN9274: 0x%x\n",
- soc_hw_version_major);
- ret = -EOPNOTSUPP;
- goto err_pci_free_region;
- }
- break;
- case WCN7850_DEVICE_ID:
- ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD;
- ab_pci->msi_config = &ath12k_msi_config[0];
- ab->static_window_map = false;
- ab_pci->pci_ops = &ath12k_pci_ops_wcn7850;
- ab->hal_rx_ops = &hal_rx_wcn7850_ops;
- ath12k_pci_read_hw_version(ab, &soc_hw_version_major,
- &soc_hw_version_minor);
- ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
- switch (soc_hw_version_major) {
- case ATH12K_PCI_SOC_HW_VERSION_2:
- ab->hw_rev = ATH12K_HW_WCN7850_HW20;
- break;
- default:
- dev_err(&pdev->dev,
- "Unknown hardware version found for WCN7850: 0x%x\n",
- soc_hw_version_major);
- ret = -EOPNOTSUPP;
- goto err_pci_free_region;
- }
- break;
+ device_id = ath12k_get_device_family(pci_dev);
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX) {
+ ath12k_err(ab, "failed to get device family id\n");
+ ret = -EINVAL;
+ goto err_pci_free_region;
+ }
+
+ ath12k_dbg(ab, ATH12K_DBG_PCI, "PCI device family id: %d\n", device_id);
- default:
- dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
- pci_dev->device);
- ret = -EOPNOTSUPP;
+ ab_pci->device_family_ops = &ath12k_pci_family_drivers[device_id]->ops;
+ ab_pci->reg_base = ath12k_pci_family_drivers[device_id]->reg_base;
+
+ /* Call device specific probe. This is the callback that can
+ * be used to override any ops in future
+ * probe is validated for NULL during registration.
+ */
+ ret = ab_pci->device_family_ops->probe(pdev, pci_dev);
+ if (ret) {
+ ath12k_err(ab, "failed to probe device: %d\n", ret);
goto err_pci_free_region;
}
@@ -1709,13 +1633,25 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
goto err_free_irq;
}
+ /* Invoke arch_init here so that arch-specific init operations
+ * can utilize already initialized ab fields, such as HAL SRNGs.
+ */
+ ret = ab_pci->device_family_ops->arch_init(ab);
+ if (ret) {
+ ath12k_err(ab, "PCI arch_init failed %d\n", ret);
+ goto err_pci_msi_free;
+ }
+
ret = ath12k_core_init(ab);
if (ret) {
ath12k_err(ab, "failed to init core: %d\n", ret);
- goto err_free_irq;
+ goto err_deinit_arch;
}
return 0;
+err_deinit_arch:
+ ab_pci->device_family_ops->arch_deinit(ab);
+
err_free_irq:
/* __free_irq() expects the caller to have cleared the affinity hint */
ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
@@ -1774,6 +1710,9 @@ qmi_fail:
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
+
+ ab_pci->device_family_ops->arch_deinit(ab);
+
ath12k_core_free(ab);
}
@@ -1862,33 +1801,47 @@ static const struct dev_pm_ops __maybe_unused ath12k_pci_pm_ops = {
ath12k_pci_pm_resume_early)
};
-static struct pci_driver ath12k_pci_driver = {
- .name = "ath12k_pci",
- .id_table = ath12k_pci_id_table,
- .probe = ath12k_pci_probe,
- .remove = ath12k_pci_remove,
- .shutdown = ath12k_pci_shutdown,
- .driver.pm = &ath12k_pci_pm_ops,
-};
-
-int ath12k_pci_init(void)
+int ath12k_pci_register_driver(const enum ath12k_device_family device_id,
+ struct ath12k_pci_driver *driver)
{
- int ret;
+ struct pci_driver *pci_driver;
- ret = pci_register_driver(&ath12k_pci_driver);
- if (ret) {
- pr_err("failed to register ath12k pci driver: %d\n",
- ret);
- return ret;
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
+ return -EINVAL;
+
+ if (!driver || !driver->ops.probe ||
+ !driver->ops.arch_init || !driver->ops.arch_deinit)
+ return -EINVAL;
+
+ if (ath12k_pci_family_drivers[device_id]) {
+ pr_err("Driver already registered for %d\n", device_id);
+ return -EALREADY;
}
- return 0;
+ ath12k_pci_family_drivers[device_id] = driver;
+
+ pci_driver = &ath12k_pci_family_drivers[device_id]->driver;
+ pci_driver->name = driver->name;
+ pci_driver->id_table = driver->id_table;
+ pci_driver->probe = ath12k_pci_probe;
+ pci_driver->remove = ath12k_pci_remove;
+ pci_driver->shutdown = ath12k_pci_shutdown;
+ pci_driver->driver.pm = &ath12k_pci_pm_ops;
+
+ return pci_register_driver(pci_driver);
}
+EXPORT_SYMBOL(ath12k_pci_register_driver);
-void ath12k_pci_exit(void)
+void ath12k_pci_unregister_driver(const enum ath12k_device_family device_id)
{
- pci_unregister_driver(&ath12k_pci_driver);
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX ||
+ !ath12k_pci_family_drivers[device_id])
+ return;
+
+ pci_unregister_driver(&ath12k_pci_family_drivers[device_id]->driver);
+ ath12k_pci_family_drivers[device_id] = NULL;
}
+EXPORT_SYMBOL(ath12k_pci_unregister_driver);
/* firmware files */
MODULE_FIRMWARE(ATH12K_FW_DIR "/QCN9274/hw2.0/*");