blob: e7331c01ea6f35188ca4b895e3954225602bbfeb [file] [log] [blame]
/****************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
*
****************************************************************************/
#ifndef __SLSI_UNITTEST_H__
#define __SLSI_UNITTEST_H__
#include "dev.h"
struct slsi_test_dev;
struct slsi_test_bh_work {
bool available;
struct slsi_test_dev *uftestdev;
struct workqueue_struct *workqueue;
struct work_struct work;
struct slsi_spinlock spinlock;
};
struct slsi_test_data_route {
bool configured;
u16 test_device_minor_number; /* index into slsi_test_devices[] */
u8 mac[ETH_ALEN];
u16 vif;
u8 ipsubnet;
u16 sequence_number;
};
struct slsi_test_dev {
/* This is used for:
* 1) The uf6kunittesthip<n> chardevice number
* 2) The uf6kunittest<n> chardevice number
* 3) The /procf/devices/unifi<n> number
*/
int device_minor_number;
void *uf_cdev;
struct device *dev;
struct slsi_dev *sdev;
struct workqueue_struct *attach_detach_work_queue;
/* a std mutex */
struct mutex attach_detach_mutex;
struct work_struct attach_work;
struct work_struct detach_work;
bool attached;
u8 hw_addr[ETH_ALEN];
struct slsi_test_bh_work bh_work;
/* a std spinlock */
spinlock_t route_spinlock;
struct slsi_test_data_route route[SLSI_AP_PEER_CONNECTIONS_MAX];
};
void slsi_test_dev_attach(struct slsi_test_dev *uftestdev);
void slsi_test_dev_detach(struct slsi_test_dev *uftestdev);
bool slsi_test_process_signal(struct slsi_test_dev *uftestdev, struct sk_buff *skb);
int slsi_test_udi_node_init(struct slsi_test_dev *uftestdev, struct device *parent);
int slsi_test_udi_node_reregister(struct slsi_test_dev *uftestdev);
int slsi_test_udi_node_deinit(struct slsi_test_dev *uftestdev);
int slsi_test_udi_init(void);
int slsi_test_udi_deinit(void);
void slsi_test_bh_work_f(struct work_struct *work);
static inline int slsi_test_bh_init(struct slsi_test_dev *uftestdev)
{
uftestdev->bh_work.available = false;
uftestdev->bh_work.uftestdev = uftestdev;
slsi_spinlock_create(&uftestdev->bh_work.spinlock);
INIT_WORK(&uftestdev->bh_work.work, slsi_test_bh_work_f);
uftestdev->bh_work.workqueue = alloc_ordered_workqueue("slsi_wlan_unittest_bh", 0);
if (!uftestdev->bh_work.workqueue)
return -ENOMEM;
uftestdev->bh_work.available = true;
return 0;
}
static inline void slsi_test_bh_start(struct slsi_test_dev *uftestdev)
{
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
uftestdev->bh_work.available = true;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
}
static inline void slsi_test_bh_run(struct slsi_test_dev *uftestdev)
{
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
if (!uftestdev->bh_work.available)
goto exit;
queue_work(uftestdev->bh_work.workqueue, &uftestdev->bh_work.work);
exit:
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
}
static inline void slsi_test_bh_stop(struct slsi_test_dev *uftestdev)
{
struct workqueue_struct *workqueue = NULL;
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
uftestdev->bh_work.available = false;
workqueue = uftestdev->bh_work.workqueue;
uftestdev->bh_work.workqueue = NULL;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
if (workqueue)
flush_workqueue(workqueue);
}
static inline void slsi_test_bh_deinit(struct slsi_test_dev *uftestdev)
{
struct workqueue_struct *workqueue = NULL;
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
WARN_ON(uftestdev->bh_work.available);
uftestdev->bh_work.available = false;
workqueue = uftestdev->bh_work.workqueue;
uftestdev->bh_work.workqueue = NULL;
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
if (workqueue) {
flush_workqueue(workqueue);
destroy_workqueue(workqueue);
}
}
#endif