Loading drivers/net/wireless/cnss2/main.c +104 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,23 @@ int cnss_get_platform_cap(struct cnss_platform_cap *cap) } EXPORT_SYMBOL(cnss_get_platform_cap); int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) { int ret = 0; struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); void *bus_priv = cnss_bus_dev_to_bus_priv(dev); if (!plat_priv) return -ENODEV; ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa); if (ret) return ret; return 0; } EXPORT_SYMBOL(cnss_get_soc_info); void cnss_set_driver_status(enum cnss_driver_status driver_status) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); Loading Loading @@ -598,6 +615,91 @@ static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv) plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev); } static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) { int ret = 0; struct cnss_pci_data *pci_priv = plat_priv->bus_priv; if (!pci_priv) return -ENODEV; if (!plat_priv->driver_ops) return -EINVAL; ret = cnss_power_on_device(plat_priv); if (ret) { cnss_pr_err("Failed to power on device, err = %d\n", ret); goto out; } ret = cnss_resume_pci_link(pci_priv); if (ret) { cnss_pr_err("Failed to resume PCI link, err = %d\n", ret); goto power_off; } if (plat_priv->driver_status == CNSS_LOAD_UNLOAD) { ret = plat_priv->driver_ops->probe(pci_priv->pci_dev, pci_priv->pci_device_id); if (ret) { cnss_pr_err("Failed to probe host driver, err = %d\n", ret); goto suspend_link; } } else if (plat_priv->recovery_in_progress) { ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev, pci_priv->pci_device_id); if (ret) { cnss_pr_err("Failed to reinit host driver, err = %d\n", ret); goto suspend_link; } plat_priv->recovery_in_progress = false; } else { cnss_pr_err("Driver state is not correct to power up!\n"); ret = -EINVAL; goto suspend_link; } return 0; suspend_link: cnss_suspend_pci_link(pci_priv); power_off: cnss_power_off_device(plat_priv); out: return ret; } static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) { int ret = 0; struct cnss_pci_data *pci_priv = plat_priv->bus_priv; if (!pci_priv) return -ENODEV; if (!plat_priv->driver_ops) return -EINVAL; if (plat_priv->driver_status == CNSS_LOAD_UNLOAD) { cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); plat_priv->driver_ops->remove(pci_priv->pci_dev); cnss_pci_set_monitor_wake_intr(pci_priv, false); cnss_pci_set_auto_suspended(pci_priv, 0); } else { plat_priv->recovery_in_progress = true; plat_priv->driver_ops->shutdown(pci_priv->pci_dev); } ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); cnss_power_off_device(plat_priv); return ret; } static int cnss_powerup(const struct subsys_desc *subsys_desc) { int ret = 0; Loading @@ -613,6 +715,7 @@ static int cnss_powerup(const struct subsys_desc *subsys_desc) ret = cnss_qca6174_powerup(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_qca6290_powerup(plat_priv); break; default: cnss_pr_err("Unknown device_id found: 0x%lx\n", Loading @@ -638,6 +741,7 @@ static int cnss_shutdown(const struct subsys_desc *subsys_desc, bool force_stop) ret = cnss_qca6174_shutdown(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_qca6290_shutdown(plat_priv); break; default: cnss_pr_err("Unknown device_id found: 0x%lx\n", Loading drivers/net/wireless/cnss2/pci.c +278 −8 Original line number Diff line number Diff line Loading @@ -27,6 +27,14 @@ #define PM_OPTIONS_LINK_DOWN \ (MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN) #define PCI_BAR_NUM 0 #ifdef CONFIG_ARM_LPAE #define PCI_DMA_MASK 64 #else #define PCI_DMA_MASK 32 #endif static DEFINE_SPINLOCK(pci_link_down_lock); static unsigned int pci_link_down_panic; Loading Loading @@ -562,6 +570,252 @@ out: } EXPORT_SYMBOL(cnss_auto_resume); int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, phys_addr_t *pa) { if (!pci_priv) return -ENODEV; *va = pci_priv->bar; *pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM); return 0; } #ifdef CONFIG_CNSS_QCA6290 #define PCI_MAX_BAR_SIZE 0xD00000 static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { resource_size_t start = pci_resource_start(dev, bar); resource_size_t len = PCI_MAX_BAR_SIZE; unsigned long flags = pci_resource_flags(dev, bar); if (!len || !start) return NULL; if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) { if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO)) return ioremap(start, len); else return ioremap_nocache(start, len); } return NULL; } #else static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { return pci_iomap(dev, bar, maxlen); } #endif static struct cnss_msi_config msi_config = { .total_vectors = 32, .total_users = 3, .users = (struct cnss_msi_user[]) { { .name = "MHI", .num_vectors = 2, .base_vector = 0 }, { .name = "CE", .num_vectors = 12, .base_vector = 2 }, { .name = "DP", .num_vectors = 18, .base_vector = 14 }, }, }; static int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv) { pci_priv->msi_config = &msi_config; return 0; } static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; int num_vectors; struct cnss_msi_config *msi_config; uint32_t ep_base_data; ret = cnss_pci_get_msi_assignment(pci_priv); if (ret) { cnss_pr_err("Failed to get MSI assignment, err = %d\n", ret); goto out; } msi_config = pci_priv->msi_config; if (!msi_config) { cnss_pr_err("msi_config is NULL!\n"); ret = -EINVAL; goto out; } num_vectors = pci_enable_msi_range(pci_dev, msi_config->total_vectors, msi_config->total_vectors); if (num_vectors != msi_config->total_vectors) { cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d", msi_config->total_vectors, num_vectors); ret = -EINVAL; goto reset_msi_config; } pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_DATA_64, &ep_base_data); pci_priv->msi_ep_base_data = ep_base_data & 0xFFFF; return 0; reset_msi_config: pci_priv->msi_config = NULL; out: return ret; } static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv) { pci_disable_msi(pci_priv->pci_dev); } int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, uint32_t *base_vector) { struct cnss_pci_data *pci_priv = dev_get_drvdata(dev); struct cnss_msi_config *msi_config; int idx; if (!pci_priv) return -ENODEV; msi_config = pci_priv->msi_config; if (!msi_config) { cnss_pr_err("MSI is not supported.\n"); return -EINVAL; } for (idx = 0; idx < msi_config->total_users; idx++) { if (strcmp(user_name, msi_config->users[idx].name) == 0) { *num_vectors = msi_config->users[idx].num_vectors; *user_base_data = msi_config->users[idx].base_vector + pci_priv->msi_ep_base_data; *base_vector = msi_config->users[idx].base_vector; cnss_pr_dbg("Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", user_name, *num_vectors, *user_base_data, *base_vector); return 0; } } cnss_pr_err("Failed to find MSI assignment for %s!\n", user_name); return -EINVAL; } EXPORT_SYMBOL(cnss_get_user_msi_assignment); int cnss_get_msi_irq(struct device *dev, unsigned int vector) { struct pci_dev *pci_dev = to_pci_dev(dev); return pci_dev->irq + vector; } EXPORT_SYMBOL(cnss_get_msi_irq); void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low, uint32_t *msi_addr_high) { struct pci_dev *pci_dev = to_pci_dev(dev); pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, msi_addr_low); pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, msi_addr_high); } EXPORT_SYMBOL(cnss_get_msi_address); static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; uint16_t device_id; pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->pci_device_id->device) { cnss_pr_err("PCI device ID mismatch, config ID: 0x%x, probe ID: 0x%x\n", device_id, pci_priv->pci_device_id->device); ret = -EIO; goto out; } ret = pci_assign_resource(pci_dev, PCI_BAR_NUM); if (ret) { pr_err("Failed to assign PCI resource, err = %d\n", ret); goto out; } ret = pci_enable_device(pci_dev); if (ret) { cnss_pr_err("Failed to enable PCI device, err = %d\n", ret); goto out; } ret = pci_request_region(pci_dev, PCI_BAR_NUM, "cnss"); if (ret) { cnss_pr_err("Failed to request PCI region, err = %d\n", ret); goto disable_device; } ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK)); if (ret) { cnss_pr_err("Failed to set PCI DMA mask (%d), err = %d\n", ret, PCI_DMA_MASK); goto release_region; } ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK)); if (ret) { cnss_pr_err("Failed to set PCI consistent DMA mask (%d), err = %d\n", ret, PCI_DMA_MASK); goto release_region; } pci_set_master(pci_dev); pci_priv->bar = cnss_pci_iomap(pci_dev, PCI_BAR_NUM, 0); if (!pci_priv->bar) { cnss_pr_err("Failed to do PCI IO map!\n"); ret = -EIO; goto clear_master; } return 0; clear_master: pci_clear_master(pci_dev); release_region: pci_release_region(pci_dev, PCI_BAR_NUM); disable_device: pci_disable_device(pci_dev); out: return ret; } static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) { struct pci_dev *pci_dev = pci_priv->pci_dev; if (pci_priv->bar) { pci_iounmap(pci_dev, pci_priv->bar); pci_priv->bar = NULL; } pci_clear_master(pci_dev); pci_release_region(pci_dev, PCI_BAR_NUM); pci_disable_device(pci_dev); } static int cnss_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { Loading Loading @@ -589,10 +843,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, pci_priv->pci_link_state = PCI_LINK_UP; pci_priv->plat_priv = plat_priv; pci_priv->pci_dev = pci_dev; plat_priv->bus_priv = pci_priv; pci_priv->pci_device_id = id; pci_priv->device_id = pci_dev->device; cnss_set_pci_priv(pci_dev, pci_priv); plat_priv->device_id = pci_dev->device; plat_priv->bus_priv = pci_priv; res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM, "smmu_iova_base"); Loading @@ -610,6 +865,16 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, } } ret = cnss_reg_pci_event(pci_priv); if (ret) { cnss_pr_err("Failed to register PCI event, err = %d\n", ret); goto deinit_smmu; } ret = cnss_pci_enable_bus(pci_priv); if (ret) goto dereg_pci_event; switch (pci_dev->device) { case QCA6174_DEVICE_ID: pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET, Loading @@ -621,21 +886,23 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_power_off_device(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_pci_enable_msi(pci_priv); if (ret) goto disable_bus; break; default: cnss_pr_err("Unknown PCI device found: 0x%x\n", pci_dev->device); ret = -ENODEV; goto deinit_smmu; } ret = cnss_reg_pci_event(pci_priv); if (ret) { cnss_pr_err("Failed to register PCI event, err = %d\n", ret); goto deinit_smmu; goto disable_bus; } return 0; disable_bus: cnss_pci_disable_bus(pci_priv); dereg_pci_event: cnss_dereg_pci_event(pci_priv); deinit_smmu: if (pci_priv->smmu_mapping) cnss_pci_deinit_smmu(pci_priv); Loading @@ -651,6 +918,9 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(&pci_dev->dev); if (pci_dev->device == QCA6290_DEVICE_ID) cnss_pci_disable_msi(pci_priv); cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); if (pci_priv->smmu_mapping) cnss_pci_deinit_smmu(pci_priv); Loading drivers/net/wireless/cnss2/pci.h +17 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ #define QCA6290_VENDOR_ID 0x168C #define QCA6290_DEVICE_ID 0xABCD struct cnss_msi_user { char *name; int num_vectors; uint32_t base_vector; }; struct cnss_msi_config { int total_vectors; int total_users; struct cnss_msi_user *users; }; struct cnss_pci_data { struct pci_dev *pci_dev; struct cnss_plat_data *plat_priv; Loading @@ -42,6 +54,9 @@ struct cnss_pci_data { struct dma_iommu_mapping *smmu_mapping; dma_addr_t smmu_iova_start; size_t smmu_iova_len; void __iomem *bar; struct cnss_msi_config *msi_config; uint32_t msi_ep_base_data; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading Loading @@ -93,5 +108,7 @@ int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv); int cnss_resume_pci_link(struct cnss_pci_data *pci_priv); int cnss_pci_init(struct cnss_plat_data *plat_priv); void cnss_pci_deinit(struct cnss_plat_data *plat_priv); int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, phys_addr_t *pa); #endif /* _CNSS_PCI_H */ include/net/cnss2.h +20 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/pci.h> #define CNSS_MAX_FILE_NAME 20 #define CNSS_MAX_TIMESTAMP_LEN 32 enum cnss_bus_width_type { CNSS_BUS_WIDTH_NONE, Loading Loading @@ -43,6 +44,17 @@ struct cnss_fw_files { char evicted_data[CNSS_MAX_FILE_NAME]; }; struct cnss_soc_info { void __iomem *va; phys_addr_t pa; uint32_t chip_id; uint32_t chip_family; uint32_t board_id; uint32_t soc_id; uint32_t fw_version; char fw_build_timestamp[CNSS_MAX_TIMESTAMP_LEN + 1]; }; struct cnss_wlan_runtime_ops { int (*runtime_suspend)(struct pci_dev *pdev); int (*runtime_resume)(struct pci_dev *pdev); Loading Loading @@ -78,6 +90,7 @@ extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, u32 target_type, u32 target_version); extern int cnss_get_platform_cap(struct cnss_platform_cap *cap); extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info); extern void cnss_set_driver_status(enum cnss_driver_status driver_status); extern int cnss_request_bus_bandwidth(int bandwidth); extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); Loading @@ -95,5 +108,12 @@ extern void cnss_release_pm_sem(void); extern int cnss_wlan_pm_control(bool vote); extern int cnss_auto_suspend(void); extern int cnss_auto_resume(void); extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, uint32_t *base_vector); extern int cnss_get_msi_irq(struct device *dev, unsigned int vector); extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low, uint32_t *msi_addr_high); #endif /* _NET_CNSS2_H */ Loading
drivers/net/wireless/cnss2/main.c +104 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,23 @@ int cnss_get_platform_cap(struct cnss_platform_cap *cap) } EXPORT_SYMBOL(cnss_get_platform_cap); int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) { int ret = 0; struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); void *bus_priv = cnss_bus_dev_to_bus_priv(dev); if (!plat_priv) return -ENODEV; ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa); if (ret) return ret; return 0; } EXPORT_SYMBOL(cnss_get_soc_info); void cnss_set_driver_status(enum cnss_driver_status driver_status) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); Loading Loading @@ -598,6 +615,91 @@ static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv) plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev); } static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) { int ret = 0; struct cnss_pci_data *pci_priv = plat_priv->bus_priv; if (!pci_priv) return -ENODEV; if (!plat_priv->driver_ops) return -EINVAL; ret = cnss_power_on_device(plat_priv); if (ret) { cnss_pr_err("Failed to power on device, err = %d\n", ret); goto out; } ret = cnss_resume_pci_link(pci_priv); if (ret) { cnss_pr_err("Failed to resume PCI link, err = %d\n", ret); goto power_off; } if (plat_priv->driver_status == CNSS_LOAD_UNLOAD) { ret = plat_priv->driver_ops->probe(pci_priv->pci_dev, pci_priv->pci_device_id); if (ret) { cnss_pr_err("Failed to probe host driver, err = %d\n", ret); goto suspend_link; } } else if (plat_priv->recovery_in_progress) { ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev, pci_priv->pci_device_id); if (ret) { cnss_pr_err("Failed to reinit host driver, err = %d\n", ret); goto suspend_link; } plat_priv->recovery_in_progress = false; } else { cnss_pr_err("Driver state is not correct to power up!\n"); ret = -EINVAL; goto suspend_link; } return 0; suspend_link: cnss_suspend_pci_link(pci_priv); power_off: cnss_power_off_device(plat_priv); out: return ret; } static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) { int ret = 0; struct cnss_pci_data *pci_priv = plat_priv->bus_priv; if (!pci_priv) return -ENODEV; if (!plat_priv->driver_ops) return -EINVAL; if (plat_priv->driver_status == CNSS_LOAD_UNLOAD) { cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); plat_priv->driver_ops->remove(pci_priv->pci_dev); cnss_pci_set_monitor_wake_intr(pci_priv, false); cnss_pci_set_auto_suspended(pci_priv, 0); } else { plat_priv->recovery_in_progress = true; plat_priv->driver_ops->shutdown(pci_priv->pci_dev); } ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); cnss_power_off_device(plat_priv); return ret; } static int cnss_powerup(const struct subsys_desc *subsys_desc) { int ret = 0; Loading @@ -613,6 +715,7 @@ static int cnss_powerup(const struct subsys_desc *subsys_desc) ret = cnss_qca6174_powerup(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_qca6290_powerup(plat_priv); break; default: cnss_pr_err("Unknown device_id found: 0x%lx\n", Loading @@ -638,6 +741,7 @@ static int cnss_shutdown(const struct subsys_desc *subsys_desc, bool force_stop) ret = cnss_qca6174_shutdown(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_qca6290_shutdown(plat_priv); break; default: cnss_pr_err("Unknown device_id found: 0x%lx\n", Loading
drivers/net/wireless/cnss2/pci.c +278 −8 Original line number Diff line number Diff line Loading @@ -27,6 +27,14 @@ #define PM_OPTIONS_LINK_DOWN \ (MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN) #define PCI_BAR_NUM 0 #ifdef CONFIG_ARM_LPAE #define PCI_DMA_MASK 64 #else #define PCI_DMA_MASK 32 #endif static DEFINE_SPINLOCK(pci_link_down_lock); static unsigned int pci_link_down_panic; Loading Loading @@ -562,6 +570,252 @@ out: } EXPORT_SYMBOL(cnss_auto_resume); int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, phys_addr_t *pa) { if (!pci_priv) return -ENODEV; *va = pci_priv->bar; *pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM); return 0; } #ifdef CONFIG_CNSS_QCA6290 #define PCI_MAX_BAR_SIZE 0xD00000 static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { resource_size_t start = pci_resource_start(dev, bar); resource_size_t len = PCI_MAX_BAR_SIZE; unsigned long flags = pci_resource_flags(dev, bar); if (!len || !start) return NULL; if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) { if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO)) return ioremap(start, len); else return ioremap_nocache(start, len); } return NULL; } #else static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { return pci_iomap(dev, bar, maxlen); } #endif static struct cnss_msi_config msi_config = { .total_vectors = 32, .total_users = 3, .users = (struct cnss_msi_user[]) { { .name = "MHI", .num_vectors = 2, .base_vector = 0 }, { .name = "CE", .num_vectors = 12, .base_vector = 2 }, { .name = "DP", .num_vectors = 18, .base_vector = 14 }, }, }; static int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv) { pci_priv->msi_config = &msi_config; return 0; } static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; int num_vectors; struct cnss_msi_config *msi_config; uint32_t ep_base_data; ret = cnss_pci_get_msi_assignment(pci_priv); if (ret) { cnss_pr_err("Failed to get MSI assignment, err = %d\n", ret); goto out; } msi_config = pci_priv->msi_config; if (!msi_config) { cnss_pr_err("msi_config is NULL!\n"); ret = -EINVAL; goto out; } num_vectors = pci_enable_msi_range(pci_dev, msi_config->total_vectors, msi_config->total_vectors); if (num_vectors != msi_config->total_vectors) { cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d", msi_config->total_vectors, num_vectors); ret = -EINVAL; goto reset_msi_config; } pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_DATA_64, &ep_base_data); pci_priv->msi_ep_base_data = ep_base_data & 0xFFFF; return 0; reset_msi_config: pci_priv->msi_config = NULL; out: return ret; } static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv) { pci_disable_msi(pci_priv->pci_dev); } int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, uint32_t *base_vector) { struct cnss_pci_data *pci_priv = dev_get_drvdata(dev); struct cnss_msi_config *msi_config; int idx; if (!pci_priv) return -ENODEV; msi_config = pci_priv->msi_config; if (!msi_config) { cnss_pr_err("MSI is not supported.\n"); return -EINVAL; } for (idx = 0; idx < msi_config->total_users; idx++) { if (strcmp(user_name, msi_config->users[idx].name) == 0) { *num_vectors = msi_config->users[idx].num_vectors; *user_base_data = msi_config->users[idx].base_vector + pci_priv->msi_ep_base_data; *base_vector = msi_config->users[idx].base_vector; cnss_pr_dbg("Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", user_name, *num_vectors, *user_base_data, *base_vector); return 0; } } cnss_pr_err("Failed to find MSI assignment for %s!\n", user_name); return -EINVAL; } EXPORT_SYMBOL(cnss_get_user_msi_assignment); int cnss_get_msi_irq(struct device *dev, unsigned int vector) { struct pci_dev *pci_dev = to_pci_dev(dev); return pci_dev->irq + vector; } EXPORT_SYMBOL(cnss_get_msi_irq); void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low, uint32_t *msi_addr_high) { struct pci_dev *pci_dev = to_pci_dev(dev); pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, msi_addr_low); pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, msi_addr_high); } EXPORT_SYMBOL(cnss_get_msi_address); static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; uint16_t device_id; pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->pci_device_id->device) { cnss_pr_err("PCI device ID mismatch, config ID: 0x%x, probe ID: 0x%x\n", device_id, pci_priv->pci_device_id->device); ret = -EIO; goto out; } ret = pci_assign_resource(pci_dev, PCI_BAR_NUM); if (ret) { pr_err("Failed to assign PCI resource, err = %d\n", ret); goto out; } ret = pci_enable_device(pci_dev); if (ret) { cnss_pr_err("Failed to enable PCI device, err = %d\n", ret); goto out; } ret = pci_request_region(pci_dev, PCI_BAR_NUM, "cnss"); if (ret) { cnss_pr_err("Failed to request PCI region, err = %d\n", ret); goto disable_device; } ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK)); if (ret) { cnss_pr_err("Failed to set PCI DMA mask (%d), err = %d\n", ret, PCI_DMA_MASK); goto release_region; } ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK)); if (ret) { cnss_pr_err("Failed to set PCI consistent DMA mask (%d), err = %d\n", ret, PCI_DMA_MASK); goto release_region; } pci_set_master(pci_dev); pci_priv->bar = cnss_pci_iomap(pci_dev, PCI_BAR_NUM, 0); if (!pci_priv->bar) { cnss_pr_err("Failed to do PCI IO map!\n"); ret = -EIO; goto clear_master; } return 0; clear_master: pci_clear_master(pci_dev); release_region: pci_release_region(pci_dev, PCI_BAR_NUM); disable_device: pci_disable_device(pci_dev); out: return ret; } static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) { struct pci_dev *pci_dev = pci_priv->pci_dev; if (pci_priv->bar) { pci_iounmap(pci_dev, pci_priv->bar); pci_priv->bar = NULL; } pci_clear_master(pci_dev); pci_release_region(pci_dev, PCI_BAR_NUM); pci_disable_device(pci_dev); } static int cnss_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { Loading Loading @@ -589,10 +843,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, pci_priv->pci_link_state = PCI_LINK_UP; pci_priv->plat_priv = plat_priv; pci_priv->pci_dev = pci_dev; plat_priv->bus_priv = pci_priv; pci_priv->pci_device_id = id; pci_priv->device_id = pci_dev->device; cnss_set_pci_priv(pci_dev, pci_priv); plat_priv->device_id = pci_dev->device; plat_priv->bus_priv = pci_priv; res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM, "smmu_iova_base"); Loading @@ -610,6 +865,16 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, } } ret = cnss_reg_pci_event(pci_priv); if (ret) { cnss_pr_err("Failed to register PCI event, err = %d\n", ret); goto deinit_smmu; } ret = cnss_pci_enable_bus(pci_priv); if (ret) goto dereg_pci_event; switch (pci_dev->device) { case QCA6174_DEVICE_ID: pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET, Loading @@ -621,21 +886,23 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_power_off_device(plat_priv); break; case QCA6290_DEVICE_ID: ret = cnss_pci_enable_msi(pci_priv); if (ret) goto disable_bus; break; default: cnss_pr_err("Unknown PCI device found: 0x%x\n", pci_dev->device); ret = -ENODEV; goto deinit_smmu; } ret = cnss_reg_pci_event(pci_priv); if (ret) { cnss_pr_err("Failed to register PCI event, err = %d\n", ret); goto deinit_smmu; goto disable_bus; } return 0; disable_bus: cnss_pci_disable_bus(pci_priv); dereg_pci_event: cnss_dereg_pci_event(pci_priv); deinit_smmu: if (pci_priv->smmu_mapping) cnss_pci_deinit_smmu(pci_priv); Loading @@ -651,6 +918,9 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(&pci_dev->dev); if (pci_dev->device == QCA6290_DEVICE_ID) cnss_pci_disable_msi(pci_priv); cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); if (pci_priv->smmu_mapping) cnss_pci_deinit_smmu(pci_priv); Loading
drivers/net/wireless/cnss2/pci.h +17 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ #define QCA6290_VENDOR_ID 0x168C #define QCA6290_DEVICE_ID 0xABCD struct cnss_msi_user { char *name; int num_vectors; uint32_t base_vector; }; struct cnss_msi_config { int total_vectors; int total_users; struct cnss_msi_user *users; }; struct cnss_pci_data { struct pci_dev *pci_dev; struct cnss_plat_data *plat_priv; Loading @@ -42,6 +54,9 @@ struct cnss_pci_data { struct dma_iommu_mapping *smmu_mapping; dma_addr_t smmu_iova_start; size_t smmu_iova_len; void __iomem *bar; struct cnss_msi_config *msi_config; uint32_t msi_ep_base_data; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading Loading @@ -93,5 +108,7 @@ int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv); int cnss_resume_pci_link(struct cnss_pci_data *pci_priv); int cnss_pci_init(struct cnss_plat_data *plat_priv); void cnss_pci_deinit(struct cnss_plat_data *plat_priv); int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, phys_addr_t *pa); #endif /* _CNSS_PCI_H */
include/net/cnss2.h +20 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/pci.h> #define CNSS_MAX_FILE_NAME 20 #define CNSS_MAX_TIMESTAMP_LEN 32 enum cnss_bus_width_type { CNSS_BUS_WIDTH_NONE, Loading Loading @@ -43,6 +44,17 @@ struct cnss_fw_files { char evicted_data[CNSS_MAX_FILE_NAME]; }; struct cnss_soc_info { void __iomem *va; phys_addr_t pa; uint32_t chip_id; uint32_t chip_family; uint32_t board_id; uint32_t soc_id; uint32_t fw_version; char fw_build_timestamp[CNSS_MAX_TIMESTAMP_LEN + 1]; }; struct cnss_wlan_runtime_ops { int (*runtime_suspend)(struct pci_dev *pdev); int (*runtime_resume)(struct pci_dev *pdev); Loading Loading @@ -78,6 +90,7 @@ extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files, u32 target_type, u32 target_version); extern int cnss_get_platform_cap(struct cnss_platform_cap *cap); extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info); extern void cnss_set_driver_status(enum cnss_driver_status driver_status); extern int cnss_request_bus_bandwidth(int bandwidth); extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); Loading @@ -95,5 +108,12 @@ extern void cnss_release_pm_sem(void); extern int cnss_wlan_pm_control(bool vote); extern int cnss_auto_suspend(void); extern int cnss_auto_resume(void); extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, uint32_t *base_vector); extern int cnss_get_msi_irq(struct device *dev, unsigned int vector); extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low, uint32_t *msi_addr_high); #endif /* _NET_CNSS2_H */