summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/eswin/ecrnx_bfmer.c
blob: 467da01f9e4f4c3d6f61411586c8b3cafe0a52c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
 ******************************************************************************
 *
 * @file ecrnx_bfmer.c
 *
 * @brief VHT Beamformer function definitions
 *
 * Copyright (C) ESWIN 2015-2020
 *
 ******************************************************************************
 */

/**
 * INCLUDE FILES
 ******************************************************************************
 */

#include <linux/slab.h>
#include "ecrnx_bfmer.h"

/**
 * FUNCTION DEFINITIONS
 ******************************************************************************
 */

int ecrnx_bfmer_report_add(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *ecrnx_sta,
                          unsigned int length)
{
    gfp_t flags;
    struct ecrnx_bfmer_report *bfm_report ;

    if (in_softirq())
        flags = GFP_ATOMIC;
    else
        flags = GFP_KERNEL;

    /* Allocate a structure that will contain the beamforming report */
    bfm_report = kmalloc(sizeof(*bfm_report) + length, flags);


    /* Check report allocation */
    if (!bfm_report) {
        /* Do not use beamforming */
        return -1;
    }

    /* Store report length */
    bfm_report->length = length;

    /*
     * Need to provide a Virtual Address to the MAC so that it can
     * upload the received Beamforming Report in driver memory
     */
    bfm_report->dma_addr = dma_map_single(ecrnx_hw->dev, &bfm_report->report[0],
                                          length, DMA_FROM_DEVICE);

    /* Check DMA mapping result */
    if (dma_mapping_error(ecrnx_hw->dev, bfm_report->dma_addr)) {
        /* Free allocated report */
        kfree(bfm_report);
        /* And leave */
        return -1;
    }

    /* Store report structure */
    ecrnx_sta->bfm_report = bfm_report;

    return 0;
}

void ecrnx_bfmer_report_del(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *ecrnx_sta)
{
    /* Verify if a report has been allocated */
    if (ecrnx_sta->bfm_report) {
        struct ecrnx_bfmer_report *bfm_report = ecrnx_sta->bfm_report;

        /* Unmap DMA region */
        dma_unmap_single(ecrnx_hw->dev, bfm_report->dma_addr,
                         bfm_report->length, DMA_BIDIRECTIONAL);

        /* Free allocated report structure and clean the pointer */
        kfree(bfm_report);
        ecrnx_sta->bfm_report = NULL;
    }
}

#ifdef CONFIG_ECRNX_FULLMAC
u8 ecrnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa)
{
    int i;
    u8 rx_nss = 0;
    u16 rx_mcs_map = le16_to_cpu(vht_capa->supp_mcs.rx_mcs_map);

    for (i = 7; i >= 0; i--) {
        u8 mcs = (rx_mcs_map >> (2 * i)) & 3;

        if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
            rx_nss = i + 1;
            break;
        }
    }

    return rx_nss;
}
#endif /* CONFIG_ECRNX_FULLMAC */