Loading Documentation/devicetree/bindings/cnss/cnss-wlan.txt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ Optional properties: - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 specifications. - qcom,wlan-en-vreg-support: Boolean property to decide the whether the WLAN_EN pin is a gpio or fixed regulator. - qcom,mhi: phandle to indicate the device which needs MHI support. Example: Loading @@ -64,4 +65,5 @@ Example: pinctrl-0 = <&cnss_default>; qcom,wlan-rc-num = <0>; qcom,wlan-smmu-iova-address = <0 0x10000000>; qcom,mhi = <&mhi_wlan>; }; drivers/net/wireless/cnss2/main.c +78 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #define CNSS_DUMP_MAGIC_VER_V2 0x42445953 #define CNSS_DUMP_NAME "CNSS_WLAN" #define WLAN_RECOVERY_DELAY 1000 #define FILE_SYSTEM_READY 1 static struct cnss_plat_data *plat_env; Loading Loading @@ -646,13 +647,19 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) goto power_off; } ret = cnss_pci_start_mhi(pci_priv); if (ret) { cnss_pr_err("Failed to start MHI, err = %d\n", ret); goto suspend_link; } 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; goto stop_mhi; } } else if (plat_priv->driver_status == CNSS_RECOVERY) { ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev, Loading @@ -660,16 +667,19 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) if (ret) { cnss_pr_err("Failed to reinit host driver, err = %d\n", ret); goto suspend_link; goto stop_mhi; } plat_priv->driver_status = CNSS_INITIALIZED; } else { cnss_pr_err("Driver state is not correct to power up!\n"); ret = -EINVAL; goto suspend_link; goto stop_mhi; } return 0; stop_mhi: cnss_pci_stop_mhi(pci_priv); suspend_link: cnss_suspend_pci_link(pci_priv); power_off: Loading Loading @@ -699,6 +709,8 @@ static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) plat_priv->driver_ops->shutdown(pci_priv->pci_dev); } cnss_pci_stop_mhi(pci_priv); ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); Loading Loading @@ -1072,6 +1084,62 @@ static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) msm_bus_scale_unregister_client(bus_bw_info->bus_client); } static ssize_t cnss_fs_ready_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int fs_ready = 0; struct cnss_plat_data *plat_priv = dev_get_drvdata(dev); if (sscanf(buf, "%du", &fs_ready) != 1) return -EINVAL; cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n", fs_ready, count); if (!plat_priv) { cnss_pr_err("plat_priv is NULL!\n"); return count; } switch (plat_priv->device_id) { case QCA6290_DEVICE_ID: break; default: cnss_pr_err("Not supported for device ID 0x%lx\n", plat_priv->device_id); return count; } if (fs_ready == FILE_SYSTEM_READY) cnss_pci_start_mhi(plat_priv->bus_priv); return count; } static DEVICE_ATTR(fs_ready, S_IWUSR | S_IWGRP, NULL, cnss_fs_ready_store); static int cnss_create_sysfs(struct cnss_plat_data *plat_priv) { int ret = 0; ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); if (ret) { cnss_pr_err("Failed to create device file, err = %d\n", ret); goto out; } return 0; out: return ret; } static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv) { device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); } static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, }, { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, }, Loading Loading @@ -1150,12 +1218,18 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto unreg_ramdump; ret = cnss_create_sysfs(plat_priv); if (ret) goto unreg_bus_scale; register_pm_notifier(&cnss_pm_notifier); cnss_pr_info("Platform driver probed successfully.\n"); return 0; unreg_bus_scale: cnss_unregister_bus_scale(plat_priv); unreg_ramdump: cnss_unregister_ramdump(plat_priv); unreg_subsys: Loading @@ -1180,6 +1254,7 @@ static int cnss_remove(struct platform_device *plat_dev) struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev); unregister_pm_notifier(&cnss_pm_notifier); cnss_remove_sysfs(plat_priv); cnss_unregister_bus_scale(plat_priv); cnss_unregister_ramdump(plat_priv); cnss_unregister_subsys(plat_priv); Loading drivers/net/wireless/cnss2/pci.c +224 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #define PCI_DMA_MASK 32 #endif #define MHI_NODE_NAME "qcom,mhi" static DEFINE_SPINLOCK(pci_link_down_lock); static unsigned int pci_link_down_panic; Loading Loading @@ -816,6 +818,216 @@ static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) pci_disable_device(pci_dev); } static int cnss_mhi_pm_runtime_get(struct pci_dev *pci_dev) { return pm_runtime_get(&pci_dev->dev); } static void cnss_mhi_pm_runtime_put_noidle(struct pci_dev *pci_dev) { pm_runtime_put_noidle(&pci_dev->dev); } static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; struct mhi_device *mhi_dev = &pci_priv->mhi_dev; mhi_dev->dev = &pci_priv->plat_priv->plat_dev->dev; mhi_dev->pci_dev = pci_dev; mhi_dev->resources[0].start = (resource_size_t)pci_priv->bar; mhi_dev->resources[0].end = (resource_size_t)pci_priv->bar + pci_resource_len(pci_dev, PCI_BAR_NUM); mhi_dev->resources[0].flags = pci_resource_flags(pci_dev, PCI_BAR_NUM); mhi_dev->resources[0].name = "BAR"; cnss_pr_dbg("BAR start is %pa, BAR end is %pa\n", &mhi_dev->resources[0].start, &mhi_dev->resources[0].end); if (!mhi_dev->resources[1].start) { mhi_dev->resources[1].start = pci_dev->irq; mhi_dev->resources[1].end = pci_dev->irq + 1; mhi_dev->resources[1].flags = IORESOURCE_IRQ; mhi_dev->resources[1].name = "IRQ"; } cnss_pr_dbg("IRQ start is %pa, IRQ end is %pa\n", &mhi_dev->resources[1].start, &mhi_dev->resources[1].end); mhi_dev->pm_runtime_get = cnss_mhi_pm_runtime_get; mhi_dev->pm_runtime_noidle = cnss_mhi_pm_runtime_put_noidle; ret = mhi_register_device(mhi_dev, MHI_NODE_NAME, (unsigned long)pci_priv); if (ret) { cnss_pr_err("Failed to register as MHI device, err = %d\n", ret); return ret; } return 0; } static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv) { } static enum mhi_dev_ctrl cnss_to_mhi_dev_state(enum cnss_mhi_state state) { switch (state) { case CNSS_MHI_INIT: return MHI_DEV_CTRL_INIT; case CNSS_MHI_DEINIT: return MHI_DEV_CTRL_DE_INIT; case CNSS_MHI_POWER_ON: return MHI_DEV_CTRL_POWER_ON; case CNSS_MHI_POWER_OFF: return MHI_DEV_CTRL_POWER_OFF; case CNSS_MHI_SUSPEND: return MHI_DEV_CTRL_SUSPEND; case CNSS_MHI_RESUME: return MHI_DEV_CTRL_RESUME; case CNSS_MHI_RAM_DUMP: return MHI_DEV_CTRL_RAM_DUMP; case CNSS_MHI_NOTIFY_LINK_ERROR: return MHI_DEV_CTRL_NOTIFY_LINK_ERROR; default: cnss_pr_err("Unknown CNSS MHI state (%d)\n", state); return -EINVAL; } } static int cnss_pci_check_mhi_state_bit(struct cnss_pci_data *pci_priv, enum mhi_dev_ctrl mhi_dev_state) { switch (mhi_dev_state) { case MHI_DEV_CTRL_INIT: if (!test_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_DE_INIT: case MHI_DEV_CTRL_POWER_ON: if (test_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state) && !test_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_POWER_OFF: case MHI_DEV_CTRL_SUSPEND: if (test_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state) && !test_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_RESUME: if (test_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state)) return 0; break; default: cnss_pr_err("Unhandled MHI DEV state (%d)\n", mhi_dev_state); } cnss_pr_err("Cannot set MHI DEV state (%d) in current MHI state (0x%lx)\n", mhi_dev_state, pci_priv->mhi_state); return -EINVAL; } static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv, enum mhi_dev_ctrl mhi_dev_state) { switch (mhi_dev_state) { case MHI_DEV_CTRL_INIT: set_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_DE_INIT: clear_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state); case MHI_DEV_CTRL_POWER_ON: set_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_POWER_OFF: clear_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_SUSPEND: set_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_RESUME: clear_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state); break; default: cnss_pr_err("Unhandled MHI DEV state (%d)\n", mhi_dev_state); } } int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state state) { int ret = 0; enum mhi_dev_ctrl mhi_dev_state = cnss_to_mhi_dev_state(state); if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return -ENODEV; } if (mhi_dev_state < 0) { cnss_pr_err("Invalid MHI DEV state (%d)\n", mhi_dev_state); return -EINVAL; } ret = cnss_pci_check_mhi_state_bit(pci_priv, mhi_dev_state); if (ret) goto out; cnss_pr_dbg("Setting MHI DEV state (%d)\n", mhi_dev_state); ret = mhi_pm_control_device(&pci_priv->mhi_dev, mhi_dev_state); if (ret) { cnss_pr_err("Failed to set MHI DEV state (%d)\n", mhi_dev_state); goto out; } cnss_pci_set_mhi_state_bit(pci_priv, mhi_dev_state); out: return ret; } int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv) { int ret = 0; if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return -ENODEV; } ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_INIT); if (ret) goto out; ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON); if (ret) goto deinit_mhi; return 0; deinit_mhi: cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); out: return ret; } void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv) { if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return; } cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF); cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); } static int cnss_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { Loading @@ -827,9 +1039,10 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n", id->vendor, pci_dev->device); if (!plat_priv) { cnss_pr_err("plat_priv is NULL!\n"); ret = -ENODEV; if (pci_dev->device == QCA6290_DEVICE_ID && !mhi_is_device_ready(&plat_priv->plat_dev->dev, MHI_NODE_NAME)) { cnss_pr_err("MHI driver is not ready, defer PCI probe!\n"); ret = -EPROBE_DEFER; goto out; } Loading Loading @@ -889,6 +1102,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, ret = cnss_pci_enable_msi(pci_priv); if (ret) goto disable_bus; ret = cnss_pci_register_mhi(pci_priv); if (ret) { cnss_pci_disable_msi(pci_priv); goto disable_bus; } break; default: cnss_pr_err("Unknown PCI device found: 0x%x\n", Loading Loading @@ -918,8 +1136,10 @@ 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) if (pci_dev->device == QCA6290_DEVICE_ID) { cnss_pci_unregister_mhi(pci_priv); cnss_pci_disable_msi(pci_priv); } cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); if (pci_priv->smmu_mapping) Loading drivers/net/wireless/cnss2/pci.h +18 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #define _CNSS_PCI_H #include <asm/dma-iommu.h> #include <linux/msm_mhi.h> #include <linux/msm_pcie.h> #include <linux/pci.h> Loading @@ -27,6 +28,17 @@ #define QCA6290_VENDOR_ID 0x168C #define QCA6290_DEVICE_ID 0xABCD enum cnss_mhi_state { CNSS_MHI_INIT, CNSS_MHI_DEINIT, CNSS_MHI_SUSPEND, CNSS_MHI_RESUME, CNSS_MHI_POWER_ON, CNSS_MHI_POWER_OFF, CNSS_MHI_RAM_DUMP, CNSS_MHI_NOTIFY_LINK_ERROR, }; struct cnss_msi_user { char *name; int num_vectors; Loading Loading @@ -57,6 +69,8 @@ struct cnss_pci_data { void __iomem *bar; struct cnss_msi_config *msi_config; uint32_t msi_ep_base_data; struct mhi_device mhi_dev; unsigned long mhi_state; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading Loading @@ -110,5 +124,9 @@ 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); int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state state); int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv); void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv); #endif /* _CNSS_PCI_H */ Loading
Documentation/devicetree/bindings/cnss/cnss-wlan.txt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ Optional properties: - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 specifications. - qcom,wlan-en-vreg-support: Boolean property to decide the whether the WLAN_EN pin is a gpio or fixed regulator. - qcom,mhi: phandle to indicate the device which needs MHI support. Example: Loading @@ -64,4 +65,5 @@ Example: pinctrl-0 = <&cnss_default>; qcom,wlan-rc-num = <0>; qcom,wlan-smmu-iova-address = <0 0x10000000>; qcom,mhi = <&mhi_wlan>; };
drivers/net/wireless/cnss2/main.c +78 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #define CNSS_DUMP_MAGIC_VER_V2 0x42445953 #define CNSS_DUMP_NAME "CNSS_WLAN" #define WLAN_RECOVERY_DELAY 1000 #define FILE_SYSTEM_READY 1 static struct cnss_plat_data *plat_env; Loading Loading @@ -646,13 +647,19 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) goto power_off; } ret = cnss_pci_start_mhi(pci_priv); if (ret) { cnss_pr_err("Failed to start MHI, err = %d\n", ret); goto suspend_link; } 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; goto stop_mhi; } } else if (plat_priv->driver_status == CNSS_RECOVERY) { ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev, Loading @@ -660,16 +667,19 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) if (ret) { cnss_pr_err("Failed to reinit host driver, err = %d\n", ret); goto suspend_link; goto stop_mhi; } plat_priv->driver_status = CNSS_INITIALIZED; } else { cnss_pr_err("Driver state is not correct to power up!\n"); ret = -EINVAL; goto suspend_link; goto stop_mhi; } return 0; stop_mhi: cnss_pci_stop_mhi(pci_priv); suspend_link: cnss_suspend_pci_link(pci_priv); power_off: Loading Loading @@ -699,6 +709,8 @@ static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv) plat_priv->driver_ops->shutdown(pci_priv->pci_dev); } cnss_pci_stop_mhi(pci_priv); ret = cnss_suspend_pci_link(pci_priv); if (ret) cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret); Loading Loading @@ -1072,6 +1084,62 @@ static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) msm_bus_scale_unregister_client(bus_bw_info->bus_client); } static ssize_t cnss_fs_ready_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int fs_ready = 0; struct cnss_plat_data *plat_priv = dev_get_drvdata(dev); if (sscanf(buf, "%du", &fs_ready) != 1) return -EINVAL; cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n", fs_ready, count); if (!plat_priv) { cnss_pr_err("plat_priv is NULL!\n"); return count; } switch (plat_priv->device_id) { case QCA6290_DEVICE_ID: break; default: cnss_pr_err("Not supported for device ID 0x%lx\n", plat_priv->device_id); return count; } if (fs_ready == FILE_SYSTEM_READY) cnss_pci_start_mhi(plat_priv->bus_priv); return count; } static DEVICE_ATTR(fs_ready, S_IWUSR | S_IWGRP, NULL, cnss_fs_ready_store); static int cnss_create_sysfs(struct cnss_plat_data *plat_priv) { int ret = 0; ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); if (ret) { cnss_pr_err("Failed to create device file, err = %d\n", ret); goto out; } return 0; out: return ret; } static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv) { device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); } static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, }, { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, }, Loading Loading @@ -1150,12 +1218,18 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto unreg_ramdump; ret = cnss_create_sysfs(plat_priv); if (ret) goto unreg_bus_scale; register_pm_notifier(&cnss_pm_notifier); cnss_pr_info("Platform driver probed successfully.\n"); return 0; unreg_bus_scale: cnss_unregister_bus_scale(plat_priv); unreg_ramdump: cnss_unregister_ramdump(plat_priv); unreg_subsys: Loading @@ -1180,6 +1254,7 @@ static int cnss_remove(struct platform_device *plat_dev) struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev); unregister_pm_notifier(&cnss_pm_notifier); cnss_remove_sysfs(plat_priv); cnss_unregister_bus_scale(plat_priv); cnss_unregister_ramdump(plat_priv); cnss_unregister_subsys(plat_priv); Loading
drivers/net/wireless/cnss2/pci.c +224 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #define PCI_DMA_MASK 32 #endif #define MHI_NODE_NAME "qcom,mhi" static DEFINE_SPINLOCK(pci_link_down_lock); static unsigned int pci_link_down_panic; Loading Loading @@ -816,6 +818,216 @@ static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv) pci_disable_device(pci_dev); } static int cnss_mhi_pm_runtime_get(struct pci_dev *pci_dev) { return pm_runtime_get(&pci_dev->dev); } static void cnss_mhi_pm_runtime_put_noidle(struct pci_dev *pci_dev) { pm_runtime_put_noidle(&pci_dev->dev); } static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv) { int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; struct mhi_device *mhi_dev = &pci_priv->mhi_dev; mhi_dev->dev = &pci_priv->plat_priv->plat_dev->dev; mhi_dev->pci_dev = pci_dev; mhi_dev->resources[0].start = (resource_size_t)pci_priv->bar; mhi_dev->resources[0].end = (resource_size_t)pci_priv->bar + pci_resource_len(pci_dev, PCI_BAR_NUM); mhi_dev->resources[0].flags = pci_resource_flags(pci_dev, PCI_BAR_NUM); mhi_dev->resources[0].name = "BAR"; cnss_pr_dbg("BAR start is %pa, BAR end is %pa\n", &mhi_dev->resources[0].start, &mhi_dev->resources[0].end); if (!mhi_dev->resources[1].start) { mhi_dev->resources[1].start = pci_dev->irq; mhi_dev->resources[1].end = pci_dev->irq + 1; mhi_dev->resources[1].flags = IORESOURCE_IRQ; mhi_dev->resources[1].name = "IRQ"; } cnss_pr_dbg("IRQ start is %pa, IRQ end is %pa\n", &mhi_dev->resources[1].start, &mhi_dev->resources[1].end); mhi_dev->pm_runtime_get = cnss_mhi_pm_runtime_get; mhi_dev->pm_runtime_noidle = cnss_mhi_pm_runtime_put_noidle; ret = mhi_register_device(mhi_dev, MHI_NODE_NAME, (unsigned long)pci_priv); if (ret) { cnss_pr_err("Failed to register as MHI device, err = %d\n", ret); return ret; } return 0; } static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv) { } static enum mhi_dev_ctrl cnss_to_mhi_dev_state(enum cnss_mhi_state state) { switch (state) { case CNSS_MHI_INIT: return MHI_DEV_CTRL_INIT; case CNSS_MHI_DEINIT: return MHI_DEV_CTRL_DE_INIT; case CNSS_MHI_POWER_ON: return MHI_DEV_CTRL_POWER_ON; case CNSS_MHI_POWER_OFF: return MHI_DEV_CTRL_POWER_OFF; case CNSS_MHI_SUSPEND: return MHI_DEV_CTRL_SUSPEND; case CNSS_MHI_RESUME: return MHI_DEV_CTRL_RESUME; case CNSS_MHI_RAM_DUMP: return MHI_DEV_CTRL_RAM_DUMP; case CNSS_MHI_NOTIFY_LINK_ERROR: return MHI_DEV_CTRL_NOTIFY_LINK_ERROR; default: cnss_pr_err("Unknown CNSS MHI state (%d)\n", state); return -EINVAL; } } static int cnss_pci_check_mhi_state_bit(struct cnss_pci_data *pci_priv, enum mhi_dev_ctrl mhi_dev_state) { switch (mhi_dev_state) { case MHI_DEV_CTRL_INIT: if (!test_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_DE_INIT: case MHI_DEV_CTRL_POWER_ON: if (test_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state) && !test_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_POWER_OFF: case MHI_DEV_CTRL_SUSPEND: if (test_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state) && !test_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state)) return 0; break; case MHI_DEV_CTRL_RESUME: if (test_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state)) return 0; break; default: cnss_pr_err("Unhandled MHI DEV state (%d)\n", mhi_dev_state); } cnss_pr_err("Cannot set MHI DEV state (%d) in current MHI state (0x%lx)\n", mhi_dev_state, pci_priv->mhi_state); return -EINVAL; } static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv, enum mhi_dev_ctrl mhi_dev_state) { switch (mhi_dev_state) { case MHI_DEV_CTRL_INIT: set_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_DE_INIT: clear_bit(MHI_DEV_CTRL_INIT, &pci_priv->mhi_state); case MHI_DEV_CTRL_POWER_ON: set_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_POWER_OFF: clear_bit(MHI_DEV_CTRL_POWER_ON, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_SUSPEND: set_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state); break; case MHI_DEV_CTRL_RESUME: clear_bit(MHI_DEV_CTRL_SUSPEND, &pci_priv->mhi_state); break; default: cnss_pr_err("Unhandled MHI DEV state (%d)\n", mhi_dev_state); } } int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state state) { int ret = 0; enum mhi_dev_ctrl mhi_dev_state = cnss_to_mhi_dev_state(state); if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return -ENODEV; } if (mhi_dev_state < 0) { cnss_pr_err("Invalid MHI DEV state (%d)\n", mhi_dev_state); return -EINVAL; } ret = cnss_pci_check_mhi_state_bit(pci_priv, mhi_dev_state); if (ret) goto out; cnss_pr_dbg("Setting MHI DEV state (%d)\n", mhi_dev_state); ret = mhi_pm_control_device(&pci_priv->mhi_dev, mhi_dev_state); if (ret) { cnss_pr_err("Failed to set MHI DEV state (%d)\n", mhi_dev_state); goto out; } cnss_pci_set_mhi_state_bit(pci_priv, mhi_dev_state); out: return ret; } int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv) { int ret = 0; if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return -ENODEV; } ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_INIT); if (ret) goto out; ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON); if (ret) goto deinit_mhi; return 0; deinit_mhi: cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); out: return ret; } void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv) { if (!pci_priv) { cnss_pr_err("pci_priv is NULL!\n"); return; } cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF); cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); } static int cnss_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { Loading @@ -827,9 +1039,10 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n", id->vendor, pci_dev->device); if (!plat_priv) { cnss_pr_err("plat_priv is NULL!\n"); ret = -ENODEV; if (pci_dev->device == QCA6290_DEVICE_ID && !mhi_is_device_ready(&plat_priv->plat_dev->dev, MHI_NODE_NAME)) { cnss_pr_err("MHI driver is not ready, defer PCI probe!\n"); ret = -EPROBE_DEFER; goto out; } Loading Loading @@ -889,6 +1102,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, ret = cnss_pci_enable_msi(pci_priv); if (ret) goto disable_bus; ret = cnss_pci_register_mhi(pci_priv); if (ret) { cnss_pci_disable_msi(pci_priv); goto disable_bus; } break; default: cnss_pr_err("Unknown PCI device found: 0x%x\n", Loading Loading @@ -918,8 +1136,10 @@ 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) if (pci_dev->device == QCA6290_DEVICE_ID) { cnss_pci_unregister_mhi(pci_priv); cnss_pci_disable_msi(pci_priv); } cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); if (pci_priv->smmu_mapping) Loading
drivers/net/wireless/cnss2/pci.h +18 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #define _CNSS_PCI_H #include <asm/dma-iommu.h> #include <linux/msm_mhi.h> #include <linux/msm_pcie.h> #include <linux/pci.h> Loading @@ -27,6 +28,17 @@ #define QCA6290_VENDOR_ID 0x168C #define QCA6290_DEVICE_ID 0xABCD enum cnss_mhi_state { CNSS_MHI_INIT, CNSS_MHI_DEINIT, CNSS_MHI_SUSPEND, CNSS_MHI_RESUME, CNSS_MHI_POWER_ON, CNSS_MHI_POWER_OFF, CNSS_MHI_RAM_DUMP, CNSS_MHI_NOTIFY_LINK_ERROR, }; struct cnss_msi_user { char *name; int num_vectors; Loading Loading @@ -57,6 +69,8 @@ struct cnss_pci_data { void __iomem *bar; struct cnss_msi_config *msi_config; uint32_t msi_ep_base_data; struct mhi_device mhi_dev; unsigned long mhi_state; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading Loading @@ -110,5 +124,9 @@ 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); int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state state); int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv); void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv); #endif /* _CNSS_PCI_H */