From c4df5e5e5d45ea3b7178fc136ed1fcf6fce875c2 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Wed, 17 Jun 2020 21:04:18 +0530 Subject: [PATCH] qcacld-3.0: Add PLD ops to notify thermal level change Add PLD layer support using which the platform driver sends thermal state change notification to WLAN host. The callback contains state variable to store the current thermal state. Add WHUNT support to validate host implementation. Change-Id: I5039eae967f940a7809a4b6e6d523362819fb28a --- core/pld/inc/pld_common.h | 39 +++++++++++++++ core/pld/src/pld_common.c | 88 ++++++++++++++++++++++++++++++++++ core/pld/src/pld_ipci.c | 31 ++++++++++++ core/pld/src/pld_ipci.h | 41 ++++++++++++++++ core/pld/src/pld_pcie_fw_sim.c | 61 +++++++++++++++++++++++ core/pld/src/pld_pcie_fw_sim.h | 41 ++++++++++++++++ 6 files changed, 301 insertions(+) diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h index 58bbafb4da6cf..22407634a1547 100644 --- a/core/pld/inc/pld_common.h +++ b/core/pld/inc/pld_common.h @@ -385,6 +385,11 @@ enum pld_wlan_time_sync_trigger_type { * hardware or at the request of software. * @suspend_noirq: optional operation, complete the actions started by suspend() * @resume_noirq: optional operation, prepare for the execution of resume() + * @set_curr_therm_cdev_state: optional operation, will be called when there is + * change in the thermal level triggered by the thermal + * subsystem thus requiring mitigation actions. This will + * be called every time there is a change in the state + * and after driver load. */ struct pld_driver_ops { int (*probe)(struct device *dev, @@ -422,6 +427,9 @@ struct pld_driver_ops { enum pld_bus_type bus_type); int (*resume_noirq)(struct device *dev, enum pld_bus_type bus_type); + int (*set_curr_therm_cdev_state)(struct device *dev, + unsigned long state, + int mon_id); }; int pld_init(void); @@ -862,6 +870,37 @@ int pld_pci_read_config_dword(struct pci_dev *pdev, int offset, uint32_t *val); * Non zero failure code for errors */ int pld_pci_write_config_dword(struct pci_dev *pdev, int offset, uint32_t val); + +/** + * pld_thermal_register() - Register the thermal device with the thermal system + * @dev: The device structure + * @state: The max state to be configured on registration + * @mon_id: Thermal cooling device ID + * + * Return: Error code on error + */ +int pld_thermal_register(struct device *dev, unsigned long state, int mon_id); + +/** + * pld_thermal_unregister() - Unregister the device with the thermal system + * @dev: The device structure + * @mon_id: Thermal cooling device ID + * + * Return: None + */ +void pld_thermal_unregister(struct device *dev, int mon_id); + +/** + * pld_get_thermal_state() - Get the current thermal state from the PLD + * @dev: The device structure + * @thermal_state: param to store the current thermal state + * @mon_id: Thermal cooling device ID + * + * Return: Non-zero code for error; zero for success + */ +int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state, + int mon_id); + #if IS_ENABLED(CONFIG_WCNSS_MEM_PRE_ALLOC) && defined(FEATURE_SKB_PRE_ALLOC) /** diff --git a/core/pld/src/pld_common.c b/core/pld/src/pld_common.c index aa353165285b5..4aa92c1eac0af 100644 --- a/core/pld/src/pld_common.c +++ b/core/pld/src/pld_common.c @@ -2862,6 +2862,94 @@ int pld_idle_restart(struct device *dev, return errno; } +int pld_thermal_register(struct device *dev, + unsigned long max_state, int mon_id) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_thermal_register(dev, max_state, + mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_thermal_register(dev, max_state, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + +void pld_thermal_unregister(struct device *dev, int mon_id) +{ + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_thermal_unregister(dev, mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + pld_ipci_thermal_unregister(dev, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } +} + +int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state, + int mon_id) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_get_thermal_state(dev, thermal_state, + mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_get_thermal_state(dev, thermal_state, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + #ifdef FEATURE_WLAN_TIME_SYNC_FTM /** * pld_get_audio_wlan_timestamp() - Get audio timestamp diff --git a/core/pld/src/pld_ipci.c b/core/pld/src/pld_ipci.c index 15c0208f5e383..fbffa4da6fec6 100644 --- a/core/pld/src/pld_ipci.c +++ b/core/pld/src/pld_ipci.c @@ -373,6 +373,36 @@ static int pld_ipci_idle_shutdown_cb(struct device *dev) return -ENODEV; } +/** + * pld_ipci_set_thermal_state() - Set thermal state for thermal mitigation + * @dev: 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_ipci_set_thermal_state(struct device *dev, + 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(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + #ifdef MULTI_IF_NAME #define PLD_IPCI_OPS_NAME "pld_ipci_" MULTI_IF_NAME #else @@ -395,6 +425,7 @@ struct icnss_driver_ops pld_ipci_ops = { .uevent = pld_ipci_uevent, .idle_restart = pld_ipci_idle_restart_cb, .idle_shutdown = pld_ipci_idle_shutdown_cb, + .set_therm_cdev_state = pld_ipci_set_thermal_state, }; /** diff --git a/core/pld/src/pld_ipci.h b/core/pld/src/pld_ipci.h index 116202fbe1d17..2ae349c5f0ce1 100644 --- a/core/pld/src/pld_ipci.h +++ b/core/pld/src/pld_ipci.h @@ -156,6 +156,26 @@ pld_ipci_qmi_send(struct device *dev, int type, void *cmd, { return 0; } + +static inline int pld_ipci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return 0; +} + +static inline void pld_ipci_thermal_unregister(struct device *dev, + int mon_id) +{ +} + +static inline int pld_ipci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return 0; +} + #else int pld_ipci_register_driver(void); void pld_ipci_unregister_driver(void); @@ -269,5 +289,26 @@ pld_ipci_qmi_send(struct device *dev, int type, void *cmd, { return icnss_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); } + +static inline int pld_ipci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return icnss_thermal_cdev_register(dev, max_state, mon_id); +} + +static inline void pld_ipci_thermal_unregister(struct device *dev, + int mon_id) +{ + icnss_thermal_cdev_unregister(dev, mon_id); +} + +static inline int pld_ipci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return icnss_get_curr_therm_cdev_state(dev, thermal_state, mon_id); +} + #endif #endif diff --git a/core/pld/src/pld_pcie_fw_sim.c b/core/pld/src/pld_pcie_fw_sim.c index 1c445a951dbeb..6a337e3d6f8f9 100644 --- a/core/pld/src/pld_pcie_fw_sim.c +++ b/core/pld/src/pld_pcie_fw_sim.c @@ -263,6 +263,36 @@ out: return; } +/** + * pld_pcie_fw_sim_set_thermal_state: Set thermal state for thermal mitigation + * @dev: 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_fw_sim_set_thermal_state(struct device *dev, + 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(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + static struct pci_device_id pld_pcie_fw_sim_id_table[] = { { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, @@ -509,6 +539,36 @@ out: return; } +/** + * pld_pcie_fw_sim_set_thermal_state: Set thermal state for thermal mitigation + * @dev: 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_fw_sim_set_thermal_state(struct device *dev, + 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(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + static struct pci_device_id pld_pcie_fw_sim_id_table[] = { { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, @@ -539,6 +599,7 @@ struct cnss_wlan_driver pld_pcie_fw_sim_ops = { .crash_shutdown = pld_pcie_fw_sim_crash_shutdown, .modem_status = pld_pcie_fw_sim_notify_handler, .update_status = pld_pcie_fw_sim_uevent, + .set_therm_cdev_state = pld_pcie_fw_sim_set_thermal_state, }; /** diff --git a/core/pld/src/pld_pcie_fw_sim.h b/core/pld/src/pld_pcie_fw_sim.h index a7773ce8bfe51..c23f5871e0837 100644 --- a/core/pld/src/pld_pcie_fw_sim.h +++ b/core/pld/src/pld_pcie_fw_sim.h @@ -128,6 +128,25 @@ static inline int pld_pcie_fw_sim_idle_restart(struct device *dev) { return 0; } + +static inline int pld_pcie_fw_sim_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_thermal_unregister(struct device *dev, + int mon_id) +{ +} + +static inline int pld_pcie_fw_sim_get_thermal_state(struct device *dev, + unsigned long *therm_state, + int mon_id) +{ + return 0; +} #else #include @@ -206,5 +225,27 @@ static inline int pld_pcie_fw_sim_idle_restart(struct device *dev) { return cnss_fw_sim_idle_restart(dev); } + +static inline int pld_pcie_fw_sim_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return cnss_fw_sim_thermal_cdev_register(dev, max_state, mon_id); +} + +static inline void pld_pcie_fw_sim_thermal_unregister(struct device *dev, + int mon_id) +{ + cnss_fw_sim_thermal_cdev_unregister(dev, mon_id); +} + +static inline int pld_pcie_fw_sim_get_thermal_state(struct device *dev, + unsigned long *therm_state, + int mon_id) +{ + return cnss_fw_sim_get_curr_therm_cdev_state(dev, therm_state, + mon_id); +} + #endif #endif