mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-14 19:15:35 +00:00
13b6fdb0b4
changes: 1. WCSWREL-191: Fixed the error when loading module param from user config for SD8801 2. WCSWREL-186: Fixed the issue of mlanutl failing on kernel higher than L5.15 3. Fixed low throughput issue for WPA3 SAE 4. Added driver change for WLAN throughput improvement on 8997 SoC 5. Updated README to recommend not to use WEP/TKIP for all chipsets 6. WCSWREL-180: Fix P2P test fail on kernel higher than L5.12 7. WCSWREL-156: kernel_write/kernel_read not allowed by drivers for L5.10 kernel GKI buildou 8. Alternative for pm_qos_add_request/pm_qos_remove_request Signed-off-by: Sherry Sun <sherry.sun@nxp.com> Approved-by: Tian Yang <yang.tian@nxp.com>
2453 lines
62 KiB
C
2453 lines
62 KiB
C
/** @file moal_pcie.c
|
|
*
|
|
* @brief This file contains PCIE IF (interface) module
|
|
* related functions.
|
|
*
|
|
*
|
|
* Copyright 2008-2021 NXP
|
|
*
|
|
* This software file (the File) is distributed by NXP
|
|
* under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the License). You may use, redistribute and/or modify the File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available by writing to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*
|
|
*/
|
|
|
|
/********************************************************
|
|
Change log:
|
|
02/01/2012: initial version
|
|
********************************************************/
|
|
|
|
#include <linux/firmware.h>
|
|
|
|
#include "moal_pcie.h"
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70)
|
|
#ifdef IMX_SUPPORT
|
|
#include <linux/busfreq-imx.h>
|
|
#endif
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
#include <net/addrconf.h>
|
|
#endif
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
#define DRV_NAME "NXP mdriver PCIe"
|
|
|
|
/* PCIE resume handler */
|
|
static int woal_pcie_resume(struct pci_dev *pdev);
|
|
static void woal_pcie_reg_dbg(moal_handle *phandle);
|
|
static void woal_pcie_unregister_dev(moal_handle *handle);
|
|
static void woal_pcie_cleanup(pcie_service_card *card);
|
|
static mlan_status woal_pcie_init(pcie_service_card *card);
|
|
|
|
/** WLAN IDs */
|
|
static const struct pci_device_id wlan_ids[] = {
|
|
#ifdef PCIE8897
|
|
{
|
|
PCIE_VENDOR_ID_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W8897P,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
#endif
|
|
#ifdef PCIE8997
|
|
{
|
|
PCIE_VENDOR_ID_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W8997P,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
{
|
|
PCIE_VENDOR_ID_V2_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W8997P,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
#endif
|
|
#ifdef PCIE9097
|
|
{
|
|
PCIE_VENDOR_ID_V2_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W9097,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
#endif
|
|
#ifdef PCIE9098
|
|
{
|
|
PCIE_VENDOR_ID_V2_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W9098P_FN0,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
{
|
|
PCIE_VENDOR_ID_V2_NXP,
|
|
PCIE_DEVICE_ID_NXP_88W9098P_FN1,
|
|
PCI_ANY_ID,
|
|
PCI_ANY_ID,
|
|
0,
|
|
0,
|
|
},
|
|
#endif
|
|
{},
|
|
};
|
|
/* moal interface ops */
|
|
static moal_if_ops pcie_ops;
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
static mlan_status woal_pcie_preinit(struct pci_dev *pdev);
|
|
|
|
/** @brief This function updates the card types
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param card A Pointer to card
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_u16 woal_update_card_type(t_void *card)
|
|
{
|
|
pcie_service_card *cardp_pcie = (pcie_service_card *)card;
|
|
t_u16 card_type = 0;
|
|
|
|
/* Update card type */
|
|
#ifdef PCIE8897
|
|
if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W8897P) {
|
|
card_type = CARD_TYPE_PCIE8897;
|
|
moal_memcpy_ext(NULL, driver_version, CARD_PCIE8897,
|
|
strlen(CARD_PCIE8897), strlen(driver_version));
|
|
moal_memcpy_ext(NULL,
|
|
driver_version + strlen(INTF_CARDTYPE) +
|
|
strlen(KERN_VERSION),
|
|
V15, strlen(V15),
|
|
strlen(driver_version) - strlen(INTF_CARDTYPE) -
|
|
strlen(KERN_VERSION));
|
|
}
|
|
#endif
|
|
#ifdef PCIE8997
|
|
if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W8997P) {
|
|
card_type = CARD_TYPE_PCIE8997;
|
|
moal_memcpy_ext(NULL, driver_version, CARD_PCIE8997,
|
|
strlen(CARD_PCIE8997), strlen(driver_version));
|
|
moal_memcpy_ext(NULL,
|
|
driver_version + strlen(INTF_CARDTYPE) +
|
|
strlen(KERN_VERSION),
|
|
V16, strlen(V16),
|
|
strlen(driver_version) - strlen(INTF_CARDTYPE) -
|
|
strlen(KERN_VERSION));
|
|
}
|
|
#endif
|
|
#ifdef PCIE9097
|
|
if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9097) {
|
|
card_type = CARD_TYPE_PCIE9097;
|
|
moal_memcpy_ext(NULL, driver_version, CARD_PCIEIW620,
|
|
strlen(CARD_PCIEIW620), strlen(driver_version));
|
|
moal_memcpy_ext(NULL,
|
|
driver_version + strlen(INTF_CARDTYPE) +
|
|
strlen(KERN_VERSION),
|
|
V17, strlen(V17),
|
|
strlen(driver_version) - strlen(INTF_CARDTYPE) -
|
|
strlen(KERN_VERSION));
|
|
}
|
|
#endif
|
|
#ifdef PCIE9098
|
|
if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN0 ||
|
|
cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1) {
|
|
card_type = CARD_TYPE_PCIE9098;
|
|
moal_memcpy_ext(NULL, driver_version, CARD_PCIE9098,
|
|
strlen(CARD_PCIE9098), strlen(driver_version));
|
|
moal_memcpy_ext(NULL,
|
|
driver_version + strlen(INTF_CARDTYPE) +
|
|
strlen(KERN_VERSION),
|
|
V17, strlen(V17),
|
|
strlen(driver_version) - strlen(INTF_CARDTYPE) -
|
|
strlen(KERN_VERSION));
|
|
}
|
|
#endif
|
|
return card_type;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
|
/**
|
|
* @brief Function to process pre/post PCIe function level reset
|
|
*
|
|
* @param handle A pointer to moal_handle structure
|
|
* @param prepare True :- its a pre FLR call from the kernel
|
|
* False :- its a post FLR call from the kernel
|
|
* @param flr True: call from FLR
|
|
*
|
|
* Note: This function is mix of woal_switch_drv_mode() and
|
|
* remove_card(). Idea is to cleanup the software only without
|
|
* touching the PCIe specific code. Likewise, during init init
|
|
* everything, including hw, but do not reinitiate PCIe stack
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_do_flr(moal_handle *handle, bool prepare, bool flr_flag)
|
|
{
|
|
unsigned int i;
|
|
int index = 0;
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
moal_private *priv = NULL;
|
|
pcie_service_card *card = NULL;
|
|
int fw_serial_bkp = 0;
|
|
|
|
ENTER();
|
|
|
|
if (!handle) {
|
|
PRINTM(MINFO, "\n Handle null during prepare=%d\n", prepare);
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
card = (pcie_service_card *)handle->card;
|
|
|
|
if (card == NULL) {
|
|
PRINTM(MERROR, "The parameter 'card' is NULL\n");
|
|
LEAVE();
|
|
return (mlan_status)MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (!IS_PCIE8997(handle->card_type) &&
|
|
!IS_PCIE9097(handle->card_type) &&
|
|
!IS_PCIE9098(handle->card_type)) {
|
|
LEAVE();
|
|
return status;
|
|
}
|
|
|
|
if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
|
|
goto exit_sem_err;
|
|
|
|
if (!prepare)
|
|
goto perform_init;
|
|
|
|
/* Reset all interfaces */
|
|
priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
|
|
woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
|
|
|
|
/* Shutdown firmware */
|
|
handle->init_wait_q_woken = MFALSE;
|
|
status = mlan_shutdown_fw(handle->pmlan_adapter);
|
|
|
|
if (status == MLAN_STATUS_PENDING)
|
|
wait_event_interruptible(handle->init_wait_q,
|
|
handle->init_wait_q_woken);
|
|
|
|
if (atomic_read(&handle->rx_pending) ||
|
|
atomic_read(&handle->tx_pending) ||
|
|
atomic_read(&handle->ioctl_pending)) {
|
|
PRINTM(MERROR,
|
|
"ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
|
|
atomic_read(&handle->rx_pending),
|
|
atomic_read(&handle->tx_pending),
|
|
atomic_read(&handle->ioctl_pending));
|
|
}
|
|
|
|
unregister_inetaddr_notifier(&handle->woal_notifier);
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
unregister_inet6addr_notifier(&handle->woal_inet6_notifier);
|
|
#endif
|
|
|
|
/* Remove interface */
|
|
for (i = 0; i < handle->priv_num; i++)
|
|
woal_remove_interface(handle, i);
|
|
|
|
/* Unregister mlan */
|
|
if (handle->pmlan_adapter) {
|
|
mlan_unregister(handle->pmlan_adapter);
|
|
if (atomic_read(&handle->lock_count) ||
|
|
atomic_read(&handle->malloc_count) ||
|
|
atomic_read(&handle->mbufalloc_count)) {
|
|
PRINTM(MERROR,
|
|
"mlan has memory leak: lock_count=%d,"
|
|
" malloc_count=%d, mbufalloc_count=%d\n",
|
|
atomic_read(&handle->lock_count),
|
|
atomic_read(&handle->malloc_count),
|
|
atomic_read(&handle->mbufalloc_count));
|
|
}
|
|
if (atomic_read(&handle->malloc_cons_count)) {
|
|
PRINTM(MERROR,
|
|
"mlan has memory leak: malloc_cons_count=%d\n",
|
|
atomic_read(&handle->malloc_cons_count));
|
|
}
|
|
handle->pmlan_adapter = NULL;
|
|
}
|
|
|
|
goto exit;
|
|
|
|
perform_init:
|
|
handle->priv_num = 0;
|
|
|
|
/* Init SW */
|
|
if (woal_init_sw(handle)) {
|
|
PRINTM(MFATAL, "Software Init Failed\n");
|
|
goto err_init_fw;
|
|
}
|
|
|
|
#ifdef PCIE9098
|
|
if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
|
|
mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 1);
|
|
else
|
|
#endif
|
|
/* Update pcie_int_mode in mlan adapter */
|
|
mlan_set_int_mode(handle->pmlan_adapter,
|
|
handle->params.pcie_int_mode, 0);
|
|
|
|
/* Init FW and HW */
|
|
/* Load wlan only binary */
|
|
if (flr_flag) {
|
|
fw_serial_bkp = moal_extflg_isset(handle, EXT_FW_SERIAL);
|
|
moal_extflg_clear(handle, EXT_FW_SERIAL);
|
|
woal_update_firmware_name(handle);
|
|
}
|
|
if (woal_init_fw(handle)) {
|
|
PRINTM(MFATAL, "Firmware Init Failed\n");
|
|
woal_pcie_reg_dbg(handle);
|
|
if (fw_serial_bkp)
|
|
moal_extflg_set(handle, EXT_FW_SERIAL);
|
|
goto err_init_fw;
|
|
}
|
|
if (flr_flag && fw_serial_bkp)
|
|
moal_extflg_set(handle, EXT_FW_SERIAL);
|
|
if (IS_PCIE9098(handle->card_type))
|
|
handle->event_fw_dump = MTRUE;
|
|
exit:
|
|
MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
|
|
exit_sem_err:
|
|
LEAVE();
|
|
return status;
|
|
|
|
err_init_fw:
|
|
if ((handle->hardware_status == HardwareStatusFwReady) ||
|
|
(handle->hardware_status == HardwareStatusReady)) {
|
|
PRINTM(MINFO, "shutdown mlan\n");
|
|
handle->init_wait_q_woken = MFALSE;
|
|
status = mlan_shutdown_fw(handle->pmlan_adapter);
|
|
if (status == MLAN_STATUS_PENDING)
|
|
wait_event_interruptible(handle->init_wait_q,
|
|
handle->init_wait_q_woken);
|
|
}
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
|
|
wakeup_source_trash(&handle->ws);
|
|
#else
|
|
wake_lock_destroy(&handle->wake_lock);
|
|
#endif
|
|
#ifdef CONFIG_PROC_FS
|
|
woal_proc_exit(handle);
|
|
#endif
|
|
/* Unregister device */
|
|
PRINTM(MINFO, "unregister device\n");
|
|
woal_pcie_unregister_dev(handle);
|
|
handle->surprise_removed = MTRUE;
|
|
#ifdef REASSOCIATION
|
|
if (handle->reassoc_thread.pid)
|
|
wake_up_interruptible(&handle->reassoc_thread.wait_q);
|
|
/* waiting for main thread quit */
|
|
while (handle->reassoc_thread.pid)
|
|
woal_sched_timeout(2);
|
|
#endif /* REASSOCIATION */
|
|
woal_terminate_workqueue(handle);
|
|
woal_free_moal_handle(handle);
|
|
|
|
for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
|
|
if (m_handle[index] == handle)
|
|
break;
|
|
}
|
|
if (index < MAX_MLAN_ADAPTER)
|
|
m_handle[index] = NULL;
|
|
card->handle = NULL;
|
|
MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
LEAVE();
|
|
return (mlan_status)MLAN_STATUS_FAILURE;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function handles PCIE driver probe
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
* @param id A pointer to pci_device_id structure
|
|
*
|
|
* @return error code
|
|
*/
|
|
static int woal_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
{
|
|
pcie_service_card *card = NULL;
|
|
t_u16 card_type = 0;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X rev=%d\n", pdev->vendor,
|
|
pdev->device, pdev->revision);
|
|
|
|
/* Preinit PCIE device so allocate PCIE memory can be successful */
|
|
if (woal_pcie_preinit(pdev)) {
|
|
PRINTM(MFATAL, "MOAL PCIE preinit failed\n");
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
card = kzalloc(sizeof(pcie_service_card), GFP_KERNEL);
|
|
if (!card) {
|
|
PRINTM(MERROR, "%s: failed to alloc memory\n", __func__);
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
card->dev = pdev;
|
|
|
|
card_type = woal_update_card_type(card);
|
|
if (!card_type) {
|
|
PRINTM(MERROR, "pcie probe: woal_update_card_type() failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto err;
|
|
}
|
|
woal_pcie_init(card);
|
|
|
|
if (woal_add_card(card, &card->dev->dev, &pcie_ops, card_type) ==
|
|
NULL) {
|
|
woal_pcie_cleanup(card);
|
|
PRINTM(MERROR, "%s: failed\n", __func__);
|
|
ret = -EFAULT;
|
|
goto err;
|
|
}
|
|
|
|
#ifdef IMX_SUPPORT
|
|
woal_regist_oob_wakeup_irq(card->handle);
|
|
#endif /* IMX_SUPPORT */
|
|
|
|
LEAVE();
|
|
return ret;
|
|
err:
|
|
kfree(card);
|
|
if (pci_is_enabled(pdev))
|
|
pci_disable_device(pdev);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles PCIE driver remove
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
*
|
|
* @return error code
|
|
*/
|
|
static void woal_pcie_remove(struct pci_dev *dev)
|
|
{
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
|
|
ENTER();
|
|
card = pci_get_drvdata(dev);
|
|
if (!card) {
|
|
PRINTM(MINFO, "PCIE card removed from slot\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
handle = card->handle;
|
|
if (!handle || !handle->priv_num) {
|
|
PRINTM(MINFO, "PCIE card handle removed\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
handle->surprise_removed = MTRUE;
|
|
|
|
#ifdef IMX_SUPPORT
|
|
woal_unregist_oob_wakeup_irq(card->handle);
|
|
#endif /* IMX_SUPPORT */
|
|
woal_remove_card(card);
|
|
woal_pcie_cleanup(card);
|
|
kfree(card);
|
|
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Handle suspend
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
* @param state PM state message
|
|
*
|
|
* @return error code
|
|
*/
|
|
static int woal_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
{
|
|
pcie_service_card *cardp;
|
|
moal_handle *handle = NULL;
|
|
moal_handle *ref_handle = NULL;
|
|
int i;
|
|
int ret = MLAN_STATUS_SUCCESS;
|
|
int hs_actived;
|
|
mlan_ds_ps_info pm_info;
|
|
int keep_power = 0;
|
|
|
|
ENTER();
|
|
if (pdev) {
|
|
cardp = (pcie_service_card *)pci_get_drvdata(pdev);
|
|
if (!cardp || !cardp->handle) {
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
PRINTM(MERROR, "PCIE device is not specified\n");
|
|
LEAVE();
|
|
return -ENOSYS;
|
|
}
|
|
|
|
handle = cardp->handle;
|
|
if (handle->second_mac)
|
|
PRINTM(MCMND, "<--- Enter woal_pcie_suspend# --->\n");
|
|
else
|
|
PRINTM(MCMND, "<--- Enter woal_pcie_suspend --->\n");
|
|
if (handle->is_suspended == MTRUE) {
|
|
PRINTM(MWARN, "Device already suspended\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
if (handle->fw_dump) {
|
|
PRINTM(MMSG, "suspend not allowed while FW dump!");
|
|
ret = -EBUSY;
|
|
goto done;
|
|
}
|
|
for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
|
|
if (handle->priv[i] &&
|
|
(GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
|
|
woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
|
|
}
|
|
handle->suspend_fail = MFALSE;
|
|
memset(&pm_info, 0, sizeof(pm_info));
|
|
#define MAX_RETRY_NUM 8
|
|
for (i = 0; i < MAX_RETRY_NUM; i++) {
|
|
if (MLAN_STATUS_SUCCESS ==
|
|
woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
|
|
&pm_info)) {
|
|
if (pm_info.is_suspend_allowed == MTRUE)
|
|
break;
|
|
else
|
|
PRINTM(MMSG,
|
|
"Suspend not allowed and retry again\n");
|
|
}
|
|
woal_sched_timeout(100);
|
|
}
|
|
if (pm_info.is_suspend_allowed == MFALSE) {
|
|
PRINTM(MMSG, "Suspend not allowed\n");
|
|
ret = -EBUSY;
|
|
goto done;
|
|
}
|
|
|
|
for (i = 0; i < handle->priv_num; i++)
|
|
netif_device_detach(handle->priv[i]->netdev);
|
|
if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER))
|
|
keep_power = MTRUE;
|
|
else
|
|
keep_power = MFALSE;
|
|
|
|
if (keep_power) {
|
|
/* Enable Host Sleep */
|
|
hs_actived = woal_enable_hs(
|
|
woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
|
|
if (hs_actived == MTRUE) {
|
|
/* Indicate device suspended */
|
|
handle->is_suspended = MTRUE;
|
|
} else {
|
|
PRINTM(MMSG, "HS not actived, suspend fail!");
|
|
handle->suspend_fail = MTRUE;
|
|
for (i = 0; i < handle->priv_num; i++)
|
|
netif_device_attach(handle->priv[i]->netdev);
|
|
ret = -EBUSY;
|
|
goto done;
|
|
}
|
|
}
|
|
woal_flush_workqueue(handle);
|
|
if (!keep_power) {
|
|
woal_do_flr(handle, true, false);
|
|
handle->surprise_removed = MTRUE;
|
|
handle->is_suspended = MTRUE;
|
|
}
|
|
#ifdef IMX_SUPPORT
|
|
woal_enable_oob_wakeup_irq(handle);
|
|
#endif /* IMX_SUPPORT */
|
|
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
|
|
pci_save_state(pdev);
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
if (ref_handle && ref_handle->is_suspended)
|
|
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
|
done:
|
|
PRINTM(MCMND, "<--- Leave woal_pcie_suspend --->\n");
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Handle resume
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
*
|
|
* @return error code
|
|
*/
|
|
static int woal_pcie_resume(struct pci_dev *pdev)
|
|
{
|
|
moal_handle *handle;
|
|
pcie_service_card *cardp;
|
|
int keep_power = 0;
|
|
int i;
|
|
|
|
ENTER();
|
|
if (pdev) {
|
|
cardp = (pcie_service_card *)pci_get_drvdata(pdev);
|
|
if (!cardp || !cardp->handle) {
|
|
PRINTM(MERROR, "Card or handle is not valid\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
PRINTM(MERROR, "PCIE device is not specified\n");
|
|
LEAVE();
|
|
return -ENOSYS;
|
|
}
|
|
handle = cardp->handle;
|
|
if (handle->second_mac)
|
|
PRINTM(MCMND, "<--- Enter woal_pcie_resume# --->\n");
|
|
else
|
|
PRINTM(MCMND, "<--- Enter woal_pcie_resume --->\n");
|
|
if (handle->is_suspended == MFALSE) {
|
|
PRINTM(MWARN, "Device already resumed\n");
|
|
goto done;
|
|
}
|
|
handle->is_suspended = MFALSE;
|
|
|
|
if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER))
|
|
keep_power = MTRUE;
|
|
else
|
|
keep_power = MFALSE;
|
|
|
|
pci_set_power_state(pdev, PCI_D0);
|
|
pci_restore_state(pdev);
|
|
pci_enable_wake(pdev, PCI_D0, 0);
|
|
if (!keep_power) {
|
|
handle->surprise_removed = MFALSE;
|
|
woal_do_flr(handle, false, false);
|
|
} else {
|
|
if (woal_check_driver_status(handle)) {
|
|
PRINTM(MERROR, "Resuem, device is in hang state\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
for (i = 0; i < handle->priv_num; i++)
|
|
netif_device_attach(handle->priv[i]->netdev);
|
|
|
|
woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
|
|
MOAL_NO_WAIT);
|
|
#ifdef IMX_SUPPORT
|
|
woal_disable_oob_wakeup_irq(handle);
|
|
#endif /* IMX_SUPPORT */
|
|
}
|
|
done:
|
|
PRINTM(MCMND, "<--- Leave woal_pcie_resume --->\n");
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
|
/**
|
|
* @brief Pcie reset prepare handler
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
*/
|
|
static void woal_pcie_reset_prepare(struct pci_dev *pdev)
|
|
{
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
moal_handle *ref_handle = NULL;
|
|
|
|
ENTER();
|
|
|
|
card = pci_get_drvdata(pdev);
|
|
if (!card) {
|
|
PRINTM(MINFO, "PCIE card removed from slot\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
handle = card->handle;
|
|
|
|
if (!handle) {
|
|
PRINTM(MINFO, "Invalid handle\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d Pre-FLR\n",
|
|
__func__, pdev->vendor, pdev->device, pdev->revision);
|
|
|
|
/* Kernel would be performing FLR after this notification.
|
|
* Cleanup up all software withouth cleaning anything related to
|
|
* PCIe and HW.
|
|
* Note. FW might not be healthy.
|
|
*/
|
|
// handle-> mac0 , ref_handle->second mac
|
|
if (handle->pref_mac) {
|
|
if (handle->second_mac) {
|
|
handle = (moal_handle *)handle->pref_mac;
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
} else {
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
}
|
|
}
|
|
handle->surprise_removed = MTRUE;
|
|
woal_do_flr(handle, true, true);
|
|
if (ref_handle) {
|
|
ref_handle->surprise_removed = MTRUE;
|
|
woal_do_flr(ref_handle, true, true);
|
|
}
|
|
|
|
LEAVE();
|
|
}
|
|
/**
|
|
* @brief Pcie reset done handler
|
|
*
|
|
* @param pdev A pointer to pci_dev structure
|
|
*/
|
|
static void woal_pcie_reset_done(struct pci_dev *pdev)
|
|
{
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
moal_handle *ref_handle = NULL;
|
|
ENTER();
|
|
|
|
card = pci_get_drvdata(pdev);
|
|
if (!card) {
|
|
PRINTM(MINFO, "PCIE card removed from slot\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
handle = card->handle;
|
|
if (!handle) {
|
|
PRINTM(MINFO, "Invalid handle\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d Post-FLR\n",
|
|
__func__, pdev->vendor, pdev->device, pdev->revision);
|
|
|
|
/* Kernel stores and restores PCIe function context before and
|
|
* after performing FLR, respectively.
|
|
*
|
|
* Reconfigure the sw and fw including fw redownload
|
|
*/
|
|
// handle-> mac0 , ref_handle->second mac
|
|
if (handle->pref_mac) {
|
|
if (handle->second_mac) {
|
|
handle = (moal_handle *)handle->pref_mac;
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
} else {
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
}
|
|
}
|
|
handle->surprise_removed = MFALSE;
|
|
woal_do_flr(handle, false, true);
|
|
if (ref_handle) {
|
|
ref_handle->surprise_removed = MFALSE;
|
|
woal_do_flr(ref_handle, false, true);
|
|
}
|
|
|
|
LEAVE();
|
|
}
|
|
#else
|
|
static void woal_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
|
|
{
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
moal_handle *ref_handle = NULL;
|
|
|
|
ENTER();
|
|
|
|
card = pci_get_drvdata(pdev);
|
|
if (!card) {
|
|
PRINTM(MINFO, "PCIE card removed from slot\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
handle = card->handle;
|
|
if (!handle) {
|
|
PRINTM(MINFO, "Invalid handle\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d %s\n",
|
|
__func__, pdev->vendor, pdev->device, pdev->revision,
|
|
prepare ? "Pre-FLR" : "Post-FLR");
|
|
|
|
// handle-> mac0 , ref_handle->second mac
|
|
if (handle->pref_mac) {
|
|
if (handle->second_mac) {
|
|
handle = (moal_handle *)handle->pref_mac;
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
} else {
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
}
|
|
}
|
|
|
|
if (prepare) {
|
|
/* Kernel would be performing FLR after this notification.
|
|
* Cleanup up all software withouth cleaning anything related to
|
|
* PCIe and HW.
|
|
* Note. FW might not be healthy.
|
|
*/
|
|
handle->surprise_removed = MTRUE;
|
|
woal_do_flr(handle, prepare, true);
|
|
if (ref_handle) {
|
|
ref_handle->surprise_removed = MTRUE;
|
|
woal_do_flr(ref_handle, prepare, true);
|
|
}
|
|
} else {
|
|
/* Kernel stores and restores PCIe function context before and
|
|
* after performing FLR, respectively.
|
|
*
|
|
* Reconfigure the sw and fw including fw redownload
|
|
*/
|
|
handle->surprise_removed = MFALSE;
|
|
woal_do_flr(handle, prepare, true);
|
|
if (ref_handle) {
|
|
ref_handle->surprise_removed = MFALSE;
|
|
woal_do_flr(ref_handle, prepare, true);
|
|
}
|
|
}
|
|
LEAVE();
|
|
}
|
|
#endif
|
|
|
|
static const struct pci_error_handlers woal_pcie_err_handler[] = {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
|
{
|
|
.reset_prepare = woal_pcie_reset_prepare,
|
|
.reset_done = woal_pcie_reset_done,
|
|
},
|
|
#else
|
|
{
|
|
.reset_notify = woal_pcie_reset_notify,
|
|
},
|
|
#endif
|
|
};
|
|
#endif // KERNEL_VERSION(3.18.0)
|
|
|
|
/* PCI Device Driver */
|
|
static struct pci_driver REFDATA wlan_pcie = {
|
|
.name = "wlan_pcie",
|
|
.id_table = wlan_ids,
|
|
.probe = woal_pcie_probe,
|
|
.remove = woal_pcie_remove,
|
|
#ifdef CONFIG_PM
|
|
/* Power Management Hooks */
|
|
.suspend = woal_pcie_suspend,
|
|
.resume = woal_pcie_resume,
|
|
#endif
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
|
.err_handler = woal_pcie_err_handler,
|
|
#endif
|
|
};
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief This function writes data into card register
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param reg Register offset
|
|
* @param data Value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_write_reg(moal_handle *handle, t_u32 reg,
|
|
t_u32 data)
|
|
{
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
|
|
iowrite32(data, card->pci_mmap1 + reg);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function reads data from card register
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param reg Register offset
|
|
* @param data Value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_read_reg(moal_handle *handle, t_u32 reg,
|
|
t_u32 *data)
|
|
{
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
*data = ioread32(card->pci_mmap1 + reg);
|
|
|
|
if (*data == MLAN_STATUS_FAILURE)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function writes multiple bytes into card memory
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param pmbuf Pointer to mlan_buffer structure
|
|
* @param port Port
|
|
* @param timeout Time out value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_write_data_sync(moal_handle *handle,
|
|
mlan_buffer *pmbuf, t_u32 port,
|
|
t_u32 timeout)
|
|
{
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function reads multiple bytes from card memory
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param pmbuf Pointer to mlan_buffer structure
|
|
* @param port Port
|
|
* @param timeout Time out value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_read_data_sync(moal_handle *handle,
|
|
mlan_buffer *pmbuf, t_u32 port,
|
|
t_u32 timeout)
|
|
{
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the interrupt.
|
|
*
|
|
* @param irq The irq no. of PCIE device
|
|
* @param dev_id A pointer to the pci_dev structure
|
|
*
|
|
* @return IRQ_HANDLED
|
|
*/
|
|
static irqreturn_t woal_pcie_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct pci_dev *pdev;
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
pdev = (struct pci_dev *)dev_id;
|
|
if (!pdev) {
|
|
PRINTM(MFATAL, "%s: pdev is NULL\n", (t_u8 *)pdev);
|
|
goto exit;
|
|
}
|
|
|
|
card = (pcie_service_card *)pci_get_drvdata(pdev);
|
|
if (!card || !card->handle) {
|
|
PRINTM(MFATAL, "%s: card=%p handle=%p\n", __func__, card,
|
|
card ? card->handle : NULL);
|
|
goto exit;
|
|
}
|
|
handle = card->handle;
|
|
if (handle->surprise_removed == MTRUE) {
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
PRINTM(MINFO, "*** IN PCIE IRQ ***\n");
|
|
handle->main_state = MOAL_RECV_INT;
|
|
if (handle->second_mac)
|
|
PRINTM(MINTR, "**\n");
|
|
else
|
|
PRINTM(MINTR, "*\n");
|
|
|
|
ret = mlan_interrupt(0xffff, handle->pmlan_adapter);
|
|
if (handle->is_suspended) {
|
|
PRINTM(MINTR, "Receive interrupt in hs_suspended\n");
|
|
goto exit;
|
|
}
|
|
queue_work(handle->workqueue, &handle->main_work);
|
|
|
|
exit:
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
return IRQ_HANDLED;
|
|
else
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the MSI-X interrupt.
|
|
*
|
|
* @param irq The irq no. of PCIE device
|
|
* @param dev_id A pointer to the msix_context structure
|
|
*
|
|
* @return IRQ_HANDLED
|
|
*/
|
|
static irqreturn_t woal_pcie_msix_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct pci_dev *pdev;
|
|
pcie_service_card *card;
|
|
moal_handle *handle;
|
|
msix_context *ctx = (msix_context *)dev_id;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
if (!ctx) {
|
|
PRINTM(MFATAL, "%s: ctx=%p is NULL\n", __func__, ctx);
|
|
goto exit;
|
|
}
|
|
|
|
pdev = ctx->dev;
|
|
|
|
if (!pdev) {
|
|
PRINTM(MFATAL, "%s: pdev is NULL\n", (t_u8 *)pdev);
|
|
goto exit;
|
|
}
|
|
|
|
card = (pcie_service_card *)pci_get_drvdata(pdev);
|
|
if (!card || !card->handle) {
|
|
PRINTM(MFATAL, "%s: card=%p handle=%p\n", __func__, card,
|
|
card ? card->handle : NULL);
|
|
goto exit;
|
|
}
|
|
handle = card->handle;
|
|
if (handle->surprise_removed == MTRUE) {
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto exit;
|
|
}
|
|
PRINTM(MINFO, "*** IN PCIE IRQ ***\n");
|
|
handle->main_state = MOAL_RECV_INT;
|
|
if (handle->second_mac)
|
|
PRINTM(MINTR, "**\n");
|
|
else
|
|
PRINTM(MINTR, "*\n");
|
|
ret = mlan_interrupt(ctx->msg_id, handle->pmlan_adapter);
|
|
queue_work(handle->workqueue, &handle->main_work);
|
|
|
|
exit:
|
|
if (ret == MLAN_STATUS_SUCCESS)
|
|
return IRQ_HANDLED;
|
|
else
|
|
return IRQ_NONE;
|
|
}
|
|
/**
|
|
* @brief This function pre-initializes the PCI-E host
|
|
* memory space, etc.
|
|
*
|
|
* @param handle A pointer to moal_handle structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_preinit(struct pci_dev *pdev)
|
|
{
|
|
int ret;
|
|
|
|
if (pdev->multifunction)
|
|
device_disable_async_suspend(&pdev->dev);
|
|
|
|
ret = pci_enable_device(pdev);
|
|
|
|
if (ret)
|
|
goto err_enable_dev;
|
|
|
|
pci_set_master(pdev);
|
|
|
|
PRINTM(MINFO, "Try set_consistent_dma_mask(32)\n");
|
|
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
PRINTM(MERROR, "set_dma_mask(32) failed\n");
|
|
goto err_set_dma_mask;
|
|
}
|
|
|
|
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
PRINTM(MERROR, "set_consistent_dma_mask(64) failed\n");
|
|
goto err_set_dma_mask;
|
|
}
|
|
return MLAN_STATUS_SUCCESS;
|
|
|
|
err_set_dma_mask:
|
|
pci_disable_device(pdev);
|
|
err_enable_dev:
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function initializes the PCI-E host
|
|
* memory space, etc.
|
|
*
|
|
* @param card A pointer to pcie_service_card structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_init(pcie_service_card *card)
|
|
{
|
|
struct pci_dev *pdev = NULL;
|
|
int ret;
|
|
|
|
pdev = card->dev;
|
|
pci_set_drvdata(pdev, card);
|
|
#if 0
|
|
ret = pci_enable_device(pdev);
|
|
if (ret)
|
|
goto err_enable_dev;
|
|
|
|
pci_set_master(pdev);
|
|
|
|
PRINTM(MINFO, "Try set_consistent_dma_mask(32)\n");
|
|
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
PRINTM(MERROR, "set_dma_mask(32) failed\n");
|
|
goto err_set_dma_mask;
|
|
}
|
|
|
|
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
PRINTM(MERROR, "set_consistent_dma_mask(64) failed\n");
|
|
goto err_set_dma_mask;
|
|
}
|
|
#endif
|
|
|
|
ret = pci_request_region(pdev, 0, DRV_NAME);
|
|
if (ret) {
|
|
PRINTM(MERROR, "req_reg(0) error\n");
|
|
goto err_req_region0;
|
|
}
|
|
card->pci_mmap = pci_iomap(pdev, 0, 0);
|
|
if (!card->pci_mmap) {
|
|
PRINTM(MERROR, "iomap(0) error\n");
|
|
goto err_iomap0;
|
|
}
|
|
ret = pci_request_region(pdev, 2, DRV_NAME);
|
|
if (ret) {
|
|
PRINTM(MERROR, "req_reg(2) error\n");
|
|
goto err_req_region2;
|
|
}
|
|
card->pci_mmap1 = pci_iomap(pdev, 2, 0);
|
|
if (!card->pci_mmap1) {
|
|
PRINTM(MERROR, "iomap(2) error\n");
|
|
goto err_iomap2;
|
|
}
|
|
|
|
PRINTM(MINFO,
|
|
"PCI memory map Virt0: %p PCI memory map Virt2: "
|
|
"%p\n",
|
|
card->pci_mmap, card->pci_mmap1);
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
|
|
err_iomap2:
|
|
pci_release_region(pdev, 2);
|
|
err_req_region2:
|
|
pci_iounmap(pdev, card->pci_mmap);
|
|
err_iomap0:
|
|
pci_release_region(pdev, 0);
|
|
err_req_region0:
|
|
#if 0
|
|
err_set_dma_mask:
|
|
#endif
|
|
|
|
#if 0
|
|
err_enable_dev:
|
|
#endif
|
|
pci_set_drvdata(pdev, NULL);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function registers the PCIE device
|
|
*
|
|
* @param handle A pointer to moal_handle structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_pcie_register_dev(moal_handle *handle)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pcie_service_card *card = NULL;
|
|
struct pci_dev *pdev = NULL;
|
|
unsigned char nvec;
|
|
unsigned char i, j;
|
|
ENTER();
|
|
|
|
if (!handle || !handle->card) {
|
|
PRINTM(MINFO, "%s: handle=%p card=%p\n", __FUNCTION__, handle,
|
|
handle ? handle->card : NULL);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
card = (pcie_service_card *)handle->card;
|
|
pdev = card->dev;
|
|
/* save adapter pointer in card */
|
|
card->handle = handle;
|
|
|
|
switch (pcie_int_mode) {
|
|
case PCIE_INT_MODE_MSIX:
|
|
pcie_int_mode = PCIE_INT_MODE_MSIX;
|
|
nvec = PCIE_NUM_MSIX_VECTORS;
|
|
|
|
for (i = 0; i < nvec; i++) {
|
|
card->msix_entries[i].entry = i;
|
|
}
|
|
|
|
/* Try to enable msix */
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
ret = pci_enable_msix_exact(pdev, card->msix_entries, nvec);
|
|
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */
|
|
ret = pci_enable_msix(pdev, card->msix_entries, nvec);
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
for (i = 0; i < nvec; i++) {
|
|
card->msix_contexts[i].dev = pdev;
|
|
card->msix_contexts[i].msg_id = i;
|
|
ret = request_irq(card->msix_entries[i].vector,
|
|
woal_pcie_msix_interrupt, 0,
|
|
"mrvl_pcie_msix",
|
|
&(card->msix_contexts[i]));
|
|
|
|
if (ret) {
|
|
PRINTM(MFATAL,
|
|
"request_irq failed: ret=%d\n",
|
|
ret);
|
|
for (j = 0; j < i; j++)
|
|
free_irq(card->msix_entries[j]
|
|
.vector,
|
|
&(card->msix_contexts
|
|
[i]));
|
|
pci_disable_msix(pdev);
|
|
break;
|
|
}
|
|
}
|
|
if (i == nvec)
|
|
break;
|
|
}
|
|
// follow through
|
|
|
|
/* fall through */
|
|
case PCIE_INT_MODE_MSI:
|
|
pcie_int_mode = PCIE_INT_MODE_MSI;
|
|
ret = pci_enable_msi(pdev);
|
|
if (ret == 0) {
|
|
ret = request_irq(pdev->irq, woal_pcie_interrupt, 0,
|
|
"mrvl_pcie_msi", pdev);
|
|
if (ret) {
|
|
PRINTM(MFATAL, "request_irq failed: ret=%d\n",
|
|
ret);
|
|
pci_disable_msi(pdev);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
// follow through
|
|
|
|
/* fall through */
|
|
case PCIE_INT_MODE_LEGACY:
|
|
pcie_int_mode = PCIE_INT_MODE_LEGACY;
|
|
ret = request_irq(pdev->irq, woal_pcie_interrupt, IRQF_SHARED,
|
|
"mrvl_pcie", pdev);
|
|
if (ret) {
|
|
PRINTM(MFATAL, "request_irq failed: ret=%d\n", ret);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
PRINTM(MFATAL, "pcie_int_mode %d failed\n", pcie_int_mode);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
break;
|
|
}
|
|
|
|
#ifdef PCIE9098
|
|
if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
|
|
mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 1);
|
|
else
|
|
#endif
|
|
mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 0);
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function cleans up the host memory spaces
|
|
*
|
|
* @param card A pointer to pcie_service_card structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void woal_pcie_cleanup(pcie_service_card *card)
|
|
{
|
|
struct pci_dev *pdev = NULL;
|
|
pdev = card->dev;
|
|
PRINTM(MINFO, "Clearing driver ready signature\n");
|
|
|
|
if (pdev) {
|
|
pci_iounmap(pdev, card->pci_mmap);
|
|
pci_iounmap(pdev, card->pci_mmap1);
|
|
|
|
if (pci_is_enabled(pdev))
|
|
pci_disable_device(pdev);
|
|
|
|
pci_release_region(pdev, 0);
|
|
pci_release_region(pdev, 2);
|
|
pci_set_drvdata(pdev, NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief This function unregisters the PCIE device
|
|
*
|
|
* @param handle A pointer to moal_handle structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static void woal_pcie_unregister_dev(moal_handle *handle)
|
|
{
|
|
pcie_service_card *card =
|
|
handle ? (pcie_service_card *)handle->card : NULL;
|
|
struct pci_dev *pdev = NULL;
|
|
unsigned char i;
|
|
unsigned char nvec;
|
|
ENTER();
|
|
|
|
if (card) {
|
|
pdev = card->dev;
|
|
PRINTM(MINFO, "%s(): calling free_irq()\n", __func__);
|
|
|
|
switch (pcie_int_mode) {
|
|
case PCIE_INT_MODE_MSIX:
|
|
nvec = PCIE_NUM_MSIX_VECTORS;
|
|
|
|
for (i = 0; i < nvec; i++)
|
|
synchronize_irq(card->msix_entries[i].vector);
|
|
|
|
for (i = 0; i < nvec; i++)
|
|
free_irq(card->msix_entries[i].vector,
|
|
&(card->msix_contexts[i]));
|
|
|
|
pci_disable_msix(pdev);
|
|
|
|
break;
|
|
|
|
case PCIE_INT_MODE_MSI:
|
|
free_irq(card->dev->irq, pdev);
|
|
pci_disable_msi(pdev);
|
|
break;
|
|
|
|
case PCIE_INT_MODE_LEGACY:
|
|
free_irq(card->dev->irq, pdev);
|
|
break;
|
|
|
|
default:
|
|
PRINTM(MFATAL, "pcie_int_mode %d failed\n",
|
|
pcie_int_mode);
|
|
break;
|
|
}
|
|
card->handle = NULL;
|
|
}
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief This function registers the IF module in bus driver
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status woal_pcie_bus_register(void)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
ENTER();
|
|
|
|
/* API registers the NXP PCIE driver */
|
|
if (pci_register_driver(&wlan_pcie)) {
|
|
PRINTM(MFATAL, "PCIE Driver Registration Failed \n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function de-registers the IF module in bus driver
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void woal_pcie_bus_unregister(void)
|
|
{
|
|
ENTER();
|
|
|
|
/* PCIE Driver Unregistration */
|
|
pci_unregister_driver(&wlan_pcie);
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
#define PCIE9098_DUMP_CTRL_REG 0x1C94
|
|
#define PCIE9098_DUMP_START_REG 0x1C98
|
|
#define PCIE9098_DUMP_END_REG 0x1C9F
|
|
#endif
|
|
#if defined(PCIE8897) || defined(PCIE8997)
|
|
#define DEBUG_DUMP_CTRL_REG 0xCF4
|
|
#define DEBUG_DUMP_START_REG 0xCF8
|
|
#define DEBUG_DUMP_END_REG 0xCFF
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
#define PCIE9098_SCRATCH_12_REG 0x1C90
|
|
#define PCIE9098_SCRATCH_14_REG 0x1C98
|
|
#define PCIE9098_SCRATCH_15_REG 0x1C9C
|
|
#define PCIE9098_DUMP_REG_START 0x1C20
|
|
#define PCIE9098_DUMP_REG_END 0x1C9C
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
#define PCIE_SCRATCH_12_REG 0x0CF0;
|
|
#define PCIE_SCRATCH_14_REG 0x0CF8;
|
|
#define PCIE_SCRATCH_15_REG 0x0CFC;
|
|
#define PCIE_DUMP_START_REG 0xC00
|
|
#define PCIE_DUMP_END_REG 0xCFC
|
|
#endif
|
|
/**
|
|
* @brief This function save the log of pcie register value
|
|
*
|
|
* @param phandle A pointer to moal_handle
|
|
* @param buffer A pointer to buffer saving log
|
|
*
|
|
* @return The length of this log
|
|
*/
|
|
static int woal_pcie_dump_reg_info(moal_handle *phandle, t_u8 *buffer)
|
|
{
|
|
char *drv_ptr = (char *)buffer;
|
|
t_u32 reg = 0, value = 0;
|
|
t_u8 i;
|
|
char buf[256], *ptr;
|
|
pcie_service_card *card = (pcie_service_card *)phandle->card;
|
|
int config_reg_table[] = {0x00, 0x04, 0x10, 0x18, 0x2c,
|
|
0x3c, 0x44, 0x80, 0x98, 0x170};
|
|
t_u32 dump_start_reg = 0;
|
|
t_u32 dump_end_reg = 0;
|
|
t_u32 scratch_14_reg = 0;
|
|
t_u32 scratch_15_reg = 0;
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
/* Tx/Rx/Event AMDA start address */
|
|
t_u32 adma_reg_table[] = {0x10000, 0x10800, 0x10880, 0x11000, 0x11080};
|
|
t_u8 j;
|
|
#endif
|
|
ENTER();
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
|
|
drv_ptr += sprintf(drv_ptr,
|
|
"------------PCIe Registers dump-------------\n");
|
|
drv_ptr += sprintf(drv_ptr, "Config Space Registers:\n");
|
|
for (i = 0; i < ARRAY_SIZE(config_reg_table); i++) {
|
|
pci_read_config_dword(card->dev, config_reg_table[i], &value);
|
|
drv_ptr += sprintf(drv_ptr, "reg:0x%02x value=0x%08x\n",
|
|
config_reg_table[i], value);
|
|
}
|
|
drv_ptr += sprintf(drv_ptr, "FW Scrach Registers:\n");
|
|
|
|
#if defined(PCIE8897) || defined(PCIE8997)
|
|
if (IS_PCIE8897(phandle->card_type) ||
|
|
IS_PCIE8997(phandle->card_type)) {
|
|
reg = PCIE_SCRATCH_12_REG;
|
|
dump_start_reg = PCIE_DUMP_START_REG;
|
|
dump_end_reg = PCIE_DUMP_END_REG;
|
|
scratch_14_reg = PCIE_SCRATCH_14_REG;
|
|
scratch_15_reg = PCIE_SCRATCH_15_REG;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
reg = PCIE9098_SCRATCH_12_REG;
|
|
dump_start_reg = PCIE9098_DUMP_REG_START;
|
|
dump_end_reg = PCIE9098_DUMP_REG_END;
|
|
scratch_14_reg = PCIE9098_SCRATCH_14_REG;
|
|
scratch_15_reg = PCIE9098_SCRATCH_15_REG;
|
|
}
|
|
#endif
|
|
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
drv_ptr += sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
|
|
for (i = 0; i < 2; i++) {
|
|
reg = scratch_14_reg;
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
drv_ptr +=
|
|
sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
|
|
|
|
reg = scratch_15_reg;
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
drv_ptr +=
|
|
sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
|
|
|
|
mdelay(100);
|
|
}
|
|
drv_ptr +=
|
|
sprintf(drv_ptr,
|
|
"Interface registers dump from offset 0x%x to 0x%x\n",
|
|
dump_start_reg, dump_end_reg);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = dump_start_reg; reg <= dump_end_reg; reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
drv_ptr += sprintf(drv_ptr, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
drv_ptr += sprintf(
|
|
drv_ptr,
|
|
"PCIE registers from offset 0x1c20 to 0x1c9c:\n");
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = 0x1c20; reg <= 0x1c9c; reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
drv_ptr += sprintf(drv_ptr, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
drv_ptr += sprintf(drv_ptr, "%s\n", buf);
|
|
}
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
drv_ptr += sprintf(drv_ptr,
|
|
"ADMA Tx/Rx/Event/Cmd/CmdResp registers:\n");
|
|
for (j = 0; j < ARRAY_SIZE(adma_reg_table); j++) {
|
|
drv_ptr += sprintf(
|
|
drv_ptr,
|
|
"ADMA registers dump from offset 0x%x to 0x%x\n",
|
|
adma_reg_table[j], adma_reg_table[j] + 0x68);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = adma_reg_table[j];
|
|
reg <= (adma_reg_table[j] + 0x68); reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
drv_ptr +=
|
|
sprintf(drv_ptr, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
drv_ptr += sprintf(drv_ptr, "%s\n", buf);
|
|
}
|
|
}
|
|
#endif
|
|
drv_ptr += sprintf(drv_ptr,
|
|
"-----------PCIe Registers dump End-----------\n");
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
|
|
LEAVE();
|
|
return drv_ptr - (char *)buffer;
|
|
}
|
|
|
|
/**
|
|
* @brief This function reads and displays PCIE scratch registers for debugging
|
|
*
|
|
* @param phandle A pointer to moal_handle
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void woal_pcie_reg_dbg(moal_handle *phandle)
|
|
{
|
|
t_u32 reg = 0, value = 0;
|
|
t_u8 i;
|
|
char buf[256], *ptr;
|
|
pcie_service_card *card = (pcie_service_card *)phandle->card;
|
|
int config_reg_table[] = {0x00, 0x04, 0x10, 0x18, 0x2c,
|
|
0x3c, 0x44, 0x80, 0x98, 0x170};
|
|
t_u32 dump_start_reg = 0;
|
|
t_u32 dump_end_reg = 0;
|
|
t_u32 scratch_14_reg = 0;
|
|
t_u32 scratch_15_reg = 0;
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
/* Tx/Rx/Event AMDA start address */
|
|
t_u32 adma_reg_table[] = {0x10000, 0x10800, 0x10880, 0x11000, 0x11080};
|
|
t_u8 j;
|
|
#endif
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
|
|
PRINTM(MMSG, "Config Space Registers:\n");
|
|
for (i = 0; i < ARRAY_SIZE(config_reg_table); i++) {
|
|
pci_read_config_dword(card->dev, config_reg_table[i], &value);
|
|
PRINTM(MERROR, "reg:0x%02x value=0x%08x\n", config_reg_table[i],
|
|
value);
|
|
}
|
|
PRINTM(MMSG, "FW Scrach Registers:\n");
|
|
#if defined(PCIE8897) || defined(PCIE8997)
|
|
if (IS_PCIE8897(phandle->card_type) ||
|
|
IS_PCIE8997(phandle->card_type)) {
|
|
reg = PCIE_SCRATCH_12_REG;
|
|
dump_start_reg = PCIE_DUMP_START_REG;
|
|
dump_end_reg = PCIE_DUMP_END_REG;
|
|
scratch_14_reg = PCIE_SCRATCH_14_REG;
|
|
scratch_15_reg = PCIE_SCRATCH_15_REG;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
reg = PCIE9098_SCRATCH_12_REG;
|
|
dump_start_reg = PCIE9098_DUMP_START_REG;
|
|
dump_end_reg = PCIE9098_DUMP_END_REG;
|
|
scratch_14_reg = PCIE9098_SCRATCH_14_REG;
|
|
scratch_15_reg = PCIE9098_SCRATCH_15_REG;
|
|
}
|
|
#endif
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
|
|
for (i = 0; i < 2; i++) {
|
|
reg = scratch_14_reg;
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
|
|
|
|
reg = scratch_15_reg;
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
|
|
|
|
mdelay(100);
|
|
}
|
|
PRINTM(MMSG, "Interface registers dump from offset 0x%x to 0x%x\n",
|
|
dump_start_reg, dump_end_reg);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = dump_start_reg; reg <= dump_end_reg; reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
PRINTM(MMSG, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
PRINTM(MMSG, "PCIE registers from offset 0x1c20 to 0x1c9c:\n");
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = 0x1c20; reg <= 0x1c9c; reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
PRINTM(MMSG, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
PRINTM(MMSG, "%s\n", buf);
|
|
}
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
PRINTM(MMSG, "ADMA Tx/Rx/Event/Cmd/CmdResp registers:\n");
|
|
for (j = 0; j < ARRAY_SIZE(adma_reg_table); j++) {
|
|
PRINTM(MMSG,
|
|
"ADMA registers dump from offset 0x%x to 0x%x\n",
|
|
adma_reg_table[j], adma_reg_table[j] + 0x68);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
i = 1;
|
|
for (reg = adma_reg_table[j];
|
|
reg <= (adma_reg_table[j] + 0x68); reg += 4) {
|
|
woal_pcie_read_reg(phandle, reg, &value);
|
|
ptr += sprintf(ptr, "%08x ", value);
|
|
if (!(i % 8)) {
|
|
PRINTM(MMSG, "%s\n", buf);
|
|
memset(buf, 0, sizeof(buf));
|
|
ptr = buf;
|
|
}
|
|
i++;
|
|
}
|
|
PRINTM(MMSG, "%s\n", buf);
|
|
}
|
|
}
|
|
#endif
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
|
|
}
|
|
|
|
#define DEBUG_FW_DONE 0xFF
|
|
#define MAX_POLL_TRIES 100
|
|
|
|
typedef enum {
|
|
DUMP_TYPE_ITCM = 0,
|
|
DUMP_TYPE_DTCM = 1,
|
|
DUMP_TYPE_SQRAM = 2,
|
|
DUMP_TYPE_IRAM = 3,
|
|
DUMP_TYPE_APU = 4,
|
|
DUMP_TYPE_CIU = 5,
|
|
DUMP_TYPE_ICU = 6,
|
|
DUMP_TYPE_MAC = 7,
|
|
} dumped_mem_type;
|
|
|
|
#define MAX_NAME_LEN 8
|
|
|
|
typedef struct {
|
|
t_u8 mem_name[MAX_NAME_LEN];
|
|
t_u8 *mem_Ptr;
|
|
struct file *pfile_mem;
|
|
t_u8 done_flag;
|
|
t_u8 type;
|
|
} memory_type_mapping;
|
|
|
|
#ifdef PCIE8897
|
|
#define DEBUG_HOST_READY_8897 0xEE
|
|
#define DEBUG_MEMDUMP_FINISH_8897 0xFE
|
|
static memory_type_mapping mem_type_mapping_tbl_8897[] = {
|
|
{"ITCM", NULL, NULL, 0xF0, FW_DUMP_TYPE_MEM_ITCM},
|
|
{"DTCM", NULL, NULL, 0xF1, FW_DUMP_TYPE_MEM_DTCM},
|
|
{"SQRAM", NULL, NULL, 0xF2, FW_DUMP_TYPE_MEM_SQRAM},
|
|
{"IRAM", NULL, NULL, 0xF3, FW_DUMP_TYPE_MEM_IRAM},
|
|
{"APU", NULL, NULL, 0xF4, FW_DUMP_TYPE_REG_APU},
|
|
{"CIU", NULL, NULL, 0xF5, FW_DUMP_TYPE_REG_CIU},
|
|
{"ICU", NULL, NULL, 0xF6, FW_DUMP_TYPE_REG_ICU},
|
|
{"MAC", NULL, NULL, 0xF7, FW_DUMP_TYPE_REG_MAC},
|
|
};
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
|
|
#define DEBUG_HOST_READY_8997 0xCC
|
|
#define DEBUG_HOST_EVENT_READY 0xAA
|
|
static memory_type_mapping mem_type_mapping_tbl_8997 = {"DUMP", NULL, NULL,
|
|
0xDD, 0x00};
|
|
|
|
#endif
|
|
|
|
#if defined(PCIE8897) || defined(PCIE8997) || defined(PCIE9098) || \
|
|
defined(PCIE9097)
|
|
/**
|
|
* @brief This function reads data by 8 bit from card register
|
|
*
|
|
* @param handle A Pointer to the moal_handle structure
|
|
* @param reg Register offset
|
|
* @param data Value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status woal_read_reg_eight_bit(moal_handle *handle, t_u32 reg,
|
|
t_u8 *data)
|
|
{
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
*data = ioread8(card->pci_mmap1 + reg);
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function read/write firmware
|
|
*
|
|
* @param phandle A pointer to moal_handle
|
|
* @param doneflag done flag
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
static rdwr_status woal_pcie_rdwr_firmware(moal_handle *phandle, t_u8 doneflag)
|
|
{
|
|
int ret = 0;
|
|
int tries = 0;
|
|
t_u8 ctrl_data = 0;
|
|
t_u32 reg_data = 0;
|
|
t_u32 debug_host_ready = 0;
|
|
t_u32 dump_ctrl_reg = 0;
|
|
|
|
#ifdef PCIE8897
|
|
if (IS_PCIE8897(phandle->card_type)) {
|
|
debug_host_ready = DEBUG_HOST_READY_8897;
|
|
dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
|
|
}
|
|
#endif
|
|
#if defined(PCIE8997)
|
|
if (IS_PCIE8997(phandle->card_type)) {
|
|
debug_host_ready = DEBUG_HOST_READY_8997;
|
|
dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
if (phandle->event_fw_dump)
|
|
debug_host_ready = DEBUG_HOST_EVENT_READY;
|
|
else
|
|
debug_host_ready = DEBUG_HOST_READY_8997;
|
|
dump_ctrl_reg = PCIE9098_DUMP_CTRL_REG;
|
|
}
|
|
#endif
|
|
|
|
ret = woal_pcie_write_reg(phandle, dump_ctrl_reg, debug_host_ready);
|
|
if (ret) {
|
|
PRINTM(MERROR, "PCIE Write ERR\n");
|
|
return RDWR_STATUS_FAILURE;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
if (phandle->event_fw_dump)
|
|
return RDWR_STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
ret = woal_pcie_read_reg(phandle, dump_ctrl_reg, ®_data);
|
|
if (ret) {
|
|
PRINTM(MERROR, "PCIE Read DEBUG_DUMP_CTRL_REG fail\n");
|
|
return RDWR_STATUS_FAILURE;
|
|
}
|
|
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
|
ret = woal_read_reg_eight_bit(phandle, dump_ctrl_reg,
|
|
&ctrl_data);
|
|
if (ret) {
|
|
PRINTM(MERROR, "PCIE READ ERR\n");
|
|
return RDWR_STATUS_FAILURE;
|
|
}
|
|
if (ctrl_data == DEBUG_FW_DONE)
|
|
break;
|
|
if (doneflag && ctrl_data == doneflag)
|
|
return RDWR_STATUS_DONE;
|
|
if (ctrl_data != debug_host_ready) {
|
|
PRINTM(MMSG, "The ctrl reg was changed, try again!\n");
|
|
ret = woal_pcie_write_reg(phandle, dump_ctrl_reg,
|
|
debug_host_ready);
|
|
if (ret) {
|
|
PRINTM(MERROR, "PCIE Write ERR\n");
|
|
return RDWR_STATUS_FAILURE;
|
|
}
|
|
}
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
|
|
usleep_range(99, 100);
|
|
#else
|
|
udelay(100);
|
|
#endif
|
|
}
|
|
if (ctrl_data == debug_host_ready) {
|
|
PRINTM(MERROR, "Fail to pull ctrl_data\n");
|
|
return RDWR_STATUS_FAILURE;
|
|
}
|
|
return RDWR_STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#ifdef PCIE8897
|
|
/**
|
|
* @brief This function dump firmware memory to file
|
|
*
|
|
* @param phandle A pointer to moal_handle
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void woal_pcie_dump_fw_info_v1(moal_handle *phandle)
|
|
{
|
|
int ret = 0;
|
|
unsigned int reg, reg_start, reg_end;
|
|
t_u8 *dbg_ptr = NULL;
|
|
t_u32 sec, usec;
|
|
t_u8 dump_num = 0;
|
|
t_u8 idx = 0;
|
|
t_u8 doneflag = 0;
|
|
rdwr_status stat;
|
|
t_u8 i = 0;
|
|
t_u8 read_reg = 0;
|
|
t_u32 memory_size = 0;
|
|
t_u32 memdump_finsh = 0;
|
|
t_u8 *end_ptr = NULL;
|
|
memory_type_mapping *mem_type_mapping_tbl = mem_type_mapping_tbl_8897;
|
|
|
|
if (!phandle) {
|
|
PRINTM(MERROR, "Could not dump firmwware info\n");
|
|
return;
|
|
}
|
|
if (!phandle->fw_dump_buf) {
|
|
ret = moal_vmalloc(phandle, FW_DUMP_INFO_LEN,
|
|
&(phandle->fw_dump_buf));
|
|
if (ret != MLAN_STATUS_SUCCESS || !phandle->fw_dump_buf) {
|
|
PRINTM(MERROR, "Failed to vmalloc fw dump bufffer\n");
|
|
return;
|
|
}
|
|
} else {
|
|
memset(phandle->fw_dump_buf, 0x00, FW_DUMP_INFO_LEN);
|
|
}
|
|
phandle->fw_dump_len = 0;
|
|
/* start dump fw memory */
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT START: %u.%06u ====\n", sec,
|
|
usec);
|
|
/* read the number of the memories which will dump */
|
|
if (RDWR_STATUS_FAILURE == woal_pcie_rdwr_firmware(phandle, doneflag))
|
|
goto done;
|
|
reg = DEBUG_DUMP_START_REG;
|
|
ret = woal_read_reg_eight_bit(phandle, reg, &dump_num);
|
|
if (ret) {
|
|
PRINTM(MMSG, "PCIE READ MEM NUM ERR\n");
|
|
goto done;
|
|
}
|
|
|
|
/* read the length of every memory which will dump */
|
|
for (idx = 0;
|
|
idx < dump_num && idx < ARRAY_SIZE(mem_type_mapping_tbl_8897);
|
|
idx++) {
|
|
if (RDWR_STATUS_FAILURE ==
|
|
woal_pcie_rdwr_firmware(phandle, doneflag))
|
|
goto done;
|
|
memory_size = 0;
|
|
reg = DEBUG_DUMP_START_REG;
|
|
for (i = 0; i < 4; i++) {
|
|
ret = woal_read_reg_eight_bit(phandle, reg, &read_reg);
|
|
if (ret) {
|
|
PRINTM(MMSG, "PCIE READ ERR\n");
|
|
goto done;
|
|
}
|
|
memory_size |= (read_reg << i * 8);
|
|
reg++;
|
|
}
|
|
if (memory_size == 0) {
|
|
PRINTM(MMSG, "Firmware Dump Finished!\n");
|
|
ret = woal_pcie_write_reg(phandle, DEBUG_DUMP_CTRL_REG,
|
|
memdump_finsh);
|
|
if (ret) {
|
|
PRINTM(MERROR,
|
|
"PCIE Write MEMDUMP_FINISH ERR\n");
|
|
goto done;
|
|
}
|
|
break;
|
|
} else {
|
|
PRINTM(MMSG, "%s_SIZE=0x%x\n",
|
|
mem_type_mapping_tbl[idx].mem_name, memory_size);
|
|
ret = moal_vmalloc(
|
|
phandle, memory_size + 1,
|
|
(t_u8 **)&mem_type_mapping_tbl[idx].mem_Ptr);
|
|
if ((ret != MLAN_STATUS_SUCCESS) ||
|
|
!mem_type_mapping_tbl[idx].mem_Ptr) {
|
|
PRINTM(MERROR,
|
|
"Error: vmalloc %s buffer failed!!!\n",
|
|
mem_type_mapping_tbl[idx].mem_name);
|
|
goto done;
|
|
}
|
|
dbg_ptr = mem_type_mapping_tbl[idx].mem_Ptr;
|
|
end_ptr = dbg_ptr + memory_size;
|
|
}
|
|
doneflag = mem_type_mapping_tbl[idx].done_flag;
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
|
|
mem_type_mapping_tbl[idx].mem_name, sec, usec);
|
|
do {
|
|
stat = woal_pcie_rdwr_firmware(phandle, doneflag);
|
|
if (RDWR_STATUS_FAILURE == stat)
|
|
goto done;
|
|
|
|
reg_start = DEBUG_DUMP_START_REG;
|
|
reg_end = DEBUG_DUMP_END_REG;
|
|
for (reg = reg_start; reg <= reg_end; reg++) {
|
|
ret = woal_read_reg_eight_bit(phandle, reg,
|
|
dbg_ptr);
|
|
if (ret) {
|
|
PRINTM(MMSG, "PCIE READ ERR\n");
|
|
goto done;
|
|
}
|
|
if (dbg_ptr < end_ptr)
|
|
dbg_ptr++;
|
|
else
|
|
PRINTM(MINFO,
|
|
"pre-allocced buf is not enough\n");
|
|
}
|
|
if (RDWR_STATUS_DONE == stat) {
|
|
PRINTM(MMSG, "%s done: size=0x%x\n",
|
|
mem_type_mapping_tbl[idx].mem_name,
|
|
(unsigned int)(dbg_ptr -
|
|
mem_type_mapping_tbl[idx]
|
|
.mem_Ptr));
|
|
woal_save_dump_info_to_buf(
|
|
phandle,
|
|
mem_type_mapping_tbl[idx].mem_Ptr,
|
|
memory_size,
|
|
mem_type_mapping_tbl[idx].type);
|
|
moal_vfree(phandle,
|
|
mem_type_mapping_tbl[idx].mem_Ptr);
|
|
mem_type_mapping_tbl[idx].mem_Ptr = NULL;
|
|
break;
|
|
}
|
|
} while (1);
|
|
}
|
|
woal_append_end_block(phandle);
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT END: %u.%06u ====\n", sec,
|
|
usec);
|
|
/* end dump fw memory */
|
|
done:
|
|
for (idx = 0;
|
|
idx < dump_num && idx < ARRAY_SIZE(mem_type_mapping_tbl_8897);
|
|
idx++) {
|
|
if (mem_type_mapping_tbl[idx].mem_Ptr) {
|
|
moal_vfree(phandle, mem_type_mapping_tbl[idx].mem_Ptr);
|
|
mem_type_mapping_tbl[idx].mem_Ptr = NULL;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
|
|
/**
|
|
* @brief This function dump firmware memory to file
|
|
*
|
|
* @param phandle A pointer to moal_handle
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void woal_pcie_dump_fw_info_v2(moal_handle *phandle)
|
|
{
|
|
int ret = 0;
|
|
unsigned int reg, reg_start, reg_end;
|
|
t_u8 *dbg_ptr = NULL;
|
|
t_u8 *tmp_ptr = NULL;
|
|
t_u32 sec, usec;
|
|
t_u8 dump_num = 0;
|
|
t_u8 doneflag = 0;
|
|
rdwr_status stat;
|
|
t_u32 memory_size = 0;
|
|
t_u8 *end_ptr = NULL;
|
|
memory_type_mapping *mem_type_mapping_tbl = &mem_type_mapping_tbl_8997;
|
|
t_u32 dump_start_reg = 0;
|
|
t_u32 dump_end_reg = 0;
|
|
|
|
if (!phandle) {
|
|
PRINTM(MERROR, "Could not dump firmwware info\n");
|
|
return;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
if (phandle->event_fw_dump) {
|
|
if (RDWR_STATUS_FAILURE !=
|
|
woal_pcie_rdwr_firmware(phandle, doneflag)) {
|
|
PRINTM(MMSG,
|
|
"====PCIE FW DUMP EVENT MODE START ====\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* start dump fw memory */
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT START: %u.%06u ====\n", sec,
|
|
usec);
|
|
/* read the number of the memories which will dump */
|
|
if (RDWR_STATUS_FAILURE == woal_pcie_rdwr_firmware(phandle, doneflag))
|
|
goto done;
|
|
#if defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
dump_start_reg = PCIE9098_DUMP_START_REG;
|
|
dump_end_reg = PCIE9098_DUMP_END_REG;
|
|
}
|
|
#endif
|
|
#ifdef PCIE8997
|
|
if (IS_PCIE8997(phandle->card_type)) {
|
|
dump_start_reg = DEBUG_DUMP_START_REG;
|
|
dump_end_reg = DEBUG_DUMP_END_REG;
|
|
}
|
|
#endif
|
|
reg = dump_start_reg;
|
|
ret = woal_read_reg_eight_bit(phandle, reg, &dump_num);
|
|
if (ret) {
|
|
PRINTM(MMSG, "PCIE READ MEM NUM ERR\n");
|
|
goto done;
|
|
}
|
|
|
|
memory_size = 0x80000;
|
|
ret = moal_vmalloc(phandle, memory_size + 1,
|
|
(t_u8 **)&mem_type_mapping_tbl->mem_Ptr);
|
|
if ((ret != MLAN_STATUS_SUCCESS) || !mem_type_mapping_tbl->mem_Ptr) {
|
|
PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n",
|
|
mem_type_mapping_tbl->mem_name);
|
|
goto done;
|
|
}
|
|
dbg_ptr = mem_type_mapping_tbl->mem_Ptr;
|
|
end_ptr = dbg_ptr + memory_size;
|
|
|
|
doneflag = mem_type_mapping_tbl->done_flag;
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
|
|
mem_type_mapping_tbl->mem_name, sec, usec);
|
|
do {
|
|
stat = woal_pcie_rdwr_firmware(phandle, doneflag);
|
|
if (RDWR_STATUS_FAILURE == stat)
|
|
goto done;
|
|
|
|
reg_start = dump_start_reg;
|
|
reg_end = dump_end_reg;
|
|
for (reg = reg_start; reg <= reg_end; reg++) {
|
|
ret = woal_read_reg_eight_bit(phandle, reg, dbg_ptr);
|
|
if (ret) {
|
|
PRINTM(MMSG, "PCIE READ ERR\n");
|
|
goto done;
|
|
}
|
|
dbg_ptr++;
|
|
if (dbg_ptr >= end_ptr) {
|
|
PRINTM(MINFO,
|
|
"pre-allocced buf is not enough\n");
|
|
ret = moal_vmalloc(phandle,
|
|
memory_size + 0x4000 + 1,
|
|
(t_u8 **)&tmp_ptr);
|
|
if ((ret != MLAN_STATUS_SUCCESS) || !tmp_ptr) {
|
|
PRINTM(MERROR,
|
|
"Error: vmalloc buffer failed!!!\n");
|
|
goto done;
|
|
}
|
|
moal_memcpy_ext(phandle, tmp_ptr,
|
|
mem_type_mapping_tbl->mem_Ptr,
|
|
memory_size,
|
|
memory_size + 0x4000);
|
|
moal_vfree(phandle,
|
|
mem_type_mapping_tbl->mem_Ptr);
|
|
mem_type_mapping_tbl->mem_Ptr = tmp_ptr;
|
|
tmp_ptr = NULL;
|
|
dbg_ptr = mem_type_mapping_tbl->mem_Ptr +
|
|
memory_size;
|
|
memory_size += 0x4000;
|
|
end_ptr = mem_type_mapping_tbl->mem_Ptr +
|
|
memory_size;
|
|
}
|
|
}
|
|
if (RDWR_STATUS_DONE == stat) {
|
|
#ifdef MLAN_64BIT
|
|
PRINTM(MMSG,
|
|
"%s done:"
|
|
"size = 0x%lx\n",
|
|
mem_type_mapping_tbl->mem_name,
|
|
dbg_ptr - mem_type_mapping_tbl->mem_Ptr);
|
|
#else
|
|
PRINTM(MMSG,
|
|
"%s done:"
|
|
"size = 0x%x\n",
|
|
mem_type_mapping_tbl->mem_name,
|
|
dbg_ptr - mem_type_mapping_tbl->mem_Ptr);
|
|
#endif
|
|
if (phandle->fw_dump_buf) {
|
|
moal_vfree(phandle, phandle->fw_dump_buf);
|
|
phandle->fw_dump_buf = NULL;
|
|
phandle->fw_dump_len = 0;
|
|
}
|
|
phandle->fw_dump_buf = mem_type_mapping_tbl->mem_Ptr;
|
|
phandle->fw_dump_len =
|
|
dbg_ptr - mem_type_mapping_tbl->mem_Ptr;
|
|
mem_type_mapping_tbl->mem_Ptr = NULL;
|
|
break;
|
|
}
|
|
} while (1);
|
|
moal_get_system_time(phandle, &sec, &usec);
|
|
PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT END: %u.%06u ====\n", sec,
|
|
usec);
|
|
/* end dump fw memory */
|
|
done:
|
|
if (mem_type_mapping_tbl->mem_Ptr) {
|
|
moal_vfree(phandle, mem_type_mapping_tbl->mem_Ptr);
|
|
mem_type_mapping_tbl->mem_Ptr = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function check if this is second mac
|
|
*
|
|
* @param handle A pointer to moal_handle structure
|
|
* @return MTRUE/MFALSE
|
|
*
|
|
*/
|
|
static t_u8 woal_pcie_is_second_mac(moal_handle *handle)
|
|
{
|
|
#ifdef PCIE9098
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
|
|
return MTRUE;
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
static void woal_pcie_dump_fw_info(moal_handle *phandle)
|
|
{
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
|
|
phandle->fw_dump = MTRUE;
|
|
#ifdef PCIE8897
|
|
if (IS_PCIE8897(phandle->card_type))
|
|
woal_pcie_dump_fw_info_v1(phandle);
|
|
#endif
|
|
#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
|
|
if (IS_PCIE8997(phandle->card_type) ||
|
|
IS_PCIE9098(phandle->card_type) ||
|
|
IS_PCIE9097(phandle->card_type)) {
|
|
woal_pcie_dump_fw_info_v2(phandle);
|
|
if (phandle->event_fw_dump) {
|
|
phandle->event_fw_dump = MFALSE;
|
|
queue_work(phandle->workqueue, &phandle->main_work);
|
|
phandle->is_fw_dump_timer_set = MTRUE;
|
|
woal_mod_timer(&phandle->fw_dump_timer, MOAL_TIMER_5S);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
woal_send_fw_dump_complete_event(
|
|
woal_get_priv(phandle, MLAN_BSS_ROLE_ANY));
|
|
phandle->fw_dump = MFALSE;
|
|
mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
|
|
queue_work(phandle->workqueue, &phandle->main_work);
|
|
woal_process_hang(phandle);
|
|
}
|
|
|
|
static mlan_status woal_pcie_get_fw_name(moal_handle *handle)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
#ifdef PCIE9098
|
|
pcie_service_card *card = (pcie_service_card *)handle->card;
|
|
moal_handle *ref_handle = NULL;
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
|
|
t_u32 rev_id_reg = handle->card_info->rev_id_reg;
|
|
t_u32 revision_id = 0;
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
|
|
t_u32 host_strap_reg = handle->card_info->host_strap_reg;
|
|
t_u32 magic_reg = handle->card_info->magic_reg;
|
|
t_u32 strap = 0;
|
|
t_u32 magic = 0;
|
|
#endif
|
|
|
|
ENTER();
|
|
|
|
if (handle->params.fw_name) {
|
|
#ifdef PCIE9097
|
|
if (IS_PCIE9097(handle->card_type)) {
|
|
woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
|
|
revision_id &= 0xff;
|
|
PRINTM(MCMND, "revision_id=0x%x\n", revision_id);
|
|
switch (revision_id) {
|
|
case PCIE9097_A0:
|
|
break;
|
|
case PCIE9097_B0:
|
|
case PCIE9097_B1:
|
|
handle->card_rev = CHIP_9097_REV_B0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
#ifdef PCIE8997
|
|
if (IS_PCIE8997(handle->card_type)) {
|
|
woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
|
|
woal_pcie_read_reg(handle, host_strap_reg, &strap);
|
|
woal_pcie_read_reg(handle, magic_reg, &magic);
|
|
revision_id &= 0xff;
|
|
strap &= 0x7;
|
|
magic &= 0xff;
|
|
PRINTM(MCMND, "magic=0x%x, strap=0x%x, revision_id=0x%x\n",
|
|
magic, strap, revision_id);
|
|
if ((revision_id == PCIE8997_A1) &&
|
|
(magic == CHIP_MAGIC_VALUE)) {
|
|
if (strap == CARD_TYPE_PCIE_UART)
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUART8997_DEFAULT_COMBO_FW_NAME);
|
|
else
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUSB8997_DEFAULT_COMBO_FW_NAME);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef PCIE9098
|
|
if (IS_PCIE9098(handle->card_type)) {
|
|
if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN0) {
|
|
woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
|
|
woal_pcie_read_reg(handle, host_strap_reg, &strap);
|
|
woal_pcie_read_reg(handle, magic_reg, &magic);
|
|
revision_id &= 0xff;
|
|
strap &= 0x7;
|
|
magic &= 0xff;
|
|
PRINTM(MCMND,
|
|
"magic=0x%x, strap=0x%x, revision_id=0x%x\n",
|
|
magic, strap, revision_id);
|
|
switch (revision_id) {
|
|
case PCIE9098_Z1Z2:
|
|
if (magic == CHIP_MAGIC_VALUE) {
|
|
if (strap == CARD_TYPE_PCIE_UART)
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEUART9098_DEFAULT_COMBO_FW_NAME);
|
|
else if (strap == CARD_TYPE_PCIE_PCIE)
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEPCIE9098_DEFAULT_COMBO_FW_NAME);
|
|
else
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEUSB9098_DEFAULT_COMBO_FW_NAME);
|
|
}
|
|
strcpy(handle->card_info->fw_name_wlan,
|
|
PCIE9098_DEFAULT_WLAN_FW_NAME);
|
|
break;
|
|
case PCIE9098_A0:
|
|
case PCIE9098_A1:
|
|
case PCIE9098_A2:
|
|
if (magic == CHIP_MAGIC_VALUE) {
|
|
if (strap == CARD_TYPE_PCIE_UART)
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEUART9098_COMBO_V1_FW_NAME);
|
|
else if (strap == CARD_TYPE_PCIE_PCIE)
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEPCIE9098_COMBO_V1_FW_NAME);
|
|
else
|
|
strcpy(handle->card_info
|
|
->fw_name,
|
|
PCIEUSB9098_COMBO_V1_FW_NAME);
|
|
}
|
|
strcpy(handle->card_info->fw_name_wlan,
|
|
PCIE9098_WLAN_V1_FW_NAME);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
ref_handle = (moal_handle *)handle->pref_mac;
|
|
if (ref_handle) {
|
|
strcpy(handle->card_info->fw_name,
|
|
ref_handle->card_info->fw_name);
|
|
strcpy(handle->card_info->fw_name_wlan,
|
|
ref_handle->card_info->fw_name_wlan);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef PCIE9097
|
|
if (IS_PCIE9097(handle->card_type)) {
|
|
woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
|
|
woal_pcie_read_reg(handle, host_strap_reg, &strap);
|
|
woal_pcie_read_reg(handle, magic_reg, &magic);
|
|
revision_id &= 0xff;
|
|
strap &= 0x7;
|
|
magic &= 0xff;
|
|
PRINTM(MCMND, "magic=0x%x, strap=0x%x, revision_id=0x%x\n",
|
|
magic, strap, revision_id);
|
|
switch (revision_id) {
|
|
case PCIE9097_A0:
|
|
if (magic == CHIP_MAGIC_VALUE) {
|
|
if (strap == CARD_TYPE_PCIE_UART)
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUART9097_DEFAULT_COMBO_FW_NAME);
|
|
else
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUSB9097_DEFAULT_COMBO_FW_NAME);
|
|
}
|
|
strcpy(handle->card_info->fw_name_wlan,
|
|
PCIE9097_DEFAULT_WLAN_FW_NAME);
|
|
break;
|
|
case PCIE9097_B0:
|
|
case PCIE9097_B1:
|
|
if (magic == CHIP_MAGIC_VALUE) {
|
|
if (strap == CARD_TYPE_PCIE_UART)
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUART9097_COMBO_V1_FW_NAME);
|
|
else
|
|
strcpy(handle->card_info->fw_name,
|
|
PCIEUSB9097_COMBO_V1_FW_NAME);
|
|
}
|
|
strcpy(handle->card_info->fw_name_wlan,
|
|
PCIE9097_WLAN_V1_FW_NAME);
|
|
handle->card_rev = CHIP_9097_REV_B0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
done:
|
|
PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
|
|
handle->card_info->fw_name_wlan);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
static moal_if_ops pcie_ops = {
|
|
.register_dev = woal_pcie_register_dev,
|
|
.unregister_dev = woal_pcie_unregister_dev,
|
|
.read_reg = woal_pcie_read_reg,
|
|
.write_reg = woal_pcie_write_reg,
|
|
.read_data_sync = woal_pcie_read_data_sync,
|
|
.write_data_sync = woal_pcie_write_data_sync,
|
|
.get_fw_name = woal_pcie_get_fw_name,
|
|
.dump_fw_info = woal_pcie_dump_fw_info,
|
|
.reg_dbg = woal_pcie_reg_dbg,
|
|
.dump_reg_info = woal_pcie_dump_reg_info,
|
|
.is_second_mac = woal_pcie_is_second_mac,
|
|
};
|