Loading Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt +6 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ PMIC voltage regulator resources. Required properties: - compatible: "qcom,cnss_sdio" - reg: memory resource to save firmware dump, optional. - reg-names: memory resource name. - subsys-name: cnss sdio subsytem device name, required. - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node. - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node. - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node. Loading @@ -17,6 +20,9 @@ Required properties: Example: qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; reg = <0x87a00000, 0x200000>; reg-names = "ramdump"; subsys-name = "AR6320"; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>; vdd-wlan-io-supply = <&mdm9607_l11>; Loading arch/arm/boot/dts/qcom/mdm9607.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -499,6 +499,9 @@ qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; reg = <0x87a00000 0x200000>; reg-names = "ramdump"; subsys-name = "AR6320"; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>; vdd-wlan-io-supply = <&mdm9607_l11>; Loading drivers/net/wireless/cnss/cnss_sdio.c +312 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,11 @@ #include <linux/slab.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> #include <linux/io.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/ramdump.h> #include <soc/qcom/memory_dump.h> #include <net/cnss.h> #define WLAN_VREG_NAME "vdd-wlan" Loading Loading @@ -57,14 +62,30 @@ struct cnss_sdio_info { const struct sdio_device_id *id; }; struct cnss_ssr_info { struct subsys_device *subsys; struct subsys_desc subsysdesc; void *subsys_handle; struct ramdump_device *ramdump_dev; unsigned long ramdump_size; void *ramdump_addr; phys_addr_t ramdump_phys; char subsys_name[10]; }; static struct cnss_sdio_data { struct cnss_sdio_regulator regulator; struct platform_device *pdev; struct cnss_dfs_nol_info dfs_info; struct cnss_unsafe_channel_list unsafe_list; struct cnss_sdio_info cnss_sdio_info; struct cnss_ssr_info ssr_info; } *cnss_pdata; #define WLAN_RECOVERY_DELAY 1 /* cnss sdio subsytem device name, required property */ #define CNSS_SUBSYS_NAME_KEY "subsys-name" /* SDIO manufacturer ID and Codes */ #define MANUFACTURER_ID_AR6320_BASE 0x500 #define MANUFACTURER_ID_QCA9377_BASE 0x700 Loading Loading @@ -203,6 +224,277 @@ int cnss_wlan_get_dfs_nol(void *info, u16 info_len) } EXPORT_SYMBOL(cnss_wlan_get_dfs_nol); static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->shutdown) wdrv->shutdown(cnss_info->func); return 0; } static int cnss_sdio_powerup(const struct subsys_desc *subsys) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; int ret = 0; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->reinit) { ret = wdrv->reinit(cnss_info->func, cnss_info->id); if (ret) pr_err("%s: wlan reinit error=%d\n", __func__, ret); } return ret; } static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; if (!cnss_pdata) return; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->crash_shutdown) wdrv->crash_shutdown(cnss_info->func); } static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys) { struct cnss_ssr_info *ssr_info; struct ramdump_segment segment; int ret; if (!cnss_pdata) return -ENODEV; if (!cnss_pdata->ssr_info.ramdump_size) return -ENOENT; if (!enable) return 0; ssr_info = &cnss_pdata->ssr_info; memset(&segment, 0, sizeof(segment)); segment.v_address = ssr_info->ramdump_addr; segment.size = ssr_info->ramdump_size; ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1); if (ret) pr_err("%s: do_ramdump failed error=%d\n", __func__, ret); return ret; } static int cnss_subsys_init(void) { struct cnss_ssr_info *ssr_info; int ret = 0; if (!cnss_pdata) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; ssr_info->subsysdesc.name = ssr_info->subsys_name; ssr_info->subsysdesc.owner = THIS_MODULE; ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown; ssr_info->subsysdesc.powerup = cnss_sdio_powerup; ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump; ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown; ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev; ssr_info->subsys = subsys_register(&ssr_info->subsysdesc); if (IS_ERR(ssr_info->subsys)) { ret = PTR_ERR(ssr_info->subsys); ssr_info->subsys = NULL; dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n", ret); goto err_subsys_reg; } ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name); if (IS_ERR(ssr_info->subsys_handle)) { ret = PTR_ERR(ssr_info->subsys_handle); ssr_info->subsys_handle = NULL; dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n", ret); goto err_subsys_get; } return 0; err_subsys_get: subsys_unregister(ssr_info->subsys); ssr_info->subsys = NULL; err_subsys_reg: return ret; } static void cnss_subsys_exit(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->subsys_handle) subsystem_put(ssr_info->subsys_handle); ssr_info->subsys_handle = NULL; if (ssr_info->subsys) subsys_unregister(ssr_info->subsys); ssr_info->subsys = NULL; } static int cnss_configure_ramdump(void) { struct cnss_ssr_info *ssr_info; int ret = 0; struct resource *res; const char *name; if (!cnss_pdata) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; ret = of_property_read_string(cnss_pdata->pdev->dev.of_node, CNSS_SUBSYS_NAME_KEY, &name); if (ret) { pr_err("%s: cnss missing DT key '%s'\n", __func__, CNSS_SUBSYS_NAME_KEY); ret = -ENODEV; goto err_subsys_name_query; } strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name)); res = platform_get_resource_byname(cnss_pdata->pdev, IORESOURCE_MEM, "ramdump"); if (res) { ssr_info->ramdump_phys = res->start; ssr_info->ramdump_size = resource_size(res); } else { pr_err("%s: CNSS ramdump mem not available\n", __func__); return 0; } ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys, ssr_info->ramdump_size); if (!ssr_info->ramdump_addr || ssr_info->ramdump_size == 0) { ssr_info->ramdump_size = 0; ssr_info->ramdump_addr = NULL; pr_err("%s: CNSS ramdump will not be collected\n", __func__); return 0; } pr_info("%s: ramdump addr: %p, phys: %pa subsys:'%s'\n", __func__, ssr_info->ramdump_addr, &ssr_info->ramdump_phys, ssr_info->subsys_name); ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name, &cnss_pdata->pdev->dev); if (!ssr_info->ramdump_dev) { ret = -ENOMEM; pr_err("%s: ramdump dev create failed: error=%d\n", __func__, ret); goto err_create_ramdump; } return 0; err_create_ramdump: iounmap(ssr_info->ramdump_addr); ssr_info->ramdump_addr = NULL; ssr_info->ramdump_size = 0; err_subsys_name_query: return ret; } static void cnss_ramdump_cleanup(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->ramdump_addr) iounmap(ssr_info->ramdump_addr); ssr_info->ramdump_addr = NULL; if (ssr_info->ramdump_dev) destroy_ramdump_device(ssr_info->ramdump_dev); ssr_info->ramdump_dev = NULL; } int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata || !cnss_pdata->pdev) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; *address = ssr_info->ramdump_phys; *size = ssr_info->ramdump_size; return 0; } EXPORT_SYMBOL(cnss_get_ramdump_mem); void *cnss_get_virt_ramdump_mem(unsigned long *size) { if (!cnss_pdata || !cnss_pdata->pdev) return NULL; *size = cnss_pdata->ssr_info.ramdump_size; return cnss_pdata->ssr_info.ramdump_addr; } EXPORT_SYMBOL(cnss_get_virt_ramdump_mem); void cnss_device_self_recovery(void) { cnss_sdio_shutdown(NULL, false); msleep(WLAN_RECOVERY_DELAY); cnss_sdio_powerup(NULL); } EXPORT_SYMBOL(cnss_device_self_recovery); static void recovery_work_handler(struct work_struct *recovery) { cnss_device_self_recovery(); } DECLARE_WORK(recovery_work, recovery_work_handler); void cnss_schedule_recovery_work(void) { schedule_work(&recovery_work); } EXPORT_SYMBOL(cnss_schedule_recovery_work); void cnss_device_crashed(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->subsys) { subsys_set_crash_status(ssr_info->subsys, true); subsystem_restart_dev(ssr_info->subsys); } } EXPORT_SYMBOL(cnss_device_crashed); static int cnss_sdio_wlan_inserted( struct sdio_func *func, const struct sdio_device_id *id) Loading Loading @@ -572,9 +864,26 @@ static int cnss_sdio_probe(struct platform_device *pdev) goto err_wlan_dsrc_enable_regulator; } error = cnss_configure_ramdump(); if (error) { dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n", error); goto err_ramdump_create; } error = cnss_subsys_init(); if (error) { dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n", error); goto err_subsys_init; } dev_info(&pdev->dev, "CNSS SDIO Driver registered"); return 0; err_subsys_init: cnss_ramdump_cleanup(); err_ramdump_create: cnss_sdio_wlan_exit(); err_wlan_dsrc_enable_regulator: regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc); err_wlan_enable_regulator: Loading @@ -595,7 +904,8 @@ static int cnss_sdio_remove(struct platform_device *pdev) dfs_info = &cnss_pdata->dfs_info; kfree(dfs_info->dfs_nol_info); cnss_subsys_exit(); cnss_ramdump_cleanup(); cnss_sdio_release_resource(); return 0; } Loading include/net/cnss.h +8 −5 Original line number Diff line number Diff line Loading @@ -115,11 +115,6 @@ enum cnss_runtime_request { extern int cnss_get_fw_image(struct image_desc_info *image_desc_info); extern void cnss_runtime_init(struct device *dev, int auto_delay); extern void cnss_runtime_exit(struct device *dev); extern void cnss_device_crashed(void); extern void cnss_device_self_recovery(void); extern int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size); extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern void cnss_schedule_recovery_work(void); extern void cnss_wlan_pci_link_down(void); extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable); extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver); Loading Loading @@ -188,6 +183,11 @@ extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, u16 buf_len); extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len); extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len); extern void cnss_device_crashed(void); extern void cnss_device_self_recovery(void); extern int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size); extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern void cnss_schedule_recovery_work(void); #ifdef CONFIG_CNSS_SDIO struct cnss_sdio_wlan_driver { Loading @@ -195,6 +195,9 @@ struct cnss_sdio_wlan_driver { const struct sdio_device_id *id_table; int (*probe)(struct sdio_func *, const struct sdio_device_id *); void (*remove)(struct sdio_func *); int (*reinit)(struct sdio_func *, const struct sdio_device_id *); void (*shutdown)(struct sdio_func *); void (*crash_shutdown)(struct sdio_func *); int (*suspend)(struct device *); int (*resume)(struct device *); }; Loading Loading
Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt +6 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ PMIC voltage regulator resources. Required properties: - compatible: "qcom,cnss_sdio" - reg: memory resource to save firmware dump, optional. - reg-names: memory resource name. - subsys-name: cnss sdio subsytem device name, required. - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node. - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node. - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node. Loading @@ -17,6 +20,9 @@ Required properties: Example: qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; reg = <0x87a00000, 0x200000>; reg-names = "ramdump"; subsys-name = "AR6320"; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>; vdd-wlan-io-supply = <&mdm9607_l11>; Loading
arch/arm/boot/dts/qcom/mdm9607.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -499,6 +499,9 @@ qcom,cnss-sdio { compatible = "qcom,cnss_sdio"; reg = <0x87a00000 0x200000>; reg-names = "ramdump"; subsys-name = "AR6320"; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>; vdd-wlan-io-supply = <&mdm9607_l11>; Loading
drivers/net/wireless/cnss/cnss_sdio.c +312 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,11 @@ #include <linux/slab.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> #include <linux/io.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/ramdump.h> #include <soc/qcom/memory_dump.h> #include <net/cnss.h> #define WLAN_VREG_NAME "vdd-wlan" Loading Loading @@ -57,14 +62,30 @@ struct cnss_sdio_info { const struct sdio_device_id *id; }; struct cnss_ssr_info { struct subsys_device *subsys; struct subsys_desc subsysdesc; void *subsys_handle; struct ramdump_device *ramdump_dev; unsigned long ramdump_size; void *ramdump_addr; phys_addr_t ramdump_phys; char subsys_name[10]; }; static struct cnss_sdio_data { struct cnss_sdio_regulator regulator; struct platform_device *pdev; struct cnss_dfs_nol_info dfs_info; struct cnss_unsafe_channel_list unsafe_list; struct cnss_sdio_info cnss_sdio_info; struct cnss_ssr_info ssr_info; } *cnss_pdata; #define WLAN_RECOVERY_DELAY 1 /* cnss sdio subsytem device name, required property */ #define CNSS_SUBSYS_NAME_KEY "subsys-name" /* SDIO manufacturer ID and Codes */ #define MANUFACTURER_ID_AR6320_BASE 0x500 #define MANUFACTURER_ID_QCA9377_BASE 0x700 Loading Loading @@ -203,6 +224,277 @@ int cnss_wlan_get_dfs_nol(void *info, u16 info_len) } EXPORT_SYMBOL(cnss_wlan_get_dfs_nol); static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->shutdown) wdrv->shutdown(cnss_info->func); return 0; } static int cnss_sdio_powerup(const struct subsys_desc *subsys) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; int ret = 0; if (!cnss_pdata) return -ENODEV; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->reinit) { ret = wdrv->reinit(cnss_info->func, cnss_info->id); if (ret) pr_err("%s: wlan reinit error=%d\n", __func__, ret); } return ret; } static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys) { struct cnss_sdio_info *cnss_info; struct cnss_sdio_wlan_driver *wdrv; if (!cnss_pdata) return; cnss_info = &cnss_pdata->cnss_sdio_info; wdrv = cnss_info->wdrv; if (wdrv && wdrv->crash_shutdown) wdrv->crash_shutdown(cnss_info->func); } static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys) { struct cnss_ssr_info *ssr_info; struct ramdump_segment segment; int ret; if (!cnss_pdata) return -ENODEV; if (!cnss_pdata->ssr_info.ramdump_size) return -ENOENT; if (!enable) return 0; ssr_info = &cnss_pdata->ssr_info; memset(&segment, 0, sizeof(segment)); segment.v_address = ssr_info->ramdump_addr; segment.size = ssr_info->ramdump_size; ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1); if (ret) pr_err("%s: do_ramdump failed error=%d\n", __func__, ret); return ret; } static int cnss_subsys_init(void) { struct cnss_ssr_info *ssr_info; int ret = 0; if (!cnss_pdata) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; ssr_info->subsysdesc.name = ssr_info->subsys_name; ssr_info->subsysdesc.owner = THIS_MODULE; ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown; ssr_info->subsysdesc.powerup = cnss_sdio_powerup; ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump; ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown; ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev; ssr_info->subsys = subsys_register(&ssr_info->subsysdesc); if (IS_ERR(ssr_info->subsys)) { ret = PTR_ERR(ssr_info->subsys); ssr_info->subsys = NULL; dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n", ret); goto err_subsys_reg; } ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name); if (IS_ERR(ssr_info->subsys_handle)) { ret = PTR_ERR(ssr_info->subsys_handle); ssr_info->subsys_handle = NULL; dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n", ret); goto err_subsys_get; } return 0; err_subsys_get: subsys_unregister(ssr_info->subsys); ssr_info->subsys = NULL; err_subsys_reg: return ret; } static void cnss_subsys_exit(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->subsys_handle) subsystem_put(ssr_info->subsys_handle); ssr_info->subsys_handle = NULL; if (ssr_info->subsys) subsys_unregister(ssr_info->subsys); ssr_info->subsys = NULL; } static int cnss_configure_ramdump(void) { struct cnss_ssr_info *ssr_info; int ret = 0; struct resource *res; const char *name; if (!cnss_pdata) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; ret = of_property_read_string(cnss_pdata->pdev->dev.of_node, CNSS_SUBSYS_NAME_KEY, &name); if (ret) { pr_err("%s: cnss missing DT key '%s'\n", __func__, CNSS_SUBSYS_NAME_KEY); ret = -ENODEV; goto err_subsys_name_query; } strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name)); res = platform_get_resource_byname(cnss_pdata->pdev, IORESOURCE_MEM, "ramdump"); if (res) { ssr_info->ramdump_phys = res->start; ssr_info->ramdump_size = resource_size(res); } else { pr_err("%s: CNSS ramdump mem not available\n", __func__); return 0; } ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys, ssr_info->ramdump_size); if (!ssr_info->ramdump_addr || ssr_info->ramdump_size == 0) { ssr_info->ramdump_size = 0; ssr_info->ramdump_addr = NULL; pr_err("%s: CNSS ramdump will not be collected\n", __func__); return 0; } pr_info("%s: ramdump addr: %p, phys: %pa subsys:'%s'\n", __func__, ssr_info->ramdump_addr, &ssr_info->ramdump_phys, ssr_info->subsys_name); ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name, &cnss_pdata->pdev->dev); if (!ssr_info->ramdump_dev) { ret = -ENOMEM; pr_err("%s: ramdump dev create failed: error=%d\n", __func__, ret); goto err_create_ramdump; } return 0; err_create_ramdump: iounmap(ssr_info->ramdump_addr); ssr_info->ramdump_addr = NULL; ssr_info->ramdump_size = 0; err_subsys_name_query: return ret; } static void cnss_ramdump_cleanup(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->ramdump_addr) iounmap(ssr_info->ramdump_addr); ssr_info->ramdump_addr = NULL; if (ssr_info->ramdump_dev) destroy_ramdump_device(ssr_info->ramdump_dev); ssr_info->ramdump_dev = NULL; } int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata || !cnss_pdata->pdev) return -ENODEV; ssr_info = &cnss_pdata->ssr_info; *address = ssr_info->ramdump_phys; *size = ssr_info->ramdump_size; return 0; } EXPORT_SYMBOL(cnss_get_ramdump_mem); void *cnss_get_virt_ramdump_mem(unsigned long *size) { if (!cnss_pdata || !cnss_pdata->pdev) return NULL; *size = cnss_pdata->ssr_info.ramdump_size; return cnss_pdata->ssr_info.ramdump_addr; } EXPORT_SYMBOL(cnss_get_virt_ramdump_mem); void cnss_device_self_recovery(void) { cnss_sdio_shutdown(NULL, false); msleep(WLAN_RECOVERY_DELAY); cnss_sdio_powerup(NULL); } EXPORT_SYMBOL(cnss_device_self_recovery); static void recovery_work_handler(struct work_struct *recovery) { cnss_device_self_recovery(); } DECLARE_WORK(recovery_work, recovery_work_handler); void cnss_schedule_recovery_work(void) { schedule_work(&recovery_work); } EXPORT_SYMBOL(cnss_schedule_recovery_work); void cnss_device_crashed(void) { struct cnss_ssr_info *ssr_info; if (!cnss_pdata) return; ssr_info = &cnss_pdata->ssr_info; if (ssr_info->subsys) { subsys_set_crash_status(ssr_info->subsys, true); subsystem_restart_dev(ssr_info->subsys); } } EXPORT_SYMBOL(cnss_device_crashed); static int cnss_sdio_wlan_inserted( struct sdio_func *func, const struct sdio_device_id *id) Loading Loading @@ -572,9 +864,26 @@ static int cnss_sdio_probe(struct platform_device *pdev) goto err_wlan_dsrc_enable_regulator; } error = cnss_configure_ramdump(); if (error) { dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n", error); goto err_ramdump_create; } error = cnss_subsys_init(); if (error) { dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n", error); goto err_subsys_init; } dev_info(&pdev->dev, "CNSS SDIO Driver registered"); return 0; err_subsys_init: cnss_ramdump_cleanup(); err_ramdump_create: cnss_sdio_wlan_exit(); err_wlan_dsrc_enable_regulator: regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc); err_wlan_enable_regulator: Loading @@ -595,7 +904,8 @@ static int cnss_sdio_remove(struct platform_device *pdev) dfs_info = &cnss_pdata->dfs_info; kfree(dfs_info->dfs_nol_info); cnss_subsys_exit(); cnss_ramdump_cleanup(); cnss_sdio_release_resource(); return 0; } Loading
include/net/cnss.h +8 −5 Original line number Diff line number Diff line Loading @@ -115,11 +115,6 @@ enum cnss_runtime_request { extern int cnss_get_fw_image(struct image_desc_info *image_desc_info); extern void cnss_runtime_init(struct device *dev, int auto_delay); extern void cnss_runtime_exit(struct device *dev); extern void cnss_device_crashed(void); extern void cnss_device_self_recovery(void); extern int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size); extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern void cnss_schedule_recovery_work(void); extern void cnss_wlan_pci_link_down(void); extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable); extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver); Loading Loading @@ -188,6 +183,11 @@ extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, u16 buf_len); extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len); extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len); extern void cnss_device_crashed(void); extern void cnss_device_self_recovery(void); extern int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size); extern void *cnss_get_virt_ramdump_mem(unsigned long *size); extern void cnss_schedule_recovery_work(void); #ifdef CONFIG_CNSS_SDIO struct cnss_sdio_wlan_driver { Loading @@ -195,6 +195,9 @@ struct cnss_sdio_wlan_driver { const struct sdio_device_id *id_table; int (*probe)(struct sdio_func *, const struct sdio_device_id *); void (*remove)(struct sdio_func *); int (*reinit)(struct sdio_func *, const struct sdio_device_id *); void (*shutdown)(struct sdio_func *); void (*crash_shutdown)(struct sdio_func *); int (*suspend)(struct device *); int (*resume)(struct device *); }; Loading