mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-15 09:14:18 -04:00
qcacmn: Move hdd_request_manager to qcacmn osif layer
Move hdd_request_manager to qcacmn osif layer, which will be used by CP_STATs component. Change-Id: Iebf7f9d259793b56cc70c5b3f9dec14a5ef35b25 CRs-Fixed: 2220035
This commit is contained in:
parent
3cb98124c1
commit
685bf25eb3
2 changed files with 433 additions and 0 deletions
204
os_if/linux/wlan_osif_request_manager.c
Normal file
204
os_if/linux/wlan_osif_request_manager.c
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was originally distributed by Qualcomm Atheros, Inc.
|
||||
* under proprietary terms before Copyright ownership was assigned
|
||||
* to the Linux Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "qdf_mem.h"
|
||||
#include "qdf_list.h"
|
||||
#include "qdf_event.h"
|
||||
#include "wlan_cfg80211.h"
|
||||
#include "wlan_osif_request_manager.h"
|
||||
|
||||
/* arbitrary value */
|
||||
#define MAX_NUM_REQUESTS 20
|
||||
|
||||
static bool is_initialized;
|
||||
static qdf_list_t requests;
|
||||
static qdf_spinlock_t spinlock;
|
||||
static void *cookie;
|
||||
|
||||
struct osif_request {
|
||||
qdf_list_node_t node;
|
||||
void *cookie;
|
||||
uint32_t reference_count;
|
||||
struct osif_request_params params;
|
||||
qdf_event_t completed;
|
||||
};
|
||||
|
||||
/* must be called with spinlock held */
|
||||
static void osif_request_unlink(struct osif_request *request)
|
||||
{
|
||||
qdf_list_remove_node(&requests, &request->node);
|
||||
}
|
||||
|
||||
static void osif_request_destroy(struct osif_request *request)
|
||||
{
|
||||
struct osif_request_params *params;
|
||||
|
||||
params = &request->params;
|
||||
if (params->dealloc) {
|
||||
void *priv = osif_request_priv(request);
|
||||
|
||||
params->dealloc(priv);
|
||||
}
|
||||
qdf_event_destroy(&request->completed);
|
||||
qdf_mem_free(request);
|
||||
}
|
||||
|
||||
/* must be called with spinlock held */
|
||||
static struct osif_request *osif_request_find(void *cookie)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct osif_request *request;
|
||||
qdf_list_node_t *node;
|
||||
|
||||
status = qdf_list_peek_front(&requests, &node);
|
||||
while (QDF_IS_STATUS_SUCCESS(status)) {
|
||||
request = qdf_container_of(node, struct osif_request, node);
|
||||
if (request->cookie == cookie)
|
||||
return request;
|
||||
status = qdf_list_peek_next(&requests, node, &node);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct osif_request *osif_request_alloc(const struct osif_request_params *params)
|
||||
{
|
||||
size_t length;
|
||||
struct osif_request *request;
|
||||
|
||||
if (!is_initialized) {
|
||||
cfg80211_err("invoked when not initialized from %pS",
|
||||
(void *)_RET_IP_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length = sizeof(*request) + params->priv_size;
|
||||
request = qdf_mem_malloc(length);
|
||||
if (!request) {
|
||||
cfg80211_err("allocation failed for %pS", (void *)_RET_IP_);
|
||||
return NULL;
|
||||
}
|
||||
request->reference_count = 1;
|
||||
request->params = *params;
|
||||
qdf_event_create(&request->completed);
|
||||
qdf_spin_lock_bh(&spinlock);
|
||||
request->cookie = cookie++;
|
||||
qdf_list_insert_back(&requests, &request->node);
|
||||
qdf_spin_unlock_bh(&spinlock);
|
||||
cfg80211_debug("request %pK, cookie %pK, caller %pS",
|
||||
request, request->cookie, (void *)_RET_IP_);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void *osif_request_priv(struct osif_request *request)
|
||||
{
|
||||
/* private data area immediately follows the struct osif_request */
|
||||
return request + 1;
|
||||
}
|
||||
|
||||
void *osif_request_cookie(struct osif_request *request)
|
||||
{
|
||||
return request->cookie;
|
||||
}
|
||||
|
||||
struct osif_request *osif_request_get(void *cookie)
|
||||
{
|
||||
struct osif_request *request;
|
||||
|
||||
if (!is_initialized) {
|
||||
cfg80211_err("invoked when not initialized from %pS",
|
||||
(void *)_RET_IP_);
|
||||
return NULL;
|
||||
}
|
||||
qdf_spin_lock_bh(&spinlock);
|
||||
request = osif_request_find(cookie);
|
||||
if (request)
|
||||
request->reference_count++;
|
||||
qdf_spin_unlock_bh(&spinlock);
|
||||
cfg80211_debug("cookie %pK, request %pK, caller %pS",
|
||||
cookie, request, (void *)_RET_IP_);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void osif_request_put(struct osif_request *request)
|
||||
{
|
||||
bool unlinked = false;
|
||||
|
||||
cfg80211_debug("request %pK, cookie %pK, caller %pS",
|
||||
request, request->cookie, (void *)_RET_IP_);
|
||||
qdf_spin_lock_bh(&spinlock);
|
||||
request->reference_count--;
|
||||
if (0 == request->reference_count) {
|
||||
osif_request_unlink(request);
|
||||
unlinked = true;
|
||||
}
|
||||
qdf_spin_unlock_bh(&spinlock);
|
||||
if (unlinked)
|
||||
osif_request_destroy(request);
|
||||
}
|
||||
|
||||
int osif_request_wait_for_response(struct osif_request *request)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
|
||||
status = qdf_wait_for_event_completion(&request->completed,
|
||||
request->params.timeout_ms);
|
||||
|
||||
return qdf_status_to_os_return(status);
|
||||
}
|
||||
|
||||
void osif_request_complete(struct osif_request *request)
|
||||
{
|
||||
(void) qdf_event_set(&request->completed);
|
||||
}
|
||||
|
||||
void osif_request_manager_init(void)
|
||||
{
|
||||
cfg80211_debug("%pS", (void *)_RET_IP_);
|
||||
if (is_initialized)
|
||||
return;
|
||||
|
||||
qdf_list_create(&requests, MAX_NUM_REQUESTS);
|
||||
qdf_spinlock_create(&spinlock);
|
||||
is_initialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* osif_request_manager_deinit implementation note:
|
||||
* It is intentional that we do not destroy the list or the spinlock.
|
||||
* This allows threads to still access the infrastructure even when it
|
||||
* has been deinitialized. Since neither lists nor spinlocks consume
|
||||
* resources this does not result in a resource leak.
|
||||
*/
|
||||
void osif_request_manager_deinit(void)
|
||||
{
|
||||
cfg80211_debug("%pS", (void *)_RET_IP_);
|
||||
is_initialized = false;
|
||||
}
|
||||
229
os_if/linux/wlan_osif_request_manager.h
Normal file
229
os_if/linux/wlan_osif_request_manager.h
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was originally distributed by Qualcomm Atheros, Inc.
|
||||
* under proprietary terms before Copyright ownership was assigned
|
||||
* to the Linux Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __WLAN_OSIF_REQUEST_MANAGER_H__
|
||||
#define __WLAN_OSIF_REQUEST_MANAGER_H__
|
||||
|
||||
/**
|
||||
* DOC: WLAN OSIF REQUEST MANAGER
|
||||
*
|
||||
* Many operations within the wlan driver occur in an asynchronous
|
||||
* manner. Requests are received by OSIF via one of the kernel
|
||||
* interfaces (ioctl, nl80211, virtual file system, etc.). The
|
||||
* requests are translated to an internal format and are then passed
|
||||
* to lower layers, usually via SME, for processing. For requests
|
||||
* which require a response, that response comes up from the lower
|
||||
* layers in a separate thread of execution, ultimately resulting in a
|
||||
* call to a callback function that was provided by OSIF as part of the
|
||||
* initial request. So a mechanism is needed to synchronize the
|
||||
* request and response. This framework provides that mechanism.
|
||||
*
|
||||
* Once the framework has been initialized, the typical sequence of
|
||||
* events is as follows:
|
||||
*
|
||||
* Request Thread:
|
||||
* 1. Create a &struct osif_request_params which describes the request.
|
||||
* 2. Call osif_request_alloc() to allocate a &struct osif_request.
|
||||
* 3. Call osif_request_priv() to get a pointer to the private data.
|
||||
* 4. Place any information which must be shared with the Response
|
||||
* Callback in the private data area.
|
||||
* 5. Call osif_request_cookie() to get the unique cookie assigned
|
||||
* to the request.
|
||||
* 6. Call the underlying request handling API, passing the cookie
|
||||
* as the callback's private context.
|
||||
* 7. Call osif_request_wait_for_response() to wait for the response
|
||||
* (or for the request to time out).
|
||||
* 8. Use the return status to see if the request was successful. If
|
||||
* it was, retrieve any response information from the private
|
||||
* structure and prepare a response for userspace.
|
||||
* 9. Call osif_request_put() to relinquish access to the request.
|
||||
* 10. Return status to the caller.
|
||||
*
|
||||
* Response Callback:
|
||||
* 1. Call osif_request_get() with the provided cookie to see if the
|
||||
* request structure is still valid. If it returns %NULL then
|
||||
* return since this means the request thread has already timed
|
||||
* out.
|
||||
* 2. Call osif_request_priv() to get access to the private data area.
|
||||
* 3. Write response data into the private data area.
|
||||
* 4. Call osif_request_complete() to indicate that the response is
|
||||
* ready to be processed by the request thread.
|
||||
* 5. Call osif_request_put() to relinquish the callback function's
|
||||
* reference to the request.
|
||||
*/
|
||||
|
||||
/* this is opaque to clients */
|
||||
struct osif_request;
|
||||
|
||||
/**
|
||||
* typedef osif_request_dealloc - Private data deallocation function
|
||||
*/
|
||||
typedef void (*osif_request_dealloc)(void *priv);
|
||||
|
||||
/**
|
||||
* struct osif_request_params - OSIF request parameters
|
||||
* @priv_size: Size of the private data area required to pass
|
||||
* information between the request thread and the response callback.
|
||||
* @timeout_ms: The amount of time to wait for a response in milliseconds.
|
||||
* @dealloc: Function to be called when the request is destroyed to
|
||||
* deallocate any allocations made in the private area of the
|
||||
* request struct. Can be %NULL if no private allocations are
|
||||
* made.
|
||||
*/
|
||||
struct osif_request_params {
|
||||
uint32_t priv_size;
|
||||
uint32_t timeout_ms;
|
||||
osif_request_dealloc dealloc;
|
||||
};
|
||||
|
||||
/**
|
||||
* osif_request_alloc() - Allocate a request struct
|
||||
* @params: parameter block that specifies the attributes of the
|
||||
* request
|
||||
*
|
||||
* This function will attempt to allocate a &struct osif_request with
|
||||
* the specified @params. If successful, the caller can then use
|
||||
* request struct to make an asynchronous request. Once the request is
|
||||
* no longer needed, the reference should be relinquished via a call
|
||||
* to osif_request_put().
|
||||
*
|
||||
* Return: A pointer to an allocated &struct osif_request (which also
|
||||
* contains room for the private buffer) if the allocation is
|
||||
* successful, %NULL if the allocation fails.
|
||||
*/
|
||||
struct osif_request *osif_request_alloc(const struct osif_request_params *params);
|
||||
|
||||
/**
|
||||
* osif_request_priv() - Get pointer to request private data
|
||||
* @request: The request struct that contains the private data
|
||||
*
|
||||
* This function will return a pointer to the private data area that
|
||||
* is part of the request struct. The caller must already have a valid
|
||||
* reference to @request from either osif_request_alloc() or
|
||||
* osif_request_get().
|
||||
*
|
||||
* Returns: pointer to the private data area. Note that this pointer
|
||||
* will always be an offset from the input @request pointer and hence
|
||||
* this function will never return %NULL.
|
||||
*/
|
||||
void *osif_request_priv(struct osif_request *request);
|
||||
|
||||
/**
|
||||
* osif_request_cookie() - Get cookie of a request
|
||||
* @request: The request struct associated with the request
|
||||
*
|
||||
* This function will return the unique cookie that has been assigned
|
||||
* to the request. This cookie can subsequently be passed to
|
||||
* osif_request_get() to retrieve the request.
|
||||
*
|
||||
* Note that the cookie is defined as a void pointer as it is intended
|
||||
* to be passed as an opaque context pointer from OSIF to underlying
|
||||
* layers when making a request, and subsequently passed back to OSIF
|
||||
* as an opaque pointer in an asynchronous callback.
|
||||
*
|
||||
* Returns: The cookie assigned to the request.
|
||||
*/
|
||||
void *osif_request_cookie(struct osif_request *request);
|
||||
|
||||
/**
|
||||
* osif_request_get() - Get a reference to a request struct
|
||||
* @cookie: The cookie of the request struct that needs to be
|
||||
* referenced
|
||||
*
|
||||
* This function will use the cookie to determine if the associated
|
||||
* request struct is valid, and if so, will increment the reference
|
||||
* count of the struct. This means the caller is guaranteed that the
|
||||
* request struct is valid and the underlying private data can be
|
||||
* dereferenced.
|
||||
*
|
||||
* Returns: The pointer to the request struct associated with @cookie
|
||||
* if the request is still valid, %NULL if the underlying request
|
||||
* struct is no longer valid.
|
||||
*/
|
||||
struct osif_request *osif_request_get(void *cookie);
|
||||
|
||||
/**
|
||||
* osif_request_put() - Release a reference to a request struct
|
||||
* @request: The request struct that no longer needs to be referenced
|
||||
*
|
||||
* This function will decrement the reference count of the struct, and
|
||||
* will clean up the request if this is the last reference. The caller
|
||||
* must already have a valid reference to @request, either from
|
||||
* osif_request_alloc() or osif_request_get().
|
||||
*
|
||||
* Returns: Nothing
|
||||
*/
|
||||
void osif_request_put(struct osif_request *request);
|
||||
|
||||
/**
|
||||
* osif_request_wait_for_response() - Wait for a response
|
||||
* @request: The request struct associated with the request
|
||||
*
|
||||
* This function will wait until either a response is received and
|
||||
* communicated via osif_request_complete(), or until the request
|
||||
* timeout period expires.
|
||||
*
|
||||
* Returns: 0 if a response was received, -ETIMEDOUT if the response
|
||||
* timed out.
|
||||
*/
|
||||
int osif_request_wait_for_response(struct osif_request *request);
|
||||
|
||||
/**
|
||||
* osif_request_complete() - Complete a request
|
||||
* @request: The request struct associated with the request
|
||||
*
|
||||
* This function is used to indicate that a response has been received
|
||||
* and that any information required by the request thread has been
|
||||
* copied into the private data area of the request struct. This will
|
||||
* unblock any osif_request_wait_for_response() that is pending on this
|
||||
* @request.
|
||||
*
|
||||
* Returns: Nothing
|
||||
*/
|
||||
void osif_request_complete(struct osif_request *request);
|
||||
|
||||
/**
|
||||
* osif_request_manager_init() - Initialize the OSIF Request Manager
|
||||
*
|
||||
* This function must be called during system initialization to
|
||||
* initialize the OSIF Request Manager.
|
||||
*
|
||||
* Returns: Nothing
|
||||
*/
|
||||
void osif_request_manager_init(void);
|
||||
|
||||
/**
|
||||
* osif_request_manager_deinit() - Deinitialize the OSIF Request Manager
|
||||
*
|
||||
* This function must be called during system shutdown to deinitialize
|
||||
* the OSIF Request Manager.
|
||||
*
|
||||
* Returns: Nothing
|
||||
*/
|
||||
void osif_request_manager_deinit(void);
|
||||
|
||||
#endif /* __WLAN_OSIF_REQUEST_MANAGER_H__ */
|
||||
Loading…
Reference in a new issue