/* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #ifdef CONFIG_PLD_PCIE_CNSS #ifdef CONFIG_CNSS_OUT_OF_TREE #include "cnss2.h" #else #include #endif #endif #include "pld_internal.h" #include "pld_pcie.h" #include "osif_psoc_sync.h" #ifdef CONFIG_PCI #ifdef QCA_WIFI_3_0_ADRASTEA #define CE_COUNT_MAX 12 #else #define CE_COUNT_MAX 8 #endif #if defined(CONFIG_PLD_PCIE_CNSS) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) #ifndef CHIP_VERSION #define CHIP_VERSION CNSS_CHIP_VER_ANY #endif #endif /** * pld_pcie_probe() - Probe function for PCIE platform driver * @pdev: PCIE device * @id: PCIE device ID table * * The probe function will be called when PCIE device provided * in the ID table is detected. * * Return: int */ static int pld_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pld_context *pld_context; int ret = 0; pld_context = pld_get_global_context(); if (!pld_context) { ret = -ENODEV; goto out; } ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE); if (ret) goto out; return pld_context->ops->probe(&pdev->dev, PLD_BUS_TYPE_PCIE, pdev, (void *)id); out: return ret; } /** * pld_pcie_remove() - Remove function for PCIE device * @pdev: PCIE device * * The remove function will be called when PCIE device is disconnected * * Return: void */ static void pld_pcie_remove(struct pci_dev *pdev) { struct pld_context *pld_context; int errno; struct osif_psoc_sync *psoc_sync; errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync); #ifdef ENFORCE_PLD_REMOVE if (errno && errno != -EINVAL) return; #else if (errno) return; #endif osif_psoc_sync_unregister(&pdev->dev); if (psoc_sync) osif_psoc_sync_wait_for_ops(psoc_sync); pld_context = pld_get_global_context(); if (!pld_context) goto out; pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE); pld_del_dev(pld_context, &pdev->dev); out: if (psoc_sync) { osif_psoc_sync_trans_stop(psoc_sync); osif_psoc_sync_destroy(psoc_sync); } } /** * pld_pcie_set_thermal_state() - Set thermal state for thermal mitigation * @pdev: PCIE device * @thermal_state: Thermal state set by thermal subsystem * @mon_id: Thermal cooling device ID * * This function will be called when thermal subsystem notifies platform * driver about change in thermal state. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_set_thermal_state(struct pci_dev *pdev, unsigned long thermal_state, int mon_id) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (!pld_context) return -EINVAL; if (pld_context->ops->set_curr_therm_cdev_state) return pld_context->ops->set_curr_therm_cdev_state(&pdev->dev, thermal_state, mon_id); return -ENOTSUPP; } #ifdef CONFIG_PLD_PCIE_CNSS /** * pld_pcie_idle_restart_cb() - Perform idle restart * @pdev: PCIE device * @id: PCIE device ID * * This function will be called if there is an idle restart request * * Return: int */ static int pld_pcie_idle_restart_cb(struct pci_dev *pdev, const struct pci_device_id *id) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->idle_restart) return pld_context->ops->idle_restart(&pdev->dev, PLD_BUS_TYPE_PCIE); return -ENODEV; } /** * pld_pcie_idle_shutdown_cb() - Perform idle shutdown * @pdev: PCIE device * * This function will be called if there is an idle shutdown request * * Return: int */ static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->shutdown) return pld_context->ops->idle_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); return -ENODEV; } /** * pld_pcie_reinit() - SSR re-initialize function for PCIE device * @pdev: PCIE device * @id: PCIE device ID * * During subsystem restart(SSR), this function will be called to * re-initialize PCIE device. * * Return: int */ static int pld_pcie_reinit(struct pci_dev *pdev, const struct pci_device_id *id) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->reinit) return pld_context->ops->reinit(&pdev->dev, PLD_BUS_TYPE_PCIE, pdev, (void *)id); return -ENODEV; } /** * pld_pcie_shutdown() - SSR shutdown function for PCIE device * @pdev: PCIE device * * During SSR, this function will be called to shutdown PCIE device. * * Return: void */ static void pld_pcie_shutdown(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->shutdown) pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); } /** * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device * @pdev: PCIE device * * This function will be called when a crash is detected, it will shutdown * the PCIE device. * * Return: void */ static void pld_pcie_crash_shutdown(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->crash_shutdown) pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); } /** * pld_pcie_notify_handler() - Modem state notification callback function * @pdev: PCIE device * @state: modem power state * * This function will be called when there's a modem power state change. * * Return: void */ static void pld_pcie_notify_handler(struct pci_dev *pdev, int state) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->modem_status) pld_context->ops->modem_status(&pdev->dev, PLD_BUS_TYPE_PCIE, state); } /** * pld_pcie_uevent() - update wlan driver status callback function * @pdev: PCIE device * @status: driver uevent status * * This function will be called when platform driver wants to update wlan * driver's status. * * Return: void */ static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status) { struct pld_context *pld_context; struct pld_uevent_data data = {0}; pld_context = pld_get_global_context(); if (!pld_context) return; switch (status) { case CNSS_RECOVERY: data.uevent = PLD_FW_RECOVERY_START; break; case CNSS_FW_DOWN: data.uevent = PLD_FW_DOWN; break; case CNSS_SYS_REBOOT: data.uevent = PLD_SYS_REBOOT; break; default: goto out; } if (pld_context->ops->uevent) pld_context->ops->uevent(&pdev->dev, &data); out: return; } #ifdef WLAN_FEATURE_SSR_DRIVER_DUMP static int pld_pcie_collect_driver_dump(struct pci_dev *pdev, struct cnss_ssr_driver_dump_entry *input_array, size_t *num_entries) { struct pld_context *pld_context; struct pld_driver_ops *ops; int ret = -EINVAL; pld_context = pld_get_global_context(); ops = pld_context->ops; if (ops->collect_driver_dump) { ret = ops->collect_driver_dump(&pdev->dev, PLD_BUS_TYPE_PCIE, input_array, num_entries); } return ret; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) /** * pld_bus_event_type_convert() - Convert enum cnss_bus_event_type * to enum pld_bus_event * @etype: enum cnss_bus_event_type value * * This function will convert enum cnss_bus_event_type to * enum pld_bus_event. * * Return: enum pld_bus_event */ static inline enum pld_bus_event pld_bus_event_type_convert(enum cnss_bus_event_type etype) { enum pld_bus_event pld_etype = PLD_BUS_EVENT_INVALID; switch (etype) { case BUS_EVENT_PCI_LINK_DOWN: pld_etype = PLD_BUS_EVENT_PCIE_LINK_DOWN; break; default: break; } return pld_etype; } /** * pld_pcie_update_event() - update wlan driver status callback function * @pdev: PCIE device * @uevent_data: driver uevent data * * This function will be called when platform driver wants to update wlan * driver's status. * * Return: 0 for success, non zero for error code */ static int pld_pcie_update_event(struct pci_dev *pdev, struct cnss_uevent_data *uevent_data) { struct pld_context *pld_context; struct pld_uevent_data data = {0}; struct cnss_hang_event *hang_event; pld_context = pld_get_global_context(); if (!pld_context || !uevent_data) return -EINVAL; switch (uevent_data->status) { case CNSS_HANG_EVENT: if (!uevent_data->data) return -EINVAL; hang_event = (struct cnss_hang_event *)uevent_data->data; data.uevent = PLD_FW_HANG_EVENT; data.hang_data.hang_event_data = hang_event->hang_event_data; data.hang_data.hang_event_data_len = hang_event->hang_event_data_len; break; case CNSS_BUS_EVENT: { struct cnss_bus_event *bus_evt = uevent_data->data; if (!bus_evt) return -EINVAL; data.uevent = PLD_BUS_EVENT; /* Process uevent_data->data if any */ data.bus_data.etype = pld_bus_event_type_convert(bus_evt->etype); data.bus_data.event_data = bus_evt->event_data; break; } default: return 0; } if (pld_context->ops->uevent) pld_context->ops->uevent(&pdev->dev, &data); return 0; } #endif #ifdef FEATURE_RUNTIME_PM /** * pld_pcie_runtime_suspend() - PM runtime suspend * @pdev: PCIE device * * PM runtime suspend callback function. * * Return: int */ static int pld_pcie_runtime_suspend(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->runtime_suspend) return pld_context->ops->runtime_suspend(&pdev->dev, PLD_BUS_TYPE_PCIE); return -ENODEV; } /** * pld_pcie_runtime_resume() - PM runtime resume * @pdev: PCIE device * * PM runtime resume callback function. * * Return: int */ static int pld_pcie_runtime_resume(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (pld_context->ops->runtime_resume) return pld_context->ops->runtime_resume(&pdev->dev, PLD_BUS_TYPE_PCIE); return -ENODEV; } #endif #ifdef FEATURE_GET_DRIVER_MODE /** * pld_pcie_get_mode() - Get current WLAN driver mode * * This function is to get current driver mode * * Return: mission mode or ftm mode */ static enum cnss_driver_mode pld_pcie_get_mode(void) { struct pld_context *pld_ctx = pld_get_global_context(); enum cnss_driver_mode cnss_mode = CNSS_MISSION; if (!pld_ctx) return cnss_mode; switch (pld_ctx->mode) { case QDF_GLOBAL_MISSION_MODE: cnss_mode = CNSS_MISSION; break; case QDF_GLOBAL_WALTEST_MODE: cnss_mode = CNSS_WALTEST; break; case QDF_GLOBAL_FTM_MODE: cnss_mode = CNSS_FTM; break; case QDF_GLOBAL_COLDBOOT_CALIB_MODE: cnss_mode = CNSS_CALIBRATION; break; case QDF_GLOBAL_EPPING_MODE: cnss_mode = CNSS_EPPING; break; case QDF_GLOBAL_QVIT_MODE: cnss_mode = CNSS_QVIT; break; default: cnss_mode = CNSS_MISSION; break; } return cnss_mode; } #endif #endif #ifdef CONFIG_PM #ifdef CONFIG_PLD_PCIE_CNSS /** * pld_pcie_suspend() - Suspend callback function for power management * @pdev: PCIE device * @state: power state * * This function is to suspend the PCIE device when power management is * enabled. * * Return: void */ static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state) { struct pld_context *pld_context; pld_context = pld_get_global_context(); return pld_context->ops->suspend(&pdev->dev, PLD_BUS_TYPE_PCIE, state); } /** * pld_pcie_resume() - Resume callback function for power management * @pdev: PCIE device * * This function is to resume the PCIE device when power management is * enabled. * * Return: void */ static int pld_pcie_resume(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE); } /** * pld_pcie_suspend_noirq() - Complete the actions started by suspend() * @pdev: PCI device * * Complete the actions started by suspend(). Carry out any additional * operations required for suspending the device that might be racing * with its driver's interrupt handler, which is guaranteed not to run * while suspend_noirq() is being executed. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_suspend_noirq(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (!pld_context) return -EINVAL; if (pld_context->ops->suspend_noirq) return pld_context->ops-> suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE); return 0; } /** * pld_pcie_resume_noirq() - Prepare for the execution of resume() * @pdev: PCI device * * Prepare for the execution of resume() by carrying out any additional * operations required for resuming the device that might be racing with * its driver's interrupt handler, which is guaranteed not to run while * resume_noirq() is being executed. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_resume_noirq(struct pci_dev *pdev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (!pld_context) return -EINVAL; if (pld_context->ops->resume_noirq) return pld_context->ops-> resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE); return 0; } #else /** * pld_pcie_pm_suspend() - Suspend callback function for power management * @dev: device * * This function is to suspend the PCIE device when power management is * enabled. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_pm_suspend(struct device *dev) { struct pld_context *pld_context; pm_message_t state = { .event = PM_EVENT_SUSPEND }; pld_context = pld_get_global_context(); return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state); } /** * pld_pcie_pm_resume() - Resume callback function for power management * @dev: device * * This function is to resume the PCIE device when power management is * enabled. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_pm_resume(struct device *dev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE); } /** * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend() * @dev: device * * Complete the actions started by suspend(). Carry out any additional * operations required for suspending the device that might be racing * with its driver's interrupt handler, which is guaranteed not to run * while suspend_noirq() is being executed. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_pm_suspend_noirq(struct device *dev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (!pld_context) return -EINVAL; if (pld_context->ops->suspend_noirq) return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE); return 0; } /** * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume() * @dev: device * * Prepare for the execution of resume() by carrying out any additional * operations required for resuming the device that might be racing with * its driver's interrupt handler, which is guaranteed not to run while * resume_noirq() is being executed. * * Return: 0 for success * Non zero failure code for errors */ static int pld_pcie_pm_resume_noirq(struct device *dev) { struct pld_context *pld_context; pld_context = pld_get_global_context(); if (!pld_context) return -EINVAL; if (pld_context->ops->resume_noirq) return pld_context->ops-> resume_noirq(dev, PLD_BUS_TYPE_PCIE); return 0; } #endif #endif static struct pci_device_id pld_pcie_id_table[] = { #ifdef CONFIG_AR6320_SUPPORT { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, #elif defined(QCA_WIFI_QCA6290) { 0x17cb, 0x1100, PCI_ANY_ID, PCI_ANY_ID }, #elif defined(QCA_WIFI_QCA6390) { 0x17cb, 0x1101, PCI_ANY_ID, PCI_ANY_ID }, #elif defined(QCA_WIFI_QCA6490) { 0x17cb, 0x1103, PCI_ANY_ID, PCI_ANY_ID }, #elif defined(QCA_WIFI_KIWI) #if defined(QCA_WIFI_PEACH) { 0x17cb, 0x110E, PCI_ANY_ID, PCI_ANY_ID }, #elif defined(QCA_WIFI_MANGO) { 0x17cb, 0x110A, PCI_ANY_ID, PCI_ANY_ID }, #else { 0x17cb, 0x1107, PCI_ANY_ID, PCI_ANY_ID }, #endif #elif defined(QCN7605_SUPPORT) { 0x17cb, 0x1102, PCI_ANY_ID, PCI_ANY_ID }, #else { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, #endif { 0 } }; #ifdef MULTI_IF_NAME #define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME #else #define PLD_PCIE_OPS_NAME "pld_pcie" #endif #ifdef CONFIG_PLD_PCIE_CNSS #ifdef FEATURE_RUNTIME_PM struct cnss_wlan_runtime_ops runtime_pm_ops = { .runtime_suspend = pld_pcie_runtime_suspend, .runtime_resume = pld_pcie_runtime_resume, }; #endif struct cnss_wlan_driver pld_pcie_ops = { .name = PLD_PCIE_OPS_NAME, .id_table = pld_pcie_id_table, .probe = pld_pcie_probe, .remove = pld_pcie_remove, .idle_restart = pld_pcie_idle_restart_cb, .idle_shutdown = pld_pcie_idle_shutdown_cb, .reinit = pld_pcie_reinit, .shutdown = pld_pcie_shutdown, .crash_shutdown = pld_pcie_crash_shutdown, .modem_status = pld_pcie_notify_handler, .update_status = pld_pcie_uevent, #ifdef WLAN_FEATURE_SSR_DRIVER_DUMP .collect_driver_dump = pld_pcie_collect_driver_dump, #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) .update_event = pld_pcie_update_event, #endif #ifdef CONFIG_PM .suspend = pld_pcie_suspend, .resume = pld_pcie_resume, .suspend_noirq = pld_pcie_suspend_noirq, .resume_noirq = pld_pcie_resume_noirq, #endif #ifdef FEATURE_RUNTIME_PM .runtime_ops = &runtime_pm_ops, #endif #ifdef FEATURE_GET_DRIVER_MODE .get_driver_mode = pld_pcie_get_mode, #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) .chip_version = CHIP_VERSION, #endif .set_therm_cdev_state = pld_pcie_set_thermal_state, }; int pld_pcie_register_driver(void) { return cnss_wlan_register_driver(&pld_pcie_ops); } void pld_pcie_unregister_driver(void) { cnss_wlan_unregister_driver(&pld_pcie_ops); } #else #ifdef CONFIG_PM static const struct dev_pm_ops pld_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume) .suspend_noirq = pld_pcie_pm_suspend_noirq, .resume_noirq = pld_pcie_pm_resume_noirq, }; #endif struct pci_driver pld_pcie_ops = { .name = PLD_PCIE_OPS_NAME, .id_table = pld_pcie_id_table, .probe = pld_pcie_probe, .remove = pld_pcie_remove, .driver = { #ifdef CONFIG_PM .pm = &pld_pm_ops, #endif }, }; int pld_pcie_register_driver(void) { return pci_register_driver(&pld_pcie_ops); } void pld_pcie_unregister_driver(void) { pci_unregister_driver(&pld_pcie_ops); } #endif int pld_pcie_get_ce_id(struct device *dev, int irq) { int ce_id = irq - 100; if (ce_id < CE_COUNT_MAX && ce_id >= 0) return ce_id; return -EINVAL; } #ifdef CONFIG_PLD_PCIE_CNSS #ifdef CONFIG_SHADOW_V3 static inline void pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, struct pld_wlan_enable_cfg *config) { cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg; cfg->shadow_reg_v3_cfg = (struct cnss_shadow_reg_v3_cfg *) config->shadow_reg_v3_cfg; } #else static inline void pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, struct pld_wlan_enable_cfg *config) { } #endif int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, enum pld_driver_mode mode, const char *host_version) { struct cnss_wlan_enable_cfg cfg; enum cnss_driver_mode cnss_mode; cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *) config->ce_tgt_cfg; cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *) config->ce_svc_cfg; cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *) config->shadow_reg_cfg; cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg; cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *) config->shadow_reg_v2_cfg; cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid; if (config->rri_over_ddr_cfg_valid) { cfg.rri_over_ddr_cfg.base_addr_low = config->rri_over_ddr_cfg.base_addr_low; cfg.rri_over_ddr_cfg.base_addr_high = config->rri_over_ddr_cfg.base_addr_high; } pld_pcie_populate_shadow_v3_cfg(&cfg, config); switch (mode) { case PLD_FTM: cnss_mode = CNSS_FTM; break; case PLD_EPPING: cnss_mode = CNSS_EPPING; break; default: cnss_mode = CNSS_MISSION; break; } return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version); } int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode) { return cnss_wlan_disable(dev, CNSS_OFF); } int pld_pcie_get_fw_files_for_target(struct device *dev, struct pld_fw_files *pfw_files, u32 target_type, u32 target_version) { int ret = 0; struct cnss_fw_files cnss_fw_files; if (!pfw_files) return -ENODEV; memset(pfw_files, 0, sizeof(*pfw_files)); ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files, target_type, target_version); if (ret) return ret; scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.image_file); scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.board_data); scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.otp_data); scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.utf_file); scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.utf_board_data); scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.epping_file); scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s", cnss_fw_files.evicted_data); return 0; } int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap) { int ret = 0; struct cnss_platform_cap cnss_cap; if (!cap) return -ENODEV; ret = cnss_get_platform_cap(dev, &cnss_cap); if (ret) return ret; memcpy(cap, &cnss_cap, sizeof(*cap)); return 0; } int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info) { int ret = 0, i; struct cnss_soc_info cnss_info = {0}; if (!info) return -ENODEV; ret = cnss_get_soc_info(dev, &cnss_info); if (ret) return ret; info->v_addr = cnss_info.va; info->p_addr = cnss_info.pa; info->chip_id = cnss_info.chip_id; info->chip_family = cnss_info.chip_family; info->board_id = cnss_info.board_id; info->soc_id = cnss_info.soc_id; info->fw_version = cnss_info.fw_version; strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp, sizeof(info->fw_build_timestamp)); info->device_version.family_number = cnss_info.device_version.family_number; info->device_version.device_number = cnss_info.device_version.device_number; info->device_version.major_version = cnss_info.device_version.major_version; info->device_version.minor_version = cnss_info.device_version.minor_version; for (i = 0; i < PLD_MAX_DEV_MEM_NUM; i++) { info->dev_mem_info[i].start = cnss_info.dev_mem_info[i].start; info->dev_mem_info[i].size = cnss_info.dev_mem_info[i].size; } strlcpy(info->fw_build_id, cnss_info.fw_build_id, sizeof(info->fw_build_id)); return 0; } void pld_pcie_schedule_recovery_work(struct device *dev, enum pld_recovery_reason reason) { enum cnss_recovery_reason cnss_reason; switch (reason) { case PLD_REASON_LINK_DOWN: cnss_reason = CNSS_REASON_LINK_DOWN; break; default: cnss_reason = CNSS_REASON_DEFAULT; break; } cnss_schedule_recovery(dev, cnss_reason); } void pld_pcie_device_self_recovery(struct device *dev, enum pld_recovery_reason reason) { enum cnss_recovery_reason cnss_reason; switch (reason) { case PLD_REASON_LINK_DOWN: cnss_reason = CNSS_REASON_LINK_DOWN; break; default: cnss_reason = CNSS_REASON_DEFAULT; break; } cnss_self_recovery(dev, cnss_reason); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) int pld_pcie_set_wfc_mode(struct device *dev, enum pld_wfc_mode wfc_mode) { struct cnss_wfc_cfg cfg; int ret; switch (wfc_mode) { case PLD_WFC_MODE_OFF: cfg.mode = CNSS_WFC_MODE_OFF; break; case PLD_WFC_MODE_ON: cfg.mode = CNSS_WFC_MODE_ON; break; default: ret = -EINVAL; goto out; } ret = cnss_set_wfc_mode(dev, cfg); out: return ret; } #endif #endif #endif