diff options
Diffstat (limited to 'pci.c')
| -rw-r--r-- | pci.c | 255 |
1 files changed, 104 insertions, 151 deletions
@@ -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/*"); |
