| /* |
| * Copyright (c) 2016 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * 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. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| #define pr_fmt(fmt) "wlan_pld:%s:%d:: " fmt, __func__, __LINE__ |
| |
| #include <linux/printk.h> |
| #include <linux/err.h> |
| #include <linux/string.h> |
| #include <linux/list.h> |
| #include <linux/slab.h> |
| #include <linux/pm.h> |
| |
| #ifdef CONFIG_CNSS |
| #include <net/cnss.h> |
| #endif |
| #ifdef CONFIG_ICNSS |
| #include <soc/qcom/icnss.h> |
| #endif |
| |
| #include "pld_pcie.h" |
| #include "pld_snoc.h" |
| #include "pld_common.h" |
| #include "pld_internal.h" |
| |
| #define PLD_PCIE_REGISTERED BIT(0) |
| #define PLD_SNOC_REGISTERED BIT(1) |
| #define PLD_BUS_MASK 0x3 |
| |
| static struct pld_context *pld_ctx; |
| |
| /** |
| * pld_init() - Initialize PLD module |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_init(void) |
| { |
| struct pld_context *pld_context; |
| |
| pld_context = kzalloc(sizeof(*pld_context), GFP_KERNEL); |
| if (!pld_context) |
| return -ENOMEM; |
| |
| spin_lock_init(&pld_context->pld_lock); |
| |
| INIT_LIST_HEAD(&pld_context->dev_list); |
| |
| pld_ctx = pld_context; |
| |
| return 0; |
| } |
| |
| /** |
| * pld_deinit() - Uninitialize PLD module |
| * |
| * Return: void |
| */ |
| void pld_deinit(void) |
| { |
| struct dev_node *dev_node; |
| struct pld_context *pld_context; |
| unsigned long flags; |
| |
| pld_context = pld_ctx; |
| if (!pld_context) { |
| pld_ctx = NULL; |
| return; |
| } |
| |
| spin_lock_irqsave(&pld_context->pld_lock, flags); |
| while (!list_empty(&pld_context->dev_list)) { |
| dev_node = list_first_entry(&pld_context->dev_list, |
| struct dev_node, list); |
| list_del(&dev_node->list); |
| kfree(dev_node); |
| } |
| spin_unlock_irqrestore(&pld_context->pld_lock, flags); |
| |
| kfree(pld_context); |
| |
| pld_ctx = NULL; |
| } |
| |
| /** |
| * pld_get_global_context() - Get global context of PLD |
| * |
| * Return: PLD global context |
| */ |
| struct pld_context *pld_get_global_context(void) |
| { |
| return pld_ctx; |
| } |
| |
| /** |
| * pld_get_bus_type() - Bus type of the device |
| * @dev: device |
| * |
| * Return: PLD bus type |
| */ |
| enum pld_bus_type pld_get_bus_type(struct device *dev) |
| { |
| struct pld_context *pld_context; |
| struct dev_node *dev_node; |
| unsigned long flags; |
| |
| pld_context = pld_get_global_context(); |
| |
| if (dev == NULL || pld_context == NULL) { |
| pr_err("Invalid info: dev %p, context %p\n", |
| dev, pld_context); |
| return PLD_BUS_TYPE_NONE; |
| } |
| |
| spin_lock_irqsave(&pld_context->pld_lock, flags); |
| list_for_each_entry(dev_node, &pld_context->dev_list, list) { |
| if (dev_node->dev == dev) { |
| spin_unlock_irqrestore(&pld_context->pld_lock, flags); |
| return dev_node->bus_type; |
| } |
| } |
| spin_unlock_irqrestore(&pld_context->pld_lock, flags); |
| |
| return PLD_BUS_TYPE_NONE; |
| } |
| |
| /** |
| * pld_register_driver() - Register driver to kernel |
| * @ops: Callback functions that will be registered to kernel |
| * |
| * This function should be called when other modules want to |
| * register platform driver callback functions to kernel. The |
| * probe() is expected to be called after registration if the |
| * device is online. |
| * |
| * Return: 0 for success |
| * pld_driver_state for errors |
| */ |
| int pld_register_driver(struct pld_driver_ops *ops) |
| { |
| int ret = 0; |
| struct pld_context *pld_context; |
| |
| pld_context = pld_get_global_context(); |
| |
| if (pld_context == NULL) { |
| pr_err("global context is NULL\n"); |
| ret = -ENODEV; |
| goto out; |
| } |
| |
| if (pld_context->ops) { |
| pr_err("driver already registered\n"); |
| ret = -EEXIST; |
| goto out; |
| } |
| |
| if (!ops || !ops->probe || !ops->remove || |
| !ops->suspend || !ops->resume) { |
| pr_err("Required callback functions are missing\n"); |
| ret = -EINVAL; |
| goto out; |
| } |
| |
| pld_context->ops = ops; |
| |
| if (0 == pld_pcie_register_driver()) |
| pld_context->pld_driver_state |= PLD_PCIE_REGISTERED; |
| if (0 == pld_snoc_register_driver()) |
| pld_context->pld_driver_state |= PLD_SNOC_REGISTERED; |
| |
| if ((PLD_BUS_MASK & pld_context->pld_driver_state) != PLD_BUS_MASK) { |
| pr_err("driver falied to register, state %x\n", |
| pld_context->pld_driver_state); |
| ret = pld_context->pld_driver_state; |
| } |
| |
| out: |
| return ret; |
| } |
| |
| /** |
| * pld_unregister_driver() - Unregister driver to kernel |
| * |
| * This function should be called when other modules want to |
| * unregister callback functions from kernel. The remove() is |
| * expected to be called after registration. |
| * |
| * Return: void |
| */ |
| void pld_unregister_driver(void) |
| { |
| struct pld_context *pld_context; |
| |
| pld_context = pld_get_global_context(); |
| |
| if (pld_context == NULL) { |
| pr_err("global context is NULL\n"); |
| return; |
| } |
| |
| if (pld_context->ops == NULL) { |
| pr_err("driver not registered\n"); |
| return; |
| } |
| |
| pld_pcie_unregister_driver(); |
| pld_snoc_unregister_driver(); |
| |
| pld_context->pld_driver_state = 0; |
| |
| pld_context->ops = NULL; |
| } |
| |
| /** |
| * pld_wlan_enable() - Enable WLAN |
| * @dev: device |
| * @config: WLAN configuration data |
| * @mode: WLAN mode |
| * @host_version: host software version |
| * |
| * This function enables WLAN FW. It passed WLAN configuration data, |
| * WLAN mode and host software version to FW. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, |
| enum pld_driver_mode mode, const char *host_version) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_wlan_enable(config, mode, host_version); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_wlan_enable(config, mode, host_version); |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_wlan_disable() - Disable WLAN |
| * @dev: device |
| * @mode: WLAN mode |
| * |
| * This function disables WLAN FW. It passes WLAN mode to FW. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_wlan_disable(mode); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_wlan_disable(mode); |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_set_fw_debug_mode() - Set FW debug mode |
| * @dev: device |
| * @enablefwlog: 0 for QXDM, 1 for WMI |
| * |
| * Switch Fw debug mode between DIAG logging and WMI logging. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_set_fw_debug_mode(struct device *dev, bool enablefwlog) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_set_fw_debug_mode(enablefwlog); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_default_fw_files() - Get default FW file names |
| * @pfw_files: buffer for FW file names |
| * |
| * Return default FW file names to the buffer. |
| * |
| * Return: void |
| */ |
| void pld_get_default_fw_files(struct pld_fw_files *pfw_files) |
| { |
| memset(pfw_files, 0, sizeof(*pfw_files)); |
| |
| strlcpy(pfw_files->image_file, PLD_IMAGE_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->board_data, PLD_BOARD_DATA_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->otp_data, PLD_OTP_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->utf_file, PLD_UTF_FIRMWARE_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->utf_board_data, PLD_BOARD_DATA_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->epping_file, PLD_EPPING_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->setup_file, PLD_SETUP_FILE, |
| PLD_MAX_FILE_NAME); |
| } |
| |
| /** |
| * pld_get_fw_files_for_target() - Get FW file names |
| * @dev: device |
| * @pfw_files: buffer for FW file names |
| * @target_type: target type |
| * @target_version: target version |
| * |
| * Return target specific FW file names to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_fw_files_for_target(struct device *dev, |
| struct pld_fw_files *pfw_files, |
| u32 target_type, u32 target_version) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_fw_files_for_target(pfw_files, |
| target_type, target_version); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_fw_image() - Get FW image descriptor |
| * @dev: device |
| * @image_desc_info: buffer for image descriptor |
| * |
| * Return FW image descriptor to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_fw_image(struct device *dev, |
| struct pld_image_desc_info *image_desc_info) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_fw_image(image_desc_info); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_is_pci_link_down() - Notification for pci link down event |
| * @dev: device |
| * |
| * Notify platform that pci link is down. |
| * |
| * Return: void |
| */ |
| void pld_is_pci_link_down(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_wlan_pci_link_down(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_pcie_shadow_control() - Control pci shadow registers |
| * @dev: device |
| * @enable: 0 for disable, 1 for enable |
| * |
| * This function is for suspend/resume. It can control if we |
| * use pci shadow registers (for saving config space) or not. |
| * During suspend we disable it to avoid config space corruption. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_pcie_shadow_control(struct device *dev, bool enable) |
| { |
| int ret = 0; |
| |
| /* cnss_shadow_control is not supported on BF64.0.3 kernel yet |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_shadow_control(enable); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| */ |
| return ret; |
| } |
| |
| /** |
| * pld_get_codeswap_struct() - Get codeswap structure |
| * @dev: device |
| * @swap_seg: buffer to codeswap information |
| * |
| * Return codeswap structure information to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_codeswap_struct(struct device *dev, |
| struct pld_codeswap_codeseg_info *swap_seg) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_codeswap_struct(swap_seg); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_set_wlan_unsafe_channel() - Set unsafe channel |
| * @dev: device |
| * @unsafe_ch_list: unsafe channel list |
| * @ch_count: number of channel |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_set_wlan_unsafe_channel(struct device *dev, |
| u16 *unsafe_ch_list, u16 ch_count) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_set_wlan_unsafe_channel(unsafe_ch_list, |
| ch_count); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_wlan_unsafe_channel() - Get unsafe channel |
| * @dev: device |
| * @unsafe_ch_list: buffer to unsafe channel list |
| * @ch_count: number of channel |
| * @buf_len: buffer length |
| * |
| * Return WLAN unsafe channel to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list, |
| u16 *ch_count, u16 buf_len) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_get_wlan_unsafe_channel(unsafe_ch_list, |
| ch_count, buf_len); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_wlan_set_dfs_nol() - Set DFS info |
| * @dev: device |
| * @info: DFS info |
| * @info_len: info length |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_wlan_set_dfs_nol(struct device *dev, void *info, u16 info_len) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_wlan_set_dfs_nol(info, info_len); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_wlan_get_dfs_nol() - Get DFS info |
| * @dev: device |
| * @info: buffer to DFS info |
| * @info_len: info length |
| * |
| * Return DFS info to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_wlan_get_dfs_nol(struct device *dev, void *info, u16 info_len) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_wlan_get_dfs_nol(info, info_len); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_schedule_recovery_work() - Schedule recovery work |
| * @dev: device |
| * |
| * Schedule a system self recovery work. |
| * |
| * Return: void |
| */ |
| void pld_schedule_recovery_work(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_schedule_recovery_work(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_wlan_pm_control() - WLAN PM control on PCIE |
| * @dev: device |
| * @vote: 0 for enable PCIE PC, 1 for disable PCIE PC |
| * |
| * This is for PCIE power collaps control during suspend/resume. |
| * When PCIE power collaps is disabled, WLAN FW can access memory |
| * through PCIE when system is suspended. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_wlan_pm_control(struct device *dev, bool vote) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_wlan_pm_control(vote); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_virt_ramdump_mem() - Get virtual ramdump memory |
| * @dev: device |
| * @size: buffer to virtual memory size |
| * |
| * Return: virtual ramdump memory address |
| */ |
| void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size) |
| { |
| void *mem = NULL; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| mem = cnss_get_virt_ramdump_mem(size); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return mem; |
| } |
| |
| /** |
| * pld_device_crashed() - Notification for device crash event |
| * @dev: device |
| * |
| * Notify subsystem a device crashed event. A subsystem restart |
| * is expected to happen after calling this function. |
| * |
| * Return: void |
| */ |
| void pld_device_crashed(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_device_crashed(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_device_self_recovery() - Device self recovery |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_device_self_recovery(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_device_self_recovery(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_intr_notify_q6() - Notify Q6 FW interrupts |
| * @dev: device |
| * |
| * Notify Q6 that a FW interrupt is triggered. |
| * |
| * Return: void |
| */ |
| void pld_intr_notify_q6(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_intr_notify_q6(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_request_pm_qos() - Request system PM |
| * @dev: device |
| * @qos_val: request value |
| * |
| * It votes for the value of aggregate QoS expectations. |
| * |
| * Return: void |
| */ |
| void pld_request_pm_qos(struct device *dev, u32 qos_val) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_request_pm_qos(qos_val); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_remove_pm_qos() - Remove system PM |
| * @dev: device |
| * |
| * Remove the vote request for Qos expectations. |
| * |
| * Return: void |
| */ |
| void pld_remove_pm_qos(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_remove_pm_qos(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_request_bus_bandwidth() - Request bus bandwidth |
| * @dev: device |
| * @bandwidth: bus bandwidth |
| * |
| * Votes for HIGH/MEDIUM/LOW bus bandwidth. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_request_bus_bandwidth(struct device *dev, int bandwidth) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_request_bus_bandwidth(bandwidth); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_platform_cap() - Get platform capabilities |
| * @dev: device |
| * @cap: buffer to the capabilities |
| * |
| * Return capabilities to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_platform_cap(cap); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_set_driver_status() - Set driver status |
| * @dev: device |
| * @status: driver status |
| * |
| * Return: void |
| */ |
| void pld_set_driver_status(struct device *dev, enum pld_driver_status status) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_set_driver_status(status); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_get_bmi_setup() - Get BMI setup |
| * @dev: device |
| * |
| * BMI read/write test should be run if BMI test is enabled. |
| * |
| * Return: BMI test setup |
| */ |
| int pld_get_bmi_setup(struct device *dev) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_get_bmi_setup(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_sha_hash() - Get sha hash number |
| * @dev: device |
| * @data: input data |
| * @data_len: data length |
| * @hash_idx: hash index |
| * @out: output buffer |
| * |
| * Return computed hash to the out buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_sha_hash(struct device *dev, const u8 *data, |
| u32 data_len, u8 *hash_idx, u8 *out) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_get_sha_hash(data, data_len, |
| hash_idx, out); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_fw_ptr() - Get secure FW memory address |
| * @dev: device |
| * |
| * Return: secure memory address |
| */ |
| void *pld_get_fw_ptr(struct device *dev) |
| { |
| void *ptr = NULL; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ptr = cnss_get_fw_ptr(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ptr; |
| } |
| |
| /** |
| * pld_auto_suspend() - Auto suspend |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_auto_suspend(struct device *dev) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_auto_suspend(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_auto_resume() - Auto resume |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_auto_resume(struct device *dev) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = cnss_auto_resume(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_ce_request_irq() - Register IRQ for CE |
| * @dev: device |
| * @ce_id: CE number |
| * @handler: IRQ callback function |
| * @flags: IRQ flags |
| * @name: IRQ name |
| * @ctx: IRQ context |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_ce_request_irq(struct device *dev, unsigned int ce_id, |
| irqreturn_t (*handler)(int, void *), |
| unsigned long flags, const char *name, void *ctx) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = icnss_ce_request_irq(ce_id, handler, flags, name, ctx); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_ce_free_irq() - Free IRQ for CE |
| * @dev: device |
| * @ce_id: CE number |
| * @ctx: IRQ context |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = icnss_ce_free_irq(ce_id, ctx); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_enable_irq() - Enable IRQ for CE |
| * @dev: device |
| * @ce_id: CE number |
| * |
| * Return: void |
| */ |
| void pld_enable_irq(struct device *dev, unsigned int ce_id) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| icnss_enable_irq(ce_id); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_disable_irq() - Disable IRQ for CE |
| * @dev: device |
| * @ce_id: CE number |
| * |
| * Return: void |
| */ |
| void pld_disable_irq(struct device *dev, unsigned int ce_id) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| icnss_disable_irq(ce_id); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_get_soc_info() - Get SOC information |
| * @dev: device |
| * @info: buffer to SOC information |
| * |
| * Return SOC info to the buffer. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_get_soc_info(struct device *dev, struct pld_soc_info *info) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_get_soc_info(info); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_ce_id() - Get CE number for the provided IRQ |
| * @dev: device |
| * @irq: IRQ number |
| * |
| * Return: CE number |
| */ |
| int pld_get_ce_id(struct device *dev, int irq) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = icnss_get_ce_id(irq); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_ce_id(irq); |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_lock_pm_sem() - Lock PM semaphore |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_lock_pm_sem(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_lock_pm_sem(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_release_pm_sem() - Release PM semaphore |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_release_pm_sem(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| cnss_release_pm_sem(); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |