qcacmn: SDIO HIF Layer refactor
1. Add ADMA channel registration APIs 2. Add ADMA support for TX and RX path 3. Remove async_task thread for ADMA, since transfer thread is present in the SDIO AL layer 4. Move hif functions which are legacy only to mailbox.c 5. get_hif_device and hif_sdio_set_drvdata changes for mailbox and adma 6. Add rx buffer allocation offload work Change-Id: Ie98b302176381035b1bd590ef35a977aeef4f09c CRs-Fixed: 2274807
This commit is contained in:

committed by
nshrivas

parent
f4ab426805
commit
cf1f958b5f
@@ -465,8 +465,8 @@ enum hif_disable_type {
|
|||||||
* enum hif_device_config_opcode: configure mode
|
* enum hif_device_config_opcode: configure mode
|
||||||
*
|
*
|
||||||
* @HIF_DEVICE_POWER_STATE: device power state
|
* @HIF_DEVICE_POWER_STATE: device power state
|
||||||
* @HIF_DEVICE_GET_MBOX_BLOCK_SIZE: get mbox block size
|
* @HIF_DEVICE_GET_BLOCK_SIZE: get block size
|
||||||
* @HIF_DEVICE_GET_MBOX_ADDR: get mbox block address
|
* @HIF_DEVICE_GET_ADDR: get block address
|
||||||
* @HIF_DEVICE_GET_PENDING_EVENTS_FUNC: get pending events functions
|
* @HIF_DEVICE_GET_PENDING_EVENTS_FUNC: get pending events functions
|
||||||
* @HIF_DEVICE_GET_IRQ_PROC_MODE: get irq proc mode
|
* @HIF_DEVICE_GET_IRQ_PROC_MODE: get irq proc mode
|
||||||
* @HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC: receive event function
|
* @HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC: receive event function
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
#include "if_sdio.h"
|
#include "if_sdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_initialize_sdio_ops() - initialize the pci ops
|
* hif_initialize_sdio_ops() - initialize the sdio ops
|
||||||
* @bus_ops: hif_bus_ops table pointer to initialize
|
* @hif_sc: hif soft context
|
||||||
*
|
*
|
||||||
* Return: QDF_STATUS_SUCCESS
|
* Return: QDF_STATUS_SUCCESS
|
||||||
*/
|
*/
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "hif.h"
|
#include "hif.h"
|
||||||
#include "if_sdio.h"
|
#include "if_sdio.h"
|
||||||
#include "regtable_sdio.h"
|
#include "regtable_sdio.h"
|
||||||
|
#include "hif_sdio_dev.h"
|
||||||
#include "qdf_module.h"
|
#include "qdf_module.h"
|
||||||
|
|
||||||
#define CPU_DBG_SEL_ADDRESS 0x00000483
|
#define CPU_DBG_SEL_ADDRESS 0x00000483
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -26,11 +26,13 @@
|
|||||||
#define MANUFACTURER_ID_AR6320_BASE 0x500
|
#define MANUFACTURER_ID_AR6320_BASE 0x500
|
||||||
#define MANUFACTURER_ID_QCA9377_BASE 0x700
|
#define MANUFACTURER_ID_QCA9377_BASE 0x700
|
||||||
#define MANUFACTURER_ID_QCA9379_BASE 0x800
|
#define MANUFACTURER_ID_QCA9379_BASE 0x800
|
||||||
#define MANUFACTURER_ID_QCN7605_BASE 0x0000 /*TODO - GenoaSDIO */
|
#define MANUFACTURER_ID_QCN7605 0x400B
|
||||||
|
#define MANUFACTURER_ID_QCN7605_BASE 0x4000
|
||||||
#define MANUFACTURER_ID_AR6K_BASE_MASK 0xFF00
|
#define MANUFACTURER_ID_AR6K_BASE_MASK 0xFF00
|
||||||
#define MANUFACTURER_ID_AR6K_REV_MASK 0x00FF
|
#define MANUFACTURER_ID_AR6K_REV_MASK 0x00FF
|
||||||
#define FUNCTION_CLASS 0x0
|
#define FUNCTION_CLASS 0x0
|
||||||
#define MANUFACTURER_CODE 0x271
|
#define MANUFACTURER_CODE 0x271 /* Atheros Manufacturer ID */
|
||||||
|
#define MANUFACTURER_QC_CODE 0x70 /* QC Manufacturer ID */
|
||||||
|
|
||||||
|
|
||||||
#endif /* _HIF_SDIO_COMMON_H_ */
|
#endif /* _HIF_SDIO_COMMON_H_ */
|
||||||
|
@@ -208,127 +208,6 @@ QDF_STATUS hif_dev_enable_interrupts(struct hif_sdio_device *pdev)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEV_CHECK_RECV_YIELD(pdev) \
|
|
||||||
((pdev)->CurrentDSRRecvCount >= \
|
|
||||||
(pdev)->HifIRQYieldParams.recv_packet_yield_count)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hif_dev_dsr_handler() - Synchronous interrupt handler
|
|
||||||
*
|
|
||||||
* @context: hif send context
|
|
||||||
*
|
|
||||||
* Return: 0 for success and non-zero for failure
|
|
||||||
*/
|
|
||||||
QDF_STATUS hif_dev_dsr_handler(void *context)
|
|
||||||
{
|
|
||||||
struct hif_sdio_device *pdev = (struct hif_sdio_device *)context;
|
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
||||||
bool done = false;
|
|
||||||
bool async_proc = false;
|
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
|
|
||||||
/* reset the recv counter that tracks when we need
|
|
||||||
* to yield from the DSR
|
|
||||||
*/
|
|
||||||
pdev->CurrentDSRRecvCount = 0;
|
|
||||||
/* reset counter used to flag a re-scan of IRQ
|
|
||||||
* status registers on the target
|
|
||||||
*/
|
|
||||||
pdev->RecheckIRQStatusCnt = 0;
|
|
||||||
|
|
||||||
while (!done) {
|
|
||||||
status = hif_dev_process_pending_irqs(pdev, &done, &async_proc);
|
|
||||||
if (QDF_IS_STATUS_ERROR(status))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (pdev->HifIRQProcessingMode == HIF_DEVICE_IRQ_SYNC_ONLY) {
|
|
||||||
/* the HIF layer does not allow async IRQ processing,
|
|
||||||
* override the asyncProc flag
|
|
||||||
*/
|
|
||||||
async_proc = false;
|
|
||||||
/* this will cause us to re-enter ProcessPendingIRQ()
|
|
||||||
* and re-read interrupt status registers.
|
|
||||||
* This has a nice side effect of blocking us until all
|
|
||||||
* async read requests are completed. This behavior is
|
|
||||||
* required as we do not allow ASYNC processing
|
|
||||||
* in interrupt handlers (like Windows CE)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev))
|
|
||||||
/* ProcessPendingIRQs() pulled enough recv
|
|
||||||
* messages to satisfy the yield count, stop
|
|
||||||
* checking for more messages and return
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (async_proc) {
|
|
||||||
/* the function does some async I/O for performance,
|
|
||||||
* we need to exit the ISR immediately, the check below
|
|
||||||
* will prevent the interrupt from being
|
|
||||||
* Ack'd while we handle it asynchronously
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) {
|
|
||||||
/* Ack the interrupt only if :
|
|
||||||
* 1. we did not get any errors in processing interrupts
|
|
||||||
* 2. there are no outstanding async processing requests
|
|
||||||
*/
|
|
||||||
if (pdev->DSRCanYield) {
|
|
||||||
/* if the DSR can yield do not ACK the interrupt, there
|
|
||||||
* could be more pending messages. The HIF layer
|
|
||||||
* must ACK the interrupt on behalf of HTC
|
|
||||||
*/
|
|
||||||
HIF_INFO("%s: Yield (RX count: %d)",
|
|
||||||
__func__, pdev->CurrentDSRRecvCount);
|
|
||||||
} else {
|
|
||||||
HIF_INFO("%s: Ack interrupt", __func__);
|
|
||||||
hif_ack_interrupt(pdev->HIFDevice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** hif_dev_set_mailbox_swap() - Set the mailbox swap from firmware
|
|
||||||
* @pdev : The HIF layer object
|
|
||||||
*
|
|
||||||
* Return: none
|
|
||||||
*/
|
|
||||||
void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
|
|
||||||
{
|
|
||||||
struct hif_sdio_device *hif_device = hif_dev_from_hif(pdev);
|
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
|
|
||||||
hif_device->swap_mailbox = true;
|
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
|
|
||||||
* @pdev : The HIF layer object
|
|
||||||
*
|
|
||||||
* Return: none
|
|
||||||
*/
|
|
||||||
bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
|
|
||||||
{
|
|
||||||
struct hif_sdio_device *hif_device;
|
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
|
|
||||||
hif_device = hif_dev_from_hif(pdev);
|
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
|
|
||||||
return hif_device->swap_mailbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_dev_setup() - set up sdio device.
|
* hif_dev_setup() - set up sdio device.
|
||||||
* @pDev: sdio device context
|
* @pDev: sdio device context
|
||||||
@@ -346,7 +225,6 @@ QDF_STATUS hif_dev_setup(struct hif_sdio_device *pdev)
|
|||||||
|
|
||||||
status = hif_dev_setup_device(pdev);
|
status = hif_dev_setup_device(pdev);
|
||||||
|
|
||||||
|
|
||||||
if (status != QDF_STATUS_SUCCESS) {
|
if (status != QDF_STATUS_SUCCESS) {
|
||||||
HIF_ERROR("%s: device specific setup failed", __func__);
|
HIF_ERROR("%s: device specific setup failed", __func__);
|
||||||
return QDF_STATUS_E_INVAL;
|
return QDF_STATUS_E_INVAL;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, 2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2016, 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <hif.h>
|
#include <hif.h>
|
||||||
#include "athstartpack.h"
|
#include "athstartpack.h"
|
||||||
#include "hif_internal.h"
|
#include "hif_internal.h"
|
||||||
|
#include "if_sdio.h"
|
||||||
|
|
||||||
struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device);
|
struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device);
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *htc_sdio_device,
|
|||||||
|
|
||||||
QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev,
|
QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev,
|
||||||
bool *done,
|
bool *done,
|
||||||
bool *async_processing);
|
bool *async_processing);
|
||||||
|
|
||||||
void hif_dev_mask_interrupts(struct hif_sdio_device *pdev);
|
void hif_dev_mask_interrupts(struct hif_sdio_device *pdev);
|
||||||
|
|
||||||
@@ -60,9 +61,9 @@ void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev);
|
|||||||
|
|
||||||
int hif_dev_setup_device(struct hif_sdio_device *pdev);
|
int hif_dev_setup_device(struct hif_sdio_device *pdev);
|
||||||
|
|
||||||
QDF_STATUS hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
|
int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
|
||||||
struct hif_device_mbox_info *config,
|
void *config,
|
||||||
uint32_t config_len);
|
uint32_t config_len);
|
||||||
|
|
||||||
void hif_dev_get_block_size(void *config);
|
void hif_dev_get_block_size(void *config);
|
||||||
|
|
||||||
@@ -70,8 +71,93 @@ void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev);
|
|||||||
|
|
||||||
bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev);
|
bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev);
|
||||||
|
|
||||||
int hif_sdio_set_drvdata(struct sdio_func *func,
|
QDF_STATUS hif_read_write(struct hif_sdio_dev *device, unsigned long address,
|
||||||
struct hif_sdio_dev *hifdevice);
|
char *buffer, uint32_t length, uint32_t request,
|
||||||
|
void *context);
|
||||||
|
|
||||||
struct hif_sdio_dev *get_hif_device(struct sdio_func *func);
|
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
||||||
|
static inline struct hif_sdio_dev *get_hif_device(struct hif_softc *hif_ctx,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
qdf_assert(func);
|
||||||
|
return (struct hif_sdio_dev *)sdio_get_drvdata(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_set_drvdata() - set wlan driver data into upper layer private
|
||||||
|
* @hif_ctx: HIF object
|
||||||
|
* @func: pointer to sdio function
|
||||||
|
* @hifdevice: pointer to hif device
|
||||||
|
*
|
||||||
|
* Return: zero for success.
|
||||||
|
*/
|
||||||
|
static inline int hif_sdio_set_drvdata(struct hif_softc *hif_ctx,
|
||||||
|
struct sdio_func *func,
|
||||||
|
struct hif_sdio_dev *hifdevice)
|
||||||
|
{
|
||||||
|
sdio_set_drvdata(func, hifdevice);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hif_dev_configure_pipes(struct hif_sdio_dev *pdev,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hif_dev_register_channels(struct hif_sdio_dev *dev,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline struct hif_sdio_dev *get_hif_device(struct hif_softc *hif_ctx,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
struct hif_sdio_softc *scn = (struct hif_sdio_softc *)hif_ctx;
|
||||||
|
|
||||||
|
return (struct hif_sdio_dev *)scn->hif_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_set_drvdata() - set wlan driver data into upper layer private
|
||||||
|
* @hif_ctx: HIF object
|
||||||
|
* @func: pointer to sdio function
|
||||||
|
* @hifdevice: pointer to hif device
|
||||||
|
*
|
||||||
|
* Return: zero for success.
|
||||||
|
*/
|
||||||
|
static inline int hif_sdio_set_drvdata(struct hif_softc *hif_ctx,
|
||||||
|
struct sdio_func *func,
|
||||||
|
struct hif_sdio_dev *hifdevice)
|
||||||
|
{
|
||||||
|
struct hif_sdio_softc *sc = (struct hif_sdio_softc *)hif_ctx;
|
||||||
|
|
||||||
|
sc->hif_handle = hifdevice;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hif_dev_configure_pipes(struct hif_sdio_dev *pdev,
|
||||||
|
struct sdio_func *func);
|
||||||
|
|
||||||
|
int hif_dev_register_channels(struct hif_sdio_dev *dev,
|
||||||
|
struct sdio_func *func);
|
||||||
|
|
||||||
|
void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
|
||||||
|
struct sdio_func *func);
|
||||||
|
#endif /* SDIO_TRANSFER */
|
||||||
|
QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func, bool resume);
|
||||||
|
QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func,
|
||||||
|
bool reset);
|
||||||
|
A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
|
||||||
|
struct sdio_func *func,
|
||||||
|
struct hif_sdio_dev *device);
|
||||||
#endif /* HIF_SDIO_DEV_H_ */
|
#endif /* HIF_SDIO_DEV_H_ */
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#if defined(CONFIG_SDIO_TRANSFER_MAILBOX)
|
#if defined(CONFIG_SDIO_TRANSFER_MAILBOX)
|
||||||
#include <transfer/mailbox.h>
|
#include <transfer/mailbox.h>
|
||||||
#elif defined(CONFIG_SDIO_TRANSFER_ADMA)
|
#elif defined(CONFIG_SDIO_TRANSFER_ADMA)
|
||||||
#error "Error - Not implemented yet"
|
#include <transfer/adma.h>
|
||||||
#else
|
#else
|
||||||
#error "Error - Invalid transfer method"
|
#error "Error - Invalid transfer method"
|
||||||
#endif
|
#endif
|
||||||
@@ -54,7 +54,6 @@ struct hif_sdio_device {
|
|||||||
qdf_spinlock_t TxLock;
|
qdf_spinlock_t TxLock;
|
||||||
qdf_spinlock_t RxLock;
|
qdf_spinlock_t RxLock;
|
||||||
struct hif_msg_callbacks hif_callbacks;
|
struct hif_msg_callbacks hif_callbacks;
|
||||||
struct hif_device_mbox_info MailBoxInfo;
|
|
||||||
uint32_t BlockSize;
|
uint32_t BlockSize;
|
||||||
uint32_t BlockMask;
|
uint32_t BlockMask;
|
||||||
enum hif_device_irq_mode HifIRQProcessingMode;
|
enum hif_device_irq_mode HifIRQProcessingMode;
|
||||||
@@ -65,8 +64,11 @@ struct hif_sdio_device {
|
|||||||
int RecheckIRQStatusCnt;
|
int RecheckIRQStatusCnt;
|
||||||
uint32_t RecvStateFlags;
|
uint32_t RecvStateFlags;
|
||||||
void *pTarget;
|
void *pTarget;
|
||||||
bool swap_mailbox;
|
|
||||||
struct devRegisters devRegisters;
|
struct devRegisters devRegisters;
|
||||||
|
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
||||||
|
bool swap_mailbox;
|
||||||
|
struct hif_device_mbox_info MailBoxInfo;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LOCK_HIF_DEV(device) qdf_spin_lock(&(device)->Lock)
|
#define LOCK_HIF_DEV(device) qdf_spin_lock(&(device)->Lock)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -181,7 +181,7 @@ void hif_sdio_disable_bus(struct hif_softc *hif_sc)
|
|||||||
{
|
{
|
||||||
struct sdio_func *func = dev_to_sdio_func(hif_sc->qdf_dev->dev);
|
struct sdio_func *func = dev_to_sdio_func(hif_sc->qdf_dev->dev);
|
||||||
|
|
||||||
hif_sdio_device_removed(func);
|
hif_sdio_device_removed(hif_sc, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -83,7 +83,7 @@ int hif_sdio_device_inserted(struct hif_softc *ol_sc,
|
|||||||
const struct sdio_device_id *id);
|
const struct sdio_device_id *id);
|
||||||
void hif_sdio_stop(struct hif_softc *hif_ctx);
|
void hif_sdio_stop(struct hif_softc *hif_ctx);
|
||||||
void hif_sdio_shutdown(struct hif_softc *hif_ctx);
|
void hif_sdio_shutdown(struct hif_softc *hif_ctx);
|
||||||
void hif_sdio_device_removed(struct sdio_func *func);
|
void hif_sdio_device_removed(struct hif_softc *hif_ctx, struct sdio_func *func);
|
||||||
int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev);
|
int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev);
|
||||||
int hif_device_resume(struct hif_softc *ol_sc, struct device *dev);
|
int hif_device_resume(struct hif_softc *ol_sc, struct device *dev);
|
||||||
void hif_register_tbl_attach(struct hif_softc *scn,
|
void hif_register_tbl_attach(struct hif_softc *scn,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <qdf_status.h>
|
#include <qdf_status.h>
|
||||||
#include <qdf_timer.h>
|
#include <qdf_timer.h>
|
||||||
#include <qdf_atomic.h>
|
#include <qdf_atomic.h>
|
||||||
|
#include <qdf_list.h>
|
||||||
#include "hif.h"
|
#include "hif.h"
|
||||||
#include "hif_debug.h"
|
#include "hif_debug.h"
|
||||||
#include "hif_sdio_common.h"
|
#include "hif_sdio_common.h"
|
||||||
@@ -167,7 +168,7 @@ struct bus_request {
|
|||||||
struct bus_request *next; /* link list of available requests */
|
struct bus_request *next; /* link list of available requests */
|
||||||
struct bus_request *inusenext; /* link list of in use requests */
|
struct bus_request *inusenext; /* link list of in use requests */
|
||||||
struct semaphore sem_req;
|
struct semaphore sem_req;
|
||||||
uint32_t address; /* request data */
|
unsigned long address; /* request data */
|
||||||
char *buffer;
|
char *buffer;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
uint32_t request;
|
uint32_t request;
|
||||||
@@ -176,6 +177,14 @@ struct bus_request {
|
|||||||
struct HIF_SCATTER_REQ_PRIV *scatter_req;
|
struct HIF_SCATTER_REQ_PRIV *scatter_req;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HIF_ADMA_MAX_CHANS 2
|
||||||
|
#ifdef CONFIG_SDIO_TRANSFER_ADMA
|
||||||
|
struct rx_q_entry {
|
||||||
|
qdf_list_node_t entry;
|
||||||
|
qdf_nbuf_t nbuf;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct hif_sdio_dev {
|
struct hif_sdio_dev {
|
||||||
struct sdio_func *func;
|
struct sdio_func *func;
|
||||||
qdf_spinlock_t asynclock;
|
qdf_spinlock_t asynclock;
|
||||||
@@ -201,6 +210,15 @@ struct hif_sdio_dev {
|
|||||||
const struct sdio_device_id *id;
|
const struct sdio_device_id *id;
|
||||||
struct mmc_host *host;
|
struct mmc_host *host;
|
||||||
void *htc_context;
|
void *htc_context;
|
||||||
|
#ifdef CONFIG_SDIO_TRANSFER_ADMA
|
||||||
|
struct sdio_al_client_handle *al_client;
|
||||||
|
struct sdio_al_channel_handle *al_chan[HIF_ADMA_MAX_CHANS];
|
||||||
|
uint8_t adma_chans_used;
|
||||||
|
qdf_list_t rx_q;
|
||||||
|
qdf_spinlock_t rx_q_lock;
|
||||||
|
qdf_work_t rx_q_alloc_work;
|
||||||
|
bool rx_q_alloc_work_scheduled;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HIF_DEVICE_OS_DEVICE_INFO {
|
struct HIF_DEVICE_OS_DEVICE_INFO {
|
||||||
@@ -270,18 +288,13 @@ QDF_STATUS hif_configure_device(struct hif_softc *ol_sc,
|
|||||||
QDF_STATUS hif_attach_htc(struct hif_sdio_dev *device,
|
QDF_STATUS hif_attach_htc(struct hif_sdio_dev *device,
|
||||||
struct htc_callbacks *callbacks);
|
struct htc_callbacks *callbacks);
|
||||||
|
|
||||||
QDF_STATUS hif_read_write(struct hif_sdio_dev *device,
|
|
||||||
uint32_t address,
|
|
||||||
char *buffer,
|
|
||||||
uint32_t length, uint32_t request, void *context);
|
|
||||||
|
|
||||||
void hif_ack_interrupt(struct hif_sdio_dev *device);
|
void hif_ack_interrupt(struct hif_sdio_dev *device);
|
||||||
|
|
||||||
void hif_mask_interrupt(struct hif_sdio_dev *device);
|
void hif_mask_interrupt(struct hif_sdio_dev *device);
|
||||||
|
|
||||||
void hif_un_mask_interrupt(struct hif_sdio_dev *device);
|
void hif_un_mask_interrupt(struct hif_sdio_dev *device);
|
||||||
|
|
||||||
void hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func);
|
int hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func);
|
||||||
|
|
||||||
struct _HIF_SCATTER_ITEM {
|
struct _HIF_SCATTER_ITEM {
|
||||||
u_int8_t *buffer; /* CPU accessible address of buffer */
|
u_int8_t *buffer; /* CPU accessible address of buffer */
|
||||||
@@ -400,14 +413,14 @@ static inline QDF_STATUS do_hif_read_write_scatter(struct hif_sdio_dev *device,
|
|||||||
#define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \
|
#define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \
|
||||||
SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value)
|
SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value)
|
||||||
|
|
||||||
void hif_sdio_quirk_force_drive_strength(struct sdio_func *func);
|
void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
|
||||||
void hif_sdio_quirk_write_cccr(struct sdio_func *func);
|
struct sdio_func *func);
|
||||||
int hif_sdio_quirk_mod_strength(struct sdio_func *func);
|
void hif_sdio_quirk_write_cccr(struct hif_softc *ol_sc, struct sdio_func *func);
|
||||||
int hif_sdio_quirk_async_intr(struct sdio_func *func);
|
int hif_sdio_quirk_mod_strength(struct hif_softc *ol_sc,
|
||||||
int hif_sdio_set_bus_speed(struct sdio_func *func);
|
struct sdio_func *func);
|
||||||
int hif_sdio_set_bus_width(struct sdio_func *func);
|
int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func);
|
||||||
int hif_sdio_func_enable(struct hif_sdio_dev *device,
|
int hif_sdio_set_bus_speed(struct hif_softc *ol_sc, struct sdio_func *func);
|
||||||
struct sdio_func *func);
|
int hif_sdio_set_bus_width(struct hif_softc *ol_sc, struct sdio_func *func);
|
||||||
QDF_STATUS hif_sdio_func_disable(struct hif_sdio_dev *device,
|
QDF_STATUS hif_sdio_func_disable(struct hif_sdio_dev *device,
|
||||||
struct sdio_func *func,
|
struct sdio_func *func,
|
||||||
bool reset);
|
bool reset);
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -91,8 +88,10 @@ module_param(brokenirq, uint, 0644);
|
|||||||
MODULE_PARM_DESC(brokenirq,
|
MODULE_PARM_DESC(brokenirq,
|
||||||
"Set as 1 to use polling method instead of interrupt mode");
|
"Set as 1 to use polling method instead of interrupt mode");
|
||||||
|
|
||||||
|
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
||||||
/**
|
/**
|
||||||
* hif_sdio_force_drive_strength() - Set SDIO drive strength
|
* hif_sdio_force_drive_strength() - Set SDIO drive strength
|
||||||
|
* @ol_sc: softc instance
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
*
|
*
|
||||||
* This function forces the driver strength of the SDIO
|
* This function forces the driver strength of the SDIO
|
||||||
@@ -100,61 +99,156 @@ MODULE_PARM_DESC(brokenirq,
|
|||||||
*
|
*
|
||||||
* Return: none.
|
* Return: none.
|
||||||
*/
|
*/
|
||||||
void hif_sdio_quirk_force_drive_strength(struct sdio_func *func)
|
void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
|
||||||
|
struct sdio_func *func)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned char value = 0;
|
unsigned char value = 0;
|
||||||
uint32_t mask = 0, addr = SDIO_CCCR_DRIVE_STRENGTH;
|
uint32_t mask = 0, addr = SDIO_CCCR_DRIVE_STRENGTH;
|
||||||
struct hif_sdio_dev *device = sdio_get_drvdata(func);
|
|
||||||
|
|
||||||
uint16_t manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
err = func0_cmd52_read_byte(func->card, addr, &value);
|
||||||
|
if (err) {
|
||||||
switch (manfid) {
|
HIF_ERROR("%s: read driver strength 0x%02X fail %d\n",
|
||||||
case MANUFACTURER_ID_QCN7605_BASE:
|
__func__, addr, err);
|
||||||
break;
|
return;
|
||||||
default:
|
|
||||||
err = func0_cmd52_read_byte(func->card, addr, &value);
|
|
||||||
if (err) {
|
|
||||||
HIF_ERROR("%s: read driver strength 0x%02X fail %d\n",
|
|
||||||
__func__, addr, err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask = (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT);
|
|
||||||
value = (value & ~mask) | SDIO_DTSx_SET_TYPE_D;
|
|
||||||
err = func0_cmd52_write_byte(func->card, addr, value);
|
|
||||||
if (err) {
|
|
||||||
HIF_ERROR("%s: write driver strength failed", __func__);
|
|
||||||
HIF_ERROR("%s: 0x%02X to 0x%02X failed: %d\n", __func__,
|
|
||||||
(uint32_t)value, addr, err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = 0;
|
|
||||||
addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR;
|
|
||||||
err = func0_cmd52_read_byte(func->card, addr, &value);
|
|
||||||
if (err) {
|
|
||||||
HIF_ERROR("%s Read CCCR 0x%02X failed: %d\n",
|
|
||||||
__func__, addr, err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK;
|
|
||||||
value = (value & ~mask) |
|
|
||||||
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A |
|
|
||||||
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
|
|
||||||
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D;
|
|
||||||
err = func0_cmd52_write_byte(func->card, addr, value);
|
|
||||||
if (err)
|
|
||||||
HIF_ERROR("%s Write CCCR 0x%02X to 0x%02X failed: %d\n",
|
|
||||||
__func__, addr, value, err);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mask = (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT);
|
||||||
|
value = (value & ~mask) | SDIO_DTSx_SET_TYPE_D;
|
||||||
|
err = func0_cmd52_write_byte(func->card, addr, value);
|
||||||
|
if (err) {
|
||||||
|
HIF_ERROR("%s: write driver strength failed", __func__);
|
||||||
|
HIF_ERROR("%s: 0x%02X to 0x%02X failed: %d\n", __func__,
|
||||||
|
(uint32_t)value, addr, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = 0;
|
||||||
|
addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR;
|
||||||
|
err = func0_cmd52_read_byte(func->card, addr, &value);
|
||||||
|
if (err) {
|
||||||
|
HIF_ERROR("%s Read CCCR 0x%02X failed: %d\n",
|
||||||
|
__func__, addr, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK;
|
||||||
|
value = (value & ~mask) | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A |
|
||||||
|
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
|
||||||
|
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D;
|
||||||
|
err = func0_cmd52_write_byte(func->card, addr, value);
|
||||||
|
if (err)
|
||||||
|
HIF_ERROR("%s Write CCCR 0x%02X to 0x%02X failed: %d\n",
|
||||||
|
__func__, addr, value, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
|
||||||
|
* @ol_sc: softc instance
|
||||||
|
* @func: pointer to sdio_func
|
||||||
|
*
|
||||||
|
* The values are taken from the module parameter asyncintdelay
|
||||||
|
* Call this with the sdhci host claimed
|
||||||
|
*
|
||||||
|
* Return: none.
|
||||||
|
*/
|
||||||
|
int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
|
{
|
||||||
|
uint8_t data;
|
||||||
|
uint16_t manfid;
|
||||||
|
int set_async_irq = 0, ret = 0;
|
||||||
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
|
|
||||||
|
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
||||||
|
|
||||||
|
switch (manfid) {
|
||||||
|
case MANUFACTURER_ID_AR6003_BASE:
|
||||||
|
set_async_irq = 1;
|
||||||
|
ret =
|
||||||
|
func0_cmd52_write_byte(func->card,
|
||||||
|
CCCR_SDIO_IRQ_MODE_REG_AR6003,
|
||||||
|
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
case MANUFACTURER_ID_AR6320_BASE:
|
||||||
|
case MANUFACTURER_ID_QCA9377_BASE:
|
||||||
|
case MANUFACTURER_ID_QCA9379_BASE:
|
||||||
|
set_async_irq = 1;
|
||||||
|
ret = func0_cmd52_read_byte(func->card,
|
||||||
|
CCCR_SDIO_IRQ_MODE_REG_AR6320,
|
||||||
|
&data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320;
|
||||||
|
ret = func0_cmd52_write_byte(func->card,
|
||||||
|
CCCR_SDIO_IRQ_MODE_REG_AR6320,
|
||||||
|
data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asyncintdelay) {
|
||||||
|
/* Set CCCR 0xF0[7:6] to increase async interrupt delay clock
|
||||||
|
* to fix interrupt missing issue on dell 8460p
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = func0_cmd52_read_byte(func->card,
|
||||||
|
CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
|
||||||
|
&data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) |
|
||||||
|
((asyncintdelay << CCCR_SDIO_ASYNC_INT_DELAY_LSB) &
|
||||||
|
CCCR_SDIO_ASYNC_INT_DELAY_MASK);
|
||||||
|
|
||||||
|
ret = func0_cmd52_write_byte(func->card,
|
||||||
|
CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
|
||||||
|
data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* hif_sdio_force_drive_strength() - Set SDIO drive strength
|
||||||
|
* @ol_sc: softc instance
|
||||||
|
* @func: pointer to sdio_func
|
||||||
|
*
|
||||||
|
* This function forces the driver strength of the SDIO
|
||||||
|
* Call this with the sdhci host claimed
|
||||||
|
*
|
||||||
|
* Return: none.
|
||||||
|
*/
|
||||||
|
void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
|
||||||
|
* @ol_sc: softc instance
|
||||||
|
* @func: pointer to sdio_func
|
||||||
|
*
|
||||||
|
* The values are taken from the module parameter asyncintdelay
|
||||||
|
* Call this with the sdhci host claimed
|
||||||
|
*
|
||||||
|
* Return: none.
|
||||||
|
*/
|
||||||
|
int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_sdio_quirk_write_cccr() - write a desired CCCR register
|
* hif_sdio_quirk_write_cccr() - write a desired CCCR register
|
||||||
|
* @ol_sc: softc instance
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
*
|
*
|
||||||
* The values are taken from the module parameter writecccr
|
* The values are taken from the module parameter writecccr
|
||||||
@@ -162,7 +256,7 @@ void hif_sdio_quirk_force_drive_strength(struct sdio_func *func)
|
|||||||
*
|
*
|
||||||
* Return: none.
|
* Return: none.
|
||||||
*/
|
*/
|
||||||
void hif_sdio_quirk_write_cccr(struct sdio_func *func)
|
void hif_sdio_quirk_write_cccr(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
int32_t err;
|
int32_t err;
|
||||||
|
|
||||||
@@ -231,6 +325,7 @@ void hif_sdio_quirk_write_cccr(struct sdio_func *func)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_sdio_quirk_mod_strength() - write a desired CCCR register
|
* hif_sdio_quirk_mod_strength() - write a desired CCCR register
|
||||||
|
* @ol_sc: softc instance
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
*
|
*
|
||||||
* The values are taken from the module parameter writecccr
|
* The values are taken from the module parameter writecccr
|
||||||
@@ -238,11 +333,11 @@ void hif_sdio_quirk_write_cccr(struct sdio_func *func)
|
|||||||
*
|
*
|
||||||
* Return: none.
|
* Return: none.
|
||||||
*/
|
*/
|
||||||
int hif_sdio_quirk_mod_strength(struct sdio_func *func)
|
int hif_sdio_quirk_mod_strength(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint32_t addr, value;
|
uint32_t addr, value;
|
||||||
struct hif_sdio_dev *device = sdio_get_drvdata(func);
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
uint16_t manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
uint16_t manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
||||||
|
|
||||||
if (!modstrength) /* TODO: Dont set this : scn is not popolated yet */
|
if (!modstrength) /* TODO: Dont set this : scn is not popolated yet */
|
||||||
@@ -287,82 +382,6 @@ int hif_sdio_quirk_mod_strength(struct sdio_func *func)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
|
|
||||||
* @func: pointer to sdio_func
|
|
||||||
*
|
|
||||||
* The values are taken from the module parameter asyncintdelay
|
|
||||||
* Call this with the sdhci host claimed
|
|
||||||
*
|
|
||||||
* Return: none.
|
|
||||||
*/
|
|
||||||
int hif_sdio_quirk_async_intr(struct sdio_func *func)
|
|
||||||
{
|
|
||||||
uint8_t data;
|
|
||||||
uint16_t manfid;
|
|
||||||
int set_async_irq = 0, ret = 0;
|
|
||||||
struct hif_sdio_dev *device = sdio_get_drvdata(func);
|
|
||||||
|
|
||||||
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
|
||||||
|
|
||||||
switch (manfid) {
|
|
||||||
case MANUFACTURER_ID_AR6003_BASE:
|
|
||||||
set_async_irq = 1;
|
|
||||||
ret =
|
|
||||||
func0_cmd52_write_byte(func->card,
|
|
||||||
CCCR_SDIO_IRQ_MODE_REG_AR6003,
|
|
||||||
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
break;
|
|
||||||
case MANUFACTURER_ID_AR6320_BASE:
|
|
||||||
case MANUFACTURER_ID_QCA9377_BASE:
|
|
||||||
case MANUFACTURER_ID_QCA9379_BASE:
|
|
||||||
set_async_irq = 1;
|
|
||||||
ret = func0_cmd52_read_byte(func->card,
|
|
||||||
CCCR_SDIO_IRQ_MODE_REG_AR6320,
|
|
||||||
&data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320;
|
|
||||||
ret = func0_cmd52_write_byte(func->card,
|
|
||||||
CCCR_SDIO_IRQ_MODE_REG_AR6320,
|
|
||||||
data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
break;
|
|
||||||
case MANUFACTURER_ID_QCN7605_BASE:
|
|
||||||
/* No async intr delay settings */
|
|
||||||
asyncintdelay = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asyncintdelay) {
|
|
||||||
/* Set CCCR 0xF0[7:6] to increase async interrupt delay clock
|
|
||||||
* to fix interrupt missing issue on dell 8460p
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = func0_cmd52_read_byte(func->card,
|
|
||||||
CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
|
|
||||||
&data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) |
|
|
||||||
((asyncintdelay << CCCR_SDIO_ASYNC_INT_DELAY_LSB) &
|
|
||||||
CCCR_SDIO_ASYNC_INT_DELAY_MASK);
|
|
||||||
|
|
||||||
ret = func0_cmd52_write_byte(func->card,
|
|
||||||
CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
|
|
||||||
data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if KERNEL_VERSION(3, 4, 0) <= LINUX_VERSION_CODE
|
#if KERNEL_VERSION(3, 4, 0) <= LINUX_VERSION_CODE
|
||||||
#ifdef SDIO_BUS_WIDTH_8BIT
|
#ifdef SDIO_BUS_WIDTH_8BIT
|
||||||
static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
|
static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
|
||||||
@@ -381,14 +400,15 @@ static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_sdio_set_bus_speed() - Set the sdio bus speed
|
* hif_sdio_set_bus_speed() - Set the sdio bus speed
|
||||||
|
* @ol_sc: softc instance
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error number otherwise.
|
* Return: 0 on success, error number otherwise.
|
||||||
*/
|
*/
|
||||||
int hif_sdio_set_bus_speed(struct sdio_func *func)
|
int hif_sdio_set_bus_speed(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
uint32_t clock, clock_set = 12500000;
|
uint32_t clock, clock_set = 12500000;
|
||||||
struct hif_sdio_dev *device = get_hif_device(func);
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
uint16_t manfid;
|
uint16_t manfid;
|
||||||
|
|
||||||
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
||||||
@@ -427,16 +447,17 @@ int hif_sdio_set_bus_speed(struct sdio_func *func)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_set_bus_width() - Set the sdio bus width
|
* hif_set_bus_width() - Set the sdio bus width
|
||||||
|
* @ol_sc: softc instance
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error number otherwise.
|
* Return: 0 on success, error number otherwise.
|
||||||
*/
|
*/
|
||||||
int hif_sdio_set_bus_width(struct sdio_func *func)
|
int hif_sdio_set_bus_width(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint16_t manfid;
|
uint16_t manfid;
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
struct hif_sdio_dev *device = get_hif_device(func);
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
|
|
||||||
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
||||||
|
|
||||||
@@ -491,66 +512,6 @@ int hif_sdio_set_bus_width(struct sdio_func *func)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* hif_sdio_func_enable() - Handle device enabling as per device
|
|
||||||
* @device: HIF device object
|
|
||||||
* @func: function pointer
|
|
||||||
*
|
|
||||||
* Return success or failure
|
|
||||||
*/
|
|
||||||
int hif_sdio_func_enable(struct hif_sdio_dev *device,
|
|
||||||
struct sdio_func *func)
|
|
||||||
{
|
|
||||||
uint16_t manfid;
|
|
||||||
|
|
||||||
manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
|
|
||||||
|
|
||||||
if (manfid == MANUFACTURER_ID_QCN7605_BASE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (device->is_disabled) {
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
sdio_claim_host(func);
|
|
||||||
|
|
||||||
ret = hif_sdio_quirk_async_intr(func);
|
|
||||||
if (ret) {
|
|
||||||
HIF_ERROR("%s: Error setting async intr:%d",
|
|
||||||
__func__, ret);
|
|
||||||
sdio_release_host(func);
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
func->enable_timeout = 100;
|
|
||||||
ret = sdio_enable_func(func);
|
|
||||||
if (ret) {
|
|
||||||
HIF_ERROR("%s: Unable to enable function: %d",
|
|
||||||
__func__, ret);
|
|
||||||
sdio_release_host(func);
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sdio_set_block_size(func, HIF_BLOCK_SIZE);
|
|
||||||
if (ret) {
|
|
||||||
HIF_ERROR("%s: Unable to set block size 0x%X : %d\n",
|
|
||||||
__func__, HIF_BLOCK_SIZE, ret);
|
|
||||||
sdio_release_host(func);
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = hif_sdio_quirk_mod_strength(func);
|
|
||||||
if (ret) {
|
|
||||||
HIF_ERROR("%s: Error setting mod strength : %d\n",
|
|
||||||
__func__, ret);
|
|
||||||
sdio_release_host(func);
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdio_release_host(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_mask_interrupt() - Disable hif device irq
|
* hif_mask_interrupt() - Disable hif device irq
|
||||||
@@ -594,11 +555,7 @@ void hif_mask_interrupt(struct hif_sdio_dev *device)
|
|||||||
*/
|
*/
|
||||||
static void hif_irq_handler(struct sdio_func *func)
|
static void hif_irq_handler(struct sdio_func *func)
|
||||||
{
|
{
|
||||||
struct hif_sdio_dev *device;
|
struct hif_sdio_dev *device = get_hif_device(NULL, func);
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
|
|
||||||
device = get_hif_device(func);
|
|
||||||
atomic_set(&device->irq_handling, 1);
|
atomic_set(&device->irq_handling, 1);
|
||||||
/* release the host during intr so we can use
|
/* release the host during intr so we can use
|
||||||
* it when we process cmds
|
* it when we process cmds
|
||||||
@@ -607,8 +564,6 @@ static void hif_irq_handler(struct sdio_func *func)
|
|||||||
device->htc_callbacks.dsr_handler(device->htc_callbacks.context);
|
device->htc_callbacks.dsr_handler(device->htc_callbacks.context);
|
||||||
sdio_claim_host(device->func);
|
sdio_claim_host(device->func);
|
||||||
atomic_set(&device->irq_handling, 0);
|
atomic_set(&device->irq_handling, 0);
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -23,7 +23,6 @@
|
|||||||
#include <linux/mmc/sdio_ids.h>
|
#include <linux/mmc/sdio_ids.h>
|
||||||
#include <linux/mmc/sdio.h>
|
#include <linux/mmc/sdio.h>
|
||||||
#include <linux/mmc/sd.h>
|
#include <linux/mmc/sd.h>
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <qdf_atomic.h>
|
#include <qdf_atomic.h>
|
||||||
@@ -38,26 +37,10 @@
|
|||||||
#include "hif_internal.h"
|
#include "hif_internal.h"
|
||||||
#include <transfer/transfer.h>
|
#include <transfer/transfer.h>
|
||||||
|
|
||||||
/* by default setup a bounce buffer for the data packets,
|
|
||||||
* if the underlying host controller driver
|
|
||||||
* does not use DMA you may be able to skip this step
|
|
||||||
* and save the memory allocation and transfer time
|
|
||||||
*/
|
|
||||||
#define HIF_USE_DMA_BOUNCE_BUFFER 1
|
#define HIF_USE_DMA_BOUNCE_BUFFER 1
|
||||||
#define ATH_MODULE_NAME hif
|
#define ATH_MODULE_NAME hif
|
||||||
#include "a_debug.h"
|
#include "a_debug.h"
|
||||||
|
|
||||||
#if HIF_USE_DMA_BOUNCE_BUFFER
|
|
||||||
/* macro to check if DMA buffer is WORD-aligned and DMA-able.
|
|
||||||
* Most host controllers assume the
|
|
||||||
* buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
|
|
||||||
* virt_addr_valid check fails on stack memory.
|
|
||||||
*/
|
|
||||||
#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || \
|
|
||||||
!virt_addr_valid((buffer)))
|
|
||||||
#else
|
|
||||||
#define BUFFER_NEEDS_BOUNCE(buffer) (false)
|
|
||||||
#endif
|
|
||||||
#define MAX_HIF_DEVICES 2
|
#define MAX_HIF_DEVICES 2
|
||||||
#ifdef HIF_MBOX_SLEEP_WAR
|
#ifdef HIF_MBOX_SLEEP_WAR
|
||||||
#define HIF_MIN_SLEEP_INACTIVITY_TIME_MS 50
|
#define HIF_MIN_SLEEP_INACTIVITY_TIME_MS 50
|
||||||
@@ -83,7 +66,8 @@ MODULE_PARM_DESC(debugcccr, "Output this cccr values");
|
|||||||
|
|
||||||
#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
|
#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
|
||||||
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
|
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
|
||||||
static struct hif_sdio_dev *add_hif_device(struct sdio_func *func);
|
static struct hif_sdio_dev *add_hif_device(struct hif_softc *hif_ctx,
|
||||||
|
struct sdio_func *func);
|
||||||
static void del_hif_device(struct hif_sdio_dev *device);
|
static void del_hif_device(struct hif_sdio_dev *device);
|
||||||
|
|
||||||
int reset_sdio_on_unload;
|
int reset_sdio_on_unload;
|
||||||
@@ -171,186 +155,6 @@ ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif,
|
|||||||
ATH_DEBUG_MASK_DEFAULTS, 0, NULL);
|
ATH_DEBUG_MASK_DEFAULTS, 0, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* __hif_read_write() - sdio read/write wrapper
|
|
||||||
* @device: pointer to hif device structure
|
|
||||||
* @address: address to read
|
|
||||||
* @buffer: buffer to hold read/write data
|
|
||||||
* @length: length to read/write
|
|
||||||
* @request: read/write/sync/async request
|
|
||||||
* @context: pointer to hold calling context
|
|
||||||
*
|
|
||||||
* Return: 0 on success, error number otherwise.
|
|
||||||
*/
|
|
||||||
static QDF_STATUS
|
|
||||||
__hif_read_write(struct hif_sdio_dev *device,
|
|
||||||
uint32_t address, char *buffer,
|
|
||||||
uint32_t length, uint32_t request, void *context)
|
|
||||||
{
|
|
||||||
uint8_t opcode;
|
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
||||||
int ret = A_OK;
|
|
||||||
uint8_t *tbuffer;
|
|
||||||
bool bounced = false;
|
|
||||||
|
|
||||||
if (!device) {
|
|
||||||
HIF_ERROR("%s: device null!", __func__);
|
|
||||||
return QDF_STATUS_E_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!device->func) {
|
|
||||||
HIF_ERROR("%s: func null!", __func__);
|
|
||||||
return QDF_STATUS_E_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HIF_INFO_HI("%s: addr:0X%06X, len:%08d, %s, %s", __func__,
|
|
||||||
address, length,
|
|
||||||
request & HIF_SDIO_READ ? "Read " : "Write",
|
|
||||||
request & HIF_ASYNCHRONOUS ? "Async" : "Sync ");
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (request & HIF_EXTENDED_IO) {
|
|
||||||
HIF_INFO_HI("%s: Command type: CMD53\n", __func__);
|
|
||||||
} else {
|
|
||||||
HIF_ERROR("%s: Invalid command type: 0x%08x\n",
|
|
||||||
__func__, request);
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request & HIF_BLOCK_BASIS) {
|
|
||||||
/* round to whole block length size */
|
|
||||||
length =
|
|
||||||
(length / HIF_BLOCK_SIZE) *
|
|
||||||
HIF_BLOCK_SIZE;
|
|
||||||
HIF_INFO_HI("%s: Block mode (BlockLen: %d)\n",
|
|
||||||
__func__, length);
|
|
||||||
} else if (request & HIF_BYTE_BASIS) {
|
|
||||||
HIF_INFO_HI("%s: Byte mode (BlockLen: %d)\n",
|
|
||||||
__func__, length);
|
|
||||||
} else {
|
|
||||||
HIF_ERROR("%s: Invalid data mode: 0x%08x\n",
|
|
||||||
__func__, request);
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (request & HIF_SDIO_WRITE) {
|
|
||||||
hif_fixup_write_param(device, request,
|
|
||||||
&length, &address);
|
|
||||||
|
|
||||||
HIF_INFO_HI("addr:%08X, len:0x%08X, dummy:0x%04X\n",
|
|
||||||
address, length,
|
|
||||||
(request & HIF_DUMMY_SPACE_MASK) >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request & HIF_FIXED_ADDRESS) {
|
|
||||||
opcode = CMD53_FIXED_ADDRESS;
|
|
||||||
HIF_INFO_HI("%s: Addr mode: fixed 0x%X\n",
|
|
||||||
__func__, address);
|
|
||||||
} else if (request & HIF_INCREMENTAL_ADDRESS) {
|
|
||||||
opcode = CMD53_INCR_ADDRESS;
|
|
||||||
HIF_INFO_HI("%s: Address mode: Incremental 0x%X\n",
|
|
||||||
__func__, address);
|
|
||||||
} else {
|
|
||||||
HIF_ERROR("%s: Invalid address mode: 0x%08x\n",
|
|
||||||
__func__, request);
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request & HIF_SDIO_WRITE) {
|
|
||||||
#if HIF_USE_DMA_BOUNCE_BUFFER
|
|
||||||
if (BUFFER_NEEDS_BOUNCE(buffer)) {
|
|
||||||
AR_DEBUG_ASSERT(device->dma_buffer);
|
|
||||||
tbuffer = device->dma_buffer;
|
|
||||||
/* copy the write data to the dma buffer */
|
|
||||||
AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
|
|
||||||
if (length > HIF_DMA_BUFFER_SIZE) {
|
|
||||||
HIF_ERROR("%s: Invalid write len: %d\n",
|
|
||||||
__func__, length);
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
memcpy(tbuffer, buffer, length);
|
|
||||||
bounced = true;
|
|
||||||
} else {
|
|
||||||
tbuffer = buffer;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
tbuffer = buffer;
|
|
||||||
#endif
|
|
||||||
if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
|
|
||||||
ret = sdio_writesb(device->func, address,
|
|
||||||
tbuffer, length);
|
|
||||||
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
|
||||||
__func__, ret, address, length,
|
|
||||||
*(int *)tbuffer);
|
|
||||||
} else if (tbuffer) {
|
|
||||||
ret = sdio_memcpy_toio(device->func, address,
|
|
||||||
tbuffer, length);
|
|
||||||
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
|
||||||
__func__, ret, address, length,
|
|
||||||
*(int *)tbuffer);
|
|
||||||
}
|
|
||||||
} else if (request & HIF_SDIO_READ) {
|
|
||||||
#if HIF_USE_DMA_BOUNCE_BUFFER
|
|
||||||
if (BUFFER_NEEDS_BOUNCE(buffer)) {
|
|
||||||
AR_DEBUG_ASSERT(device->dma_buffer);
|
|
||||||
AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
|
|
||||||
if (length > HIF_DMA_BUFFER_SIZE) {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
|
||||||
("%s: Invalid read length: %d\n",
|
|
||||||
__func__, length));
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tbuffer = device->dma_buffer;
|
|
||||||
bounced = true;
|
|
||||||
} else {
|
|
||||||
tbuffer = buffer;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
tbuffer = buffer;
|
|
||||||
#endif
|
|
||||||
if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
|
|
||||||
ret = sdio_readsb(device->func, tbuffer,
|
|
||||||
address, length);
|
|
||||||
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
|
||||||
__func__, ret, address, length,
|
|
||||||
*(int *)tbuffer);
|
|
||||||
} else if (tbuffer) {
|
|
||||||
ret = sdio_memcpy_fromio(device->func,
|
|
||||||
tbuffer, address,
|
|
||||||
length);
|
|
||||||
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
|
||||||
__func__, ret, address, length,
|
|
||||||
*(int *)tbuffer);
|
|
||||||
}
|
|
||||||
#if HIF_USE_DMA_BOUNCE_BUFFER
|
|
||||||
if (bounced && tbuffer)
|
|
||||||
memcpy(buffer, tbuffer, length);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
HIF_ERROR("%s: Invalid dir: 0x%08x", __func__, request);
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
HIF_ERROR("%s: SDIO bus operation failed!", __func__);
|
|
||||||
HIF_ERROR("%s: MMC stack returned : %d", __func__, ret);
|
|
||||||
HIF_ERROR("%s: addr:0X%06X, len:%08d, %s, %s",
|
|
||||||
__func__, address, length,
|
|
||||||
request & HIF_SDIO_READ ? "Read " : "Write",
|
|
||||||
request & HIF_ASYNCHRONOUS ?
|
|
||||||
"Async" : "Sync");
|
|
||||||
status = QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add_to_async_list() - add bus reqest to async task list
|
* add_to_async_list() - add bus reqest to async task list
|
||||||
* @device: pointer to hif device
|
* @device: pointer to hif device
|
||||||
@@ -380,222 +184,6 @@ void add_to_async_list(struct hif_sdio_dev *device,
|
|||||||
qdf_spin_unlock_irqrestore(&device->asynclock);
|
qdf_spin_unlock_irqrestore(&device->asynclock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* hif_read_write() - queue a read/write request
|
|
||||||
* @device: pointer to hif device structure
|
|
||||||
* @address: address to read
|
|
||||||
* @buffer: buffer to hold read/write data
|
|
||||||
* @length: length to read/write
|
|
||||||
* @request: read/write/sync/async request
|
|
||||||
* @context: pointer to hold calling context
|
|
||||||
*
|
|
||||||
* Return: 0 on success, error number otherwise.
|
|
||||||
*/
|
|
||||||
QDF_STATUS
|
|
||||||
hif_read_write(struct hif_sdio_dev *device,
|
|
||||||
uint32_t address,
|
|
||||||
char *buffer, uint32_t length,
|
|
||||||
uint32_t request, void *context)
|
|
||||||
{
|
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
||||||
struct bus_request *busrequest;
|
|
||||||
|
|
||||||
AR_DEBUG_ASSERT(device);
|
|
||||||
AR_DEBUG_ASSERT(device->func);
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: device 0x%pK addr 0x%X buffer 0x%pK len %d req 0x%X context 0x%pK",
|
|
||||||
__func__, device, address, buffer,
|
|
||||||
length, request, context));
|
|
||||||
|
|
||||||
/*sdio r/w action is not needed when suspend, so just return */
|
|
||||||
if ((device->is_suspend == true)
|
|
||||||
&& (device->power_config == HIF_DEVICE_POWER_CUT)) {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n"));
|
|
||||||
return QDF_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
if ((request & HIF_ASYNCHRONOUS) ||
|
|
||||||
(request & HIF_SYNCHRONOUS)) {
|
|
||||||
/* serialize all requests through the async thread */
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: Execution mode: %s\n", __func__,
|
|
||||||
(request & HIF_ASYNCHRONOUS) ? "Async"
|
|
||||||
: "Synch"));
|
|
||||||
busrequest = hif_allocate_bus_request(device);
|
|
||||||
if (!busrequest) {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
|
||||||
("no async bus requests available (%s, addr:0x%X, len:%d)\n",
|
|
||||||
request & HIF_SDIO_READ ? "READ" :
|
|
||||||
"WRITE", address, length));
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
busrequest->address = address;
|
|
||||||
busrequest->buffer = buffer;
|
|
||||||
busrequest->length = length;
|
|
||||||
busrequest->request = request;
|
|
||||||
busrequest->context = context;
|
|
||||||
|
|
||||||
add_to_async_list(device, busrequest);
|
|
||||||
|
|
||||||
if (request & HIF_SYNCHRONOUS) {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: queued sync req: 0x%lX\n",
|
|
||||||
__func__, (unsigned long)busrequest));
|
|
||||||
|
|
||||||
/* wait for completion */
|
|
||||||
up(&device->sem_async);
|
|
||||||
if (down_interruptible(&busrequest->sem_req) !=
|
|
||||||
0) {
|
|
||||||
/* interrupted, exit */
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
} else {
|
|
||||||
QDF_STATUS status = busrequest->status;
|
|
||||||
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: sync return freeing 0x%lX: 0x%X\n",
|
|
||||||
__func__,
|
|
||||||
(unsigned long)
|
|
||||||
busrequest,
|
|
||||||
busrequest->status));
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: freeing req: 0x%X\n",
|
|
||||||
__func__,
|
|
||||||
(unsigned int)
|
|
||||||
request));
|
|
||||||
hif_free_bus_request(device,
|
|
||||||
busrequest);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: queued async req: 0x%lX\n",
|
|
||||||
__func__,
|
|
||||||
(unsigned long)busrequest));
|
|
||||||
up(&device->sem_async);
|
|
||||||
return QDF_STATUS_E_PENDING;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
|
||||||
("%s: Invalid execution mode: 0x%08x\n",
|
|
||||||
__func__,
|
|
||||||
(unsigned int)request));
|
|
||||||
status = QDF_STATUS_E_INVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* async_task() - thread function to serialize all bus requests
|
|
||||||
* @param: pointer to hif device
|
|
||||||
*
|
|
||||||
* thread function to serialize all requests, both sync and async
|
|
||||||
* Return: 0 on success, error number otherwise.
|
|
||||||
*/
|
|
||||||
static int async_task(void *param)
|
|
||||||
{
|
|
||||||
struct hif_sdio_dev *device;
|
|
||||||
struct bus_request *request;
|
|
||||||
QDF_STATUS status;
|
|
||||||
bool claimed = false;
|
|
||||||
|
|
||||||
device = (struct hif_sdio_dev *) param;
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
|
||||||
while (!device->async_shutdown) {
|
|
||||||
/* wait for work */
|
|
||||||
if (down_interruptible(&device->sem_async) != 0) {
|
|
||||||
/* interrupted, exit */
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: async task interrupted\n",
|
|
||||||
__func__));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (device->async_shutdown) {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: async task stopping\n",
|
|
||||||
__func__));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* we want to hold the host over multiple cmds
|
|
||||||
* if possible, but holding the host blocks
|
|
||||||
* card interrupts
|
|
||||||
*/
|
|
||||||
qdf_spin_lock_irqsave(&device->asynclock);
|
|
||||||
/* pull the request to work on */
|
|
||||||
while (device->asyncreq) {
|
|
||||||
request = device->asyncreq;
|
|
||||||
if (request->inusenext)
|
|
||||||
device->asyncreq = request->inusenext;
|
|
||||||
else
|
|
||||||
device->asyncreq = NULL;
|
|
||||||
qdf_spin_unlock_irqrestore(&device->asynclock);
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: async_task processing req: 0x%lX\n",
|
|
||||||
__func__, (unsigned long)request));
|
|
||||||
|
|
||||||
if (!claimed) {
|
|
||||||
sdio_claim_host(device->func);
|
|
||||||
claimed = true;
|
|
||||||
}
|
|
||||||
if (request->scatter_req) {
|
|
||||||
A_ASSERT(device->scatter_enabled);
|
|
||||||
/* pass the request to scatter routine which
|
|
||||||
* executes it synchronously, note, no need
|
|
||||||
* to free the request since scatter requests
|
|
||||||
* are maintained on a separate list
|
|
||||||
*/
|
|
||||||
status = do_hif_read_write_scatter(device,
|
|
||||||
request);
|
|
||||||
} else {
|
|
||||||
/* call hif_read_write in sync mode */
|
|
||||||
status =
|
|
||||||
__hif_read_write(device,
|
|
||||||
request->address,
|
|
||||||
request->buffer,
|
|
||||||
request->length,
|
|
||||||
request->
|
|
||||||
request &
|
|
||||||
~HIF_SYNCHRONOUS,
|
|
||||||
NULL);
|
|
||||||
if (request->request & HIF_ASYNCHRONOUS) {
|
|
||||||
void *context = request->context;
|
|
||||||
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: freeing req: 0x%lX\n",
|
|
||||||
__func__, (unsigned long)
|
|
||||||
request));
|
|
||||||
hif_free_bus_request(device, request);
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: async_task completion req 0x%lX\n",
|
|
||||||
__func__, (unsigned long)
|
|
||||||
request));
|
|
||||||
device->htc_callbacks.
|
|
||||||
rw_compl_handler(context, status);
|
|
||||||
} else {
|
|
||||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
|
||||||
("%s: async_task upping req: 0x%lX\n",
|
|
||||||
__func__, (unsigned long)
|
|
||||||
request));
|
|
||||||
request->status = status;
|
|
||||||
up(&request->sem_req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qdf_spin_lock_irqsave(&device->asynclock);
|
|
||||||
}
|
|
||||||
qdf_spin_unlock_irqrestore(&device->asynclock);
|
|
||||||
if (claimed) {
|
|
||||||
sdio_release_host(device->func);
|
|
||||||
claimed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
complete_and_exit(&device->async_completion, 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup IRQ mode for deep sleep and WoW
|
* Setup IRQ mode for deep sleep and WoW
|
||||||
* Switch back to 1 bits mode when we suspend for
|
* Switch back to 1 bits mode when we suspend for
|
||||||
@@ -603,6 +191,7 @@ static int async_task(void *param)
|
|||||||
* Re-enable async 4-bit irq mode for some host controllers
|
* Re-enable async 4-bit irq mode for some host controllers
|
||||||
* after resume.
|
* after resume.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
||||||
static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
|
static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -675,34 +264,12 @@ static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
static QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
|
static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
|
||||||
struct sdio_func *func,
|
|
||||||
bool reset)
|
|
||||||
{
|
{
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
return 0;
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
device = get_hif_device(func);
|
|
||||||
if (!IS_ERR(device->async_task)) {
|
|
||||||
init_completion(&device->async_completion);
|
|
||||||
device->async_shutdown = 1;
|
|
||||||
up(&device->sem_async);
|
|
||||||
wait_for_completion(&device->async_completion);
|
|
||||||
device->async_task = NULL;
|
|
||||||
sema_init(&device->sem_async, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = hif_sdio_func_disable(device, func, reset);
|
|
||||||
if (status == QDF_STATUS_SUCCESS)
|
|
||||||
device->is_disabled = true;
|
|
||||||
|
|
||||||
cleanup_hif_scatter_resources(device);
|
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_sdio_probe() - configure sdio device
|
* hif_sdio_probe() - configure sdio device
|
||||||
@@ -712,9 +279,9 @@ static QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
|
|||||||
*
|
*
|
||||||
* Return: 0 for success and non-zero for failure
|
* Return: 0 for success and non-zero for failure
|
||||||
*/
|
*/
|
||||||
static A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
|
A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
|
||||||
struct sdio_func *func,
|
struct sdio_func *func,
|
||||||
struct hif_sdio_dev *device)
|
struct hif_sdio_dev *device)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const struct sdio_device_id *id;
|
const struct sdio_device_id *id;
|
||||||
@@ -794,7 +361,9 @@ static A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
|
|||||||
goto err_attach1;
|
goto err_attach1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ret = hif_dev_register_channels(device, func);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
err_attach1:
|
err_attach1:
|
||||||
if (scn->ramdump_base)
|
if (scn->ramdump_base)
|
||||||
@@ -803,48 +372,9 @@ err_attach1:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QDF_STATUS hif_enable_func(struct hif_softc *ol_sc,
|
|
||||||
struct hif_sdio_dev *device,
|
|
||||||
struct sdio_func *func,
|
|
||||||
bool resume)
|
|
||||||
{
|
|
||||||
int ret = QDF_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
HIF_ENTER();
|
|
||||||
|
|
||||||
if (!device) {
|
|
||||||
HIF_ERROR("%s: HIF device is NULL", __func__);
|
|
||||||
return QDF_STATUS_E_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hif_sdio_func_enable(device, func))
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
|
|
||||||
/* create async I/O thread */
|
|
||||||
if (!device->async_task && device->is_disabled) {
|
|
||||||
device->async_shutdown = 0;
|
|
||||||
device->async_task = kthread_create(async_task,
|
|
||||||
(void *)device,
|
|
||||||
"AR6K Async");
|
|
||||||
if (IS_ERR(device->async_task)) {
|
|
||||||
HIF_ERROR("%s: Error creating async task",
|
|
||||||
__func__);
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
|
||||||
}
|
|
||||||
device->is_disabled = false;
|
|
||||||
wake_up_process(device->async_task);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resume == false)
|
|
||||||
ret = hif_sdio_probe(ol_sc, func, device);
|
|
||||||
|
|
||||||
HIF_EXIT();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* power_state_change_notify() - SDIO bus power notification handler
|
* power_state_change_notify() - SDIO bus power notification handler
|
||||||
|
* @ol_sc: HIF device context
|
||||||
* @config: hif device power change type
|
* @config: hif device power change type
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error number otherwise.
|
* Return: 0 on success, error number otherwise.
|
||||||
@@ -910,6 +440,7 @@ power_state_change_notify(struct hif_softc *ol_sc,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_configure_device() - configure sdio device
|
* hif_configure_device() - configure sdio device
|
||||||
|
* @ol_sc: HIF device context
|
||||||
* @device: pointer to hif device structure
|
* @device: pointer to hif device structure
|
||||||
* @opcode: configuration type
|
* @opcode: configuration type
|
||||||
* @config: configuration value to set
|
* @config: configuration value to set
|
||||||
@@ -1032,6 +563,7 @@ void hif_sdio_shutdown(struct hif_softc *hif_ctx)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_device_inserted() - hif-sdio driver probe handler
|
* hif_device_inserted() - hif-sdio driver probe handler
|
||||||
|
* @ol_sc: HIF device context
|
||||||
* @func: pointer to sdio_func
|
* @func: pointer to sdio_func
|
||||||
* @id: pointer to sdio_device_id
|
* @id: pointer to sdio_device_id
|
||||||
*
|
*
|
||||||
@@ -1057,10 +589,10 @@ static int hif_device_inserted(struct hif_softc *ol_sc,
|
|||||||
if (hifdevice &&
|
if (hifdevice &&
|
||||||
hifdevice->power_config == HIF_DEVICE_POWER_CUT &&
|
hifdevice->power_config == HIF_DEVICE_POWER_CUT &&
|
||||||
hifdevice->host == func->card->host) {
|
hifdevice->host == func->card->host) {
|
||||||
device = get_hif_device(func);
|
device = get_hif_device(ol_sc, func);
|
||||||
hifdevice->func = func;
|
hifdevice->func = func;
|
||||||
hifdevice->power_config = HIF_DEVICE_POWER_UP;
|
hifdevice->power_config = HIF_DEVICE_POWER_UP;
|
||||||
hif_sdio_set_drvdata(func, hifdevice);
|
hif_sdio_set_drvdata(ol_sc, func, hifdevice);
|
||||||
|
|
||||||
if (device->is_suspend) {
|
if (device->is_suspend) {
|
||||||
HIF_INFO("%s: Resume from suspend", __func__);
|
HIF_INFO("%s: Resume from suspend", __func__);
|
||||||
@@ -1072,9 +604,10 @@ static int hif_device_inserted(struct hif_softc *ol_sc,
|
|||||||
|
|
||||||
/* If device not found, then it is a new insertion, alloc and add it */
|
/* If device not found, then it is a new insertion, alloc and add it */
|
||||||
if (!device) {
|
if (!device) {
|
||||||
if (add_hif_device(func) == NULL)
|
if (!add_hif_device(ol_sc, func))
|
||||||
return QDF_STATUS_E_FAILURE;
|
return QDF_STATUS_E_FAILURE;
|
||||||
device = get_hif_device(func);
|
|
||||||
|
device = get_hif_device(ol_sc, func);
|
||||||
|
|
||||||
for (i = 0; i < MAX_HIF_DEVICES; ++i) {
|
for (i = 0; i < MAX_HIF_DEVICES; ++i) {
|
||||||
if (!hif_devices[i]) {
|
if (!hif_devices[i]) {
|
||||||
@@ -1095,13 +628,13 @@ static int hif_device_inserted(struct hif_softc *ol_sc,
|
|||||||
*/
|
*/
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
hif_sdio_quirk_force_drive_strength(func);
|
hif_sdio_quirk_force_drive_strength(ol_sc, func);
|
||||||
|
|
||||||
hif_sdio_quirk_write_cccr(func);
|
hif_sdio_quirk_write_cccr(ol_sc, func);
|
||||||
|
|
||||||
ret = hif_sdio_set_bus_speed(func);
|
ret = hif_sdio_set_bus_speed(ol_sc, func);
|
||||||
|
|
||||||
ret = hif_sdio_set_bus_width(func);
|
ret = hif_sdio_set_bus_width(ol_sc, func);
|
||||||
if (debugcccr)
|
if (debugcccr)
|
||||||
hif_dump_cccr(device);
|
hif_dump_cccr(device);
|
||||||
|
|
||||||
@@ -1174,11 +707,11 @@ void hif_ack_interrupt(struct hif_sdio_dev *device)
|
|||||||
* @pdev - HIF layer object
|
* @pdev - HIF layer object
|
||||||
* @func - SDIO bus function object
|
* @func - SDIO bus function object
|
||||||
*
|
*
|
||||||
* Return - NONE
|
* Return - error in case of failure to configure, else success
|
||||||
*/
|
*/
|
||||||
void hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func)
|
int hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
/* ADMA-TODO */
|
return hif_dev_configure_pipes(dev, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1233,7 +766,7 @@ void hif_free_bus_request(struct hif_sdio_dev *device,
|
|||||||
int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev)
|
int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev)
|
||||||
{
|
{
|
||||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||||
struct hif_sdio_dev *device = get_hif_device(func);
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
mmc_pm_flag_t pm_flag = 0;
|
mmc_pm_flag_t pm_flag = 0;
|
||||||
enum HIF_DEVICE_POWER_CHANGE_TYPE config;
|
enum HIF_DEVICE_POWER_CHANGE_TYPE config;
|
||||||
struct mmc_host *host = func->card->host;
|
struct mmc_host *host = func->card->host;
|
||||||
@@ -1314,7 +847,7 @@ int hif_device_resume(struct hif_softc *ol_sc, struct device *dev)
|
|||||||
enum HIF_DEVICE_POWER_CHANGE_TYPE config;
|
enum HIF_DEVICE_POWER_CHANGE_TYPE config;
|
||||||
struct hif_sdio_dev *device;
|
struct hif_sdio_dev *device;
|
||||||
|
|
||||||
device = get_hif_device(func);
|
device = get_hif_device(ol_sc, func);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
HIF_ERROR("%s: hif object is null", __func__);
|
HIF_ERROR("%s: hif object is null", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -1367,7 +900,8 @@ static A_STATUS hif_sdio_remove(void *context, void *hif_handle)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static void hif_device_removed(struct sdio_func *func)
|
|
||||||
|
static void hif_device_removed(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
struct hif_sdio_dev *device;
|
struct hif_sdio_dev *device;
|
||||||
@@ -1375,7 +909,7 @@ static void hif_device_removed(struct sdio_func *func)
|
|||||||
|
|
||||||
AR_DEBUG_ASSERT(func);
|
AR_DEBUG_ASSERT(func);
|
||||||
HIF_ENTER();
|
HIF_ENTER();
|
||||||
device = get_hif_device(func);
|
device = get_hif_device(ol_sc, func);
|
||||||
|
|
||||||
if (device->power_config == HIF_DEVICE_POWER_CUT) {
|
if (device->power_config == HIF_DEVICE_POWER_CUT) {
|
||||||
device->func = NULL; /* func will be free by mmc stack */
|
device->func = NULL; /* func will be free by mmc stack */
|
||||||
@@ -1406,7 +940,8 @@ static void hif_device_removed(struct sdio_func *func)
|
|||||||
HIF_EXIT();
|
HIF_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hif_sdio_dev *add_hif_device(struct sdio_func *func)
|
static struct hif_sdio_dev *add_hif_device(struct hif_softc *ol_sc,
|
||||||
|
struct sdio_func *func)
|
||||||
{
|
{
|
||||||
struct hif_sdio_dev *hifdevice = NULL;
|
struct hif_sdio_dev *hifdevice = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -1430,8 +965,8 @@ static struct hif_sdio_dev *add_hif_device(struct sdio_func *func)
|
|||||||
hifdevice->func = func;
|
hifdevice->func = func;
|
||||||
hifdevice->power_config = HIF_DEVICE_POWER_UP;
|
hifdevice->power_config = HIF_DEVICE_POWER_UP;
|
||||||
hifdevice->device_state = HIF_DEVICE_STATE_ON;
|
hifdevice->device_state = HIF_DEVICE_STATE_ON;
|
||||||
ret = hif_sdio_set_drvdata(func, hifdevice);
|
ret = hif_sdio_set_drvdata(ol_sc, func, hifdevice);
|
||||||
hif_info("status %d", ret);
|
HIF_INFO("status %d", ret);
|
||||||
|
|
||||||
return hifdevice;
|
return hifdevice;
|
||||||
}
|
}
|
||||||
@@ -1552,12 +1087,12 @@ int hif_sdio_device_inserted(struct hif_softc *ol_sc,
|
|||||||
|
|
||||||
HIF_ERROR("%s: Enter", __func__);
|
HIF_ERROR("%s: Enter", __func__);
|
||||||
status = hif_device_inserted(ol_sc, func, id);
|
status = hif_device_inserted(ol_sc, func, id);
|
||||||
HIF_ERROR("%s: Exit", __func__);
|
HIF_ERROR("%s: Exit: status:%d", __func__, status);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hif_sdio_device_removed(struct sdio_func *func)
|
void hif_sdio_device_removed(struct hif_softc *ol_sc, struct sdio_func *func)
|
||||||
{
|
{
|
||||||
hif_device_removed(func);
|
hif_device_removed(ol_sc, func);
|
||||||
}
|
}
|
||||||
|
858
hif/src/sdio/transfer/adma.c
Normal file
858
hif/src/sdio/transfer/adma.c
Normal file
@@ -0,0 +1,858 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
|
* above copyright notice and this permission notice appear in all
|
||||||
|
* copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <qdf_lock.h>
|
||||||
|
#include "adma.h"
|
||||||
|
#include "hif_sdio_internal.h"
|
||||||
|
#include "pld_sdio.h"
|
||||||
|
#include "if_sdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_get_fifo_address() - get the fifo addresses for dma
|
||||||
|
* @pdev: SDIO HIF object
|
||||||
|
* @c : FIFO address config pointer
|
||||||
|
*
|
||||||
|
* Return : 0 for success, non-zero for error
|
||||||
|
*/
|
||||||
|
int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
|
||||||
|
void *c,
|
||||||
|
uint32_t config_len)
|
||||||
|
{
|
||||||
|
/* SDIO AL handles DMA Addresses */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_get_block_size() - get the adma block size for dma
|
||||||
|
* @config : block size config pointer
|
||||||
|
*
|
||||||
|
* Return : NONE
|
||||||
|
*/
|
||||||
|
void hif_dev_get_block_size(void *config)
|
||||||
|
{
|
||||||
|
/* TODO Get block size used by AL Layer in Mission ROM Mode */
|
||||||
|
*((uint32_t *)config) = HIF_BLOCK_SIZE; /* QCN_SDIO_MROM_BLK_SZ TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_configure_pipes() - configure pipes
|
||||||
|
* @pdev: SDIO HIF object
|
||||||
|
* @func: sdio function object
|
||||||
|
*
|
||||||
|
* Return : 0 for success, non-zero for error
|
||||||
|
*/
|
||||||
|
int hif_dev_configure_pipes(struct hif_sdio_dev *pdev, struct sdio_func *func)
|
||||||
|
{
|
||||||
|
/* SDIO AL Configures SDIO Channels */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_set_mailbox_swap() - Set the mailbox swap
|
||||||
|
* @pdev : The HIF layer object
|
||||||
|
*
|
||||||
|
* Return: none
|
||||||
|
*/
|
||||||
|
void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
|
||||||
|
{
|
||||||
|
/* SDIO AL doesn't use mailbox architecture */
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
|
||||||
|
* @pdev : The HIF layer object
|
||||||
|
*
|
||||||
|
* Return: true or false
|
||||||
|
*/
|
||||||
|
bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
|
||||||
|
{
|
||||||
|
/* SDIO AL doesn't use mailbox architecture */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_dsr_handler() - Synchronous interrupt handler
|
||||||
|
*
|
||||||
|
* @context: hif send context
|
||||||
|
*
|
||||||
|
* Return: 0 for success and non-zero for failure
|
||||||
|
*/
|
||||||
|
QDF_STATUS hif_dev_dsr_handler(void *context)
|
||||||
|
{
|
||||||
|
/* SDIO AL handles interrupts */
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id.
|
||||||
|
* @pDev: SDIO HIF object
|
||||||
|
* @ServiceId: sevice index
|
||||||
|
* @ULPipe: uplink pipe id
|
||||||
|
* @DLPipe: down-linklink pipe id
|
||||||
|
*
|
||||||
|
* Return: 0 on success, error value on invalid map
|
||||||
|
*/
|
||||||
|
QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_dev *pdev, uint16_t svc,
|
||||||
|
uint8_t *ul_pipe, uint8_t *dl_pipe)
|
||||||
|
{
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
switch (svc) {
|
||||||
|
case HTT_DATA_MSG_SVC:
|
||||||
|
*dl_pipe = 2;
|
||||||
|
*ul_pipe = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HTC_CTRL_RSVD_SVC:
|
||||||
|
case HTC_RAW_STREAMS_SVC:
|
||||||
|
*dl_pipe = 0;
|
||||||
|
*ul_pipe = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMI_DATA_BE_SVC:
|
||||||
|
case WMI_DATA_BK_SVC:
|
||||||
|
case WMI_DATA_VI_SVC:
|
||||||
|
case WMI_DATA_VO_SVC:
|
||||||
|
*dl_pipe = 2;
|
||||||
|
*ul_pipe = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMI_CONTROL_SVC:
|
||||||
|
*dl_pipe = 0;
|
||||||
|
*ul_pipe = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
HIF_ERROR("%s: Err : Invalid service (%d)",
|
||||||
|
__func__, svc);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_setup_device() - Setup device specific stuff here required for hif
|
||||||
|
* @pdev : HIF layer object
|
||||||
|
*
|
||||||
|
* return 0 on success, error otherwise
|
||||||
|
*/
|
||||||
|
int hif_dev_setup_device(struct hif_sdio_device *pdev)
|
||||||
|
{
|
||||||
|
hif_dev_get_block_size(&pdev->BlockSize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_mask_interrupts() - Disable the interrupts in the device
|
||||||
|
* @pdev SDIO HIF Object
|
||||||
|
*
|
||||||
|
* Return: NONE
|
||||||
|
*/
|
||||||
|
void hif_dev_mask_interrupts(struct hif_sdio_device *pdev)
|
||||||
|
{
|
||||||
|
/* SDIO AL Handles Interrupts */
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_unmask_interrupts() - Enable the interrupts in the device
|
||||||
|
* @pdev SDIO HIF Object
|
||||||
|
*
|
||||||
|
* Return: NONE
|
||||||
|
*/
|
||||||
|
void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev)
|
||||||
|
{
|
||||||
|
/* SDIO AL Handles Interrupts */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_map_pipe_to_adma_chan() - maps pipe id to adma chan
|
||||||
|
* @pdev: The pointer to the hif device object
|
||||||
|
* @pipeid: pipe index
|
||||||
|
*
|
||||||
|
* Return: adma channel handle
|
||||||
|
*/
|
||||||
|
struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan
|
||||||
|
(
|
||||||
|
struct hif_sdio_device *dev,
|
||||||
|
uint8_t pipeid
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct hif_sdio_dev *pdev = dev->HIFDevice;
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
if ((pipeid == 0) || (pipeid == 1))
|
||||||
|
return pdev->al_chan[0];
|
||||||
|
else if ((pipeid == 2) || (pipeid == 3))
|
||||||
|
return pdev->al_chan[1];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_map_adma_chan_to_pipe() - map adma chan to htc pipe
|
||||||
|
* @pdev: The pointer to the hif device object
|
||||||
|
* @chan: channel number
|
||||||
|
* @upload: boolean to decide upload or download
|
||||||
|
*
|
||||||
|
* Return: Invalid pipe index
|
||||||
|
*/
|
||||||
|
uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev,
|
||||||
|
uint8_t chan, bool upload)
|
||||||
|
{
|
||||||
|
HIF_INFO("%s: chan: %u, %s", __func__, chan,
|
||||||
|
upload ? "Upload" : "Download");
|
||||||
|
|
||||||
|
if (chan == 0) /* chan 0 is mapped to HTT */
|
||||||
|
return upload ? 1 : 0;
|
||||||
|
else if (chan == 1) /* chan 1 is mapped to WMI */
|
||||||
|
return upload ? 3 : 2;
|
||||||
|
|
||||||
|
return (uint8_t)-1; /* invalid channel id */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_get_send_address() - Get the transfer pipe address
|
||||||
|
* @pdev: The pointer to the hif device object
|
||||||
|
* @pipe: The pipe identifier
|
||||||
|
*
|
||||||
|
* Return 0 for success and non-zero for failure to map
|
||||||
|
*/
|
||||||
|
int hif_get_send_address(struct hif_sdio_device *pdev,
|
||||||
|
uint8_t pipe, unsigned long *addr)
|
||||||
|
{
|
||||||
|
struct sdio_al_channel_handle *chan = NULL;
|
||||||
|
|
||||||
|
HIF_INFO("pipe: %u", pipe);
|
||||||
|
|
||||||
|
if (!addr)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*addr = 0;
|
||||||
|
chan = hif_dev_map_pipe_to_adma_chan(pdev, pipe);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*addr = (unsigned long)chan;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_fixup_write_param() - Tweak the address and length parameters
|
||||||
|
* @pdev: The pointer to the hif device object
|
||||||
|
* @length: The length pointer
|
||||||
|
* @addr: The addr pointer
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
void hif_fixup_write_param(struct hif_sdio_dev *pdev, uint32_t req,
|
||||||
|
uint32_t *length, uint32_t *addr)
|
||||||
|
{
|
||||||
|
HIF_ENTER();
|
||||||
|
/* ADMA-TODO */
|
||||||
|
HIF_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HIF_MAX_RX_Q_ALLOC 0 /* TODO */
|
||||||
|
#define HIF_RX_Q_ALLOC_THRESHOLD 100
|
||||||
|
QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func,
|
||||||
|
bool reset)
|
||||||
|
{
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
#if HIF_MAX_RX_Q_ALLOC
|
||||||
|
qdf_list_node_t *node;
|
||||||
|
struct rx_q_entry *rx_q_elem;
|
||||||
|
#endif
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
#if HIF_MAX_RX_Q_ALLOC
|
||||||
|
qdf_spin_lock_irqsave(&device->rx_q_lock);
|
||||||
|
|
||||||
|
for (; device->rx_q.count; ) {
|
||||||
|
qdf_list_remove_back(&device->rx_q, &node);
|
||||||
|
rx_q_elem = container_of(node, struct rx_q_entry, entry);
|
||||||
|
if (rx_q_elem) {
|
||||||
|
if (rx_q_elem->nbuf)
|
||||||
|
qdf_nbuf_free(rx_q_elem->nbuf);
|
||||||
|
qdf_mem_free(rx_q_elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qdf_destroy_work(0, &device->rx_q_alloc_work);
|
||||||
|
|
||||||
|
qdf_spin_unlock_irqrestore(&device->rx_q_lock);
|
||||||
|
|
||||||
|
qdf_spinlock_destroy(&device->rx_q_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status = hif_sdio_func_disable(device, func, reset);
|
||||||
|
if (status == QDF_STATUS_SUCCESS)
|
||||||
|
device->is_disabled = true;
|
||||||
|
|
||||||
|
cleanup_hif_scatter_resources(device);
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_enable_func() - Enable SDIO function
|
||||||
|
*
|
||||||
|
* @ol_sc: HIF object pointer
|
||||||
|
* @device: HIF device pointer
|
||||||
|
* @sdio_func: SDIO function pointer
|
||||||
|
* @resume: If this is called from resume or probe
|
||||||
|
*
|
||||||
|
* Return: 0 in case of success, else error value
|
||||||
|
*/
|
||||||
|
QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func, bool resume)
|
||||||
|
{
|
||||||
|
int ret = QDF_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
HIF_ERROR("%s: HIF device is NULL", __func__);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resume)
|
||||||
|
ret = hif_sdio_probe(ol_sc, func, device);
|
||||||
|
|
||||||
|
#if HIF_MAX_RX_Q_ALLOC
|
||||||
|
if (!ret) {
|
||||||
|
qdf_list_create(&device->rx_q, HIF_MAX_RX_Q_ALLOC);
|
||||||
|
qdf_spinlock_create(&device->rx_q_lock);
|
||||||
|
qdf_create_work(0, &device->rx_q_alloc_work,
|
||||||
|
hif_sdio_rx_q_alloc, (void *)device);
|
||||||
|
device->rx_q_alloc_work_scheduled = true;
|
||||||
|
qdf_sched_work(0, &device->rx_q_alloc_work);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_get_net_buf() - Get a network buffer from the rx q
|
||||||
|
* @dev - HIF device object
|
||||||
|
*
|
||||||
|
* Return - NULL if out of buffers, else qdf_nbuf_t
|
||||||
|
*/
|
||||||
|
#define HEAD_ROOM 256
|
||||||
|
#define len_head_room(len) ((len) + HEAD_ROOM)
|
||||||
|
#define is_pad_block(buf) (*((uint32_t *)buf) == 0xbabababa)
|
||||||
|
#if HIF_MAX_RX_Q_ALLOC
|
||||||
|
qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev)
|
||||||
|
{
|
||||||
|
qdf_list_node_t *node;
|
||||||
|
qdf_nbuf_t nbuf = NULL;
|
||||||
|
qdf_list_t *q = &dev->rx_q;
|
||||||
|
struct rx_q_entry *elem = NULL;
|
||||||
|
|
||||||
|
qdf_spin_lock_irqsave(&dev->rx_q_lock);
|
||||||
|
|
||||||
|
if (q->count) {
|
||||||
|
qdf_list_remove_front(q, &node);
|
||||||
|
elem = qdf_container_of(node, struct rx_q_entry, entry);
|
||||||
|
nbuf = elem->nbuf;
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: no rx q elements", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q->count <= HIF_RX_Q_ALLOC_THRESHOLD &&
|
||||||
|
!dev->rx_q_alloc_work_scheduled) {
|
||||||
|
dev->rx_q_alloc_work_scheduled = true;
|
||||||
|
qdf_sched_work(0, &dev->rx_q_alloc_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
|
||||||
|
|
||||||
|
qdf_mem_free(elem);
|
||||||
|
|
||||||
|
return nbuf;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev)
|
||||||
|
{
|
||||||
|
qdf_nbuf_t nbuf;
|
||||||
|
|
||||||
|
nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE + HEAD_ROOM,
|
||||||
|
HEAD_ROOM, 4, 0);
|
||||||
|
return nbuf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* hif_sdio_rx_q_alloc() - Deferred work for pre-alloc rx q
|
||||||
|
* @ctx - Pointer to context object
|
||||||
|
*
|
||||||
|
* Return NONE
|
||||||
|
*/
|
||||||
|
#if HIF_MAX_RX_Q_ALLOC
|
||||||
|
void hif_sdio_rx_q_alloc(void *ctx)
|
||||||
|
{
|
||||||
|
struct rx_q_entry *rx_q_elem;
|
||||||
|
struct hif_sdio_dev *dev = (struct hif_sdio_dev *)ctx;
|
||||||
|
unsigned int rx_q_count = dev->rx_q.count;
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
qdf_spin_lock_irqsave(&dev->rx_q_lock);
|
||||||
|
|
||||||
|
for (; rx_q_count < dev->rx_q.max_size; rx_q_count++) {
|
||||||
|
rx_q_elem = qdf_mem_malloc(sizeof(struct rx_q_entry));
|
||||||
|
if (!rx_q_elem) {
|
||||||
|
HIF_ERROR("%s: failed to alloc rx q elem", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_q_elem->nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE +
|
||||||
|
HEAD_ROOM, HEAD_ROOM, 4, 0);
|
||||||
|
if (!rx_q_elem->nbuf) {
|
||||||
|
HIF_ERROR("%s: failed to alloc nbuf for rx", __func__);
|
||||||
|
qdf_mem_free(rx_q_elem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdf_list_insert_back(&dev->rx_q, &rx_q_elem->entry);
|
||||||
|
}
|
||||||
|
dev->rx_q_alloc_work_scheduled = false;
|
||||||
|
|
||||||
|
qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
|
||||||
|
HIF_EXIT();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void hif_sdio_rx_q_alloc(void *ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <linux/qcn_sdio_al.h>
|
||||||
|
|
||||||
|
struct sdio_al_channel_data qcn7605_chan[HIF_SDIO_MAX_AL_CHANNELS] = {
|
||||||
|
{
|
||||||
|
.name = "SDIO_AL_WLAN_CH0", /* HTT */
|
||||||
|
.client_data = NULL, /* populate from client handle */
|
||||||
|
.ul_xfer_cb = ul_xfer_cb,
|
||||||
|
.dl_xfer_cb = dl_xfer_cb,
|
||||||
|
.dl_data_avail_cb = dl_data_avail_cb,
|
||||||
|
.dl_meta_data_cb = NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "SDIO_AL_WLAN_CH1", /* WMI */
|
||||||
|
.client_data = NULL, /* populate from client handle */
|
||||||
|
.ul_xfer_cb = ul_xfer_cb,
|
||||||
|
.dl_xfer_cb = dl_xfer_cb,
|
||||||
|
.dl_data_avail_cb = dl_data_avail_cb,
|
||||||
|
.dl_meta_data_cb = NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_register_channels()- Register transport layer channels
|
||||||
|
* @dev : HIF device object
|
||||||
|
* @func : SDIO function pointer
|
||||||
|
*
|
||||||
|
* Return : success on configuration, else failure
|
||||||
|
*/
|
||||||
|
int hif_dev_register_channels(struct hif_sdio_dev *dev, struct sdio_func *func)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int chan;
|
||||||
|
struct sdio_al_channel_data *chan_data[HIF_ADMA_MAX_CHANS];
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
dev->al_client = pld_sdio_get_sdio_al_client_handle(func);
|
||||||
|
if (ret || !dev->al_client) {
|
||||||
|
HIF_ERROR("%s: Failed to get get sdio al handle", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
|
||||||
|
MANUFACTURER_ID_QCN7605_BASE) {
|
||||||
|
dev->adma_chans_used = 2;
|
||||||
|
qcn7605_chan[0].client_data = dev->al_client->client_data;
|
||||||
|
qcn7605_chan[1].client_data = dev->al_client->client_data;
|
||||||
|
chan_data[0] = &qcn7605_chan[0];
|
||||||
|
chan_data[1] = &qcn7605_chan[1];
|
||||||
|
} else {
|
||||||
|
dev->adma_chans_used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (chan = 0; chan < dev->adma_chans_used; chan++) {
|
||||||
|
dev->al_chan[chan] =
|
||||||
|
pld_sdio_register_sdio_al_channel(dev->al_client,
|
||||||
|
chan_data[chan]);
|
||||||
|
if (!dev->al_chan[chan] || IS_ERR(dev->al_chan[chan])) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
HIF_ERROR("%s: Channel registration failed", __func__);
|
||||||
|
} else {
|
||||||
|
dev->al_chan[chan]->priv = (void *)dev;
|
||||||
|
HIF_INFO("%s: chan %s : id : %u", __func__,
|
||||||
|
chan_data[chan]->name,
|
||||||
|
dev->al_chan[chan]->channel_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_dev_unregister_channels()- Register transport layer channels
|
||||||
|
* @dev : HIF device object
|
||||||
|
* @func : SDIO Function pointer
|
||||||
|
*
|
||||||
|
* Return : None
|
||||||
|
*/
|
||||||
|
void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
unsigned int chan;
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
HIF_ERROR("%s: hif_sdio_dev is null", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (chan = 0; chan < dev->adma_chans_used; chan++) {
|
||||||
|
dev->al_chan[chan]->priv = NULL;
|
||||||
|
pld_sdio_unregister_sdio_al_channel(dev->al_chan[chan]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_read_write() - queue a read/write request
|
||||||
|
* @dev: pointer to hif device structure
|
||||||
|
* @address: address to read, actually channel pointer
|
||||||
|
* @buffer: buffer to hold read/write data
|
||||||
|
* @length: length to read/write
|
||||||
|
* @request: read/write/sync/async request
|
||||||
|
* @context: pointer to hold calling context
|
||||||
|
*
|
||||||
|
* Return: 0, pending on success, error number otherwise.
|
||||||
|
*/
|
||||||
|
QDF_STATUS
|
||||||
|
hif_read_write(struct hif_sdio_dev *dev,
|
||||||
|
unsigned long sdio_al_ch_handle,
|
||||||
|
char *cbuffer, uint32_t length,
|
||||||
|
uint32_t request, void *context)
|
||||||
|
{
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
struct sdio_al_channel_handle *ch;
|
||||||
|
struct bus_request *bus_req;
|
||||||
|
enum sdio_al_dma_direction dir;
|
||||||
|
struct hif_sdio_device *device;
|
||||||
|
QDF_STATUS (*rx_comp)(void *, qdf_nbuf_t, uint8_t);
|
||||||
|
qdf_nbuf_t nbuf;
|
||||||
|
int ret = 0, payload_len = 0;
|
||||||
|
unsigned char *buffer = (unsigned char *)cbuffer;
|
||||||
|
|
||||||
|
if (!dev || !sdio_al_ch_handle) {
|
||||||
|
HIF_ERROR("%s: device = %pK, addr = %lu", __func__,
|
||||||
|
dev, sdio_al_ch_handle);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(request & HIF_ASYNCHRONOUS) &&
|
||||||
|
!(request & HIF_SYNCHRONOUS)) {
|
||||||
|
HIF_ERROR("%s: Invalid request mode", __func__);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*sdio r/w action is not needed when suspend, so just return */
|
||||||
|
if ((dev->is_suspend) &&
|
||||||
|
(dev->power_config == HIF_DEVICE_POWER_CUT)) {
|
||||||
|
HIF_INFO("%s: skip in suspend", __func__);
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = (struct sdio_al_channel_handle *)sdio_al_ch_handle;
|
||||||
|
|
||||||
|
bus_req = hif_allocate_bus_request(dev);
|
||||||
|
if (!bus_req) {
|
||||||
|
HIF_ERROR("%s: Bus alloc failed", __func__);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus_req->address = sdio_al_ch_handle;
|
||||||
|
bus_req->length = length;
|
||||||
|
bus_req->request = request;
|
||||||
|
bus_req->context = context;
|
||||||
|
bus_req->buffer = buffer;
|
||||||
|
|
||||||
|
/* Request SDIO AL to do transfer */
|
||||||
|
dir = (request & HIF_SDIO_WRITE) ? SDIO_AL_TX : SDIO_AL_RX;
|
||||||
|
|
||||||
|
if (request & HIF_SDIO_WRITE)
|
||||||
|
HIF_TRACE("%s: Tx len %d", __func__, length);
|
||||||
|
|
||||||
|
if (request & HIF_SDIO_READ)
|
||||||
|
HIF_TRACE("%s: Rx len %d", __func__, length);
|
||||||
|
|
||||||
|
if (request & HIF_SYNCHRONOUS) {
|
||||||
|
ret = sdio_al_queue_transfer(ch,
|
||||||
|
dir,
|
||||||
|
bus_req->buffer,
|
||||||
|
bus_req->length,
|
||||||
|
1); /* higher priority */
|
||||||
|
if (ret) {
|
||||||
|
status = QDF_STATUS_E_FAILURE;
|
||||||
|
HIF_ERROR("%s: SYNC REQ failed ret=%d", __func__, ret);
|
||||||
|
} else {
|
||||||
|
status = QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
hif_free_bus_request(dev, bus_req);
|
||||||
|
|
||||||
|
if ((status == QDF_STATUS_SUCCESS) && (dir == SDIO_AL_RX)) {
|
||||||
|
nbuf = (qdf_nbuf_t)context;
|
||||||
|
payload_len = HTC_GET_FIELD(bus_req->buffer,
|
||||||
|
HTC_FRAME_HDR,
|
||||||
|
PAYLOADLEN);
|
||||||
|
qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH);
|
||||||
|
device = (struct hif_sdio_device *)dev->htc_context;
|
||||||
|
rx_comp = device->hif_callbacks.rxCompletionHandler;
|
||||||
|
rx_comp(device->hif_callbacks.Context, nbuf, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = sdio_al_queue_transfer_async(ch,
|
||||||
|
dir,
|
||||||
|
bus_req->buffer,
|
||||||
|
bus_req->length,
|
||||||
|
1, /* higher priority */
|
||||||
|
(void *)bus_req);
|
||||||
|
if (ret) {
|
||||||
|
status = QDF_STATUS_E_FAILURE;
|
||||||
|
HIF_ERROR("%s: ASYNC REQ fail ret=%d for len=%d ch=%d",
|
||||||
|
__func__, ret, length, ch->channel_id);
|
||||||
|
hif_free_bus_request(dev, bus_req);
|
||||||
|
} else {
|
||||||
|
status = QDF_STATUS_E_PENDING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ul_xfer_cb() - Completion call back for asyncronous transfer
|
||||||
|
* @ch_handle: The sdio al channel handle
|
||||||
|
* @result: The result of the operation
|
||||||
|
* @context: pointer to request context
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
struct sdio_al_xfer_result *result,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
struct bus_request *req = (struct bus_request *)ctx;
|
||||||
|
struct hif_sdio_dev *dev;
|
||||||
|
|
||||||
|
if (!ch_handle || !result) {
|
||||||
|
HIF_ERROR("%s: Invalid args", __func__);
|
||||||
|
qdf_assert_always(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = (struct hif_sdio_dev *)ch_handle->priv;
|
||||||
|
|
||||||
|
if (result->xfer_status) {
|
||||||
|
req->status = QDF_STATUS_E_FAILURE;
|
||||||
|
HIF_ERROR("%s: ASYNC Tx failed status=%d", __func__,
|
||||||
|
result->xfer_status);
|
||||||
|
} else {
|
||||||
|
req->status = QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->htc_callbacks.rw_compl_handler(req->context, req->status);
|
||||||
|
|
||||||
|
hif_free_bus_request(dev, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dl_data_avail_cb() - Called when data is available on a channel
|
||||||
|
* @ch_handle: The sdio al channel handle
|
||||||
|
* @len: The len of data available to download
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
/* Use the asynchronous method of transfer. This will help in
|
||||||
|
* completing READ in the transfer done callback later which
|
||||||
|
* runs in sdio al thread context. If we do the syncronous
|
||||||
|
* transfer here, the thread context won't be available and
|
||||||
|
* perhaps a new thread may be reaquired here.
|
||||||
|
*/
|
||||||
|
void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
unsigned int len)
|
||||||
|
{
|
||||||
|
struct hif_sdio_dev *dev;
|
||||||
|
unsigned int chan;
|
||||||
|
qdf_nbuf_t nbuf;
|
||||||
|
|
||||||
|
if (!ch_handle || !len) {
|
||||||
|
HIF_ERROR("%s: Invalid args %u", __func__, len);
|
||||||
|
qdf_assert_always(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = (struct hif_sdio_dev *)ch_handle->priv;
|
||||||
|
chan = ch_handle->channel_id;
|
||||||
|
|
||||||
|
if (chan > HIF_SDIO_MAX_AL_CHANNELS) {
|
||||||
|
HIF_ERROR("%s: Invalid Ch ID %d", __func__, chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a buffer for reading the data from the chip.
|
||||||
|
* Note that this is raw, unparsed buffer and will be
|
||||||
|
* processed in the transfer done callback.
|
||||||
|
*/
|
||||||
|
/* TODO, use global buffer instead of runtime allocations */
|
||||||
|
nbuf = qdf_nbuf_alloc(NULL, len_head_room(len), HEAD_ROOM, 4, 0);
|
||||||
|
|
||||||
|
if (!nbuf) {
|
||||||
|
HIF_ERROR("%s: Unable to alloc netbuf %u bytes", __func__, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hif_read_write(dev, (unsigned long)ch_handle, nbuf->data, len,
|
||||||
|
HIF_RD_ASYNC_BLOCK_FIX, nbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dl_xfer_cb() - Call from lower layer after transfer is completed
|
||||||
|
* @ch_handle: The sdio al channel handle
|
||||||
|
* @result: The xfer result
|
||||||
|
* @ctx: Context passed in the transfer queuing
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
struct sdio_al_xfer_result *result,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
unsigned char *buf;
|
||||||
|
qdf_nbuf_t nbuf;
|
||||||
|
uint32_t len, nbuflen, payload_len = 0;
|
||||||
|
uint8_t *nbufdata;
|
||||||
|
struct hif_sdio_dev *dev;
|
||||||
|
struct hif_sdio_device *device;
|
||||||
|
struct bus_request *bus_req = (struct bus_request *)ctx;
|
||||||
|
bool last_htc_packet = false;
|
||||||
|
QDF_STATUS (*rx_completion)(void *, qdf_nbuf_t, uint8_t);
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
HIF_ERROR("%s: Net buf context NULL!!!", __func__);
|
||||||
|
|
||||||
|
if (!ctx || !ch_handle || !result) {
|
||||||
|
HIF_ERROR("%s: Invalid args", __func__);
|
||||||
|
qdf_assert_always(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = (struct hif_sdio_dev *)ch_handle->priv;
|
||||||
|
if (result->xfer_status) {
|
||||||
|
HIF_ERROR("%s: ASYNC Rx failed %d", __func__,
|
||||||
|
result->xfer_status);
|
||||||
|
/* TODO - Free nbuf if hif_sdio_get_nbuf is used, when bundling
|
||||||
|
* is enabled
|
||||||
|
*/
|
||||||
|
hif_free_bus_request(dev, (struct bus_request *)ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = (struct hif_sdio_device *)dev->htc_context;
|
||||||
|
rx_completion = device->hif_callbacks.rxCompletionHandler;
|
||||||
|
|
||||||
|
buf = (unsigned char *)result->buf_addr;
|
||||||
|
len = (unsigned int)result->xfer_len;
|
||||||
|
|
||||||
|
/* ADMA-TODO - Discard the padding data
|
||||||
|
* Its still not decided that the padding is informed
|
||||||
|
* via the hdr->flags or a padding magic inline in the
|
||||||
|
* buffer. So, lets see.
|
||||||
|
*/
|
||||||
|
while (len > 0 && len >= sizeof(HTC_FRAME_HDR)) {
|
||||||
|
if (last_htc_packet) {
|
||||||
|
HIF_ERROR("ERRR last htc_packet processed already\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID) >=
|
||||||
|
ENDPOINT_MAX) {
|
||||||
|
HIF_ERROR("%s: invalid endpoint id: %u", __func__,
|
||||||
|
HTC_GET_FIELD(buf, HTC_FRAME_HDR,
|
||||||
|
ENDPOINTID));
|
||||||
|
hif_free_bus_request(dev, (struct bus_request *)ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* last_htc_packet is currently used to test non bundling case
|
||||||
|
* on Rumi Emulation platform.
|
||||||
|
* TODO - Remove last_htc_packet logic when bundling is
|
||||||
|
* enabled and use is_pad_block for bundling
|
||||||
|
*/
|
||||||
|
last_htc_packet = 1;
|
||||||
|
/* TODO - get net buf using hif_sdio_get_nbuf, when bundling is
|
||||||
|
* enabled
|
||||||
|
*/
|
||||||
|
nbuf = (qdf_nbuf_t)bus_req->context;
|
||||||
|
if (!nbuf) {
|
||||||
|
HIF_ERROR("%s: failed to alloc rx buffer", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nbufdata = qdf_nbuf_data(nbuf);
|
||||||
|
nbuflen = qdf_nbuf_len(nbuf);
|
||||||
|
|
||||||
|
/* Copy the HTC frame to the alloc'd packet buffer */
|
||||||
|
payload_len = HTC_GET_FIELD(buf, HTC_FRAME_HDR, PAYLOADLEN);
|
||||||
|
if (!payload_len) {
|
||||||
|
HIF_ERROR("%s:Invalid Payload len %d bytes", __func__,
|
||||||
|
payload_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO - Check if payload fits in netbuf data */
|
||||||
|
if (0) { //nbuflen < payload_len) {
|
||||||
|
HIF_ERROR("%s: nbuf %d < payload %d bytes", __func__,
|
||||||
|
nbuflen, payload_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdf_mem_copy(nbufdata, buf,
|
||||||
|
payload_len + HTC_HEADER_LEN);
|
||||||
|
|
||||||
|
qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH);
|
||||||
|
rx_completion(device->hif_callbacks.Context,
|
||||||
|
nbuf,
|
||||||
|
0); /* don't care, not used */
|
||||||
|
|
||||||
|
if (len && last_htc_packet) {
|
||||||
|
unsigned int pad;
|
||||||
|
|
||||||
|
pad = DEV_CALC_RECV_PADDED_LEN(device, payload_len +
|
||||||
|
HTC_HEADER_LEN);
|
||||||
|
/* Decrement the length to be processed yet */
|
||||||
|
len -= pad;
|
||||||
|
/* Move the data pointer */
|
||||||
|
buf += pad;
|
||||||
|
} else {
|
||||||
|
len -= payload_len + HTC_HDR_LENGTH;
|
||||||
|
buf += payload_len + HTC_HDR_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hif_free_bus_request(dev, (struct bus_request *)ctx);
|
||||||
|
}
|
63
hif/src/sdio/transfer/adma.h
Normal file
63
hif/src/sdio/transfer/adma.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
|
* above copyright notice and this permission notice appear in all
|
||||||
|
* copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ADMA_H_
|
||||||
|
#define _ADMA_H_
|
||||||
|
|
||||||
|
#include "hif_sdio_dev.h"
|
||||||
|
#include "htc_packet.h"
|
||||||
|
#include "htc_api.h"
|
||||||
|
#include "hif_internal.h"
|
||||||
|
|
||||||
|
/* This should align with the underlying transport layer */
|
||||||
|
#define HIF_DEFAULT_IO_BLOCK_SIZE 512
|
||||||
|
#define HIF_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE
|
||||||
|
#define HIF_DUMMY_SPACE_MASK 0x0FFFFFFF
|
||||||
|
|
||||||
|
#define HIF_SDIO_MAX_AL_CHANNELS 2
|
||||||
|
|
||||||
|
struct devRegisters {
|
||||||
|
uint32_t dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "transfer.h"
|
||||||
|
#define DEV_REGISTERS_SIZE sizeof(struct devRegisters)
|
||||||
|
|
||||||
|
uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev,
|
||||||
|
uint8_t chan, bool upload);
|
||||||
|
|
||||||
|
struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan
|
||||||
|
(
|
||||||
|
struct hif_sdio_device *pdev,
|
||||||
|
uint8_t pipeid
|
||||||
|
);
|
||||||
|
|
||||||
|
void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
struct sdio_al_xfer_result *result,
|
||||||
|
void *ctx);
|
||||||
|
void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
struct sdio_al_xfer_result *result,
|
||||||
|
void *ctx);
|
||||||
|
|
||||||
|
void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle,
|
||||||
|
unsigned int len);
|
||||||
|
|
||||||
|
void hif_sdio_rx_q_alloc(void *ctx);
|
||||||
|
qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev);
|
||||||
|
#endif
|
@@ -1,7 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
* above copyright notice and this permission notice appear in all
|
* above copyright notice and this permission notice appear in all
|
||||||
@@ -19,6 +18,7 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
|
||||||
#define ATH_MODULE_NAME hif
|
#define ATH_MODULE_NAME hif
|
||||||
|
#include <linux/kthread.h>
|
||||||
#include <qdf_types.h>
|
#include <qdf_types.h>
|
||||||
#include <qdf_status.h>
|
#include <qdf_status.h>
|
||||||
#include <qdf_timer.h>
|
#include <qdf_timer.h>
|
||||||
@@ -44,6 +44,24 @@
|
|||||||
#include "regtable.h"
|
#include "regtable.h"
|
||||||
#include "transfer.h"
|
#include "transfer.h"
|
||||||
|
|
||||||
|
/* by default setup a bounce buffer for the data packets,
|
||||||
|
* if the underlying host controller driver
|
||||||
|
* does not use DMA you may be able to skip this step
|
||||||
|
* and save the memory allocation and transfer time
|
||||||
|
*/
|
||||||
|
#define HIF_USE_DMA_BOUNCE_BUFFER 1
|
||||||
|
#if HIF_USE_DMA_BOUNCE_BUFFER
|
||||||
|
/* macro to check if DMA buffer is WORD-aligned and DMA-able.
|
||||||
|
* Most host controllers assume the
|
||||||
|
* buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
|
||||||
|
* virt_addr_valid check fails on stack memory.
|
||||||
|
*/
|
||||||
|
#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || \
|
||||||
|
!virt_addr_valid((buffer)))
|
||||||
|
#else
|
||||||
|
#define BUFFER_NEEDS_BOUNCE(buffer) (false)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SDIO_3_0
|
#ifdef SDIO_3_0
|
||||||
/**
|
/**
|
||||||
* set_extended_mbox_size() - set extended MBOX size
|
* set_extended_mbox_size() - set extended MBOX size
|
||||||
@@ -170,6 +188,40 @@ static void set_extended_mbox_window_info(uint16_t manf_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** hif_dev_set_mailbox_swap() - Set the mailbox swap from firmware
|
||||||
|
* @pdev : The HIF layer object
|
||||||
|
*
|
||||||
|
* Return: none
|
||||||
|
*/
|
||||||
|
void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
|
||||||
|
{
|
||||||
|
struct hif_sdio_device *hif_device = hif_dev_from_hif(pdev);
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
hif_device->swap_mailbox = true;
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
|
||||||
|
* @pdev : The HIF layer object
|
||||||
|
*
|
||||||
|
* Return: true or false
|
||||||
|
*/
|
||||||
|
bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
|
||||||
|
{
|
||||||
|
struct hif_sdio_device *hif_device;
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
hif_device = hif_dev_from_hif(pdev);
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
|
||||||
|
return hif_device->swap_mailbox;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hif_dev_get_fifo_address() - get the fifo addresses for dma
|
* hif_dev_get_fifo_address() - get the fifo addresses for dma
|
||||||
* @pdev: SDIO HIF object
|
* @pdev: SDIO HIF object
|
||||||
@@ -177,22 +229,24 @@ static void set_extended_mbox_window_info(uint16_t manf_id,
|
|||||||
*
|
*
|
||||||
* Return : 0 for success, non-zero for error
|
* Return : 0 for success, non-zero for error
|
||||||
*/
|
*/
|
||||||
QDF_STATUS hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
|
int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
|
||||||
struct hif_device_mbox_info *config,
|
void *config,
|
||||||
uint32_t config_len)
|
uint32_t config_len)
|
||||||
{
|
{
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
struct hif_device_mbox_info *cfg =
|
||||||
|
(struct hif_device_mbox_info *)config;
|
||||||
|
|
||||||
for (count = 0; count < 4; count++)
|
for (count = 0; count < 4; count++)
|
||||||
config->mbox_addresses[count] = HIF_MBOX_START_ADDR(count);
|
cfg->mbox_addresses[count] = HIF_MBOX_START_ADDR(count);
|
||||||
|
|
||||||
if (config_len >= sizeof(struct hif_device_mbox_info)) {
|
if (config_len >= sizeof(struct hif_device_mbox_info)) {
|
||||||
set_extended_mbox_window_info((uint16_t)pdev->func->device,
|
set_extended_mbox_window_info((uint16_t)pdev->func->device,
|
||||||
config);
|
cfg);
|
||||||
return QDF_STATUS_SUCCESS;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QDF_STATUS_E_INVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -488,7 +542,7 @@ static uint8_t hif_dev_map_mail_box_to_pipe(struct hif_sdio_device *pdev,
|
|||||||
* Return 0 for success and non-zero for failure to map
|
* Return 0 for success and non-zero for failure to map
|
||||||
*/
|
*/
|
||||||
int hif_get_send_address(struct hif_sdio_device *pdev,
|
int hif_get_send_address(struct hif_sdio_device *pdev,
|
||||||
uint8_t pipe, uint32_t *addr)
|
uint8_t pipe, unsigned long *addr)
|
||||||
{
|
{
|
||||||
uint8_t mbox_index = INVALID_MAILBOX_NUMBER;
|
uint8_t mbox_index = INVALID_MAILBOX_NUMBER;
|
||||||
|
|
||||||
@@ -586,9 +640,9 @@ static QDF_STATUS hif_dev_recv_packet(struct hif_sdio_device *pdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* mailbox index is saved in Endpoint member */
|
/* mailbox index is saved in Endpoint member */
|
||||||
HIF_INFO("%s : hdr:0x%x, len:%d, padded length: %d Mbox:0x%x",
|
HIF_INFO_HI("%s : hdr:0x%x, len:%d, padded length: %d Mbox:0x%x",
|
||||||
__func__, packet->PktInfo.AsRx.ExpectedHdr, recv_length,
|
__func__, packet->PktInfo.AsRx.ExpectedHdr, recv_length,
|
||||||
padded_length, mbox_index);
|
padded_length, mbox_index);
|
||||||
|
|
||||||
status = hif_read_write(pdev->HIFDevice,
|
status = hif_read_write(pdev->HIFDevice,
|
||||||
pdev->MailBoxInfo.mbox_addresses[mbox_index],
|
pdev->MailBoxInfo.mbox_addresses[mbox_index],
|
||||||
@@ -604,11 +658,11 @@ static QDF_STATUS hif_dev_recv_packet(struct hif_sdio_device *pdev,
|
|||||||
if (status == QDF_STATUS_SUCCESS) {
|
if (status == QDF_STATUS_SUCCESS) {
|
||||||
HTC_FRAME_HDR *hdr = (HTC_FRAME_HDR *) packet->pBuffer;
|
HTC_FRAME_HDR *hdr = (HTC_FRAME_HDR *) packet->pBuffer;
|
||||||
|
|
||||||
HIF_INFO("%s: EP:%d,Len:%d,Flag:%d,CB:0x%02X,0x%02X\n",
|
HIF_INFO_HI("%s:EP:%d,Len:%d,Flg:%d,CB:0x%02X,0x%02X\n",
|
||||||
__func__,
|
__func__,
|
||||||
hdr->EndpointID, hdr->PayloadLen,
|
hdr->EndpointID, hdr->PayloadLen,
|
||||||
hdr->Flags, hdr->ControlBytes0,
|
hdr->Flags, hdr->ControlBytes0,
|
||||||
hdr->ControlBytes1);
|
hdr->ControlBytes1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +799,7 @@ QDF_STATUS hif_dev_recv_message_pending_handler(struct hif_sdio_device *pdev,
|
|||||||
HTC_PACKET_QUEUE recv_q, sync_comp_q;
|
HTC_PACKET_QUEUE recv_q, sync_comp_q;
|
||||||
QDF_STATUS (*rxCompletion)(void *, qdf_nbuf_t, uint8_t);
|
QDF_STATUS (*rxCompletion)(void *, qdf_nbuf_t, uint8_t);
|
||||||
|
|
||||||
HIF_INFO("%s: NumLookAheads: %d\n", __func__, num_look_aheads);
|
HIF_INFO_HI("%s: NumLookAheads: %d\n", __func__, num_look_aheads);
|
||||||
|
|
||||||
if (num_pkts_fetched)
|
if (num_pkts_fetched)
|
||||||
*num_pkts_fetched = 0;
|
*num_pkts_fetched = 0;
|
||||||
@@ -1321,33 +1375,610 @@ QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) && \
|
#define DEV_CHECK_RECV_YIELD(pdev) \
|
||||||
!defined(WITH_BACKPORTS)
|
((pdev)->CurrentDSRRecvCount >= \
|
||||||
|
(pdev)->HifIRQYieldParams.recv_packet_yield_count)
|
||||||
/**
|
/**
|
||||||
* hif_sdio_set_drvdata() - set wlan driver data into upper layer private
|
* hif_dev_dsr_handler() - Synchronous interrupt handler
|
||||||
* @func: pointer to sdio function
|
|
||||||
* @hifdevice: pointer to hif device
|
|
||||||
*
|
*
|
||||||
* Return: non zero for success.
|
* @context: hif send context
|
||||||
|
*
|
||||||
|
* Return: 0 for success and non-zero for failure
|
||||||
*/
|
*/
|
||||||
int hif_sdio_set_drvdata(struct sdio_func *func,
|
QDF_STATUS hif_dev_dsr_handler(void *context)
|
||||||
struct hif_sdio_dev *hifdevice)
|
|
||||||
{
|
{
|
||||||
return sdio_set_drvdata(func, hifdevice);
|
struct hif_sdio_device *pdev = (struct hif_sdio_device *)context;
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
bool done = false;
|
||||||
|
bool async_proc = false;
|
||||||
|
|
||||||
|
/* reset the recv counter that tracks when we need
|
||||||
|
* to yield from the DSR
|
||||||
|
*/
|
||||||
|
pdev->CurrentDSRRecvCount = 0;
|
||||||
|
/* reset counter used to flag a re-scan of IRQ
|
||||||
|
* status registers on the target
|
||||||
|
*/
|
||||||
|
pdev->RecheckIRQStatusCnt = 0;
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
status = hif_dev_process_pending_irqs(pdev, &done, &async_proc);
|
||||||
|
if (QDF_IS_STATUS_ERROR(status))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pdev->HifIRQProcessingMode == HIF_DEVICE_IRQ_SYNC_ONLY) {
|
||||||
|
/* the HIF layer does not allow async IRQ processing,
|
||||||
|
* override the asyncProc flag
|
||||||
|
*/
|
||||||
|
async_proc = false;
|
||||||
|
/* this will cause us to re-enter ProcessPendingIRQ()
|
||||||
|
* and re-read interrupt status registers.
|
||||||
|
* This has a nice side effect of blocking us until all
|
||||||
|
* async read requests are completed. This behavior is
|
||||||
|
* required as we do not allow ASYNC processing
|
||||||
|
* in interrupt handlers (like Windows CE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev))
|
||||||
|
/* ProcessPendingIRQs() pulled enough recv
|
||||||
|
* messages to satisfy the yield count, stop
|
||||||
|
* checking for more messages and return
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (async_proc) {
|
||||||
|
/* the function does some async I/O for performance,
|
||||||
|
* we need to exit the ISR immediately, the check below
|
||||||
|
* will prevent the interrupt from being
|
||||||
|
* Ack'd while we handle it asynchronously
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) {
|
||||||
|
/* Ack the interrupt only if :
|
||||||
|
* 1. we did not get any errors in processing interrupts
|
||||||
|
* 2. there are no outstanding async processing requests
|
||||||
|
*/
|
||||||
|
if (pdev->DSRCanYield) {
|
||||||
|
/* if the DSR can yield do not ACK the interrupt, there
|
||||||
|
* could be more pending messages. The HIF layer
|
||||||
|
* must ACK the interrupt on behalf of HTC
|
||||||
|
*/
|
||||||
|
HIF_INFO("%s: Yield (RX count: %d)",
|
||||||
|
__func__, pdev->CurrentDSRRecvCount);
|
||||||
|
} else {
|
||||||
|
hif_ack_interrupt(pdev->HIFDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
int hif_sdio_set_drvdata(struct sdio_func *func,
|
/**
|
||||||
struct hif_sdio_dev *hifdevice)
|
* hif_read_write() - queue a read/write request
|
||||||
|
* @device: pointer to hif device structure
|
||||||
|
* @address: address to read
|
||||||
|
* @buffer: buffer to hold read/write data
|
||||||
|
* @length: length to read/write
|
||||||
|
* @request: read/write/sync/async request
|
||||||
|
* @context: pointer to hold calling context
|
||||||
|
*
|
||||||
|
* Return: 0 on success, error number otherwise.
|
||||||
|
*/
|
||||||
|
QDF_STATUS
|
||||||
|
hif_read_write(struct hif_sdio_dev *device,
|
||||||
|
unsigned long address,
|
||||||
|
char *buffer, uint32_t length,
|
||||||
|
uint32_t request, void *context)
|
||||||
{
|
{
|
||||||
sdio_set_drvdata(func, hifdevice);
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
struct bus_request *busrequest;
|
||||||
|
|
||||||
|
AR_DEBUG_ASSERT(device);
|
||||||
|
AR_DEBUG_ASSERT(device->func);
|
||||||
|
HIF_TRACE("%s: device 0x%pK addr 0x%lX buffer 0x%pK",
|
||||||
|
__func__, device, address, buffer);
|
||||||
|
HIF_TRACE("%s: len %d req 0x%X context 0x%pK",
|
||||||
|
__func__, length, request, context);
|
||||||
|
|
||||||
|
/*sdio r/w action is not needed when suspend, so just return */
|
||||||
|
if ((device->is_suspend) &&
|
||||||
|
(device->power_config == HIF_DEVICE_POWER_CUT)) {
|
||||||
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n"));
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if ((request & HIF_ASYNCHRONOUS) ||
|
||||||
|
(request & HIF_SYNCHRONOUS)) {
|
||||||
|
/* serialize all requests through the async thread */
|
||||||
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||||
|
("%s: Execution mode: %s\n", __func__,
|
||||||
|
(request & HIF_ASYNCHRONOUS) ? "Async"
|
||||||
|
: "Synch"));
|
||||||
|
busrequest = hif_allocate_bus_request(device);
|
||||||
|
if (!busrequest) {
|
||||||
|
HIF_ERROR("%s:bus requests unavail", __func__);
|
||||||
|
HIF_ERROR("%s, addr:0x%lX, len:%d",
|
||||||
|
request & HIF_SDIO_READ ? "READ" :
|
||||||
|
"WRITE", address, length);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
busrequest->address = address;
|
||||||
|
busrequest->buffer = buffer;
|
||||||
|
busrequest->length = length;
|
||||||
|
busrequest->request = request;
|
||||||
|
busrequest->context = context;
|
||||||
|
|
||||||
|
add_to_async_list(device, busrequest);
|
||||||
|
|
||||||
|
if (request & HIF_SYNCHRONOUS) {
|
||||||
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||||
|
("%s: queued sync req: 0x%lX\n",
|
||||||
|
__func__,
|
||||||
|
(unsigned long)busrequest));
|
||||||
|
|
||||||
|
/* wait for completion */
|
||||||
|
up(&device->sem_async);
|
||||||
|
if (down_interruptible(&busrequest->sem_req) ==
|
||||||
|
0) {
|
||||||
|
QDF_STATUS status = busrequest->status;
|
||||||
|
|
||||||
|
HIF_TRACE("%s: sync freeing 0x%lX:0x%X",
|
||||||
|
__func__,
|
||||||
|
(unsigned long)busrequest,
|
||||||
|
busrequest->status);
|
||||||
|
HIF_TRACE("%s: freeing req: 0x%X",
|
||||||
|
__func__,
|
||||||
|
(unsigned int)request);
|
||||||
|
hif_free_bus_request(device,
|
||||||
|
busrequest);
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
/* interrupted, exit */
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HIF_TRACE("%s: queued async req: 0x%lX",
|
||||||
|
__func__, (unsigned long)busrequest);
|
||||||
|
up(&device->sem_async);
|
||||||
|
return QDF_STATUS_E_PENDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: Invalid execution mode: 0x%08x",
|
||||||
|
__func__, (unsigned int)request);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_sdio_func_enable() - Handle device enabling as per device
|
||||||
|
* @device: HIF device object
|
||||||
|
* @func: function pointer
|
||||||
|
*
|
||||||
|
* Return success or failure
|
||||||
|
*/
|
||||||
|
static int hif_sdio_func_enable(struct hif_softc *ol_sc,
|
||||||
|
struct sdio_func *func)
|
||||||
|
{
|
||||||
|
struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
|
||||||
|
|
||||||
|
if (device->is_disabled) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
sdio_claim_host(func);
|
||||||
|
|
||||||
|
ret = hif_sdio_quirk_async_intr(ol_sc, func);
|
||||||
|
if (ret) {
|
||||||
|
HIF_ERROR("%s: Error setting async intr:%d",
|
||||||
|
__func__, ret);
|
||||||
|
sdio_release_host(func);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
func->enable_timeout = 100;
|
||||||
|
ret = sdio_enable_func(func);
|
||||||
|
if (ret) {
|
||||||
|
HIF_ERROR("%s: Unable to enable function: %d",
|
||||||
|
__func__, ret);
|
||||||
|
sdio_release_host(func);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdio_set_block_size(func, HIF_BLOCK_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
HIF_ERROR("%s: Unable to set block size 0x%X : %d\n",
|
||||||
|
__func__, HIF_BLOCK_SIZE, ret);
|
||||||
|
sdio_release_host(func);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hif_sdio_quirk_mod_strength(ol_sc, func);
|
||||||
|
if (ret) {
|
||||||
|
HIF_ERROR("%s: Error setting mod strength : %d\n",
|
||||||
|
__func__, ret);
|
||||||
|
sdio_release_host(func);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdio_release_host(func);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* LINUX VERSION */
|
|
||||||
|
|
||||||
struct hif_sdio_dev *get_hif_device(struct sdio_func *func)
|
/**
|
||||||
|
* __hif_read_write() - sdio read/write wrapper
|
||||||
|
* @device: pointer to hif device structure
|
||||||
|
* @address: address to read
|
||||||
|
* @buffer: buffer to hold read/write data
|
||||||
|
* @length: length to read/write
|
||||||
|
* @request: read/write/sync/async request
|
||||||
|
* @context: pointer to hold calling context
|
||||||
|
*
|
||||||
|
* Return: 0 on success, error number otherwise.
|
||||||
|
*/
|
||||||
|
static QDF_STATUS
|
||||||
|
__hif_read_write(struct hif_sdio_dev *device,
|
||||||
|
uint32_t address, char *buffer,
|
||||||
|
uint32_t length, uint32_t request, void *context)
|
||||||
{
|
{
|
||||||
qdf_assert(func);
|
uint8_t opcode;
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
int ret = A_OK;
|
||||||
|
uint8_t *tbuffer;
|
||||||
|
bool bounced = false;
|
||||||
|
|
||||||
return (struct hif_sdio_dev *)sdio_get_drvdata(func);
|
if (!device) {
|
||||||
|
HIF_ERROR("%s: device null!", __func__);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device->func) {
|
||||||
|
HIF_ERROR("%s: func null!", __func__);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIF_INFO_HI("%s: addr:0X%06X, len:%08d, %s, %s", __func__,
|
||||||
|
address, length,
|
||||||
|
request & HIF_SDIO_READ ? "Read " : "Write",
|
||||||
|
request & HIF_ASYNCHRONOUS ? "Async" : "Sync ");
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (request & HIF_EXTENDED_IO) {
|
||||||
|
HIF_INFO_HI("%s: Command type: CMD53\n", __func__);
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: Invalid command type: 0x%08x\n",
|
||||||
|
__func__, request);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request & HIF_BLOCK_BASIS) {
|
||||||
|
/* round to whole block length size */
|
||||||
|
length =
|
||||||
|
(length / HIF_BLOCK_SIZE) *
|
||||||
|
HIF_BLOCK_SIZE;
|
||||||
|
HIF_INFO_HI("%s: Block mode (BlockLen: %d)\n",
|
||||||
|
__func__, length);
|
||||||
|
} else if (request & HIF_BYTE_BASIS) {
|
||||||
|
HIF_INFO_HI("%s: Byte mode (BlockLen: %d)\n",
|
||||||
|
__func__, length);
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: Invalid data mode: 0x%08x\n",
|
||||||
|
__func__, request);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (request & HIF_SDIO_WRITE) {
|
||||||
|
hif_fixup_write_param(device, request,
|
||||||
|
&length, &address);
|
||||||
|
|
||||||
|
HIF_INFO_HI("addr:%08X, len:0x%08X, dummy:0x%04X\n",
|
||||||
|
address, length,
|
||||||
|
(request & HIF_DUMMY_SPACE_MASK) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request & HIF_FIXED_ADDRESS) {
|
||||||
|
opcode = CMD53_FIXED_ADDRESS;
|
||||||
|
HIF_INFO_HI("%s: Addr mode: fixed 0x%X\n",
|
||||||
|
__func__, address);
|
||||||
|
} else if (request & HIF_INCREMENTAL_ADDRESS) {
|
||||||
|
opcode = CMD53_INCR_ADDRESS;
|
||||||
|
HIF_INFO_HI("%s: Address mode: Incremental 0x%X\n",
|
||||||
|
__func__, address);
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: Invalid address mode: 0x%08x\n",
|
||||||
|
__func__, request);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request & HIF_SDIO_WRITE) {
|
||||||
|
#if HIF_USE_DMA_BOUNCE_BUFFER
|
||||||
|
if (BUFFER_NEEDS_BOUNCE(buffer)) {
|
||||||
|
AR_DEBUG_ASSERT(device->dma_buffer);
|
||||||
|
tbuffer = device->dma_buffer;
|
||||||
|
/* copy the write data to the dma buffer */
|
||||||
|
AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
|
||||||
|
if (length > HIF_DMA_BUFFER_SIZE) {
|
||||||
|
HIF_ERROR("%s: Invalid write len: %d\n",
|
||||||
|
__func__, length);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(tbuffer, buffer, length);
|
||||||
|
bounced = true;
|
||||||
|
} else {
|
||||||
|
tbuffer = buffer;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
tbuffer = buffer;
|
||||||
|
#endif
|
||||||
|
if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
|
||||||
|
ret = sdio_writesb(device->func, address,
|
||||||
|
tbuffer, length);
|
||||||
|
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
||||||
|
__func__, ret, address, length,
|
||||||
|
*(int *)tbuffer);
|
||||||
|
} else if (tbuffer) {
|
||||||
|
ret = sdio_memcpy_toio(device->func, address,
|
||||||
|
tbuffer, length);
|
||||||
|
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
||||||
|
__func__, ret, address, length,
|
||||||
|
*(int *)tbuffer);
|
||||||
|
}
|
||||||
|
} else if (request & HIF_SDIO_READ) {
|
||||||
|
#if HIF_USE_DMA_BOUNCE_BUFFER
|
||||||
|
if (BUFFER_NEEDS_BOUNCE(buffer)) {
|
||||||
|
AR_DEBUG_ASSERT(device->dma_buffer);
|
||||||
|
AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
|
||||||
|
if (length > HIF_DMA_BUFFER_SIZE) {
|
||||||
|
HIF_ERROR("%s: Invalid read len: %d\n",
|
||||||
|
__func__, length);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tbuffer = device->dma_buffer;
|
||||||
|
bounced = true;
|
||||||
|
} else {
|
||||||
|
tbuffer = buffer;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
tbuffer = buffer;
|
||||||
|
#endif
|
||||||
|
if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
|
||||||
|
ret = sdio_readsb(device->func, tbuffer,
|
||||||
|
address, length);
|
||||||
|
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
||||||
|
__func__, ret, address, length,
|
||||||
|
*(int *)tbuffer);
|
||||||
|
} else if (tbuffer) {
|
||||||
|
ret = sdio_memcpy_fromio(device->func,
|
||||||
|
tbuffer, address,
|
||||||
|
length);
|
||||||
|
HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
|
||||||
|
__func__, ret, address, length,
|
||||||
|
*(int *)tbuffer);
|
||||||
|
}
|
||||||
|
#if HIF_USE_DMA_BOUNCE_BUFFER
|
||||||
|
if (bounced && tbuffer)
|
||||||
|
memcpy(buffer, tbuffer, length);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
HIF_ERROR("%s: Invalid dir: 0x%08x", __func__, request);
|
||||||
|
status = QDF_STATUS_E_INVAL;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
HIF_ERROR("%s: SDIO bus operation failed!", __func__);
|
||||||
|
HIF_ERROR("%s: MMC stack returned : %d", __func__, ret);
|
||||||
|
HIF_ERROR("%s: addr:0X%06X, len:%08d, %s, %s",
|
||||||
|
__func__, address, length,
|
||||||
|
request & HIF_SDIO_READ ? "Read " : "Write",
|
||||||
|
request & HIF_ASYNCHRONOUS ?
|
||||||
|
"Async" : "Sync");
|
||||||
|
status = QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* async_task() - thread function to serialize all bus requests
|
||||||
|
* @param: pointer to hif device
|
||||||
|
*
|
||||||
|
* thread function to serialize all requests, both sync and async
|
||||||
|
* Return: 0 on success, error number otherwise.
|
||||||
|
*/
|
||||||
|
static int async_task(void *param)
|
||||||
|
{
|
||||||
|
struct hif_sdio_dev *device;
|
||||||
|
struct bus_request *request;
|
||||||
|
QDF_STATUS status;
|
||||||
|
bool claimed = false;
|
||||||
|
|
||||||
|
device = (struct hif_sdio_dev *)param;
|
||||||
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
while (!device->async_shutdown) {
|
||||||
|
/* wait for work */
|
||||||
|
if (down_interruptible(&device->sem_async) != 0) {
|
||||||
|
/* interrupted, exit */
|
||||||
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||||
|
("%s: async task interrupted\n",
|
||||||
|
__func__));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (device->async_shutdown) {
|
||||||
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||||
|
("%s: async task stopping\n",
|
||||||
|
__func__));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* we want to hold the host over multiple cmds
|
||||||
|
* if possible, but holding the host blocks
|
||||||
|
* card interrupts
|
||||||
|
*/
|
||||||
|
qdf_spin_lock_irqsave(&device->asynclock);
|
||||||
|
/* pull the request to work on */
|
||||||
|
while (device->asyncreq) {
|
||||||
|
request = device->asyncreq;
|
||||||
|
if (request->inusenext)
|
||||||
|
device->asyncreq = request->inusenext;
|
||||||
|
else
|
||||||
|
device->asyncreq = NULL;
|
||||||
|
qdf_spin_unlock_irqrestore(&device->asynclock);
|
||||||
|
HIF_TRACE("%s: processing req: 0x%lX",
|
||||||
|
__func__, (unsigned long)request);
|
||||||
|
|
||||||
|
if (!claimed) {
|
||||||
|
sdio_claim_host(device->func);
|
||||||
|
claimed = true;
|
||||||
|
}
|
||||||
|
if (request->scatter_req) {
|
||||||
|
A_ASSERT(device->scatter_enabled);
|
||||||
|
/* pass the request to scatter routine which
|
||||||
|
* executes it synchronously, note, no need
|
||||||
|
* to free the request since scatter requests
|
||||||
|
* are maintained on a separate list
|
||||||
|
*/
|
||||||
|
status = do_hif_read_write_scatter(device,
|
||||||
|
request);
|
||||||
|
} else {
|
||||||
|
/* call hif_read_write in sync mode */
|
||||||
|
status =
|
||||||
|
__hif_read_write(device,
|
||||||
|
request->address,
|
||||||
|
request->buffer,
|
||||||
|
request->length,
|
||||||
|
request->
|
||||||
|
request &
|
||||||
|
~HIF_SYNCHRONOUS,
|
||||||
|
NULL);
|
||||||
|
if (request->request & HIF_ASYNCHRONOUS) {
|
||||||
|
void *context = request->context;
|
||||||
|
|
||||||
|
HIF_TRACE("%s: freeing req: 0x%lX",
|
||||||
|
__func__,
|
||||||
|
(unsigned long)request);
|
||||||
|
hif_free_bus_request(device, request);
|
||||||
|
|
||||||
|
HIF_TRACE("%s: completion req 0x%lX",
|
||||||
|
__func__,
|
||||||
|
(unsigned long)request);
|
||||||
|
device->htc_callbacks.
|
||||||
|
rw_compl_handler(context, status);
|
||||||
|
} else {
|
||||||
|
HIF_TRACE("%s: upping req: 0x%lX",
|
||||||
|
__func__,
|
||||||
|
(unsigned long)request);
|
||||||
|
request->status = status;
|
||||||
|
up(&request->sem_req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qdf_spin_lock_irqsave(&device->asynclock);
|
||||||
|
}
|
||||||
|
qdf_spin_unlock_irqrestore(&device->asynclock);
|
||||||
|
if (claimed) {
|
||||||
|
sdio_release_host(device->func);
|
||||||
|
claimed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_and_exit(&device->async_completion, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_disable_func() - Disable SDIO function
|
||||||
|
*
|
||||||
|
* @device: HIF device pointer
|
||||||
|
* @func: SDIO function pointer
|
||||||
|
* @reset: If this is called from resume or probe
|
||||||
|
*
|
||||||
|
* Return: 0 in case of success, else error value
|
||||||
|
*/
|
||||||
|
QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func,
|
||||||
|
bool reset)
|
||||||
|
{
|
||||||
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
if (!IS_ERR(device->async_task)) {
|
||||||
|
init_completion(&device->async_completion);
|
||||||
|
device->async_shutdown = 1;
|
||||||
|
up(&device->sem_async);
|
||||||
|
wait_for_completion(&device->async_completion);
|
||||||
|
device->async_task = NULL;
|
||||||
|
sema_init(&device->sem_async, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = hif_sdio_func_disable(device, func, reset);
|
||||||
|
if (status == QDF_STATUS_SUCCESS)
|
||||||
|
device->is_disabled = true;
|
||||||
|
|
||||||
|
cleanup_hif_scatter_resources(device);
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hif_enable_func() - Enable SDIO function
|
||||||
|
*
|
||||||
|
* @ol_sc: HIF object pointer
|
||||||
|
* @device: HIF device pointer
|
||||||
|
* @sdio_func: SDIO function pointer
|
||||||
|
* @resume: If this is called from resume or probe
|
||||||
|
*
|
||||||
|
* Return: 0 in case of success, else error value
|
||||||
|
*/
|
||||||
|
QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
|
||||||
|
struct sdio_func *func, bool resume)
|
||||||
|
{
|
||||||
|
int ret = QDF_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
HIF_ENTER();
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
HIF_ERROR("%s: HIF device is NULL", __func__);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hif_sdio_func_enable(ol_sc, func))
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
|
||||||
|
/* create async I/O thread */
|
||||||
|
if (!device->async_task && device->is_disabled) {
|
||||||
|
device->async_shutdown = 0;
|
||||||
|
device->async_task = kthread_create(async_task,
|
||||||
|
(void *)device,
|
||||||
|
"AR6K Async");
|
||||||
|
if (IS_ERR(device->async_task)) {
|
||||||
|
HIF_ERROR("%s: Error creating async task",
|
||||||
|
__func__);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
device->is_disabled = false;
|
||||||
|
wake_up_process(device->async_task);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resume)
|
||||||
|
ret = hif_sdio_probe(ol_sc, func, device);
|
||||||
|
|
||||||
|
HIF_EXIT();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SDIO_TRANSFER_MAILBOX */
|
#endif /* CONFIG_SDIO_TRANSFER_MAILBOX */
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -146,11 +146,6 @@
|
|||||||
*/
|
*/
|
||||||
#define HIF_DUMMY_SPACE_MASK 0xFFFF0000
|
#define HIF_DUMMY_SPACE_MASK 0xFFFF0000
|
||||||
|
|
||||||
/*
|
|
||||||
* data written into the dummy space will not put into the final mbox FIFO
|
|
||||||
*/
|
|
||||||
#define HIF_DUMMY_SPACE_MASK 0xFFFF0000
|
|
||||||
|
|
||||||
PREPACK struct MBOX_IRQ_PROC_REGISTERS {
|
PREPACK struct MBOX_IRQ_PROC_REGISTERS {
|
||||||
uint8_t host_int_status;
|
uint8_t host_int_status;
|
||||||
uint8_t cpu_int_status;
|
uint8_t cpu_int_status;
|
||||||
@@ -190,4 +185,9 @@ struct devRegisters {
|
|||||||
#define DEV_REGISTERS_SIZE (sizeof(struct MBOX_IRQ_PROC_REGISTERS) + \
|
#define DEV_REGISTERS_SIZE (sizeof(struct MBOX_IRQ_PROC_REGISTERS) + \
|
||||||
sizeof(struct MBOX_IRQ_ENABLE_REGISTERS) + \
|
sizeof(struct MBOX_IRQ_ENABLE_REGISTERS) + \
|
||||||
sizeof(struct MBOX_COUNTER_REGISTERS))
|
sizeof(struct MBOX_COUNTER_REGISTERS))
|
||||||
|
|
||||||
|
void hif_dev_dump_registers(struct hif_sdio_device *pdev,
|
||||||
|
struct MBOX_IRQ_PROC_REGISTERS *irq_proc,
|
||||||
|
struct MBOX_IRQ_ENABLE_REGISTERS *irq_en,
|
||||||
|
struct MBOX_COUNTER_REGISTERS *mbox_regs);
|
||||||
#endif /* _MAILBOX_H_ */
|
#endif /* _MAILBOX_H_ */
|
||||||
|
@@ -91,7 +91,8 @@ QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *pdev, uint32_t xfer_id,
|
|||||||
unsigned char *pData;
|
unsigned char *pData;
|
||||||
struct hif_sendContext *sctx;
|
struct hif_sendContext *sctx;
|
||||||
uint32_t request = hif_get_send_buffer_flags(pdev);
|
uint32_t request = hif_get_send_buffer_flags(pdev);
|
||||||
uint32_t padded_length, addr = 0;
|
uint32_t padded_length;
|
||||||
|
unsigned long addr = 0;
|
||||||
int frag_count = 0, i, count, head_len;
|
int frag_count = 0, i, count, head_len;
|
||||||
|
|
||||||
if (hif_get_send_address(pdev, pipe, &addr)) {
|
if (hif_get_send_address(pdev, pipe, &addr)) {
|
||||||
@@ -381,7 +382,7 @@ QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev,
|
|||||||
HTC_RECORD_HDR *record;
|
HTC_RECORD_HDR *record;
|
||||||
HTC_LOOKAHEAD_REPORT *look_ahead;
|
HTC_LOOKAHEAD_REPORT *look_ahead;
|
||||||
|
|
||||||
HIF_INFO("%s: length:%d", __func__, length);
|
HIF_INFO_HI("%s: length:%d", __func__, length);
|
||||||
|
|
||||||
orig_buffer = buffer;
|
orig_buffer = buffer;
|
||||||
orig_length = length;
|
orig_length = length;
|
||||||
@@ -515,7 +516,7 @@ QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev,
|
|||||||
debug_dump_bytes(orig_buffer, orig_length,
|
debug_dump_bytes(orig_buffer, orig_length,
|
||||||
"BAD Recv Trailer");
|
"BAD Recv Trailer");
|
||||||
|
|
||||||
HIF_INFO("%s: status = %d", __func__, status);
|
HIF_INFO_HI("%s: status = %d", __func__, status);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -65,13 +65,8 @@ struct hif_sendContext {
|
|||||||
unsigned int head_data_len;
|
unsigned int head_data_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
void hif_dev_dump_registers(struct hif_sdio_device *pdev,
|
|
||||||
struct MBOX_IRQ_PROC_REGISTERS *irq_proc,
|
|
||||||
struct MBOX_IRQ_ENABLE_REGISTERS *irq_en,
|
|
||||||
struct MBOX_COUNTER_REGISTERS *mbox_regs);
|
|
||||||
|
|
||||||
int hif_get_send_address(struct hif_sdio_device *pdev,
|
int hif_get_send_address(struct hif_sdio_device *pdev,
|
||||||
uint8_t pipe, uint32_t *addr);
|
uint8_t pipe, unsigned long *addr);
|
||||||
|
|
||||||
QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
|
QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
|
||||||
uint32_t look_aheads[],
|
uint32_t look_aheads[],
|
||||||
@@ -104,7 +99,11 @@ static inline uint32_t hif_get_send_buffer_flags(struct hif_sdio_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#elif defined(CONFIG_SDIO_TRANSFER_ADMA)
|
#elif defined(CONFIG_SDIO_TRANSFER_ADMA)
|
||||||
#error "Error - Not implemented yet"
|
static inline uint32_t hif_get_send_buffer_flags(struct hif_sdio_device *pdev)
|
||||||
|
{
|
||||||
|
/* ADAM-TODO */
|
||||||
|
return (uint32_t)HIF_WR_ASYNC_BLOCK_FIX;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __TRANSFER_H__ */
|
#endif /* __TRANSFER_H__ */
|
||||||
|
Reference in New Issue
Block a user