245 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
#include "nvt_bus.h"
 | 
						|
#include "nvt_util_dbg.h"
 | 
						|
#include "nvt_icfg.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_txdata - send tx skb to bus
 | 
						|
 * @nvt_bus: bus structrue
 | 
						|
 * @skb: tx skb buffer
 | 
						|
 *
 | 
						|
 * this function will call bus tx_data ops to send it to bus.
 | 
						|
 *
 | 
						|
 * Return: zero - success
 | 
						|
 *         negative - failure
 | 
						|
 */
 | 
						|
s32 nvt_bus_txdata(struct _nvt_bus *nvt_bus, struct sk_buff *skb)
 | 
						|
{
 | 
						|
        s32 err = 0;
 | 
						|
 | 
						|
#ifdef BUS_UTILIZATION
 | 
						|
        //do not accept any tx data when we are in bus utilization mode
 | 
						|
        if (nvt_bus->nvt_bu->tx_enable) {
 | 
						|
                return -1;
 | 
						|
        }
 | 
						|
#endif
 | 
						|
        err = nvt_bus->nvt_wdev_bus_ops.tx_data(nvt_bus, skb);
 | 
						|
 | 
						|
        return err;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_attach - nvt bus allocation and initialization
 | 
						|
 * @dev - set nvt_bus to this device
 | 
						|
 * @bus_ops - nvt_bus operation table
 | 
						|
 *
 | 
						|
 * Return: a nvt_bus pointer
 | 
						|
 */
 | 
						|
struct _nvt_bus *nvt_bus_attach(struct device *dev,
 | 
						|
        struct _nvt_wdev_bus_ops bus_ops)
 | 
						|
{
 | 
						|
        s32 ret = 0;
 | 
						|
        struct _nvt_bus *nvt_bus;
 | 
						|
        nvt_bus = kzalloc(sizeof(struct _nvt_bus), GFP_ATOMIC);
 | 
						|
        if (nvt_bus == NULL) {
 | 
						|
                nvt_dbg(ERROR, "%s: Alloc nvt_bus failed\n", __func__);
 | 
						|
                ret = -ENOMEM;
 | 
						|
                goto alloc_failed;
 | 
						|
        }
 | 
						|
 | 
						|
        nvt_bus->icfg_pkg_buff = kzalloc(sizeof(struct _nvt_icfg_pkt_buff),
 | 
						|
                GFP_ATOMIC);
 | 
						|
        mutex_init(&nvt_bus->icfg_pkg_buff->iconfig_mutex);
 | 
						|
 | 
						|
        nvt_bus->dev = dev;
 | 
						|
        nvt_bus->state = NVT_BUS_STATE_DOWN;
 | 
						|
        dev_set_drvdata(dev, nvt_bus);
 | 
						|
        nvt_bus->nvt_wdev_bus_ops = bus_ops;
 | 
						|
 | 
						|
        init_waitqueue_head(&nvt_bus->fw_rdy_wait);
 | 
						|
        nvt_bus->fw_rdy_completed = 0;
 | 
						|
 | 
						|
        //20160122 nash: bus statistic
 | 
						|
        nvt_bus->statistic.pkt_tx_cnt = 0;
 | 
						|
        nvt_bus->statistic.pkt_rx_cnt = 0;
 | 
						|
        nvt_bus->statistic.pkt_tx_err_cnt = 0;
 | 
						|
        nvt_bus->statistic.pkt_rx_err_cnt = 0;
 | 
						|
 | 
						|
        nvt_bus->statistic.ctl_tx_cnt = 0;
 | 
						|
        nvt_bus->statistic.ctl_rx_cnt = 0;
 | 
						|
        nvt_bus->statistic.ctl_tx_err_cnt = 0;
 | 
						|
        nvt_bus->statistic.ctl_rx_err_cnt = 0;
 | 
						|
 | 
						|
#ifdef BUS_UTILIZATION
 | 
						|
        nvt_bus->nvt_bu = kzalloc(sizeof(struct _nvt_bus_utilization),
 | 
						|
                        GFP_ATOMIC);
 | 
						|
        if (!nvt_bus->nvt_bu) {
 | 
						|
                nvt_dbg(ERROR, "%s: bus utilization alloc fail\n", __func__);
 | 
						|
                kfree(nvt_bus);
 | 
						|
                return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        nvt_bus->nvt_bu->tx_enable = false;
 | 
						|
        nvt_bus->nvt_bu->rx_enable = false;
 | 
						|
        nvt_bus->nvt_bu->tx_total_cnt = 0;
 | 
						|
        nvt_bus->nvt_bu->tx_runtime_cnt = 0;
 | 
						|
        nvt_bus->nvt_bu->rx_total_cnt = 0;
 | 
						|
        nvt_bus->nvt_bu->rx_runtime_cnt = 0;
 | 
						|
        nvt_bus->nvt_bu->start_time = 0;
 | 
						|
        nvt_bus->nvt_bu->end_time = 0;
 | 
						|
        nvt_bus->nvt_bu->total_pkt_size_in_byte = 0;
 | 
						|
        nvt_bus->nvt_bu->tx_mode = NVT_BUS_BU_TX_VARIABLE_LEN;
 | 
						|
#endif
 | 
						|
 | 
						|
        return nvt_bus;
 | 
						|
alloc_failed:
 | 
						|
        return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_detach - free nvt_bus
 | 
						|
 * @dev - get nvt_bus to this device
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * Return: 0 for success, a negative value for fail
 | 
						|
 */
 | 
						|
s32 nvt_bus_detach(struct device *dev)
 | 
						|
{
 | 
						|
        struct _nvt_bus *nvt_bus = dev_get_drvdata(dev);
 | 
						|
        kfree(nvt_bus);
 | 
						|
        return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_register_txdone_callback - register your own TX done callback
 | 
						|
 * function
 | 
						|
 * @nvt_bus: nvt_bus structure
 | 
						|
 * @txdone_cb: callback function pointer
 | 
						|
 *
 | 
						|
 * Register your own TX done callback function by this function. When TX done,
 | 
						|
 * your callback would be executed
 | 
						|
 *
 | 
						|
 * Return: 0:success, -1:fail
 | 
						|
 */
 | 
						|
s32 nvt_bus_register_txdone_callback(struct _nvt_bus *nvt_bus,
 | 
						|
        void (*txdone_cb)(struct sk_buff *, s32 status_code))
 | 
						|
{
 | 
						|
        if (nvt_bus == NULL) {
 | 
						|
                return -1;
 | 
						|
        }
 | 
						|
 | 
						|
        nvt_bus->tx_done_callback = txdone_cb;
 | 
						|
        return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef BUS_UTILIZATION
 | 
						|
/**
 | 
						|
 * nvt_bus_bu_tx_on - control TX bus utilization on or off
 | 
						|
 * @nvt_bus: nvt bus structure
 | 
						|
 * @on: true:on, false:off
 | 
						|
 * @pkt_cnt: packet number for transmit
 | 
						|
 *
 | 
						|
 * Return: 0:success, -1:fail
 | 
						|
 */
 | 
						|
s32 nvt_bus_bu_tx_on(struct _nvt_bus *nvt_bus, bool on, u32 pkt_cnt)
 | 
						|
{
 | 
						|
        if (!nvt_bus) {
 | 
						|
                return -1;
 | 
						|
        }
 | 
						|
 | 
						|
        if (on) {
 | 
						|
                nvt_bus->nvt_bu->tx_total_cnt = pkt_cnt;
 | 
						|
                nvt_bus->nvt_bu->tx_runtime_cnt = 0;
 | 
						|
                nvt_bus->nvt_bu->start_time = get_jiffies_64();
 | 
						|
                nvt_bus->nvt_bu->total_pkt_size_in_byte = 0;
 | 
						|
                nvt_bus->nvt_bu->tx_enable = true;
 | 
						|
        } else {
 | 
						|
                nvt_bus->nvt_bu->tx_enable = false;
 | 
						|
                nvt_bus->nvt_bu->tx_total_cnt = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_bu_rx_on - control RX bus utilization on or off
 | 
						|
 * @nvt_bus: nvt bus structure
 | 
						|
 * @on: true:on, false:off
 | 
						|
 * @pkt_cnt: packet number for transmit
 | 
						|
 *
 | 
						|
 * Return: 0:success, -1:fail
 | 
						|
 */
 | 
						|
s32 nvt_bus_bu_rx_on(struct _nvt_bus *nvt_bus, bool on, u32 pkt_cnt)
 | 
						|
{
 | 
						|
        if (!nvt_bus) {
 | 
						|
                return -1;
 | 
						|
        }
 | 
						|
 | 
						|
        if (on) {
 | 
						|
                nvt_bus->nvt_bu->rx_total_cnt = pkt_cnt;
 | 
						|
                nvt_bus->nvt_bu->rx_runtime_cnt = 0;
 | 
						|
                nvt_bus->nvt_bu->start_time = 0;
 | 
						|
                nvt_bus->nvt_bu->total_pkt_size_in_byte = 0;
 | 
						|
                nvt_bus->nvt_bu->rx_enable = true;
 | 
						|
        } else {
 | 
						|
                nvt_bus->nvt_bu->rx_enable = false;
 | 
						|
                nvt_bus->nvt_bu->rx_total_cnt = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        return 0;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nvt_bus_bu_show_result - show bus utilization result for both TX/RX
 | 
						|
 * @nvt_bus: nvt bus structure
 | 
						|
 * @is_tx: true:TX, false:RX
 | 
						|
 *
 | 
						|
 * Return: none
 | 
						|
 */
 | 
						|
void nvt_bus_bu_show_result(struct _nvt_bus *nvt_bus, bool is_tx)
 | 
						|
{
 | 
						|
        u64 interval = 0;
 | 
						|
        u64 bu_rate = 0;
 | 
						|
        u8 *str_tbl[2] = {"TX", "RX"};
 | 
						|
        u8 *str;
 | 
						|
        s32 pkt_cnt = 0;
 | 
						|
        u32 ret_val;
 | 
						|
 | 
						|
        if (!nvt_bus) {
 | 
						|
                nvt_dbg(ERROR, "%s: nvt_bus is NULL!!\n", __func__);
 | 
						|
                return;
 | 
						|
        }
 | 
						|
 | 
						|
        nvt_bus->nvt_bu->end_time = get_jiffies_64();
 | 
						|
        interval = nvt_bus->nvt_bu->end_time - nvt_bus->nvt_bu->start_time;
 | 
						|
 | 
						|
        if (is_tx) {
 | 
						|
                nvt_bus->nvt_bu->tx_enable = false;
 | 
						|
                str = str_tbl[0];
 | 
						|
                pkt_cnt = nvt_bus->nvt_bu->tx_runtime_cnt;
 | 
						|
        } else {
 | 
						|
                nvt_bus->nvt_bu->rx_enable = false;
 | 
						|
                str = str_tbl[1];
 | 
						|
                pkt_cnt = nvt_bus->nvt_bu->rx_runtime_cnt;
 | 
						|
        }
 | 
						|
 | 
						|
        nvt_dbg(INFO, "\n[BU]: %s %d packets took %llu jiffies\n",
 | 
						|
                str, pkt_cnt, interval);
 | 
						|
 | 
						|
        nvt_dbg(INFO, "[BU]: total pkt size=%llu\n",
 | 
						|
                nvt_bus->nvt_bu->total_pkt_size_in_byte);
 | 
						|
 | 
						|
        bu_rate = nvt_bus->nvt_bu->total_pkt_size_in_byte * HZ;
 | 
						|
        if (interval > 0) {
 | 
						|
                ret_val = do_div(bu_rate, interval);
 | 
						|
                bu_rate *= 8;
 | 
						|
                nvt_dbg(INFO, "[BU]: SDIO %s bus utilization: %llu bps\n",
 | 
						|
                        str, bu_rate);
 | 
						|
        }
 | 
						|
 | 
						|
        return;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 |