mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
wireless-drivers-next patches for 4.16
Major changes: wil6210 * add PCI device id for Talyn * support flashless device ath9k * improve RSSI/signal accuracy on AR9003 series mt76 * validate CCMP PN from received frames to avoid replay attacks qtnfmac * support 64-bit network stats * report more hardware information to kernel log and some via ethtool -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJaa1x7AAoJEG4XJFUm622bdc8H/3JSWFnXlkrQvjZzL1NWR0Hn vUYou/W04mgzYtXIcscNL3otDa9TGwLW6Sr5wP0MDH/TGU9zXoEZxBxnYy4zq4np 7ZP7M6VsOzOhlNNsTcNAiMGyObtIT4btrfKlmp2yvf3Sra7nHNJJmprFeuyH3f02 vk5ZQWjMcEAe0afBGPcHrzndoAvVqIHHOAbM/w694n/8cdT8edcQeQ8rwlFO6ENU db9yqkr4RvjWv9oJwa2us6d0lolJDk8ATWhDTyZL40X9yk84XR7E0jMdN5LQ/CJj CCCMWsDYjUpEDUJVmwLdXzGavgo43QAs9a+O+z7MDJ4uwqYkZh3rzQZay+dYLKk= =D4LX -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2018-01-26' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next Kalle Valo says: ==================== wireless-drivers-next patches for 4.16 Major changes: wil6210 * add PCI device id for Talyn * support flashless device ath9k * improve RSSI/signal accuracy on AR9003 series mt76 * validate CCMP PN from received frames to avoid replay attacks qtnfmac * support 64-bit network stats * report more hardware information to kernel log and some via ethtool ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
868c36dcc9
@ -3310,6 +3310,12 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
|
||||
if (ar9300_check_eeprom_header(ah, read, cptr))
|
||||
goto found;
|
||||
|
||||
cptr = AR9300_BASE_ADDR_4K;
|
||||
ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n",
|
||||
cptr);
|
||||
if (ar9300_check_eeprom_header(ah, read, cptr))
|
||||
goto found;
|
||||
|
||||
cptr = AR9300_BASE_ADDR_512;
|
||||
ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n",
|
||||
cptr);
|
||||
@ -3430,6 +3436,60 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ar9003_dump_cal_data(struct ath_hw *ah, char *buf, u32 len, u32 size,
|
||||
bool is_2g)
|
||||
{
|
||||
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
|
||||
struct ar9300_base_eep_hdr *pBase;
|
||||
struct ar9300_cal_data_per_freq_op_loop *cal_pier;
|
||||
int cal_pier_nr;
|
||||
int freq;
|
||||
int i, j;
|
||||
|
||||
pBase = &eep->baseEepHeader;
|
||||
|
||||
if (is_2g)
|
||||
cal_pier_nr = AR9300_NUM_2G_CAL_PIERS;
|
||||
else
|
||||
cal_pier_nr = AR9300_NUM_5G_CAL_PIERS;
|
||||
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
if (!((pBase->txrxMask >> i) & 1))
|
||||
continue;
|
||||
|
||||
len += snprintf(buf + len, size - len, "Chain %d\n", i);
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"Freq\t ref\tvolt\ttemp\tnf_cal\tnf_pow\trx_temp\n");
|
||||
|
||||
for (j = 0; j < cal_pier_nr; j++) {
|
||||
if (is_2g) {
|
||||
cal_pier = &eep->calPierData2G[i][j];
|
||||
freq = 2300 + eep->calFreqPier2G[j];
|
||||
} else {
|
||||
cal_pier = &eep->calPierData5G[i][j];
|
||||
freq = 4800 + eep->calFreqPier5G[j] * 5;
|
||||
}
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%d\t", freq);
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%d\t%d\t%d\t%d\t%d\t%d\n",
|
||||
cal_pier->refPower,
|
||||
cal_pier->voltMeas,
|
||||
cal_pier->tempMeas,
|
||||
cal_pier->rxTempMeas ?
|
||||
N2DBM(cal_pier->rxNoisefloorCal) : 0,
|
||||
cal_pier->rxTempMeas ?
|
||||
N2DBM(cal_pier->rxNoisefloorPower) : 0,
|
||||
cal_pier->rxTempMeas);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
@ -3441,10 +3501,18 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len = ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader2G);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
|
||||
len += scnprintf(buf + len, size - len, "Calibration data\n");
|
||||
len = ar9003_dump_cal_data(ah, buf, len, size, true);
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "5GHz modal Header");
|
||||
len = ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader5G);
|
||||
|
||||
len += snprintf(buf + len, size - len, "Calibration data\n");
|
||||
len = ar9003_dump_cal_data(ah, buf, len, size, false);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -4683,7 +4751,8 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
|
||||
int ichain,
|
||||
int *pfrequency,
|
||||
int *pcorrection,
|
||||
int *ptemperature, int *pvoltage)
|
||||
int *ptemperature, int *pvoltage,
|
||||
int *pnf_cal, int *pnf_power)
|
||||
{
|
||||
u8 *pCalPier;
|
||||
struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct;
|
||||
@ -4725,6 +4794,10 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
|
||||
*pcorrection = pCalPierStruct->refPower;
|
||||
*ptemperature = pCalPierStruct->tempMeas;
|
||||
*pvoltage = pCalPierStruct->voltMeas;
|
||||
*pnf_cal = pCalPierStruct->rxTempMeas ?
|
||||
N2DBM(pCalPierStruct->rxNoisefloorCal) : 0;
|
||||
*pnf_power = pCalPierStruct->rxTempMeas ?
|
||||
N2DBM(pCalPierStruct->rxNoisefloorPower) : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4889,14 +4962,18 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
int mode;
|
||||
int lfrequency[AR9300_MAX_CHAINS],
|
||||
lcorrection[AR9300_MAX_CHAINS],
|
||||
ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS];
|
||||
ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS],
|
||||
lnf_cal[AR9300_MAX_CHAINS], lnf_pwr[AR9300_MAX_CHAINS];
|
||||
int hfrequency[AR9300_MAX_CHAINS],
|
||||
hcorrection[AR9300_MAX_CHAINS],
|
||||
htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS];
|
||||
htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS],
|
||||
hnf_cal[AR9300_MAX_CHAINS], hnf_pwr[AR9300_MAX_CHAINS];
|
||||
int fdiff;
|
||||
int correction[AR9300_MAX_CHAINS],
|
||||
voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS];
|
||||
int pfrequency, pcorrection, ptemperature, pvoltage;
|
||||
voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS],
|
||||
nf_cal[AR9300_MAX_CHAINS], nf_pwr[AR9300_MAX_CHAINS];
|
||||
int pfrequency, pcorrection, ptemperature, pvoltage,
|
||||
pnf_cal, pnf_pwr;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
mode = (frequency >= 4000);
|
||||
@ -4914,7 +4991,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
for (ipier = 0; ipier < npier; ipier++) {
|
||||
if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain,
|
||||
&pfrequency, &pcorrection,
|
||||
&ptemperature, &pvoltage)) {
|
||||
&ptemperature, &pvoltage,
|
||||
&pnf_cal, &pnf_pwr)) {
|
||||
fdiff = frequency - pfrequency;
|
||||
|
||||
/*
|
||||
@ -4936,6 +5014,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
htemperature[ichain] =
|
||||
ptemperature;
|
||||
hvoltage[ichain] = pvoltage;
|
||||
hnf_cal[ichain] = pnf_cal;
|
||||
hnf_pwr[ichain] = pnf_pwr;
|
||||
}
|
||||
}
|
||||
if (fdiff >= 0) {
|
||||
@ -4952,6 +5032,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
ltemperature[ichain] =
|
||||
ptemperature;
|
||||
lvoltage[ichain] = pvoltage;
|
||||
lnf_cal[ichain] = pnf_cal;
|
||||
lnf_pwr[ichain] = pnf_pwr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4960,15 +5042,20 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
|
||||
/* interpolate */
|
||||
for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
|
||||
ath_dbg(common, EEPROM, "ch=%d f=%d low=%d %d h=%d %d\n",
|
||||
ath_dbg(common, EEPROM,
|
||||
"ch=%d f=%d low=%d %d h=%d %d n=%d %d p=%d %d\n",
|
||||
ichain, frequency, lfrequency[ichain],
|
||||
lcorrection[ichain], hfrequency[ichain],
|
||||
hcorrection[ichain]);
|
||||
hcorrection[ichain], lnf_cal[ichain],
|
||||
hnf_cal[ichain], lnf_pwr[ichain],
|
||||
hnf_pwr[ichain]);
|
||||
/* they're the same, so just pick one */
|
||||
if (hfrequency[ichain] == lfrequency[ichain]) {
|
||||
correction[ichain] = lcorrection[ichain];
|
||||
voltage[ichain] = lvoltage[ichain];
|
||||
temperature[ichain] = ltemperature[ichain];
|
||||
nf_cal[ichain] = lnf_cal[ichain];
|
||||
nf_pwr[ichain] = lnf_pwr[ichain];
|
||||
}
|
||||
/* the low frequency is good */
|
||||
else if (frequency - lfrequency[ichain] < 1000) {
|
||||
@ -4992,12 +5079,26 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
hfrequency[ichain],
|
||||
lvoltage[ichain],
|
||||
hvoltage[ichain]);
|
||||
|
||||
nf_cal[ichain] = interpolate(frequency,
|
||||
lfrequency[ichain],
|
||||
hfrequency[ichain],
|
||||
lnf_cal[ichain],
|
||||
hnf_cal[ichain]);
|
||||
|
||||
nf_pwr[ichain] = interpolate(frequency,
|
||||
lfrequency[ichain],
|
||||
hfrequency[ichain],
|
||||
lnf_pwr[ichain],
|
||||
hnf_pwr[ichain]);
|
||||
}
|
||||
/* only low is good, use it */
|
||||
else {
|
||||
correction[ichain] = lcorrection[ichain];
|
||||
temperature[ichain] = ltemperature[ichain];
|
||||
voltage[ichain] = lvoltage[ichain];
|
||||
nf_cal[ichain] = lnf_cal[ichain];
|
||||
nf_pwr[ichain] = lnf_pwr[ichain];
|
||||
}
|
||||
}
|
||||
/* only high is good, use it */
|
||||
@ -5005,10 +5106,14 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
correction[ichain] = hcorrection[ichain];
|
||||
temperature[ichain] = htemperature[ichain];
|
||||
voltage[ichain] = hvoltage[ichain];
|
||||
nf_cal[ichain] = hnf_cal[ichain];
|
||||
nf_pwr[ichain] = hnf_pwr[ichain];
|
||||
} else { /* nothing is good, presume 0???? */
|
||||
correction[ichain] = 0;
|
||||
temperature[ichain] = 0;
|
||||
voltage[ichain] = 0;
|
||||
nf_cal[ichain] = 0;
|
||||
nf_pwr[ichain] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5019,6 +5124,16 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
|
||||
"for frequency=%d, calibration correction = %d %d %d\n",
|
||||
frequency, correction[0], correction[1], correction[2]);
|
||||
|
||||
/* Store calibrated noise floor values */
|
||||
for (ichain = 0; ichain < AR5416_MAX_CHAINS; ichain++)
|
||||
if (mode) {
|
||||
ah->nf_5g.cal[ichain] = nf_cal[ichain];
|
||||
ah->nf_5g.pwr[ichain] = nf_pwr[ichain];
|
||||
} else {
|
||||
ah->nf_2g.cal[ichain] = nf_cal[ichain];
|
||||
ah->nf_2g.pwr[ichain] = nf_pwr[ichain];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,16 @@
|
||||
*/
|
||||
#define AR9300_PWR_TABLE_OFFSET 0
|
||||
|
||||
/* Noise power data definitions
|
||||
* units are: 4 x dBm - NOISE_PWR_DATA_OFFSET
|
||||
* (e.g. -25 = (-25/4 - 90) = -96.25 dBm)
|
||||
* range (for 6 signed bits) is (-32 to 31) + offset => -122dBm to -59dBm
|
||||
* resolution (2 bits) is 0.25dBm
|
||||
*/
|
||||
#define NOISE_PWR_DATA_OFFSET -90
|
||||
#define NOISE_PWR_DBM_2_INT(_p) ((((_p) + 3) >> 2) + NOISE_PWR_DATA_OFFSET)
|
||||
#define N2DBM(_p) NOISE_PWR_DBM_2_INT(_p)
|
||||
|
||||
/* byte addressable */
|
||||
#define AR9300_EEPROM_SIZE (16*1024)
|
||||
|
||||
|
@ -58,19 +58,25 @@ static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
|
||||
}
|
||||
|
||||
static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
struct ath9k_channel *chan,
|
||||
int chain)
|
||||
{
|
||||
s16 calib_nf = ath9k_hw_get_nf_limits(ah, chan)->cal[chain];
|
||||
|
||||
if (calib_nf)
|
||||
return calib_nf;
|
||||
else
|
||||
return ath9k_hw_get_nf_limits(ah, chan)->nominal;
|
||||
}
|
||||
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
s16 nf)
|
||||
{
|
||||
s8 noise = ATH_DEFAULT_NOISE_FLOOR;
|
||||
s8 noise = ath9k_hw_get_default_nf(ah, chan, 0);
|
||||
|
||||
if (nf) {
|
||||
s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH -
|
||||
ath9k_hw_get_default_nf(ah, chan);
|
||||
ath9k_hw_get_default_nf(ah, chan, 0);
|
||||
if (delta > 0)
|
||||
noise += delta;
|
||||
}
|
||||
@ -240,7 +246,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
unsigned i, j;
|
||||
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||
s16 default_nf = ath9k_hw_get_nf_limits(ah, chan)->nominal;
|
||||
u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
|
||||
|
||||
if (ah->caldata)
|
||||
@ -258,8 +264,13 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
nfval = ah->nf_override;
|
||||
else if (h)
|
||||
nfval = h[i].privNF;
|
||||
else
|
||||
else {
|
||||
/* Try to get calibrated noise floor value */
|
||||
nfval =
|
||||
ath9k_hw_get_nf_limits(ah, chan)->cal[i];
|
||||
if (nfval > -60 || nfval < -127)
|
||||
nfval = default_nf;
|
||||
}
|
||||
|
||||
REG_RMW(ah, ah->nf_regs[i],
|
||||
(((u32) nfval << 1) & 0x1ff), 0x1ff);
|
||||
@ -429,20 +440,19 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath9k_nfcal_hist *h;
|
||||
s16 default_nf;
|
||||
int i, j;
|
||||
int i, j, k = 0;
|
||||
|
||||
ah->caldata->channel = chan->channel;
|
||||
ah->caldata->channelFlags = chan->channelFlags;
|
||||
h = ah->caldata->nfCalHist;
|
||||
default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||||
h[i].currIndex = 0;
|
||||
h[i].privNF = default_nf;
|
||||
h[i].privNF = ath9k_hw_get_default_nf(ah, chan, k);
|
||||
h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
|
||||
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
|
||||
h[i].nfCalBuffer[j] = default_nf;
|
||||
}
|
||||
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++)
|
||||
h[i].nfCalBuffer[j] = h[i].privNF;
|
||||
if (++k >= AR5416_MAX_CHAINS)
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,6 +754,8 @@ struct ath_nf_limits {
|
||||
s16 max;
|
||||
s16 min;
|
||||
s16 nominal;
|
||||
s16 cal[AR5416_MAX_CHAINS];
|
||||
s16 pwr[AR5416_MAX_CHAINS];
|
||||
};
|
||||
|
||||
enum ath_cal_list {
|
||||
|
@ -826,9 +826,9 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
|
||||
sc->rx.discard_next = false;
|
||||
|
||||
/*
|
||||
* Discard zero-length packets.
|
||||
* Discard zero-length packets and packets smaller than an ACK
|
||||
*/
|
||||
if (!rx_stats->rs_datalen) {
|
||||
if (rx_stats->rs_datalen < 10) {
|
||||
RX_STAT_INC(rx_len_err);
|
||||
goto corrupt;
|
||||
}
|
||||
|
@ -236,6 +236,14 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wcn36xx_dxe_deinit_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn_ch)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
|
||||
dma_free_coherent(dev, size,wcn_ch->cpu_addr, wcn_ch->dma_addr);
|
||||
}
|
||||
|
||||
static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch,
|
||||
struct wcn36xx_dxe_mem_pool *pool)
|
||||
{
|
||||
@ -722,7 +730,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
/***************************************/
|
||||
/* Init descriptors for TX LOW channel */
|
||||
/***************************************/
|
||||
wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch);
|
||||
ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch);
|
||||
if (ret) {
|
||||
dev_err(wcn->dev, "Error allocating descriptor\n");
|
||||
return ret;
|
||||
}
|
||||
wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool);
|
||||
|
||||
/* Write channel head to a NEXT register */
|
||||
@ -740,7 +752,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
/***************************************/
|
||||
/* Init descriptors for TX HIGH channel */
|
||||
/***************************************/
|
||||
wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch);
|
||||
ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch);
|
||||
if (ret) {
|
||||
dev_err(wcn->dev, "Error allocating descriptor\n");
|
||||
goto out_err_txh_ch;
|
||||
}
|
||||
|
||||
wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool);
|
||||
|
||||
/* Write channel head to a NEXT register */
|
||||
@ -760,7 +777,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
/***************************************/
|
||||
/* Init descriptors for RX LOW channel */
|
||||
/***************************************/
|
||||
wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch);
|
||||
ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch);
|
||||
if (ret) {
|
||||
dev_err(wcn->dev, "Error allocating descriptor\n");
|
||||
goto out_err_rxl_ch;
|
||||
}
|
||||
|
||||
|
||||
/* For RX we need to preallocated buffers */
|
||||
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch);
|
||||
@ -790,7 +812,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
/***************************************/
|
||||
/* Init descriptors for RX HIGH channel */
|
||||
/***************************************/
|
||||
wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch);
|
||||
ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch);
|
||||
if (ret) {
|
||||
dev_err(wcn->dev, "Error allocating descriptor\n");
|
||||
goto out_err_rxh_ch;
|
||||
}
|
||||
|
||||
/* For RX we need to prealocat buffers */
|
||||
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch);
|
||||
@ -819,11 +845,19 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
|
||||
ret = wcn36xx_dxe_request_irqs(wcn);
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
goto out_err_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
out_err_irq:
|
||||
wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_h_ch);
|
||||
out_err_rxh_ch:
|
||||
wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_l_ch);
|
||||
out_err_rxl_ch:
|
||||
wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_h_ch);
|
||||
out_err_txh_ch:
|
||||
wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_l_ch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 {
|
||||
/* valid only for version 2 and above */
|
||||
__le32 bl_assert_code; /* 0x880A58 BL Assert code */
|
||||
__le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */
|
||||
__le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */
|
||||
__le32 bl_shutdown_handshake; /* 0x880A60 BL cleaner shutdown */
|
||||
__le32 bl_reserved[21]; /* 0x880A64 - 0x880AB4 */
|
||||
__le32 bl_magic_number; /* 0x880AB8 BL Magic number */
|
||||
} __packed;
|
||||
|
||||
@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 {
|
||||
u8 mac_address[6]; /* 0x880A4c BL mac address */
|
||||
} __packed;
|
||||
|
||||
/* bits for bl_shutdown_handshake */
|
||||
#define BL_SHUTDOWN_HS_GRTD BIT(0)
|
||||
#define BL_SHUTDOWN_HS_RTD BIT(1)
|
||||
#define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31)
|
||||
|
||||
#endif /* BOOT_LOADER_EXPORT_H_ */
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -58,15 +59,30 @@ struct wil_fw_record_comment { /* type == wil_fw_type_comment */
|
||||
u8 data[0]; /* free-form data [data_size], see above */
|
||||
} __packed;
|
||||
|
||||
/* Comment header - common for all comment record types */
|
||||
struct wil_fw_record_comment_hdr {
|
||||
__le32 magic;
|
||||
};
|
||||
|
||||
/* FW capabilities encoded inside a comment record */
|
||||
#define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba)
|
||||
struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
|
||||
/* identifies capabilities record */
|
||||
__le32 magic;
|
||||
struct wil_fw_record_comment_hdr hdr;
|
||||
/* capabilities (variable size), see enum wmi_fw_capability */
|
||||
u8 capabilities[0];
|
||||
};
|
||||
|
||||
/* brd file info encoded inside a comment record */
|
||||
#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
|
||||
struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */
|
||||
/* identifies brd file record */
|
||||
struct wil_fw_record_comment_hdr hdr;
|
||||
__le32 version;
|
||||
__le32 base_addr;
|
||||
__le32 max_size_bytes;
|
||||
} __packed;
|
||||
|
||||
/* perform action
|
||||
* data_size = @head.size - offsetof(struct wil_fw_record_action, data)
|
||||
*/
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -128,14 +129,13 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
|
||||
}
|
||||
|
||||
static int
|
||||
fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
const struct wil_fw_record_capabilities *rec = data;
|
||||
size_t capa_size;
|
||||
|
||||
if (size < sizeof(*rec) ||
|
||||
le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
|
||||
if (size < sizeof(*rec)) {
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
return 0;
|
||||
@ -151,8 +151,56 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
||||
static int
|
||||
fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
const struct wil_fw_record_brd_file *rec = data;
|
||||
|
||||
if (size < sizeof(*rec)) {
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wil->brd_file_addr = le32_to_cpu(rec->base_addr);
|
||||
wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes);
|
||||
|
||||
wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n",
|
||||
wil->brd_file_addr, wil->brd_file_max_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
const struct wil_fw_record_comment_hdr *hdr = data;
|
||||
u32 magic;
|
||||
int rc = 0;
|
||||
|
||||
if (size < sizeof(*hdr))
|
||||
return 0;
|
||||
|
||||
magic = le32_to_cpu(hdr->magic);
|
||||
|
||||
switch (magic) {
|
||||
case WIL_FW_CAPABILITIES_MAGIC:
|
||||
wil_dbg_fw(wil, "magic is WIL_FW_CAPABILITIES_MAGIC\n");
|
||||
rc = fw_handle_capabilities(wil, data, size);
|
||||
break;
|
||||
case WIL_BRD_FILE_MAGIC:
|
||||
wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
|
||||
rc = fw_handle_brd_file(wil, data, size);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __fw_handle_data(struct wil6210_priv *wil, const void *data,
|
||||
size_t size, __le32 addr)
|
||||
{
|
||||
const struct wil_fw_record_data *d = data;
|
||||
void __iomem *dst;
|
||||
@ -163,16 +211,23 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
|
||||
if (!wil_fw_addr_check(wil, &dst, addr, s, "address"))
|
||||
return -EINVAL;
|
||||
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
|
||||
s);
|
||||
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s);
|
||||
wil_memcpy_toio_32(dst, d->data, s);
|
||||
wmb(); /* finish before processing next record */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
const struct wil_fw_record_data *d = data;
|
||||
|
||||
return __fw_handle_data(wil, data, size, d->addr);
|
||||
}
|
||||
|
||||
static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
@ -551,6 +606,100 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* wil_brd_process - process section from BRD file
|
||||
*
|
||||
* Return error code
|
||||
*/
|
||||
static int wil_brd_process(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
int rc = 0;
|
||||
const struct wil_fw_record_head *hdr = data;
|
||||
size_t s, hdr_sz;
|
||||
u16 type;
|
||||
|
||||
/* Assuming the board file includes only one header record and one data
|
||||
* record. Each record starts with wil_fw_record_head.
|
||||
*/
|
||||
if (size < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
s = sizeof(*hdr) + le32_to_cpu(hdr->size);
|
||||
if (s > size)
|
||||
return -EINVAL;
|
||||
|
||||
/* Skip the header record and handle the data record */
|
||||
hdr = (const void *)hdr + s;
|
||||
size -= s;
|
||||
if (size < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
hdr_sz = le32_to_cpu(hdr->size);
|
||||
|
||||
if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size)
|
||||
return -EINVAL;
|
||||
if (sizeof(*hdr) + hdr_sz > size)
|
||||
return -EINVAL;
|
||||
if (hdr_sz % 4) {
|
||||
wil_err_fw(wil, "unaligned record size: %zu\n",
|
||||
hdr_sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
type = le16_to_cpu(hdr->type);
|
||||
if (type != wil_fw_type_data) {
|
||||
wil_err_fw(wil, "invalid record type for board file: %d\n",
|
||||
type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (hdr_sz < sizeof(struct wil_fw_record_data)) {
|
||||
wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n",
|
||||
wil->brd_file_addr);
|
||||
|
||||
rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
|
||||
cpu_to_le32(wil->brd_file_addr));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* wil_request_board - Request board file
|
||||
*
|
||||
* Request board image from the file
|
||||
* board file address and max size are read from FW file
|
||||
* during initialization.
|
||||
* brd file shall include one header and one data section.
|
||||
*
|
||||
* Return error code
|
||||
*/
|
||||
int wil_request_board(struct wil6210_priv *wil, const char *name)
|
||||
{
|
||||
int rc, dlen;
|
||||
const struct firmware *brd;
|
||||
|
||||
rc = request_firmware(&brd, name, wil_to_dev(wil));
|
||||
if (rc) {
|
||||
wil_err_fw(wil, "Failed to load brd %s\n", name);
|
||||
return rc;
|
||||
}
|
||||
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, brd->size);
|
||||
|
||||
/* Verify the header */
|
||||
dlen = wil_fw_verify(wil, brd->data, brd->size);
|
||||
if (dlen < 0) {
|
||||
rc = dlen;
|
||||
goto out;
|
||||
}
|
||||
/* Process the data record */
|
||||
rc = wil_brd_process(wil, brd->data, dlen);
|
||||
|
||||
out:
|
||||
release_firmware(brd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* wil_fw_verify_file_exists - checks if firmware file exist
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -395,8 +396,9 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
wil6210_mask_irq_misc(wil, false);
|
||||
|
||||
if (isr & ISR_MISC_FW_ERROR) {
|
||||
u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
|
||||
u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE);
|
||||
u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
|
||||
u32 ucode_assert_code =
|
||||
wil_r(wil, wil->rgf_ucode_assert_code_addr);
|
||||
|
||||
wil_err(wil,
|
||||
"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -637,6 +638,98 @@ void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
destroy_workqueue(wil->wmi_wq);
|
||||
}
|
||||
|
||||
static void wil_shutdown_bl(struct wil6210_priv *wil)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
wil_s(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v1,
|
||||
bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD);
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
val = wil_r(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v1,
|
||||
bl_shutdown_handshake));
|
||||
if (val & BL_SHUTDOWN_HS_RTD) {
|
||||
wil_dbg_misc(wil, "BL is ready for halt\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wil_err(wil, "BL did not report ready for halt\n");
|
||||
}
|
||||
|
||||
/* this format is used by ARC embedded CPU for instruction memory */
|
||||
static inline u32 ARC_me_imm32(u32 d)
|
||||
{
|
||||
return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16);
|
||||
}
|
||||
|
||||
/* defines access to interrupt vectors for wil_freeze_bl */
|
||||
#define ARC_IRQ_VECTOR_OFFSET(N) ((N) * 8)
|
||||
/* ARC long jump instruction */
|
||||
#define ARC_JAL_INST (0x20200f80)
|
||||
|
||||
static void wil_freeze_bl(struct wil6210_priv *wil)
|
||||
{
|
||||
u32 jal, upc, saved;
|
||||
u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3);
|
||||
|
||||
jal = wil_r(wil, wil->iccm_base + ivt3);
|
||||
if (jal != ARC_me_imm32(ARC_JAL_INST)) {
|
||||
wil_dbg_misc(wil, "invalid IVT entry found, skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* prevent the target from entering deep sleep
|
||||
* and disabling memory access
|
||||
*/
|
||||
saved = wil_r(wil, RGF_USER_USAGE_8);
|
||||
wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP);
|
||||
usleep_range(20, 25); /* let the BL process the bit */
|
||||
|
||||
/* redirect to endless loop in the INT_L1 context and let it trap */
|
||||
wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3));
|
||||
usleep_range(20, 25); /* let the BL get into the trap */
|
||||
|
||||
/* verify the BL is frozen */
|
||||
upc = wil_r(wil, RGF_USER_CPU_PC);
|
||||
if (upc < ivt3 || (upc > (ivt3 + 8)))
|
||||
wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc);
|
||||
|
||||
wil_w(wil, RGF_USER_USAGE_8, saved);
|
||||
}
|
||||
|
||||
static void wil_bl_prepare_halt(struct wil6210_priv *wil)
|
||||
{
|
||||
u32 tmp, ver;
|
||||
|
||||
/* before halting device CPU driver must make sure BL is not accessing
|
||||
* host memory. This is done differently depending on BL version:
|
||||
* 1. For very old BL versions the procedure is skipped
|
||||
* (not supported).
|
||||
* 2. For old BL version we use a special trick to freeze the BL
|
||||
* 3. For new BL versions we shutdown the BL using handshake procedure.
|
||||
*/
|
||||
tmp = wil_r(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v0,
|
||||
boot_loader_struct_version));
|
||||
if (!tmp) {
|
||||
wil_dbg_misc(wil, "old BL, skipping halt preperation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = wil_r(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v1,
|
||||
bl_shutdown_handshake));
|
||||
ver = BL_SHUTDOWN_HS_PROT_VER(tmp);
|
||||
|
||||
if (ver > 0)
|
||||
wil_shutdown_bl(wil);
|
||||
else
|
||||
wil_freeze_bl(wil);
|
||||
}
|
||||
|
||||
static inline void wil_halt_cpu(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
|
||||
@ -670,7 +763,7 @@ static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode)
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_target_reset(struct wil6210_priv *wil)
|
||||
static int wil_target_reset(struct wil6210_priv *wil, int no_flash)
|
||||
{
|
||||
int delay = 0;
|
||||
u32 x, x1 = 0;
|
||||
@ -684,9 +777,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
|
||||
|
||||
wil_halt_cpu(wil);
|
||||
|
||||
if (!no_flash) {
|
||||
/* clear all boot loader "ready" bits */
|
||||
wil_w(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
|
||||
offsetof(struct bl_dedicated_registers_v0,
|
||||
boot_loader_ready), 0);
|
||||
/* this should be safe to write even with old BLs */
|
||||
wil_w(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v1,
|
||||
bl_shutdown_handshake), 0);
|
||||
}
|
||||
/* Clear Fw Download notification */
|
||||
wil_c(wil, RGF_USER_USAGE_6, BIT(0));
|
||||
|
||||
@ -727,13 +827,25 @@ static int wil_target_reset(struct wil6210_priv *wil)
|
||||
wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
|
||||
|
||||
/* wait until device ready. typical time is 20..80 msec */
|
||||
if (no_flash)
|
||||
do {
|
||||
msleep(RST_DELAY);
|
||||
x = wil_r(wil, USER_EXT_USER_PMU_3);
|
||||
if (delay++ > RST_COUNT) {
|
||||
wil_err(wil, "Reset not completed, PMU_3 0x%08x\n",
|
||||
x);
|
||||
return -ETIME;
|
||||
}
|
||||
} while ((x & BIT_PMU_DEVICE_RDY) == 0);
|
||||
else
|
||||
do {
|
||||
msleep(RST_DELAY);
|
||||
x = wil_r(wil, RGF_USER_BL +
|
||||
offsetof(struct bl_dedicated_registers_v0,
|
||||
boot_loader_ready));
|
||||
if (x1 != x) {
|
||||
wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
|
||||
wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n",
|
||||
x1, x);
|
||||
x1 = x;
|
||||
}
|
||||
if (delay++ > RST_COUNT) {
|
||||
@ -749,6 +861,21 @@ static int wil_target_reset(struct wil6210_priv *wil)
|
||||
wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN |
|
||||
BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);
|
||||
|
||||
if (no_flash) {
|
||||
/* Reset OTP HW vectors to fit 40MHz */
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001);
|
||||
wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001);
|
||||
wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57);
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
|
||||
return 0;
|
||||
}
|
||||
@ -906,6 +1033,27 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err)
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_get_otp_info(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
u8 mac[8];
|
||||
|
||||
wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC),
|
||||
sizeof(mac));
|
||||
if (!is_valid_ether_addr(mac)) {
|
||||
wil_err(wil, "Invalid MAC %pM\n", mac);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ether_addr_copy(ndev->perm_addr, mac);
|
||||
ether_addr_copy(wiphy->perm_addr, mac);
|
||||
if (!is_valid_ether_addr(ndev->dev_addr))
|
||||
ether_addr_copy(ndev->dev_addr, mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
|
||||
{
|
||||
ulong to = msecs_to_jiffies(1000);
|
||||
@ -999,6 +1147,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
{
|
||||
int rc;
|
||||
unsigned long status_flags = BIT(wil_status_resetting);
|
||||
int no_flash;
|
||||
|
||||
wil_dbg_misc(wil, "reset\n");
|
||||
|
||||
@ -1074,20 +1223,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
flush_workqueue(wil->wq_service);
|
||||
flush_workqueue(wil->wmi_wq);
|
||||
|
||||
no_flash = test_bit(hw_capa_no_flash, wil->hw_capa);
|
||||
if (!no_flash)
|
||||
wil_bl_crash_info(wil, false);
|
||||
wil_disable_irq(wil);
|
||||
rc = wil_target_reset(wil);
|
||||
rc = wil_target_reset(wil, no_flash);
|
||||
wil6210_clear_irq(wil);
|
||||
wil_enable_irq(wil);
|
||||
wil_rx_fini(wil);
|
||||
if (rc) {
|
||||
if (!no_flash)
|
||||
wil_bl_crash_info(wil, true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (no_flash) {
|
||||
rc = wil_get_otp_info(wil);
|
||||
} else {
|
||||
rc = wil_get_bl_info(wil);
|
||||
if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
|
||||
if (rc == -EAGAIN && !load_fw)
|
||||
/* ignore RF error if not going up */
|
||||
rc = 0;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@ -1096,13 +1253,21 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
wil_info(wil, "Use firmware <%s> + board <%s>\n",
|
||||
wil->wil_fw_name, WIL_BOARD_FILE_NAME);
|
||||
|
||||
if (!no_flash)
|
||||
wil_bl_prepare_halt(wil);
|
||||
|
||||
wil_halt_cpu(wil);
|
||||
memset(wil->fw_version, 0, sizeof(wil->fw_version));
|
||||
/* Loading f/w from the file */
|
||||
rc = wil_request_firmware(wil, wil->wil_fw_name, true);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
|
||||
if (wil->brd_file_addr)
|
||||
rc = wil_request_board(wil, WIL_BOARD_FILE_NAME);
|
||||
else
|
||||
rc = wil_request_firmware(wil,
|
||||
WIL_BOARD_FILE_NAME,
|
||||
true);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -35,15 +36,16 @@ static int wil6210_pm_notify(struct notifier_block *notify_block,
|
||||
unsigned long mode, void *unused);
|
||||
|
||||
static
|
||||
void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
int wil_set_capabilities(struct wil6210_priv *wil)
|
||||
{
|
||||
const char *wil_fw_name;
|
||||
u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
|
||||
u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
|
||||
RGF_USER_REVISION_ID_MASK);
|
||||
int platform_capa;
|
||||
struct fw_map *iccm_section, *sct;
|
||||
|
||||
bitmap_zero(wil->hw_capabilities, hw_capability_last);
|
||||
bitmap_zero(wil->hw_capa, hw_capa_last);
|
||||
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
|
||||
bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
|
||||
wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
|
||||
@ -52,6 +54,8 @@ void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
|
||||
switch (jtag_id) {
|
||||
case JTAG_DEV_ID_SPARROW:
|
||||
memcpy(fw_mapping, sparrow_fw_mapping,
|
||||
sizeof(sparrow_fw_mapping));
|
||||
switch (chip_revision) {
|
||||
case REVISION_ID_SPARROW_D0:
|
||||
wil->hw_name = "Sparrow D0";
|
||||
@ -61,6 +65,12 @@ void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
|
||||
if (wil_fw_verify_file_exists(wil, wil_fw_name))
|
||||
wil->wil_fw_name = wil_fw_name;
|
||||
sct = wil_find_fw_mapping("mac_rgf_ext");
|
||||
if (!sct) {
|
||||
wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct));
|
||||
break;
|
||||
case REVISION_ID_SPARROW_B0:
|
||||
wil->hw_name = "Sparrow B0";
|
||||
@ -71,15 +81,36 @@ void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
wil->hw_version = HW_VER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE;
|
||||
wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE;
|
||||
break;
|
||||
case JTAG_DEV_ID_TALYN:
|
||||
wil->hw_name = "Talyn";
|
||||
wil->hw_version = HW_VER_TALYN;
|
||||
memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping));
|
||||
wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
|
||||
wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
|
||||
if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
|
||||
BIT_NO_FLASH_INDICATION)
|
||||
set_bit(hw_capa_no_flash, wil->hw_capa);
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
|
||||
jtag_id, chip_revision);
|
||||
wil->hw_name = "Unknown";
|
||||
wil->hw_version = HW_VER_UNKNOWN;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_info(wil, "Board hardware is %s\n", wil->hw_name);
|
||||
iccm_section = wil_find_fw_mapping("fw_code");
|
||||
if (!iccm_section) {
|
||||
wil_err(wil, "fw_code section not found in fw_mapping\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
wil->iccm_base = iccm_section->host;
|
||||
|
||||
wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name,
|
||||
test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : "");
|
||||
|
||||
/* Get platform capabilities */
|
||||
if (wil->platform_ops.get_capa) {
|
||||
@ -92,6 +123,8 @@ void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
/* extract FW capabilities from file without loading the FW */
|
||||
wil_request_firmware(wil, wil->wil_fw_name, false);
|
||||
wil_refresh_fw_capabilities(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_disable_irq(struct wil6210_priv *wil)
|
||||
@ -302,7 +335,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
/* rollback to err_iounmap */
|
||||
wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
|
||||
|
||||
wil_set_capabilities(wil);
|
||||
rc = wil_set_capabilities(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc);
|
||||
goto err_iounmap;
|
||||
}
|
||||
wil6210_clear_irq(wil);
|
||||
|
||||
/* FW should raise IRQ when ready */
|
||||
@ -378,6 +415,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
|
||||
static const struct pci_device_id wil6210_pcie_ids[] = {
|
||||
{ PCI_DEVICE(0x1ae9, 0x0310) },
|
||||
{ PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
|
||||
{ PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -169,6 +170,7 @@ struct RGF_ICR {
|
||||
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
|
||||
#define RGF_USER_USER_CPU_0 (0x8801e0)
|
||||
#define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */
|
||||
#define RGF_USER_CPU_PC (0x8801e8)
|
||||
#define RGF_USER_MAC_CPU_0 (0x8801fc)
|
||||
#define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
|
||||
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
|
||||
@ -194,6 +196,19 @@ struct RGF_ICR {
|
||||
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
|
||||
#define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */
|
||||
#define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2)
|
||||
#define RGF_USER_OTP_HW_RD_MACHINE_1 (0x880ce0)
|
||||
#define BIT_NO_FLASH_INDICATION BIT(8)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME1 (0x880cec)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME2 (0x880cf0)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME3 (0x880cf4)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME4 (0x880cf8)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME5 (0x880cfc)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME6 (0x880d00)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME7 (0x880d04)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME8 (0x880d08)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME9 (0x880d0c)
|
||||
#define RGF_USER_XPM_IFC_RD_TIME10 (0x880d10)
|
||||
#define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64)
|
||||
|
||||
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
|
||||
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
|
||||
@ -284,22 +299,33 @@ struct RGF_ICR {
|
||||
#define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
|
||||
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
|
||||
|
||||
#define USER_EXT_USER_PMU_3 (0x88d00c)
|
||||
#define BIT_PMU_DEVICE_RDY BIT(0)
|
||||
|
||||
#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
|
||||
#define JTAG_DEV_ID_SPARROW (0x2632072f)
|
||||
#define JTAG_DEV_ID_TALYN (0x7e0e1)
|
||||
|
||||
#define RGF_USER_REVISION_ID (0x88afe4)
|
||||
#define RGF_USER_REVISION_ID_MASK (3)
|
||||
#define REVISION_ID_SPARROW_B0 (0x0)
|
||||
#define REVISION_ID_SPARROW_D0 (0x3)
|
||||
|
||||
#define RGF_OTP_MAC (0x8a0620)
|
||||
|
||||
/* crash codes for FW/Ucode stored here */
|
||||
#define RGF_FW_ASSERT_CODE (0x91f020)
|
||||
#define RGF_UCODE_ASSERT_CODE (0x91f028)
|
||||
|
||||
/* ASSERT RGFs */
|
||||
#define SPARROW_RGF_FW_ASSERT_CODE (0x91f020)
|
||||
#define SPARROW_RGF_UCODE_ASSERT_CODE (0x91f028)
|
||||
#define TALYN_RGF_FW_ASSERT_CODE (0xa37020)
|
||||
#define TALYN_RGF_UCODE_ASSERT_CODE (0xa37028)
|
||||
|
||||
enum {
|
||||
HW_VER_UNKNOWN,
|
||||
HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
|
||||
HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
|
||||
HW_VER_TALYN, /* JTAG_DEV_ID_TALYN */
|
||||
};
|
||||
|
||||
/* popular locations */
|
||||
@ -315,6 +341,10 @@ enum {
|
||||
#define WIL_DATA_COMPLETION_TO_MS 200
|
||||
|
||||
/* Hardware definitions end */
|
||||
#define SPARROW_FW_MAPPING_TABLE_SIZE 10
|
||||
#define TALYN_FW_MAPPING_TABLE_SIZE 13
|
||||
#define MAX_FW_MAPPING_TABLE_SIZE 13
|
||||
|
||||
struct fw_map {
|
||||
u32 from; /* linker address - from, inclusive */
|
||||
u32 to; /* linker address - to, exclusive */
|
||||
@ -324,7 +354,10 @@ struct fw_map {
|
||||
};
|
||||
|
||||
/* array size should be in sync with actual definition in the wmi.c */
|
||||
extern const struct fw_map fw_mapping[10];
|
||||
extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE];
|
||||
extern const struct fw_map sparrow_d0_mac_rgf_ext;
|
||||
extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE];
|
||||
extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
|
||||
|
||||
/**
|
||||
* mk_cidxtid - construct @cidxtid field
|
||||
@ -570,7 +603,8 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
hw_capability_last
|
||||
hw_capa_no_flash,
|
||||
hw_capa_last
|
||||
};
|
||||
|
||||
struct wil_probe_client_req {
|
||||
@ -646,7 +680,10 @@ struct wil6210_priv {
|
||||
u8 chip_revision;
|
||||
const char *hw_name;
|
||||
const char *wil_fw_name;
|
||||
DECLARE_BITMAP(hw_capabilities, hw_capability_last);
|
||||
char *board_file;
|
||||
u32 brd_file_addr;
|
||||
u32 brd_file_max_size;
|
||||
DECLARE_BITMAP(hw_capa, hw_capa_last);
|
||||
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
|
||||
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
|
||||
u8 n_mids; /* number of additional MIDs as reported by FW */
|
||||
@ -720,7 +757,7 @@ struct wil6210_priv {
|
||||
atomic_t isr_count_rx, isr_count_tx;
|
||||
/* debugfs */
|
||||
struct dentry *debug;
|
||||
struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
|
||||
struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE];
|
||||
u8 discovery_mode;
|
||||
u8 abft_len;
|
||||
u8 wakeup_trigger;
|
||||
@ -755,6 +792,10 @@ struct wil6210_priv {
|
||||
bool suspend_resp_comp;
|
||||
u32 bus_request_kbps;
|
||||
u32 bus_request_kbps_pre_suspend;
|
||||
|
||||
u32 rgf_fw_assert_code_addr;
|
||||
u32 rgf_ucode_assert_code_addr;
|
||||
u32 iccm_base;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
@ -880,6 +921,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||
void wil_set_ethtoolops(struct net_device *ndev);
|
||||
|
||||
struct fw_map *wil_find_fw_mapping(const char *section);
|
||||
void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
@ -1013,6 +1055,7 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type);
|
||||
|
||||
int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
||||
bool load);
|
||||
int wil_request_board(struct wil6210_priv *wil, const char *name);
|
||||
bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
|
||||
|
||||
void wil_pm_runtime_allow(struct wil6210_priv *wil);
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -70,23 +71,23 @@ MODULE_PARM_DESC(led_id,
|
||||
* On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
|
||||
* AHB addresses starting from 0x880000
|
||||
*
|
||||
* Internally, firmware uses addresses that allows faster access but
|
||||
* Internally, firmware uses addresses that allow faster access but
|
||||
* are invisible from the host. To read from these addresses, alternative
|
||||
* AHB address must be used.
|
||||
*
|
||||
* Memory mapping
|
||||
* Linker address PCI/Host address
|
||||
* 0x880000 .. 0xa80000 2Mb BAR0
|
||||
* 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM
|
||||
* 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fw_mapping provides memory remapping table
|
||||
* @sparrow_fw_mapping provides memory remapping table for sparrow
|
||||
*
|
||||
* array size should be in sync with the declaration in the wil6210.h
|
||||
*
|
||||
* Sparrow memory mapping:
|
||||
* Linker address PCI/Host address
|
||||
* 0x880000 .. 0xa80000 2Mb BAR0
|
||||
* 0x800000 .. 0x808000 0x900000 .. 0x908000 32k DCCM
|
||||
* 0x840000 .. 0x860000 0x908000 .. 0x928000 128k PERIPH
|
||||
*/
|
||||
const struct fw_map fw_mapping[] = {
|
||||
const struct fw_map sparrow_fw_mapping[] = {
|
||||
/* FW code RAM 256k */
|
||||
{0x000000, 0x040000, 0x8c0000, "fw_code", true},
|
||||
/* FW data RAM 32k */
|
||||
@ -112,6 +113,59 @@ const struct fw_map fw_mapping[] = {
|
||||
{0x800000, 0x804000, 0x940000, "uc_data", false},
|
||||
};
|
||||
|
||||
/**
|
||||
* @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
|
||||
* it is a bit larger to support extra features
|
||||
*/
|
||||
const struct fw_map sparrow_d0_mac_rgf_ext = {
|
||||
0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
|
||||
};
|
||||
|
||||
/**
|
||||
* @talyn_fw_mapping provides memory remapping table for Talyn
|
||||
*
|
||||
* array size should be in sync with the declaration in the wil6210.h
|
||||
*
|
||||
* Talyn memory mapping:
|
||||
* Linker address PCI/Host address
|
||||
* 0x880000 .. 0xc80000 4Mb BAR0
|
||||
* 0x800000 .. 0x820000 0xa00000 .. 0xa20000 128k DCCM
|
||||
* 0x840000 .. 0x858000 0xa20000 .. 0xa38000 96k PERIPH
|
||||
*/
|
||||
const struct fw_map talyn_fw_mapping[] = {
|
||||
/* FW code RAM 1M */
|
||||
{0x000000, 0x100000, 0x900000, "fw_code", true},
|
||||
/* FW data RAM 128k */
|
||||
{0x800000, 0x820000, 0xa00000, "fw_data", true},
|
||||
/* periph. data RAM 96k */
|
||||
{0x840000, 0x858000, 0xa20000, "fw_peri", true},
|
||||
/* various RGF 40k */
|
||||
{0x880000, 0x88a000, 0x880000, "rgf", true},
|
||||
/* AGC table 4k */
|
||||
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
|
||||
/* Pcie_ext_rgf 4k */
|
||||
{0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
|
||||
/* mac_ext_rgf 1344b */
|
||||
{0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
|
||||
/* ext USER RGF 4k */
|
||||
{0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
|
||||
/* OTP 4k */
|
||||
{0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
|
||||
/* DMA EXT RGF 64k */
|
||||
{0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
|
||||
/* upper area 1536k */
|
||||
{0x900000, 0xa80000, 0x900000, "upper", true},
|
||||
/* UCODE areas - accessible by debugfs blobs but not by
|
||||
* wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
|
||||
*/
|
||||
/* ucode code RAM 256k */
|
||||
{0x000000, 0x040000, 0xa38000, "uc_code", false},
|
||||
/* ucode data RAM 32k */
|
||||
{0x800000, 0x808000, 0xa78000, "uc_data", false},
|
||||
};
|
||||
|
||||
struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
|
||||
|
||||
struct blink_on_off_time led_blink_time[] = {
|
||||
{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
|
||||
{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
|
||||
@ -138,6 +192,24 @@ static u32 wmi_addr_remap(u32 x)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* find fw_mapping entry by section name
|
||||
* @section - section name
|
||||
*
|
||||
* Return pointer to section or NULL if not found
|
||||
*/
|
||||
struct fw_map *wil_find_fw_mapping(const char *section)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
|
||||
if (fw_mapping[i].name &&
|
||||
!strcmp(section, fw_mapping[i].name))
|
||||
return &fw_mapping[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check address validity for WMI buffer; remap if needed
|
||||
* @ptr - internal (linker) fw/ucode address
|
||||
|
@ -165,7 +165,7 @@ static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
|
||||
|
||||
static int
|
||||
brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
void *buf, uint len)
|
||||
void *buf, uint len, int *fwerr)
|
||||
{
|
||||
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
|
||||
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
|
||||
@ -175,6 +175,7 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
|
||||
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
|
||||
|
||||
*fwerr = 0;
|
||||
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
|
||||
if (ret < 0) {
|
||||
brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
|
||||
@ -211,25 +212,27 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
memcpy(buf, info, len);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* Check the ERROR flag */
|
||||
if (flags & BCDC_DCMD_ERROR)
|
||||
ret = le32_to_cpu(msg->status);
|
||||
|
||||
*fwerr = le32_to_cpu(msg->status);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
void *buf, uint len)
|
||||
void *buf, uint len, int *fwerr)
|
||||
{
|
||||
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
|
||||
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
u32 flags, id;
|
||||
|
||||
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
|
||||
|
||||
*fwerr = 0;
|
||||
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
@ -249,9 +252,11 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* Check the ERROR flag */
|
||||
if (flags & BCDC_DCMD_ERROR)
|
||||
ret = le32_to_cpu(msg->status);
|
||||
*fwerr = le32_to_cpu(msg->status);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
|
@ -107,7 +107,7 @@ static s32
|
||||
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
|
||||
{
|
||||
struct brcmf_pub *drvr = ifp->drvr;
|
||||
s32 err;
|
||||
s32 err, fwerr;
|
||||
|
||||
if (drvr->bus_if->state != BRCMF_BUS_UP) {
|
||||
brcmf_err("bus is down. we have nothing to do.\n");
|
||||
@ -117,16 +117,20 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
|
||||
if (data != NULL)
|
||||
len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
|
||||
if (set)
|
||||
err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
|
||||
err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
|
||||
data, len, &fwerr);
|
||||
else
|
||||
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
|
||||
|
||||
if (err >= 0)
|
||||
return 0;
|
||||
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
|
||||
data, len, &fwerr);
|
||||
|
||||
if (err) {
|
||||
brcmf_dbg(FIL, "Failed: %s (%d)\n",
|
||||
brcmf_fil_get_errstr((u32)(-err)), err);
|
||||
|
||||
} else if (fwerr < 0) {
|
||||
brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
|
||||
brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
|
||||
err = -EBADE;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -477,7 +477,7 @@ static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)
|
||||
|
||||
|
||||
static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
uint cmd, void *buf, uint len)
|
||||
uint cmd, void *buf, uint len, int *fwerr)
|
||||
{
|
||||
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
|
||||
struct sk_buff *skb = NULL;
|
||||
@ -485,6 +485,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
int err;
|
||||
|
||||
brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);
|
||||
*fwerr = 0;
|
||||
msgbuf->ctl_completed = false;
|
||||
err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);
|
||||
if (err)
|
||||
@ -508,14 +509,15 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
}
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
|
||||
return msgbuf->ioctl_resp_status;
|
||||
*fwerr = msgbuf->ioctl_resp_status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
uint cmd, void *buf, uint len)
|
||||
uint cmd, void *buf, uint len, int *fwerr)
|
||||
{
|
||||
return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len);
|
||||
return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,9 +30,9 @@ struct brcmf_proto {
|
||||
int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
|
||||
struct sk_buff *skb, struct brcmf_if **ifp);
|
||||
int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
|
||||
void *buf, uint len);
|
||||
void *buf, uint len, int *fwerr);
|
||||
int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
|
||||
uint len);
|
||||
uint len, int *fwerr);
|
||||
int (*tx_queue_data)(struct brcmf_pub *drvr, int ifidx,
|
||||
struct sk_buff *skb);
|
||||
int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset,
|
||||
@ -71,14 +71,16 @@ static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
|
||||
return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
|
||||
}
|
||||
static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
uint cmd, void *buf, uint len)
|
||||
uint cmd, void *buf, uint len,
|
||||
int *fwerr)
|
||||
{
|
||||
return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);
|
||||
return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len,fwerr);
|
||||
}
|
||||
static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
|
||||
uint cmd, void *buf, uint len)
|
||||
uint cmd, void *buf, uint len,
|
||||
int *fwerr)
|
||||
{
|
||||
return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
|
||||
return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
|
||||
}
|
||||
|
||||
static inline int brcmf_proto_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
|
||||
|
@ -2,7 +2,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o
|
||||
obj-$(CONFIG_MT76x2E) += mt76x2e.o
|
||||
|
||||
mt76-y := \
|
||||
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o
|
||||
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o agg-rx.o
|
||||
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
|
258
drivers/net/wireless/mediatek/mt76/agg-rx.c
Normal file
258
drivers/net/wireless/mediatek/mt76/agg-rx.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* 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 "mt76.h"
|
||||
|
||||
#define REORDER_TIMEOUT (HZ / 10)
|
||||
|
||||
static void
|
||||
mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
tid->head = ieee80211_sn_inc(tid->head);
|
||||
|
||||
skb = tid->reorder_buf[idx];
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
tid->reorder_buf[idx] = NULL;
|
||||
tid->nframes--;
|
||||
__skb_queue_tail(frames, skb);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, struct sk_buff_head *frames,
|
||||
u16 head)
|
||||
{
|
||||
int idx;
|
||||
|
||||
while (ieee80211_sn_less(tid->head, head)) {
|
||||
idx = tid->head % tid->size;
|
||||
mt76_aggr_release(tid, frames, idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_rx_aggr_release_head(struct mt76_rx_tid *tid, struct sk_buff_head *frames)
|
||||
{
|
||||
int idx = tid->head % tid->size;
|
||||
|
||||
while (tid->reorder_buf[idx]) {
|
||||
mt76_aggr_release(tid, frames, idx);
|
||||
idx = tid->head % tid->size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames)
|
||||
{
|
||||
struct mt76_rx_status *status;
|
||||
struct sk_buff *skb;
|
||||
int start, idx, nframes;
|
||||
|
||||
if (!tid->nframes)
|
||||
return;
|
||||
|
||||
mt76_rx_aggr_release_head(tid, frames);
|
||||
|
||||
start = tid->head % tid->size;
|
||||
nframes = tid->nframes;
|
||||
|
||||
for (idx = (tid->head + 1) % tid->size;
|
||||
idx != start && nframes;
|
||||
idx = (idx + 1) % tid->size) {
|
||||
|
||||
skb = tid->reorder_buf[idx];
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
nframes--;
|
||||
status = (struct mt76_rx_status *) skb->cb;
|
||||
if (!time_after(jiffies, status->reorder_time +
|
||||
REORDER_TIMEOUT))
|
||||
continue;
|
||||
|
||||
mt76_rx_aggr_release_frames(tid, frames, status->seqno);
|
||||
}
|
||||
|
||||
mt76_rx_aggr_release_head(tid, frames);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_rx_aggr_reorder_work(struct work_struct *work)
|
||||
{
|
||||
struct mt76_rx_tid *tid = container_of(work, struct mt76_rx_tid,
|
||||
reorder_work.work);
|
||||
struct mt76_dev *dev = tid->dev;
|
||||
struct sk_buff_head frames;
|
||||
|
||||
__skb_queue_head_init(&frames);
|
||||
|
||||
local_bh_disable();
|
||||
|
||||
spin_lock(&tid->lock);
|
||||
mt76_rx_aggr_check_release(tid, &frames);
|
||||
spin_unlock(&tid->lock);
|
||||
|
||||
ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, REORDER_TIMEOUT);
|
||||
mt76_rx_complete(dev, &frames, -1);
|
||||
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
|
||||
{
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct ieee80211_sta *sta;
|
||||
struct mt76_rx_tid *tid;
|
||||
bool sn_less;
|
||||
u16 seqno, head, size;
|
||||
u8 idx;
|
||||
|
||||
__skb_queue_tail(frames, skb);
|
||||
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta || !status->aggr)
|
||||
return;
|
||||
|
||||
tid = rcu_dereference(wcid->aggr[status->tid]);
|
||||
if (!tid)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&tid->lock);
|
||||
|
||||
if (tid->stopped)
|
||||
goto out;
|
||||
|
||||
head = tid->head;
|
||||
seqno = status->seqno;
|
||||
size = tid->size;
|
||||
sn_less = ieee80211_sn_less(seqno, head);
|
||||
|
||||
if (!tid->started) {
|
||||
if (sn_less)
|
||||
goto out;
|
||||
|
||||
tid->started = true;
|
||||
}
|
||||
|
||||
if (sn_less) {
|
||||
__skb_unlink(skb, frames);
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (seqno == head) {
|
||||
tid->head = ieee80211_sn_inc(head);
|
||||
if (tid->nframes)
|
||||
mt76_rx_aggr_release_head(tid, frames);
|
||||
goto out;
|
||||
}
|
||||
|
||||
__skb_unlink(skb, frames);
|
||||
|
||||
/*
|
||||
* Frame sequence number exceeds buffering window, free up some space
|
||||
* by releasing previous frames
|
||||
*/
|
||||
if (!ieee80211_sn_less(seqno, head + size)) {
|
||||
head = ieee80211_sn_inc(ieee80211_sn_sub(seqno, size));
|
||||
mt76_rx_aggr_release_frames(tid, frames, head);
|
||||
}
|
||||
|
||||
idx = seqno % size;
|
||||
|
||||
/* Discard if the current slot is already in use */
|
||||
if (tid->reorder_buf[idx]) {
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status->reorder_time = jiffies;
|
||||
tid->reorder_buf[idx] = skb;
|
||||
tid->nframes++;
|
||||
mt76_rx_aggr_release_head(tid, frames);
|
||||
|
||||
ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, REORDER_TIMEOUT);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&tid->lock);
|
||||
}
|
||||
|
||||
int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno,
|
||||
u16 ssn, u8 size)
|
||||
{
|
||||
struct mt76_rx_tid *tid;
|
||||
|
||||
mt76_rx_aggr_stop(dev, wcid, tidno);
|
||||
|
||||
tid = kzalloc(sizeof(*tid) + size * sizeof(tid->reorder_buf[0]),
|
||||
GFP_KERNEL);
|
||||
if (!tid)
|
||||
return -ENOMEM;
|
||||
|
||||
tid->dev = dev;
|
||||
tid->head = ssn;
|
||||
tid->size = size;
|
||||
INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work);
|
||||
spin_lock_init(&tid->lock);
|
||||
|
||||
rcu_assign_pointer(wcid->aggr[tidno], tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_rx_aggr_start);
|
||||
|
||||
static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid)
|
||||
{
|
||||
u8 size = tid->size;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&tid->lock);
|
||||
|
||||
tid->stopped = true;
|
||||
for (i = 0; tid->nframes && i < size; i++) {
|
||||
struct sk_buff *skb = tid->reorder_buf[i];
|
||||
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
tid->nframes--;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&tid->lock);
|
||||
|
||||
cancel_delayed_work_sync(&tid->reorder_work);
|
||||
}
|
||||
|
||||
void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno)
|
||||
{
|
||||
struct mt76_rx_tid *tid;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
tid = rcu_dereference(wcid->aggr[tidno]);
|
||||
if (tid) {
|
||||
rcu_assign_pointer(wcid->aggr[tidno], NULL);
|
||||
mt76_rx_aggr_shutdown(dev, tid);
|
||||
kfree_rcu(tid, rcu_head);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop);
|
@ -387,17 +387,25 @@ static int
|
||||
mt76_dma_rx_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct mt76_dev *dev;
|
||||
int qid, done;
|
||||
int qid, done = 0, cur;
|
||||
|
||||
dev = container_of(napi->dev, struct mt76_dev, napi_dev);
|
||||
qid = napi - dev->napi;
|
||||
|
||||
done = mt76_dma_rx_process(dev, &dev->q_rx[qid], budget);
|
||||
rcu_read_lock();
|
||||
|
||||
do {
|
||||
cur = mt76_dma_rx_process(dev, &dev->q_rx[qid], budget - done);
|
||||
mt76_rx_poll_complete(dev, qid);
|
||||
done += cur;
|
||||
} while (cur && done < budget);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (done < budget) {
|
||||
napi_complete(napi);
|
||||
dev->drv->rx_poll_complete(dev, qid);
|
||||
}
|
||||
mt76_rx_complete(dev, qid);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
@ -384,10 +384,122 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_get_survey);
|
||||
|
||||
void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q)
|
||||
void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ieee80211_key_seq seq;
|
||||
int i;
|
||||
|
||||
wcid->rx_check_pn = false;
|
||||
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||
wcid->rx_check_pn = true;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
ieee80211_get_key_rx_seq(key, i, &seq);
|
||||
memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mt76_wcid_key_setup);
|
||||
|
||||
static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct mt76_rx_status mstat;
|
||||
|
||||
mstat = *((struct mt76_rx_status *) skb->cb);
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
status->flag = mstat.flag;
|
||||
status->freq = mstat.freq;
|
||||
status->enc_flags = mstat.enc_flags;
|
||||
status->encoding = mstat.encoding;
|
||||
status->bw = mstat.bw;
|
||||
status->rate_idx = mstat.rate_idx;
|
||||
status->nss = mstat.nss;
|
||||
status->band = mstat.band;
|
||||
status->signal = mstat.signal;
|
||||
status->chains = mstat.chains;
|
||||
|
||||
BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
|
||||
BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal));
|
||||
memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal));
|
||||
|
||||
return wcid_to_sta(mstat.wcid);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_check_ccmp_pn(struct sk_buff *skb)
|
||||
{
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int ret;
|
||||
|
||||
if (!(status->flag & RX_FLAG_DECRYPTED))
|
||||
return 0;
|
||||
|
||||
if (!wcid || !wcid->rx_check_pn)
|
||||
return 0;
|
||||
|
||||
if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
|
||||
/*
|
||||
* Validate the first fragment both here and in mac80211
|
||||
* All further fragments will be validated by mac80211 only.
|
||||
*/
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
if (ieee80211_is_frag(hdr) &&
|
||||
!ieee80211_is_first_frag(hdr->frame_control))
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
|
||||
ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
|
||||
sizeof(status->iv));
|
||||
if (ret <= 0)
|
||||
return -EINVAL; /* replay */
|
||||
|
||||
memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
|
||||
|
||||
if (status->flag & RX_FLAG_IV_STRIPPED)
|
||||
status->flag |= RX_FLAG_PN_VALIDATED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
int queue)
|
||||
{
|
||||
struct napi_struct *napi = NULL;
|
||||
struct ieee80211_sta *sta;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL)
|
||||
ieee80211_rx_napi(dev->hw, NULL, skb, &dev->napi[q]);
|
||||
if (queue >= 0)
|
||||
napi = &dev->napi[queue];
|
||||
|
||||
while ((skb = __skb_dequeue(frames)) != NULL) {
|
||||
if (mt76_check_ccmp_pn(skb)) {
|
||||
dev_kfree_skb(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
sta = mt76_rx_convert(skb);
|
||||
ieee80211_rx_napi(dev->hw, sta, skb, napi);
|
||||
}
|
||||
}
|
||||
|
||||
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q)
|
||||
{
|
||||
struct sk_buff_head frames;
|
||||
struct sk_buff *skb;
|
||||
|
||||
__skb_queue_head_init(&frames);
|
||||
|
||||
while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL)
|
||||
mt76_rx_aggr_reorder(skb, &frames);
|
||||
|
||||
mt76_rx_complete(dev, &frames, q);
|
||||
}
|
||||
|
@ -122,13 +122,23 @@ struct mt76_queue_ops {
|
||||
};
|
||||
|
||||
struct mt76_wcid {
|
||||
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
|
||||
|
||||
struct work_struct aggr_work;
|
||||
|
||||
u8 idx;
|
||||
u8 hw_key_idx;
|
||||
|
||||
u8 sta:1;
|
||||
|
||||
u8 rx_check_pn;
|
||||
u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
|
||||
|
||||
__le16 tx_rate;
|
||||
bool tx_rate_set;
|
||||
u8 tx_rate_nss;
|
||||
s8 max_txpwr_adj;
|
||||
bool sw_iv;
|
||||
};
|
||||
|
||||
struct mt76_txq {
|
||||
@ -149,6 +159,24 @@ struct mt76_txwi_cache {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
||||
struct mt76_rx_tid {
|
||||
struct rcu_head rcu_head;
|
||||
|
||||
struct mt76_dev *dev;
|
||||
|
||||
spinlock_t lock;
|
||||
struct delayed_work reorder_work;
|
||||
|
||||
u16 head;
|
||||
u8 size;
|
||||
u8 nframes;
|
||||
|
||||
u8 started:1, stopped:1, timer_pending:1;
|
||||
|
||||
struct sk_buff *reorder_buf[];
|
||||
};
|
||||
|
||||
enum {
|
||||
MT76_STATE_INITIALIZED,
|
||||
MT76_STATE_RUNNING,
|
||||
@ -249,6 +277,29 @@ struct mt76_rate_power {
|
||||
};
|
||||
};
|
||||
|
||||
struct mt76_rx_status {
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
unsigned long reorder_time;
|
||||
|
||||
u8 iv[6];
|
||||
|
||||
u8 aggr:1;
|
||||
u8 tid;
|
||||
u16 seqno;
|
||||
|
||||
u16 freq;
|
||||
u32 flag;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3;
|
||||
u8 rate_idx;
|
||||
u8 nss;
|
||||
u8 band;
|
||||
u8 signal;
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
};
|
||||
|
||||
#define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__)
|
||||
@ -329,6 +380,17 @@ mtxq_to_txq(struct mt76_txq *mtxq)
|
||||
return container_of(ptr, struct ieee80211_txq, drv_priv);
|
||||
}
|
||||
|
||||
static inline struct ieee80211_sta *
|
||||
wcid_to_sta(struct mt76_wcid *wcid)
|
||||
{
|
||||
void *ptr = wcid;
|
||||
|
||||
if (!wcid || !wcid->sta)
|
||||
return NULL;
|
||||
|
||||
return container_of(ptr, struct ieee80211_sta, drv_priv);
|
||||
}
|
||||
|
||||
int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta);
|
||||
@ -352,9 +414,19 @@ void mt76_set_channel(struct mt76_dev *dev);
|
||||
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
|
||||
int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid,
|
||||
u16 ssn, u8 size);
|
||||
void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid);
|
||||
|
||||
void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key);
|
||||
|
||||
/* internal */
|
||||
void mt76_tx_free(struct mt76_dev *dev);
|
||||
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
|
||||
void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q);
|
||||
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
int queue);
|
||||
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q);
|
||||
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
|
||||
|
||||
#endif
|
||||
|
@ -144,6 +144,7 @@ struct mt76x2_vif {
|
||||
struct mt76x2_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
struct mt76x2_vif *vif;
|
||||
struct mt76x2_tx_status status;
|
||||
int n_frames;
|
||||
};
|
||||
|
@ -460,8 +460,8 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
|
||||
{
|
||||
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
|
||||
|
||||
tasklet_kill(&dev->dfs_pd.dfs_tasklet);
|
||||
if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
|
||||
if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
dev->dfs_pd.region != NL80211_DFS_UNSET) {
|
||||
mt76x2_dfs_set_bbp_params(dev);
|
||||
/* enable debug mode */
|
||||
mt76x2_dfs_set_capture_mode_ctrl(dev, true);
|
||||
@ -491,3 +491,16 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev)
|
||||
(unsigned long)dev);
|
||||
}
|
||||
|
||||
void mt76x2_dfs_set_domain(struct mt76x2_dev *dev,
|
||||
enum nl80211_dfs_regions region)
|
||||
{
|
||||
struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
|
||||
if (dfs_pd->region != region) {
|
||||
tasklet_disable(&dfs_pd->dfs_tasklet);
|
||||
dfs_pd->region = region;
|
||||
mt76x2_dfs_init_params(dev);
|
||||
tasklet_enable(&dfs_pd->dfs_tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,5 +76,7 @@ struct mt76x2_dfs_pattern_detector {
|
||||
void mt76x2_dfs_init_params(struct mt76x2_dev *dev);
|
||||
void mt76x2_dfs_init_detector(struct mt76x2_dev *dev);
|
||||
void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev);
|
||||
void mt76x2_dfs_set_domain(struct mt76x2_dev *dev,
|
||||
enum nl80211_dfs_regions region);
|
||||
|
||||
#endif /* __MT76x2_DFS_H */
|
||||
|
@ -55,6 +55,7 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
|
||||
|
||||
q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
|
||||
q->ndesc = n_desc;
|
||||
q->hw_idx = idx;
|
||||
|
||||
ret = mt76_queue_alloc(dev, q);
|
||||
if (ret)
|
||||
|
@ -131,7 +131,7 @@ mt76_write_mac_initvals(struct mt76x2_dev *dev)
|
||||
{ MT_RX_FILTR_CFG, 0x00015f97 },
|
||||
{ MT_LEGACY_BASIC_RATE, 0x0000017f },
|
||||
{ MT_HT_BASIC_RATE, 0x00004003 },
|
||||
{ MT_PN_PAD_MODE, 0x00000002 },
|
||||
{ MT_PN_PAD_MODE, 0x00000003 },
|
||||
{ MT_TXOP_HLDR_ET, 0x00000002 },
|
||||
{ 0xa44, 0x00000000 },
|
||||
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
|
||||
@ -614,6 +614,8 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev)
|
||||
|
||||
void mt76x2_cleanup(struct mt76x2_dev *dev)
|
||||
{
|
||||
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
|
||||
tasklet_disable(&dev->pre_tbtt_tasklet);
|
||||
mt76x2_stop_hardware(dev);
|
||||
mt76x2_dma_cleanup(dev);
|
||||
mt76x2_mcu_cleanup(dev);
|
||||
@ -652,7 +654,7 @@ static void mt76x2_regd_notifier(struct wiphy *wiphy,
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt76x2_dev *dev = hw->priv;
|
||||
|
||||
dev->dfs_pd.region = request->dfs_region;
|
||||
mt76x2_dfs_set_domain(dev, request->dfs_region);
|
||||
}
|
||||
|
||||
#define CCK_RATE(_idx, _rate) { \
|
||||
@ -840,6 +842,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
|
||||
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
|
||||
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
|
||||
|
||||
INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate);
|
||||
INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work);
|
||||
|
||||
|
@ -29,7 +29,7 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr)
|
||||
}
|
||||
|
||||
static int
|
||||
mt76x2_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
|
||||
mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate)
|
||||
{
|
||||
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
|
||||
|
||||
@ -171,10 +171,13 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *rate = &info->control.rates[0];
|
||||
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
|
||||
u16 txwi_flags = 0;
|
||||
u8 nss;
|
||||
s8 txpwr_adj, max_txpwr_adj;
|
||||
u8 ccmp_pn[8];
|
||||
|
||||
memset(txwi, 0, sizeof(*txwi));
|
||||
|
||||
@ -185,6 +188,20 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
|
||||
|
||||
txwi->pktid = 1;
|
||||
|
||||
if (wcid && wcid->sw_iv && key) {
|
||||
u64 pn = atomic64_inc_return(&key->tx_pn);
|
||||
ccmp_pn[0] = pn;
|
||||
ccmp_pn[1] = pn >> 8;
|
||||
ccmp_pn[2] = 0;
|
||||
ccmp_pn[3] = 0x20 | (key->keyidx << 6);
|
||||
ccmp_pn[4] = pn >> 16;
|
||||
ccmp_pn[5] = pn >> 24;
|
||||
ccmp_pn[6] = pn >> 32;
|
||||
ccmp_pn[7] = pn >> 40;
|
||||
txwi->iv = *((u32 *) &ccmp_pn[0]);
|
||||
txwi->eiv = *((u32 *) &ccmp_pn[1]);
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->mt76.lock);
|
||||
if (wcid && (rate->idx < 0 || !rate->count)) {
|
||||
txwi->rate = wcid->tx_rate;
|
||||
@ -232,36 +249,101 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
|
||||
sta->ht_cap.ampdu_density);
|
||||
}
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control) ||
|
||||
ieee80211_is_beacon(hdr->frame_control))
|
||||
txwi_flags |= MT_TXWI_FLAGS_TS;
|
||||
|
||||
txwi->flags |= cpu_to_le16(txwi_flags);
|
||||
txwi->len_ctl = cpu_to_le16(skb->len);
|
||||
}
|
||||
|
||||
static void mt76x2_remove_hdr_pad(struct sk_buff *skb)
|
||||
static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len)
|
||||
{
|
||||
int len = ieee80211_get_hdrlen_from_skb(skb);
|
||||
int hdrlen;
|
||||
|
||||
memmove(skb->data + 2, skb->data, len);
|
||||
skb_pull(skb, 2);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
memmove(skb->data + len, skb->data, hdrlen);
|
||||
skb_pull(skb, len);
|
||||
}
|
||||
|
||||
static struct mt76_wcid *
|
||||
mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, u8 idx, bool unicast)
|
||||
{
|
||||
struct mt76x2_sta *sta;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= ARRAY_SIZE(dev->wcid))
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[idx]);
|
||||
if (unicast || !wcid)
|
||||
return wcid;
|
||||
|
||||
sta = container_of(wcid, struct mt76x2_sta, wcid);
|
||||
return &sta->vif->group_wcid;
|
||||
}
|
||||
|
||||
int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
|
||||
void *rxi)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
|
||||
struct mt76x2_rxwi *rxwi = rxi;
|
||||
u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
|
||||
u32 ctl = le32_to_cpu(rxwi->ctl);
|
||||
u16 rate = le16_to_cpu(rxwi->rate);
|
||||
u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
|
||||
bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
|
||||
int pad_len = 0;
|
||||
u8 pn_len;
|
||||
u8 wcid;
|
||||
int len;
|
||||
|
||||
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD))
|
||||
mt76x2_remove_hdr_pad(skb);
|
||||
if (rxinfo & MT_RXINFO_L2PAD)
|
||||
pad_len += 2;
|
||||
|
||||
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
|
||||
if (rxinfo & MT_RXINFO_DECRYPT) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_MIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED;
|
||||
}
|
||||
|
||||
wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
|
||||
status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast);
|
||||
|
||||
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
|
||||
pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
|
||||
if (pn_len) {
|
||||
int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
|
||||
u8 *data = skb->data + offset;
|
||||
|
||||
status->iv[0] = data[7];
|
||||
status->iv[1] = data[6];
|
||||
status->iv[2] = data[5];
|
||||
status->iv[3] = data[4];
|
||||
status->iv[4] = data[1];
|
||||
status->iv[5] = data[0];
|
||||
|
||||
/*
|
||||
* Driver CCMP validation can't deal with fragments.
|
||||
* Let mac80211 take care of it.
|
||||
*/
|
||||
if (rxinfo & MT_RXINFO_FRAG) {
|
||||
status->flag &= ~RX_FLAG_IV_STRIPPED;
|
||||
} else {
|
||||
pad_len += pn_len << 2;
|
||||
len -= pn_len << 2;
|
||||
}
|
||||
}
|
||||
|
||||
mt76x2_remove_hdr_pad(skb, pad_len);
|
||||
|
||||
if (rxinfo & MT_RXINFO_BA)
|
||||
status->aggr = true;
|
||||
|
||||
if (WARN_ON_ONCE(len > skb->len))
|
||||
return -EINVAL;
|
||||
|
||||
@ -273,6 +355,9 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
|
||||
status->freq = dev->mt76.chandef.chan->center_freq;
|
||||
status->band = dev->mt76.chandef.chan->band;
|
||||
|
||||
status->tid = FIELD_GET(MT_RXWI_TID, tid_sn);
|
||||
status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
|
||||
|
||||
return mt76x2_mac_process_rate(status, rate);
|
||||
}
|
||||
|
||||
@ -618,7 +703,6 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
|
||||
return -ENOSPC;
|
||||
|
||||
mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL);
|
||||
txwi.flags |= cpu_to_le16(MT_TXWI_FLAGS_TS);
|
||||
|
||||
mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
|
||||
offset += sizeof(txwi);
|
||||
|
@ -127,6 +127,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
mt76_set_channel(&dev->mt76);
|
||||
|
||||
tasklet_disable(&dev->pre_tbtt_tasklet);
|
||||
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
|
||||
cancel_delayed_work_sync(&dev->cal_work);
|
||||
|
||||
mt76x2_mac_stop(dev, true);
|
||||
@ -139,6 +140,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
mt76x2_dfs_init_params(dev);
|
||||
|
||||
mt76x2_mac_resume(dev);
|
||||
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
|
||||
tasklet_enable(&dev->pre_tbtt_tasklet);
|
||||
|
||||
return ret;
|
||||
@ -271,6 +273,8 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
goto out;
|
||||
}
|
||||
|
||||
msta->vif = mvif;
|
||||
msta->wcid.sta = 1;
|
||||
msta->wcid.idx = idx;
|
||||
msta->wcid.hw_key_idx = -1;
|
||||
mt76x2_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
|
||||
@ -355,12 +359,19 @@ mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
if (cmd == SET_KEY) {
|
||||
key->hw_key_idx = wcid->idx;
|
||||
wcid->hw_key_idx = idx;
|
||||
if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
wcid->sw_iv = true;
|
||||
}
|
||||
} else {
|
||||
if (idx == wcid->hw_key_idx)
|
||||
if (idx == wcid->hw_key_idx) {
|
||||
wcid->hw_key_idx = -1;
|
||||
wcid->sw_iv = true;
|
||||
}
|
||||
|
||||
key = NULL;
|
||||
}
|
||||
mt76_wcid_key_setup(&dev->mt76, wcid, key);
|
||||
|
||||
if (!msta) {
|
||||
if (key || wcid->hw_key_idx == idx) {
|
||||
@ -380,9 +391,11 @@ mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct mt76x2_dev *dev = hw->priv;
|
||||
u8 cw_min = 5, cw_max = 10;
|
||||
u8 cw_min = 5, cw_max = 10, qid;
|
||||
u32 val;
|
||||
|
||||
qid = dev->mt76.q_tx[queue].hw_idx;
|
||||
|
||||
if (params->cw_min)
|
||||
cw_min = fls(params->cw_min);
|
||||
if (params->cw_max)
|
||||
@ -392,26 +405,26 @@ mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
|
||||
FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
|
||||
FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
|
||||
FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
|
||||
mt76_wr(dev, MT_EDCA_CFG_AC(queue), val);
|
||||
mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
|
||||
|
||||
val = mt76_rr(dev, MT_WMM_TXOP(queue));
|
||||
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(queue));
|
||||
val |= params->txop << MT_WMM_TXOP_SHIFT(queue);
|
||||
mt76_wr(dev, MT_WMM_TXOP(queue), val);
|
||||
val = mt76_rr(dev, MT_WMM_TXOP(qid));
|
||||
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
|
||||
val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
|
||||
mt76_wr(dev, MT_WMM_TXOP(qid), val);
|
||||
|
||||
val = mt76_rr(dev, MT_WMM_AIFSN);
|
||||
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(queue));
|
||||
val |= params->aifs << MT_WMM_AIFSN_SHIFT(queue);
|
||||
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
|
||||
val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
|
||||
mt76_wr(dev, MT_WMM_AIFSN, val);
|
||||
|
||||
val = mt76_rr(dev, MT_WMM_CWMIN);
|
||||
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(queue));
|
||||
val |= cw_min << MT_WMM_CWMIN_SHIFT(queue);
|
||||
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
|
||||
val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
|
||||
mt76_wr(dev, MT_WMM_CWMIN, val);
|
||||
|
||||
val = mt76_rr(dev, MT_WMM_CWMAX);
|
||||
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(queue));
|
||||
val |= cw_max << MT_WMM_CWMAX_SHIFT(queue);
|
||||
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
|
||||
val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
|
||||
mt76_wr(dev, MT_WMM_CWMAX, val);
|
||||
|
||||
return 0;
|
||||
@ -476,9 +489,11 @@ mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn, params->buf_size);
|
||||
mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
|
||||
mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
|
||||
BIT(16 + tid));
|
||||
break;
|
||||
|
@ -36,7 +36,9 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
|
||||
|
||||
msta = (struct mt76x2_sta *) control->sta->drv_priv;
|
||||
wcid = &msta->wcid;
|
||||
} else if (vif) {
|
||||
}
|
||||
|
||||
if (vif || (!info->control.hw_key && wcid->hw_key_idx != -1)) {
|
||||
struct mt76x2_vif *mvif;
|
||||
|
||||
mvif = (struct mt76x2_vif *) vif->drv_priv;
|
||||
@ -166,7 +168,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
|
||||
*tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
|
||||
MT_TXD_INFO_80211;
|
||||
|
||||
if (!wcid || wcid->hw_key_idx == 0xff)
|
||||
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
|
||||
*tx_info |= MT_TXD_INFO_WIV;
|
||||
|
||||
return 0;
|
||||
|
@ -80,6 +80,41 @@ qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
qtnf_validate_iface_combinations(struct wiphy *wiphy,
|
||||
struct qtnf_vif *change_vif,
|
||||
enum nl80211_iftype new_type)
|
||||
{
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_vif *vif;
|
||||
int i;
|
||||
int ret = 0;
|
||||
struct iface_combination_params params = {
|
||||
.num_different_channels = 1,
|
||||
};
|
||||
|
||||
mac = wiphy_priv(wiphy);
|
||||
if (!mac)
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
||||
vif = &mac->iflist[i];
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
|
||||
params.iftype_num[vif->wdev.iftype]++;
|
||||
}
|
||||
|
||||
if (change_vif) {
|
||||
params.iftype_num[new_type]++;
|
||||
params.iftype_num[change_vif->wdev.iftype]--;
|
||||
} else {
|
||||
params.iftype_num[new_type]++;
|
||||
}
|
||||
|
||||
ret = cfg80211_check_combinations(wiphy, ¶ms);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
@ -90,6 +125,13 @@ qtnf_change_virtual_intf(struct wiphy *wiphy,
|
||||
u8 *mac_addr;
|
||||
int ret;
|
||||
|
||||
ret = qtnf_validate_iface_combinations(wiphy, vif, type);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u combination check: failed to set type %d\n",
|
||||
vif->mac->macid, vif->vifid, type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (params)
|
||||
mac_addr = params->macaddr;
|
||||
else
|
||||
@ -120,10 +162,6 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||
|
||||
qtnf_scan_done(vif->mac, true);
|
||||
|
||||
if (qtnf_cmd_send_del_intf(vif))
|
||||
pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
|
||||
/* Stop data */
|
||||
netif_tx_stop_all_queues(netdev);
|
||||
if (netif_carrier_ok(netdev))
|
||||
@ -132,6 +170,10 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||
if (netdev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdevice(netdev);
|
||||
|
||||
if (qtnf_cmd_send_del_intf(vif))
|
||||
pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
|
||||
vif->netdev->ieee80211_ptr = NULL;
|
||||
vif->netdev = NULL;
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
@ -150,12 +192,20 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_vif *vif;
|
||||
u8 *mac_addr = NULL;
|
||||
int ret;
|
||||
|
||||
mac = wiphy_priv(wiphy);
|
||||
|
||||
if (!mac)
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
ret = qtnf_validate_iface_combinations(wiphy, NULL, type);
|
||||
if (ret) {
|
||||
pr_err("MAC%u invalid combination: failed to add type %d\n",
|
||||
mac->macid, type);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_AP:
|
||||
@ -545,19 +595,13 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qtnf_scan_timeout(struct timer_list *t)
|
||||
{
|
||||
struct qtnf_wmac *mac = from_timer(mac, t, scan_timeout);
|
||||
|
||||
pr_warn("mac%d scan timed out\n", mac->macid);
|
||||
qtnf_scan_done(mac, true);
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
|
||||
cancel_delayed_work_sync(&mac->scan_timeout);
|
||||
|
||||
mac->scan_req = request;
|
||||
|
||||
if (qtnf_cmd_send_scan(mac)) {
|
||||
@ -566,9 +610,8 @@ qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mac->scan_timeout.function = qtnf_scan_timeout;
|
||||
mod_timer(&mac->scan_timeout,
|
||||
jiffies + QTNF_SCAN_TIMEOUT_SEC * HZ);
|
||||
queue_delayed_work(mac->bus->workqueue, &mac->scan_timeout,
|
||||
QTNF_SCAN_TIMEOUT_SEC * HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -629,7 +672,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -876,29 +918,29 @@ struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus)
|
||||
return wiphy;
|
||||
}
|
||||
|
||||
static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy,
|
||||
struct ieee80211_iface_combination *if_comb,
|
||||
const struct qtnf_mac_info *mac_info)
|
||||
static int
|
||||
qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, struct qtnf_mac_info *mac_info)
|
||||
{
|
||||
size_t max_interfaces = 0;
|
||||
struct ieee80211_iface_combination *if_comb;
|
||||
size_t n_if_comb;
|
||||
u16 interface_modes = 0;
|
||||
size_t i;
|
||||
size_t i, j;
|
||||
|
||||
if (unlikely(!mac_info->limits || !mac_info->n_limits))
|
||||
if_comb = mac_info->if_comb;
|
||||
n_if_comb = mac_info->n_if_comb;
|
||||
|
||||
if (!if_comb || !n_if_comb)
|
||||
return -ENOENT;
|
||||
|
||||
if_comb->limits = mac_info->limits;
|
||||
if_comb->n_limits = mac_info->n_limits;
|
||||
for (i = 0; i < n_if_comb; i++) {
|
||||
if_comb[i].radar_detect_widths = mac_info->radar_detect_widths;
|
||||
|
||||
for (i = 0; i < mac_info->n_limits; i++) {
|
||||
max_interfaces += mac_info->limits[i].max;
|
||||
interface_modes |= mac_info->limits[i].types;
|
||||
for (j = 0; j < if_comb[i].n_limits; j++)
|
||||
interface_modes |= if_comb[i].limits[j].types;
|
||||
}
|
||||
|
||||
if_comb->num_different_channels = 1;
|
||||
if_comb->beacon_int_infra_match = true;
|
||||
if_comb->max_interfaces = max_interfaces;
|
||||
if_comb->radar_detect_widths = mac_info->radar_detect_widths;
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = n_if_comb;
|
||||
wiphy->interface_modes = interface_modes;
|
||||
|
||||
return 0;
|
||||
@ -907,7 +949,6 @@ static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy,
|
||||
int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
{
|
||||
struct wiphy *wiphy = priv_to_wiphy(mac);
|
||||
struct ieee80211_iface_combination *iface_comb = NULL;
|
||||
int ret;
|
||||
|
||||
if (!wiphy) {
|
||||
@ -915,14 +956,6 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
iface_comb = kzalloc(sizeof(*iface_comb), GFP_KERNEL);
|
||||
if (!iface_comb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = qtnf_wiphy_setup_if_comb(wiphy, iface_comb, &mac->macinfo);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
wiphy->frag_threshold = mac->macinfo.frag_thr;
|
||||
wiphy->rts_threshold = mac->macinfo.rts_thr;
|
||||
wiphy->retry_short = mac->macinfo.sretry_limit;
|
||||
@ -934,11 +967,12 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
wiphy->mgmt_stypes = qtnf_mgmt_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
wiphy->max_acl_mac_addrs = mac->macinfo.max_acl_mac_addrs;
|
||||
|
||||
wiphy->iface_combinations = iface_comb;
|
||||
wiphy->n_iface_combinations = 1;
|
||||
wiphy->max_num_csa_counters = 2;
|
||||
|
||||
ret = qtnf_wiphy_setup_if_comb(wiphy, &mac->macinfo);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Initialize cipher suits */
|
||||
wiphy->cipher_suites = qtnf_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(qtnf_cipher_suites);
|
||||
@ -972,6 +1006,10 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
|
||||
}
|
||||
|
||||
strlcpy(wiphy->fw_version, hw_info->fw_version,
|
||||
sizeof(wiphy->fw_version));
|
||||
wiphy->hw_version = hw_info->hw_version;
|
||||
|
||||
ret = wiphy_register(wiphy);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -983,14 +1021,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
ret = regulatory_hint(wiphy, hw_info->rd->alpha2);
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
kfree(iface_comb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qtnf_netdev_updown(struct net_device *ndev, bool up)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
|
@ -28,23 +28,4 @@ void qtnf_band_init_rates(struct ieee80211_supported_band *band);
|
||||
void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo,
|
||||
struct ieee80211_supported_band *band);
|
||||
|
||||
static inline void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted)
|
||||
{
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = aborted,
|
||||
};
|
||||
|
||||
if (timer_pending(&mac->scan_timeout))
|
||||
del_timer_sync(&mac->scan_timeout);
|
||||
|
||||
mutex_lock(&mac->mac_lock);
|
||||
|
||||
if (mac->scan_req) {
|
||||
cfg80211_scan_done(mac->scan_req, &info);
|
||||
mac->scan_req = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&mac->mac_lock);
|
||||
}
|
||||
|
||||
#endif /* _QTN_FMAC_CFG80211_H_ */
|
||||
|
@ -187,7 +187,8 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
|
||||
len += sizeof(struct qlink_tlv_chandef);
|
||||
|
||||
if (s->acl)
|
||||
len += qtnf_cmd_acl_data_size(s->acl);
|
||||
len += sizeof(struct qlink_tlv_hdr) +
|
||||
qtnf_cmd_acl_data_size(s->acl);
|
||||
|
||||
if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
|
||||
pr_err("VIF%u.%u: can not fit AP settings: %u\n",
|
||||
@ -214,7 +215,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_START_AP,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct qlink_cmd_start_ap *)cmd_skb->data;
|
||||
@ -334,7 +335,7 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_STOP_AP,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -368,7 +369,7 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_REGISTER_MGMT,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -411,7 +412,7 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_SEND_MGMT_FRAME,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -457,7 +458,7 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_MGMT_SET_APPIE,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len);
|
||||
@ -712,8 +713,7 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_GET_STA_INFO,
|
||||
sizeof(*cmd));
|
||||
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -778,7 +778,7 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
cmd_type,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -851,7 +851,7 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_DEL_INTF,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -948,6 +948,16 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
|
||||
struct qtnf_hw_info *hwinfo = &bus->hw_info;
|
||||
const struct qlink_tlv_hdr *tlv;
|
||||
const struct qlink_tlv_reg_rule *tlv_rule;
|
||||
const char *bld_name = NULL;
|
||||
const char *bld_rev = NULL;
|
||||
const char *bld_type = NULL;
|
||||
const char *bld_label = NULL;
|
||||
u32 bld_tmstamp = 0;
|
||||
u32 plat_id = 0;
|
||||
const char *hw_id = NULL;
|
||||
const char *calibration_ver = NULL;
|
||||
const char *uboot_ver = NULL;
|
||||
u32 hw_ver = 0;
|
||||
struct ieee80211_reg_rule *rule;
|
||||
u16 tlv_type;
|
||||
u16 tlv_value_len;
|
||||
@ -974,6 +984,10 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
|
||||
hwinfo->rd->alpha2[0] = resp->alpha2[0];
|
||||
hwinfo->rd->alpha2[1] = resp->alpha2[1];
|
||||
|
||||
bld_tmstamp = le32_to_cpu(resp->bld_tmstamp);
|
||||
plat_id = le32_to_cpu(resp->plat_id);
|
||||
hw_ver = le32_to_cpu(resp->hw_ver);
|
||||
|
||||
switch (resp->dfs_region) {
|
||||
case QLINK_DFS_FCC:
|
||||
hwinfo->rd->dfs_region = NL80211_DFS_FCC;
|
||||
@ -1034,6 +1048,27 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
|
||||
rule->flags = qtnf_cmd_resp_reg_rule_flags_parse(
|
||||
le32_to_cpu(tlv_rule->flags));
|
||||
break;
|
||||
case QTN_TLV_ID_BUILD_NAME:
|
||||
bld_name = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_BUILD_REV:
|
||||
bld_rev = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_BUILD_TYPE:
|
||||
bld_type = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_BUILD_LABEL:
|
||||
bld_label = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_HW_ID:
|
||||
hw_id = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_CALIBRATION_VER:
|
||||
calibration_ver = (const void *)tlv->val;
|
||||
break;
|
||||
case QTN_TLV_ID_UBOOT_VER:
|
||||
uboot_ver = (const void *)tlv->val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1056,25 +1091,46 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
|
||||
hwinfo->total_tx_chain, hwinfo->total_rx_chain,
|
||||
hwinfo->hw_capab);
|
||||
|
||||
pr_info("\nBuild name: %s" \
|
||||
"\nBuild revision: %s" \
|
||||
"\nBuild type: %s" \
|
||||
"\nBuild label: %s" \
|
||||
"\nBuild timestamp: %lu" \
|
||||
"\nPlatform ID: %lu" \
|
||||
"\nHardware ID: %s" \
|
||||
"\nCalibration version: %s" \
|
||||
"\nU-Boot version: %s" \
|
||||
"\nHardware version: 0x%08x",
|
||||
bld_name, bld_rev, bld_type, bld_label,
|
||||
(unsigned long)bld_tmstamp,
|
||||
(unsigned long)plat_id,
|
||||
hw_id, calibration_ver, uboot_ver, hw_ver);
|
||||
|
||||
strlcpy(hwinfo->fw_version, bld_label, sizeof(hwinfo->fw_version));
|
||||
hwinfo->hw_version = hw_ver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
|
||||
const u8 *tlv_buf, size_t tlv_buf_size)
|
||||
{
|
||||
struct ieee80211_iface_limit *limits = NULL;
|
||||
const struct qlink_iface_limit *limit_record;
|
||||
size_t record_count = 0, rec = 0;
|
||||
u16 tlv_type, tlv_value_len;
|
||||
struct qlink_iface_comb_num *comb;
|
||||
struct ieee80211_iface_combination *comb = NULL;
|
||||
size_t n_comb = 0;
|
||||
struct ieee80211_iface_limit *limits;
|
||||
const struct qlink_iface_comb_num *comb_num;
|
||||
const struct qlink_iface_limit_record *rec;
|
||||
const struct qlink_iface_limit *lim;
|
||||
u16 rec_len;
|
||||
u16 tlv_type;
|
||||
u16 tlv_value_len;
|
||||
size_t tlv_full_len;
|
||||
const struct qlink_tlv_hdr *tlv;
|
||||
u8 *ext_capa = NULL;
|
||||
u8 *ext_capa_mask = NULL;
|
||||
u8 ext_capa_len = 0;
|
||||
u8 ext_capa_mask_len = 0;
|
||||
|
||||
mac->macinfo.n_limits = 0;
|
||||
int i = 0;
|
||||
|
||||
tlv = (const struct qlink_tlv_hdr *)tlv_buf;
|
||||
while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) {
|
||||
@ -1089,52 +1145,77 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
|
||||
|
||||
switch (tlv_type) {
|
||||
case QTN_TLV_ID_NUM_IFACE_COMB:
|
||||
if (unlikely(tlv_value_len != sizeof(*comb)))
|
||||
if (tlv_value_len != sizeof(*comb_num))
|
||||
return -EINVAL;
|
||||
|
||||
comb = (void *)tlv->val;
|
||||
record_count = le16_to_cpu(comb->iface_comb_num);
|
||||
comb_num = (void *)tlv->val;
|
||||
|
||||
mac->macinfo.n_limits = record_count;
|
||||
/* free earlier iface limits memory */
|
||||
kfree(mac->macinfo.limits);
|
||||
mac->macinfo.limits =
|
||||
kzalloc(sizeof(*mac->macinfo.limits) *
|
||||
record_count, GFP_KERNEL);
|
||||
/* free earlier iface comb memory */
|
||||
qtnf_mac_iface_comb_free(mac);
|
||||
|
||||
if (unlikely(!mac->macinfo.limits))
|
||||
mac->macinfo.n_if_comb =
|
||||
le32_to_cpu(comb_num->iface_comb_num);
|
||||
|
||||
mac->macinfo.if_comb =
|
||||
kcalloc(mac->macinfo.n_if_comb,
|
||||
sizeof(*mac->macinfo.if_comb),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!mac->macinfo.if_comb)
|
||||
return -ENOMEM;
|
||||
|
||||
limits = mac->macinfo.limits;
|
||||
comb = mac->macinfo.if_comb;
|
||||
|
||||
pr_debug("MAC%u: %zu iface combinations\n",
|
||||
mac->macid, mac->macinfo.n_if_comb);
|
||||
|
||||
break;
|
||||
case QTN_TLV_ID_IFACE_LIMIT:
|
||||
if (unlikely(!limits)) {
|
||||
pr_warn("MAC%u: limits are not inited\n",
|
||||
if (unlikely(!comb)) {
|
||||
pr_warn("MAC%u: no combinations advertised\n",
|
||||
mac->macid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(tlv_value_len != sizeof(*limit_record))) {
|
||||
pr_warn("MAC%u: record size mismatch\n",
|
||||
if (n_comb >= mac->macinfo.n_if_comb) {
|
||||
pr_warn("MAC%u: combinations count exceeded\n",
|
||||
mac->macid);
|
||||
n_comb++;
|
||||
break;
|
||||
}
|
||||
|
||||
rec = (void *)tlv->val;
|
||||
rec_len = sizeof(*rec) + rec->n_limits * sizeof(*lim);
|
||||
|
||||
if (unlikely(tlv_value_len != rec_len)) {
|
||||
pr_warn("MAC%u: record %zu size mismatch\n",
|
||||
mac->macid, n_comb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
limit_record = (void *)tlv->val;
|
||||
limits[rec].max = le16_to_cpu(limit_record->max_num);
|
||||
limits[rec].types = qlink_iface_type_to_nl_mask(
|
||||
le16_to_cpu(limit_record->type));
|
||||
limits = kzalloc(sizeof(*limits) * rec->n_limits,
|
||||
GFP_KERNEL);
|
||||
if (!limits)
|
||||
return -ENOMEM;
|
||||
|
||||
/* supported modes: STA, AP */
|
||||
limits[rec].types &= BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_AP_VLAN) |
|
||||
BIT(NL80211_IFTYPE_STATION);
|
||||
comb[n_comb].num_different_channels =
|
||||
rec->num_different_channels;
|
||||
comb[n_comb].max_interfaces =
|
||||
le16_to_cpu(rec->max_interfaces);
|
||||
comb[n_comb].n_limits = rec->n_limits;
|
||||
comb[n_comb].limits = limits;
|
||||
|
||||
pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid,
|
||||
limits[rec].max, limits[rec].types);
|
||||
for (i = 0; i < rec->n_limits; i++) {
|
||||
lim = &rec->limits[i];
|
||||
limits[i].max = le16_to_cpu(lim->max_num);
|
||||
limits[i].types =
|
||||
qlink_iface_type_to_nl_mask(le16_to_cpu(lim->type));
|
||||
pr_debug("MAC%u: comb[%zu]: MAX:%u TYPES:%.4X\n",
|
||||
mac->macid, n_comb,
|
||||
limits[i].max, limits[i].types);
|
||||
}
|
||||
|
||||
if (limits[rec].types)
|
||||
rec++;
|
||||
n_comb++;
|
||||
break;
|
||||
case WLAN_EID_EXT_CAPABILITY:
|
||||
if (unlikely(tlv_value_len > U8_MAX))
|
||||
@ -1162,9 +1243,9 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mac->macinfo.n_limits != rec) {
|
||||
if (mac->macinfo.n_if_comb != n_comb) {
|
||||
pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n",
|
||||
mac->macid, mac->macinfo.n_limits, rec);
|
||||
mac->macid, mac->macinfo.n_if_comb, n_comb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1575,7 +1656,7 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
|
||||
QLINK_CMD_MAC_INFO,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(mac->bus);
|
||||
@ -1613,7 +1694,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
|
||||
QLINK_CMD_GET_HW_INFO,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
@ -1793,7 +1874,7 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
|
||||
QLINK_CMD_FW_INIT,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
@ -1842,7 +1923,7 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_ADD_KEY,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -1895,7 +1976,7 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_DEL_KEY,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -1936,7 +2017,7 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_SET_DEFAULT_KEY,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -1971,7 +2052,7 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_SET_DEFAULT_MGMT_KEY,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -2026,7 +2107,7 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_CHANGE_STA,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -2078,7 +2159,7 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_DEL_STA,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -2148,7 +2229,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
|
||||
QLINK_CMD_SCAN,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(mac->bus);
|
||||
@ -2218,7 +2299,7 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_CONNECT,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct qlink_cmd_connect *)cmd_skb->data;
|
||||
@ -2320,7 +2401,7 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_DISCONNECT,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(vif->mac->bus);
|
||||
@ -2354,7 +2435,7 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_UPDOWN_INTF,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct qlink_cmd_updown *)cmd_skb->data;
|
||||
@ -2515,8 +2596,7 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
|
||||
QLINK_CMD_CHAN_SWITCH,
|
||||
sizeof(*cmd));
|
||||
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(mac->bus);
|
||||
@ -2568,7 +2648,7 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_CHAN_GET,
|
||||
sizeof(struct qlink_cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
@ -2607,7 +2687,7 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_START_CAC,
|
||||
sizeof(*cmd));
|
||||
if (unlikely(!cmd_skb))
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct qlink_cmd_start_cac *)cmd_skb->data;
|
||||
@ -2637,19 +2717,21 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
|
||||
{
|
||||
struct qtnf_bus *bus = vif->mac->bus;
|
||||
struct sk_buff *cmd_skb;
|
||||
struct qlink_cmd_set_mac_acl *cmd;
|
||||
struct qlink_tlv_hdr *tlv;
|
||||
size_t acl_size = qtnf_cmd_acl_data_size(params);
|
||||
u16 res_code;
|
||||
int ret;
|
||||
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_SET_MAC_ACL,
|
||||
sizeof(*cmd) +
|
||||
qtnf_cmd_acl_data_size(params));
|
||||
if (unlikely(!cmd_skb))
|
||||
sizeof(struct qlink_cmd));
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct qlink_cmd_set_mac_acl *)cmd_skb->data;
|
||||
qlink_acl_data_cfg2q(params, &cmd->acl);
|
||||
tlv = skb_put(cmd_skb, sizeof(*tlv) + acl_size);
|
||||
tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
|
||||
tlv->len = cpu_to_le16(acl_size);
|
||||
qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val);
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
|
||||
|
@ -119,9 +119,38 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
|
||||
/* Netdev handler for getting stats.
|
||||
*/
|
||||
static struct net_device_stats *qtnf_netdev_get_stats(struct net_device *dev)
|
||||
static void qtnf_netdev_get_stats64(struct net_device *ndev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
return &dev->stats;
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
unsigned int start;
|
||||
int cpu;
|
||||
|
||||
netdev_stats_to_stats64(stats, &ndev->stats);
|
||||
|
||||
if (!vif->stats64)
|
||||
return;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct pcpu_sw_netstats *stats64;
|
||||
u64 rx_packets, rx_bytes;
|
||||
u64 tx_packets, tx_bytes;
|
||||
|
||||
stats64 = per_cpu_ptr(vif->stats64, cpu);
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&stats64->syncp);
|
||||
rx_packets = stats64->rx_packets;
|
||||
rx_bytes = stats64->rx_bytes;
|
||||
tx_packets = stats64->tx_packets;
|
||||
tx_bytes = stats64->tx_bytes;
|
||||
} while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
|
||||
|
||||
stats->rx_packets += rx_packets;
|
||||
stats->rx_bytes += rx_bytes;
|
||||
stats->tx_packets += tx_packets;
|
||||
stats->tx_bytes += tx_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* Netdev handler for transmission timeout.
|
||||
@ -156,7 +185,7 @@ const struct net_device_ops qtnf_netdev_ops = {
|
||||
.ndo_stop = qtnf_netdev_close,
|
||||
.ndo_start_xmit = qtnf_netdev_hard_start_xmit,
|
||||
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
|
||||
.ndo_get_stats = qtnf_netdev_get_stats,
|
||||
.ndo_get_stats64 = qtnf_netdev_get_stats64,
|
||||
};
|
||||
|
||||
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
|
||||
@ -233,6 +262,23 @@ struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac)
|
||||
return vif;
|
||||
}
|
||||
|
||||
void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac)
|
||||
{
|
||||
struct ieee80211_iface_combination *comb;
|
||||
int i;
|
||||
|
||||
if (mac->macinfo.if_comb) {
|
||||
for (i = 0; i < mac->macinfo.n_if_comb; i++) {
|
||||
comb = &mac->macinfo.if_comb[i];
|
||||
kfree(comb->limits);
|
||||
comb->limits = NULL;
|
||||
}
|
||||
|
||||
kfree(mac->macinfo.if_comb);
|
||||
mac->macinfo.if_comb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void qtnf_vif_reset_handler(struct work_struct *work)
|
||||
{
|
||||
struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work);
|
||||
@ -265,6 +311,37 @@ static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac)
|
||||
vif->cons_tx_timeout_cnt = 0;
|
||||
}
|
||||
|
||||
static void qtnf_mac_scan_finish(struct qtnf_wmac *mac, bool aborted)
|
||||
{
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = aborted,
|
||||
};
|
||||
|
||||
mutex_lock(&mac->mac_lock);
|
||||
|
||||
if (mac->scan_req) {
|
||||
cfg80211_scan_done(mac->scan_req, &info);
|
||||
mac->scan_req = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&mac->mac_lock);
|
||||
}
|
||||
|
||||
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted)
|
||||
{
|
||||
cancel_delayed_work_sync(&mac->scan_timeout);
|
||||
qtnf_mac_scan_finish(mac, aborted);
|
||||
}
|
||||
|
||||
static void qtnf_mac_scan_timeout(struct work_struct *work)
|
||||
{
|
||||
struct qtnf_wmac *mac =
|
||||
container_of(work, struct qtnf_wmac, scan_timeout.work);
|
||||
|
||||
pr_warn("MAC%d: scan timed out\n", mac->macid);
|
||||
qtnf_mac_scan_finish(mac, true);
|
||||
}
|
||||
|
||||
static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
||||
unsigned int macid)
|
||||
{
|
||||
@ -288,7 +365,12 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
||||
mac->iflist[i].vifid = i;
|
||||
qtnf_sta_list_init(&mac->iflist[i].sta_list);
|
||||
mutex_init(&mac->mac_lock);
|
||||
timer_setup(&mac->scan_timeout, NULL, 0);
|
||||
INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout);
|
||||
mac->iflist[i].stats64 =
|
||||
netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!mac->iflist[i].stats64)
|
||||
pr_warn("VIF%u.%u: per cpu stats allocation failed\n",
|
||||
macid, i);
|
||||
}
|
||||
|
||||
qtnf_mac_init_primary_intf(mac);
|
||||
@ -297,6 +379,10 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
||||
return mac;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops qtnf_ethtool_ops = {
|
||||
.get_drvinfo = cfg80211_get_drvinfo,
|
||||
};
|
||||
|
||||
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
||||
const char *name, unsigned char name_assign_type)
|
||||
{
|
||||
@ -324,6 +410,7 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
||||
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
|
||||
dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT;
|
||||
dev->tx_queue_len = 100;
|
||||
dev->ethtool_ops = &qtnf_ethtool_ops;
|
||||
|
||||
qdev_vif = netdev_priv(dev);
|
||||
*((void **)qdev_vif) = vif;
|
||||
@ -364,6 +451,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
|
||||
}
|
||||
rtnl_unlock();
|
||||
qtnf_sta_list_free(&vif->sta_list);
|
||||
free_percpu(vif->stats64);
|
||||
}
|
||||
|
||||
if (mac->wiphy_registered)
|
||||
@ -380,10 +468,9 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
|
||||
wiphy->bands[band] = NULL;
|
||||
}
|
||||
|
||||
kfree(mac->macinfo.limits);
|
||||
qtnf_mac_iface_comb_free(mac);
|
||||
kfree(mac->macinfo.extended_capabilities);
|
||||
kfree(mac->macinfo.extended_capabilities_mask);
|
||||
kfree(wiphy->iface_combinations);
|
||||
wiphy_free(wiphy);
|
||||
bus->mac[macid] = NULL;
|
||||
}
|
||||
@ -643,6 +730,46 @@ void qtnf_wake_all_queues(struct net_device *ndev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_wake_all_queues);
|
||||
|
||||
void qtnf_update_rx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
struct pcpu_sw_netstats *stats64;
|
||||
|
||||
if (unlikely(!vif || !vif->stats64)) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
return;
|
||||
}
|
||||
|
||||
stats64 = this_cpu_ptr(vif->stats64);
|
||||
|
||||
u64_stats_update_begin(&stats64->syncp);
|
||||
stats64->rx_packets++;
|
||||
stats64->rx_bytes += skb->len;
|
||||
u64_stats_update_end(&stats64->syncp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_update_rx_stats);
|
||||
|
||||
void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
struct pcpu_sw_netstats *stats64;
|
||||
|
||||
if (unlikely(!vif || !vif->stats64)) {
|
||||
ndev->stats.tx_packets++;
|
||||
ndev->stats.tx_bytes += skb->len;
|
||||
return;
|
||||
}
|
||||
|
||||
stats64 = this_cpu_ptr(vif->stats64);
|
||||
|
||||
u64_stats_update_begin(&stats64->syncp);
|
||||
stats64->tx_packets++;
|
||||
stats64->tx_bytes += skb->len;
|
||||
u64_stats_update_end(&stats64->syncp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_update_tx_stats);
|
||||
|
||||
MODULE_AUTHOR("Quantenna Communications");
|
||||
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -89,6 +89,8 @@ struct qtnf_vif {
|
||||
struct qtnf_sta_list sta_list;
|
||||
unsigned long cons_tx_timeout_cnt;
|
||||
int generation;
|
||||
|
||||
struct pcpu_sw_netstats __percpu *stats64;
|
||||
};
|
||||
|
||||
struct qtnf_mac_info {
|
||||
@ -106,8 +108,8 @@ struct qtnf_mac_info {
|
||||
u32 max_acl_mac_addrs;
|
||||
struct ieee80211_ht_cap ht_cap_mod_mask;
|
||||
struct ieee80211_vht_cap vht_cap_mod_mask;
|
||||
struct ieee80211_iface_limit *limits;
|
||||
size_t n_limits;
|
||||
struct ieee80211_iface_combination *if_comb;
|
||||
size_t n_if_comb;
|
||||
u8 *extended_capabilities;
|
||||
u8 *extended_capabilities_mask;
|
||||
u8 extended_capabilities_len;
|
||||
@ -131,7 +133,7 @@ struct qtnf_wmac {
|
||||
struct qtnf_vif iflist[QTNF_MAX_INTF];
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct mutex mac_lock; /* lock during wmac speicific ops */
|
||||
struct timer_list scan_timeout;
|
||||
struct delayed_work scan_timeout;
|
||||
};
|
||||
|
||||
struct qtnf_hw_info {
|
||||
@ -143,10 +145,13 @@ struct qtnf_hw_info {
|
||||
struct ieee80211_regdomain *rd;
|
||||
u8 total_tx_chain;
|
||||
u8 total_rx_chain;
|
||||
char fw_version[ETHTOOL_FWVERS_LEN];
|
||||
u32 hw_version;
|
||||
};
|
||||
|
||||
struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac);
|
||||
struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac);
|
||||
void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac);
|
||||
struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);
|
||||
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,
|
||||
const char *name, unsigned char name_assign_type);
|
||||
@ -157,9 +162,13 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac);
|
||||
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid);
|
||||
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb);
|
||||
void qtnf_wake_all_queues(struct net_device *ndev);
|
||||
void qtnf_update_rx_stats(struct net_device *ndev, const struct sk_buff *skb);
|
||||
void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb);
|
||||
|
||||
void qtnf_virtual_intf_cleanup(struct net_device *ndev);
|
||||
|
||||
void qtnf_netdev_updown(struct net_device *ndev, bool up);
|
||||
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted);
|
||||
|
||||
static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)
|
||||
{
|
||||
|
@ -541,9 +541,9 @@ static int qtnf_event_process_skb(struct qtnf_bus *bus,
|
||||
if (unlikely(!mac))
|
||||
return -ENXIO;
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
rtnl_lock();
|
||||
res = qtnf_event_parse(mac, skb);
|
||||
qtnf_bus_unlock(bus);
|
||||
rtnl_unlock();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -615,8 +615,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv)
|
||||
PCI_DMA_TODEVICE);
|
||||
|
||||
if (skb->dev) {
|
||||
skb->dev->stats.tx_packets++;
|
||||
skb->dev->stats.tx_bytes += skb->len;
|
||||
qtnf_update_tx_stats(skb->dev, skb);
|
||||
if (unlikely(priv->tx_stopped)) {
|
||||
qtnf_wake_all_queues(skb->dev);
|
||||
priv->tx_stopped = 0;
|
||||
@ -855,9 +854,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget)
|
||||
skb_put(skb, psize);
|
||||
ndev = qtnf_classify_skb(bus, skb);
|
||||
if (likely(ndev)) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
|
||||
qtnf_update_rx_stats(ndev, skb);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
napi_gro_receive(napi, skb);
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#define QLINK_PROTO_VER 10
|
||||
#define QLINK_PROTO_VER 11
|
||||
|
||||
#define QLINK_MACID_RSVD 0xFF
|
||||
#define QLINK_VIFID_RSVD 0xFF
|
||||
@ -663,16 +663,6 @@ struct qlink_acl_data {
|
||||
struct qlink_mac_address mac_addrs[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_set_mac_acl - data for QLINK_CMD_SET_MAC_ACL command
|
||||
*
|
||||
* @acl: ACL data.
|
||||
*/
|
||||
struct qlink_cmd_set_mac_acl {
|
||||
struct qlink_cmd chdr;
|
||||
struct qlink_acl_data acl;
|
||||
} __packed;
|
||||
|
||||
/* QLINK Command Responses messages related definitions
|
||||
*/
|
||||
|
||||
@ -774,6 +764,9 @@ struct qlink_resp_get_hw_info {
|
||||
struct qlink_resp rhdr;
|
||||
__le32 fw_ver;
|
||||
__le32 hw_capab;
|
||||
__le32 bld_tmstamp;
|
||||
__le32 plat_id;
|
||||
__le32 hw_ver;
|
||||
__le16 ql_proto_ver;
|
||||
u8 num_mac;
|
||||
u8 mac_bitmap;
|
||||
@ -1084,6 +1077,13 @@ enum qlink_tlv_id {
|
||||
QTN_TLV_ID_IE_SET = 0x0305,
|
||||
QTN_TLV_ID_EXT_CAPABILITY_MASK = 0x0306,
|
||||
QTN_TLV_ID_ACL_DATA = 0x0307,
|
||||
QTN_TLV_ID_BUILD_NAME = 0x0401,
|
||||
QTN_TLV_ID_BUILD_REV = 0x0402,
|
||||
QTN_TLV_ID_BUILD_TYPE = 0x0403,
|
||||
QTN_TLV_ID_BUILD_LABEL = 0x0404,
|
||||
QTN_TLV_ID_HW_ID = 0x0405,
|
||||
QTN_TLV_ID_CALIBRATION_VER = 0x0406,
|
||||
QTN_TLV_ID_UBOOT_VER = 0x0407,
|
||||
};
|
||||
|
||||
struct qlink_tlv_hdr {
|
||||
@ -1092,13 +1092,20 @@ struct qlink_tlv_hdr {
|
||||
u8 val[0];
|
||||
} __packed;
|
||||
|
||||
struct qlink_iface_comb_num {
|
||||
__le32 iface_comb_num;
|
||||
} __packed;
|
||||
|
||||
struct qlink_iface_limit {
|
||||
__le16 max_num;
|
||||
__le16 type;
|
||||
} __packed;
|
||||
|
||||
struct qlink_iface_comb_num {
|
||||
__le16 iface_comb_num;
|
||||
struct qlink_iface_limit_record {
|
||||
__le16 max_interfaces;
|
||||
u8 num_different_channels;
|
||||
u8 n_limits;
|
||||
struct qlink_iface_limit limits[0];
|
||||
} __packed;
|
||||
|
||||
#define QLINK_RSSI_OFFSET 120
|
||||
|
@ -1172,7 +1172,7 @@ struct rtl8723bu_c2h {
|
||||
|
||||
u8 basic_rate:1;
|
||||
u8 bt_has_reset:1;
|
||||
u8 dummy4_1:1;;
|
||||
u8 dummy4_1:1;
|
||||
u8 ignore_wlan:1;
|
||||
u8 auto_report:1;
|
||||
u8 dummy4_2:3;
|
||||
|
@ -244,7 +244,8 @@ static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
|
||||
|
||||
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
|
||||
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE ||
|
||||
rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) {
|
||||
u16 mcs_map;
|
||||
|
||||
vht_cap->vht_supported = true;
|
||||
@ -697,14 +698,94 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
|
||||
}
|
||||
}
|
||||
|
||||
u8 rtl_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index,
|
||||
enum wireless_mode wirelessmode)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_phy *rtlphy = &rtlpriv->phy;
|
||||
u8 ret = 0;
|
||||
|
||||
switch (rate_index) {
|
||||
case RATR_INX_WIRELESS_NGB:
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_BGN_40M_1SS;
|
||||
else
|
||||
ret = RATEID_IDX_BGN_40M_2SS;
|
||||
; break;
|
||||
case RATR_INX_WIRELESS_N:
|
||||
case RATR_INX_WIRELESS_NG:
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_GN_N1SS;
|
||||
else
|
||||
ret = RATEID_IDX_GN_N2SS;
|
||||
; break;
|
||||
case RATR_INX_WIRELESS_NB:
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_BGN_20M_1SS_BN;
|
||||
else
|
||||
ret = RATEID_IDX_BGN_20M_2SS_BN;
|
||||
; break;
|
||||
case RATR_INX_WIRELESS_GB:
|
||||
ret = RATEID_IDX_BG;
|
||||
break;
|
||||
case RATR_INX_WIRELESS_G:
|
||||
ret = RATEID_IDX_G;
|
||||
break;
|
||||
case RATR_INX_WIRELESS_B:
|
||||
ret = RATEID_IDX_B;
|
||||
break;
|
||||
case RATR_INX_WIRELESS_MC:
|
||||
if (wirelessmode == WIRELESS_MODE_B ||
|
||||
wirelessmode == WIRELESS_MODE_G ||
|
||||
wirelessmode == WIRELESS_MODE_N_24G ||
|
||||
wirelessmode == WIRELESS_MODE_AC_24G)
|
||||
ret = RATEID_IDX_BG;
|
||||
else
|
||||
ret = RATEID_IDX_G;
|
||||
break;
|
||||
case RATR_INX_WIRELESS_AC_5N:
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_VHT_1SS;
|
||||
else
|
||||
ret = RATEID_IDX_VHT_2SS;
|
||||
break;
|
||||
case RATR_INX_WIRELESS_AC_24N:
|
||||
if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_VHT_1SS;
|
||||
else
|
||||
ret = RATEID_IDX_VHT_2SS;
|
||||
} else {
|
||||
if (rtlphy->rf_type == RF_1T1R)
|
||||
ret = RATEID_IDX_MIX1;
|
||||
else
|
||||
ret = RATEID_IDX_MIX2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = RATEID_IDX_BGN_40M_2SS;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rtl_mrate_idx_to_arfr_id);
|
||||
|
||||
static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
struct rtl_tcb_desc *tcb_desc)
|
||||
{
|
||||
#define SET_RATE_ID(rate_id) \
|
||||
({typeof(rate_id) _id = rate_id; \
|
||||
((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \
|
||||
rtl_mrate_idx_to_arfr_id(hw, _id, \
|
||||
(sta_entry ? sta_entry->wireless_mode : \
|
||||
WIRELESS_MODE_G)) : \
|
||||
_id); })
|
||||
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
||||
struct rtl_sta_info *sta_entry = NULL;
|
||||
u8 ratr_index = 7;
|
||||
u8 ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC);
|
||||
|
||||
if (sta) {
|
||||
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
|
||||
@ -719,7 +800,8 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
||||
tcb_desc->hw_rate =
|
||||
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
|
||||
tcb_desc->use_driver_rate = 1;
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_MC);
|
||||
} else {
|
||||
tcb_desc->ratr_index = ratr_index;
|
||||
}
|
||||
@ -735,22 +817,30 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
||||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
|
||||
tcb_desc->mac_id = 0;
|
||||
|
||||
if (mac->mode == WIRELESS_MODE_AC_5G)
|
||||
if (sta &&
|
||||
(rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID))
|
||||
; /* use sta_entry->ratr_index */
|
||||
else if (mac->mode == WIRELESS_MODE_AC_5G)
|
||||
tcb_desc->ratr_index =
|
||||
RATR_INX_WIRELESS_AC_5N;
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_AC_5N);
|
||||
else if (mac->mode == WIRELESS_MODE_AC_24G)
|
||||
tcb_desc->ratr_index =
|
||||
RATR_INX_WIRELESS_AC_24N;
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_AC_24N);
|
||||
else if (mac->mode == WIRELESS_MODE_N_24G)
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_NGB);
|
||||
else if (mac->mode == WIRELESS_MODE_N_5G)
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_NG);
|
||||
else if (mac->mode & WIRELESS_MODE_G)
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_GB);
|
||||
else if (mac->mode & WIRELESS_MODE_B)
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_B);
|
||||
else if (mac->mode & WIRELESS_MODE_A)
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_G);
|
||||
|
||||
} else if (mac->opmode == NL80211_IFTYPE_AP ||
|
||||
mac->opmode == NL80211_IFTYPE_ADHOC) {
|
||||
@ -764,6 +854,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SET_RATE_ID
|
||||
}
|
||||
|
||||
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
|
||||
@ -1140,9 +1231,19 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
|
||||
{
|
||||
#define SET_RATE_ID(rate_id) \
|
||||
({typeof(rate_id) _id = rate_id; \
|
||||
((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \
|
||||
rtl_mrate_idx_to_arfr_id(hw, _id, \
|
||||
(sta_entry ? sta_entry->wireless_mode : \
|
||||
WIRELESS_MODE_G)) : \
|
||||
_id); })
|
||||
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
|
||||
struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
|
||||
struct rtl_sta_info *sta_entry =
|
||||
(sta ? (struct rtl_sta_info *)sta->drv_priv : NULL);
|
||||
|
||||
__le16 fc = rtl_get_fc(skb);
|
||||
|
||||
@ -1165,7 +1266,8 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
||||
if (info->control.rates[0].idx == 0 ||
|
||||
ieee80211_is_nullfunc(fc)) {
|
||||
tcb_desc->use_driver_rate = true;
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
|
||||
tcb_desc->ratr_index =
|
||||
SET_RATE_ID(RATR_INX_WIRELESS_MC);
|
||||
|
||||
tcb_desc->disable_ratefallback = 1;
|
||||
} else {
|
||||
@ -1207,11 +1309,12 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
||||
_rtl_query_protection_mode(hw, tcb_desc, info);
|
||||
} else {
|
||||
tcb_desc->use_driver_rate = true;
|
||||
tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
|
||||
tcb_desc->ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC);
|
||||
tcb_desc->disable_ratefallback = 1;
|
||||
tcb_desc->mac_id = 0;
|
||||
tcb_desc->packet_bw = false;
|
||||
}
|
||||
#undef SET_RATE_ID
|
||||
}
|
||||
EXPORT_SYMBOL(rtl_get_tcb_desc);
|
||||
|
||||
|
@ -162,6 +162,8 @@ void rtl_c2hcmd_wq_callback(void *data);
|
||||
void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec);
|
||||
void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val);
|
||||
|
||||
u8 rtl_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index,
|
||||
enum wireless_mode wirelessmode);
|
||||
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_sta *sta,
|
||||
|
@ -29,7 +29,7 @@
|
||||
* Debug related function
|
||||
***************************************************/
|
||||
|
||||
const char *const gl_btc_wifi_bw_string[] = {
|
||||
static const char *const gl_btc_wifi_bw_string[] = {
|
||||
"11bg",
|
||||
"HT20",
|
||||
"HT40",
|
||||
@ -37,7 +37,7 @@ const char *const gl_btc_wifi_bw_string[] = {
|
||||
"HT160"
|
||||
};
|
||||
|
||||
const char *const gl_btc_wifi_freq_string[] = {
|
||||
static const char *const gl_btc_wifi_freq_string[] = {
|
||||
"2.4G",
|
||||
"5G"
|
||||
};
|
||||
@ -95,21 +95,6 @@ static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool halbtc_is_bt40(struct rtl_priv *adapter)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = adapter;
|
||||
struct rtl_phy *rtlphy = &(rtlpriv->phy);
|
||||
bool is_ht40 = true;
|
||||
enum ht_channel_width bw = rtlphy->current_chan_bw;
|
||||
|
||||
if (bw == HT_CHANNEL_WIDTH_20)
|
||||
is_ht40 = false;
|
||||
else if (bw == HT_CHANNEL_WIDTH_20_40)
|
||||
is_ht40 = true;
|
||||
|
||||
return is_ht40;
|
||||
}
|
||||
|
||||
static bool halbtc_legacy(struct rtl_priv *adapter)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = adapter;
|
||||
@ -135,18 +120,26 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter)
|
||||
|
||||
static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist)
|
||||
{
|
||||
struct rtl_priv *rtlpriv =
|
||||
(struct rtl_priv *)btcoexist->adapter;
|
||||
struct rtl_priv *rtlpriv = btcoexist->adapter;
|
||||
struct rtl_phy *rtlphy = &rtlpriv->phy;
|
||||
u32 wifi_bw = BTC_WIFI_BW_HT20;
|
||||
|
||||
if (halbtc_is_bt40(rtlpriv)) {
|
||||
wifi_bw = BTC_WIFI_BW_HT40;
|
||||
} else {
|
||||
if (halbtc_legacy(rtlpriv))
|
||||
if (halbtc_legacy(rtlpriv)) {
|
||||
wifi_bw = BTC_WIFI_BW_LEGACY;
|
||||
else
|
||||
} else {
|
||||
switch (rtlphy->current_chan_bw) {
|
||||
case HT_CHANNEL_WIDTH_20:
|
||||
wifi_bw = BTC_WIFI_BW_HT20;
|
||||
break;
|
||||
case HT_CHANNEL_WIDTH_20_40:
|
||||
wifi_bw = BTC_WIFI_BW_HT40;
|
||||
break;
|
||||
case HT_CHANNEL_WIDTH_80:
|
||||
wifi_bw = BTC_WIFI_BW_HT80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wifi_bw;
|
||||
}
|
||||
|
||||
@ -163,7 +156,7 @@ static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist)
|
||||
return chnl;
|
||||
}
|
||||
|
||||
u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
|
||||
static u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
|
||||
|
||||
@ -178,12 +171,12 @@ u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
|
||||
return rtlpriv->btcoexist.btc_info.single_ant_path;
|
||||
}
|
||||
|
||||
u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv)
|
||||
static u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
return rtlpriv->btcoexist.btc_info.bt_type;
|
||||
}
|
||||
|
||||
u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
||||
static u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
|
||||
u8 num;
|
||||
@ -200,7 +193,7 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
||||
return num;
|
||||
}
|
||||
|
||||
u8 rtl_get_hwpg_package_type(struct rtl_priv *rtlpriv)
|
||||
static u8 rtl_get_hwpg_package_type(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
|
||||
|
||||
@ -511,7 +504,7 @@ static u32 halbtc_get_bt_forbidden_slot_val(void *btc_context)
|
||||
return btcoexist->bt_info.bt_forb_slot_val;
|
||||
}
|
||||
|
||||
u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist)
|
||||
static u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist)
|
||||
{
|
||||
/* return value:
|
||||
* [31:16] => connected port number
|
||||
@ -987,7 +980,8 @@ static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data)
|
||||
rtl_write_dword(rtlpriv, reg_addr, data);
|
||||
}
|
||||
|
||||
void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, u8 data)
|
||||
static void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr,
|
||||
u8 data)
|
||||
{
|
||||
struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
|
||||
struct rtl_priv *rtlpriv = btcoexist->adapter;
|
||||
@ -1000,22 +994,6 @@ void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, u8 data)
|
||||
rtl_write_byte(rtlpriv, reg_addr, data);
|
||||
}
|
||||
|
||||
void halbtc_set_macreg(void *btc_context, u32 reg_addr, u32 bit_mask, u32 data)
|
||||
{
|
||||
struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
|
||||
struct rtl_priv *rtlpriv = btcoexist->adapter;
|
||||
|
||||
rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data);
|
||||
}
|
||||
|
||||
u32 halbtc_get_macreg(void *btc_context, u32 reg_addr, u32 bit_mask)
|
||||
{
|
||||
struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
|
||||
struct rtl_priv *rtlpriv = btcoexist->adapter;
|
||||
|
||||
return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask);
|
||||
}
|
||||
|
||||
static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask,
|
||||
u32 data)
|
||||
{
|
||||
@ -1061,6 +1039,7 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id,
|
||||
cmd_len, cmd_buf);
|
||||
}
|
||||
|
||||
static
|
||||
void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val)
|
||||
{
|
||||
struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
|
||||
@ -1100,7 +1079,7 @@ static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type,
|
||||
}
|
||||
}
|
||||
|
||||
bool halbtc_under_ips(struct btc_coexist *btcoexist)
|
||||
static bool halbtc_under_ips(struct btc_coexist *btcoexist)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = btcoexist->adapter;
|
||||
struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
|
||||
@ -1254,6 +1233,40 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
|
||||
struct wifi_only_haldata *wifionly_haldata;
|
||||
|
||||
if (!wifionly_cfg)
|
||||
return false;
|
||||
|
||||
wifionly_cfg->adapter = rtlpriv;
|
||||
|
||||
switch (rtlpriv->rtlhal.interface) {
|
||||
case INTF_PCI:
|
||||
wifionly_cfg->chip_interface = BTC_INTF_PCI;
|
||||
break;
|
||||
case INTF_USB:
|
||||
wifionly_cfg->chip_interface = BTC_INTF_USB;
|
||||
break;
|
||||
default:
|
||||
wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
wifionly_haldata = &wifionly_cfg->haldata_info;
|
||||
|
||||
wifionly_haldata->customer_id = CUSTOMER_NORMAL;
|
||||
wifionly_haldata->efuse_pg_antnum = rtl_get_hwpg_ant_num(rtlpriv);
|
||||
wifionly_haldata->efuse_pg_antpath =
|
||||
rtl_get_hwpg_single_ant_path(rtlpriv);
|
||||
wifionly_haldata->rfe_type = rtl_get_hwpg_rfe_type(rtlpriv);
|
||||
wifionly_haldata->ant_div_cfg = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = adapter;
|
||||
@ -1317,6 +1330,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
|
||||
"[BTCoex], Package Type = Non-TFBGA\n");
|
||||
|
||||
btcoexist->board_info.rfe_type = rtl_get_hwpg_rfe_type(rtlpriv);
|
||||
btcoexist->board_info.ant_div_cfg = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1374,6 +1388,10 @@ void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only)
|
||||
}
|
||||
}
|
||||
|
||||
void exhalbtc_init_hw_config_wifi_only(struct wifi_only_cfg *wifionly_cfg)
|
||||
{
|
||||
}
|
||||
|
||||
void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
|
||||
{
|
||||
if (!halbtc_is_bt_coexist_available(btcoexist))
|
||||
@ -1500,6 +1518,11 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
|
||||
halbtc_normal_low_power(btcoexist);
|
||||
}
|
||||
|
||||
void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
|
||||
u8 is_5g)
|
||||
{
|
||||
}
|
||||
|
||||
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
|
||||
{
|
||||
u8 asso_type;
|
||||
@ -1917,3 +1940,21 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist,
|
||||
|
||||
halbtc_normal_low_power(btcoexist);
|
||||
}
|
||||
|
||||
void exhalbtc_switch_band_notify(struct btc_coexist *btcoexist, u8 type)
|
||||
{
|
||||
if (!halbtc_is_bt_coexist_available(btcoexist))
|
||||
return;
|
||||
|
||||
if (btcoexist->manual_control)
|
||||
return;
|
||||
|
||||
halbtc_leave_low_power(btcoexist);
|
||||
|
||||
halbtc_normal_low_power(btcoexist);
|
||||
}
|
||||
|
||||
void exhalbtc_switch_band_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
|
||||
u8 is_5g)
|
||||
{
|
||||
}
|
||||
|
@ -153,6 +153,7 @@ struct btc_board_info {
|
||||
bool tfbga_package;
|
||||
|
||||
u8 rfe_type;
|
||||
u8 ant_div_cfg;
|
||||
};
|
||||
|
||||
enum btc_dbg_opcode {
|
||||
@ -190,6 +191,7 @@ enum btc_wifi_bw_mode {
|
||||
BTC_WIFI_BW_LEGACY = 0x0,
|
||||
BTC_WIFI_BW_HT20 = 0x1,
|
||||
BTC_WIFI_BW_HT40 = 0x2,
|
||||
BTC_WIFI_BW_HT80 = 0x3,
|
||||
BTC_WIFI_BW_MAX
|
||||
};
|
||||
|
||||
@ -384,6 +386,14 @@ enum btc_notify_type_scan {
|
||||
BTC_SCAN_MAX
|
||||
};
|
||||
|
||||
enum btc_notify_type_switchband {
|
||||
BTC_NOT_SWITCH = 0x0,
|
||||
BTC_SWITCH_TO_24G = 0x1,
|
||||
BTC_SWITCH_TO_5G = 0x2,
|
||||
BTC_SWITCH_TO_24G_NOFORSCAN = 0x3,
|
||||
BTC_SWITCH_MAX
|
||||
};
|
||||
|
||||
enum btc_notify_type_associate {
|
||||
BTC_ASSOCIATE_FINISH = 0x0,
|
||||
BTC_ASSOCIATE_START = 0x1,
|
||||
@ -573,6 +583,8 @@ struct btc_coexist {
|
||||
*/
|
||||
bool auto_report_1ant;
|
||||
bool auto_report_2ant;
|
||||
bool dbg_mode_1ant;
|
||||
bool dbg_mode_2ant;
|
||||
bool initilized;
|
||||
bool stop_coex_dm;
|
||||
bool manual_control;
|
||||
@ -626,21 +638,31 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter);
|
||||
|
||||
#define rtl_btc_coexist(rtlpriv) \
|
||||
((struct btc_coexist *)((rtlpriv)->btcoexist.btc_context))
|
||||
#define rtl_btc_wifi_only(rtlpriv) \
|
||||
((struct wifi_only_cfg *)((rtlpriv)->btcoexist.wifi_only_context))
|
||||
|
||||
struct wifi_only_cfg;
|
||||
|
||||
bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv);
|
||||
bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv);
|
||||
bool exhalbtc_bind_bt_coex_withadapter(void *adapter);
|
||||
void exhalbtc_power_on_setting(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only);
|
||||
void exhalbtc_init_hw_config_wifi_only(struct wifi_only_cfg *wifionly_cfg);
|
||||
void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
|
||||
u8 is_5g);
|
||||
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
|
||||
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
|
||||
enum rt_media_status media_status);
|
||||
void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
|
||||
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
|
||||
u8 length);
|
||||
void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
|
||||
@ -648,6 +670,8 @@ void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_periodical(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
|
||||
u8 *data);
|
||||
void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq,
|
||||
u32 offset, u32 span, u32 seconds);
|
||||
void exhalbtc_stack_update_profile_info(void);
|
||||
void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version);
|
||||
void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist,
|
||||
@ -658,6 +682,9 @@ void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type);
|
||||
void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num);
|
||||
void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist,
|
||||
struct seq_file *m);
|
||||
void exhalbtc_switch_band_notify(struct btc_coexist *btcoexist, u8 type);
|
||||
void exhalbtc_switch_band_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
|
||||
u8 is_5g);
|
||||
void exhalbtc_signal_compensation(struct btc_coexist *btcoexist,
|
||||
u8 *rssi_wifi, u8 *rssi_bt);
|
||||
void exhalbtc_lps_leave(struct btc_coexist *btcoexist);
|
||||
@ -665,4 +692,41 @@ void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist);
|
||||
void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist,
|
||||
u8 single_ant_path);
|
||||
|
||||
/* The following are used by wifi_only case */
|
||||
enum wifionly_chip_interface {
|
||||
WIFIONLY_INTF_UNKNOWN = 0,
|
||||
WIFIONLY_INTF_PCI = 1,
|
||||
WIFIONLY_INTF_USB = 2,
|
||||
WIFIONLY_INTF_SDIO = 3,
|
||||
WIFIONLY_INTF_MAX
|
||||
};
|
||||
|
||||
enum wifionly_customer_id {
|
||||
CUSTOMER_NORMAL = 0,
|
||||
CUSTOMER_HP_1 = 1,
|
||||
};
|
||||
|
||||
struct wifi_only_haldata {
|
||||
u16 customer_id;
|
||||
u8 efuse_pg_antnum;
|
||||
u8 efuse_pg_antpath;
|
||||
u8 rfe_type;
|
||||
u8 ant_div_cfg;
|
||||
};
|
||||
|
||||
struct wifi_only_cfg {
|
||||
void *adapter;
|
||||
struct wifi_only_haldata haldata_info;
|
||||
enum wifionly_chip_interface chip_interface;
|
||||
};
|
||||
|
||||
static inline
|
||||
void halwifionly_phy_set_bb_reg(struct wifi_only_cfg *wifi_conly_cfg,
|
||||
u32 regaddr, u32 bitmask, u32 data)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = (struct rtl_priv *)wifi_conly_cfg->adapter;
|
||||
|
||||
rtl_set_bbreg(rtlpriv->hw, regaddr, bitmask, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,13 +31,16 @@
|
||||
|
||||
static struct rtl_btc_ops rtl_btc_operation = {
|
||||
.btc_init_variables = rtl_btc_init_variables,
|
||||
.btc_init_variables_wifi_only = rtl_btc_init_variables_wifi_only,
|
||||
.btc_deinit_variables = rtl_btc_deinit_variables,
|
||||
.btc_init_hal_vars = rtl_btc_init_hal_vars,
|
||||
.btc_power_on_setting = rtl_btc_power_on_setting,
|
||||
.btc_init_hw_config = rtl_btc_init_hw_config,
|
||||
.btc_init_hw_config_wifi_only = rtl_btc_init_hw_config_wifi_only,
|
||||
.btc_ips_notify = rtl_btc_ips_notify,
|
||||
.btc_lps_notify = rtl_btc_lps_notify,
|
||||
.btc_scan_notify = rtl_btc_scan_notify,
|
||||
.btc_scan_notify_wifi_only = rtl_btc_scan_notify_wifi_only,
|
||||
.btc_connect_notify = rtl_btc_connect_notify,
|
||||
.btc_mediastatus_notify = rtl_btc_mediastatus_notify,
|
||||
.btc_periodical = rtl_btc_periodical,
|
||||
@ -48,6 +51,8 @@ static struct rtl_btc_ops rtl_btc_operation = {
|
||||
.btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
|
||||
.btc_is_bt_disabled = rtl_btc_is_bt_disabled,
|
||||
.btc_special_packet_notify = rtl_btc_special_packet_notify,
|
||||
.btc_switch_band_notify = rtl_btc_switch_band_notify,
|
||||
.btc_switch_band_notify_wifi_only = rtl_btc_switch_band_notify_wifionly,
|
||||
.btc_record_pwr_mode = rtl_btc_record_pwr_mode,
|
||||
.btc_get_lps_val = rtl_btc_get_lps_val,
|
||||
.btc_get_rpwm_val = rtl_btc_get_rpwm_val,
|
||||
@ -146,6 +151,10 @@ void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg,
|
||||
|
||||
static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only)
|
||||
{
|
||||
if (wifi_only)
|
||||
rtlpriv->btcoexist.wifi_only_context =
|
||||
kzalloc(sizeof(struct wifi_only_cfg), GFP_KERNEL);
|
||||
else
|
||||
rtlpriv->btcoexist.btc_context =
|
||||
kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);
|
||||
}
|
||||
@ -154,6 +163,9 @@ static void rtl_btc_free_variable(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
kfree(rtlpriv->btcoexist.btc_context);
|
||||
rtlpriv->btcoexist.btc_context = NULL;
|
||||
|
||||
kfree(rtlpriv->btcoexist.wifi_only_context);
|
||||
rtlpriv->btcoexist.wifi_only_context = NULL;
|
||||
}
|
||||
|
||||
void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
|
||||
@ -164,6 +176,13 @@ void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
|
||||
exhalbtc_bind_bt_coex_withadapter(rtlpriv);
|
||||
}
|
||||
|
||||
void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
rtl_btc_alloc_variable(rtlpriv, true);
|
||||
|
||||
exhalbtc_initlize_variables_wifi_only(rtlpriv);
|
||||
}
|
||||
|
||||
void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
rtl_btc_free_variable(rtlpriv);
|
||||
@ -203,6 +222,16 @@ void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
|
||||
exhalbtc_init_coex_dm(btcoexist);
|
||||
}
|
||||
|
||||
void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv)
|
||||
{
|
||||
struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
|
||||
|
||||
if (!wifionly_cfg)
|
||||
return;
|
||||
|
||||
exhalbtc_init_hw_config_wifi_only(wifionly_cfg);
|
||||
}
|
||||
|
||||
void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
|
||||
{
|
||||
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
|
||||
@ -211,6 +240,14 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
|
||||
return;
|
||||
|
||||
exhalbtc_ips_notify(btcoexist, type);
|
||||
|
||||
if (type == ERFON) {
|
||||
/* In some situation, it doesn't scan after leaving IPS, and
|
||||
* this will cause btcoex in wrong state.
|
||||
*/
|
||||
exhalbtc_scan_notify(btcoexist, 1);
|
||||
exhalbtc_scan_notify(btcoexist, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
|
||||
@ -233,6 +270,18 @@ void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
|
||||
exhalbtc_scan_notify(btcoexist, scantype);
|
||||
}
|
||||
|
||||
void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype)
|
||||
{
|
||||
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
|
||||
struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
|
||||
u8 is_5g = (rtlhal->current_bandtype == BAND_ON_5G);
|
||||
|
||||
if (!wifionly_cfg)
|
||||
return;
|
||||
|
||||
exhalbtc_scan_notify_wifi_only(wifionly_cfg, is_5g);
|
||||
}
|
||||
|
||||
void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
|
||||
{
|
||||
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
|
||||
@ -423,6 +472,44 @@ void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
|
||||
return exhalbtc_special_packet_notify(btcoexist, pkt_type);
|
||||
}
|
||||
|
||||
void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
|
||||
bool scanning)
|
||||
{
|
||||
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
|
||||
u8 type = BTC_NOT_SWITCH;
|
||||
|
||||
if (!btcoexist)
|
||||
return;
|
||||
|
||||
switch (band_type) {
|
||||
case BAND_ON_2_4G:
|
||||
if (scanning)
|
||||
type = BTC_SWITCH_TO_24G;
|
||||
else
|
||||
type = BTC_SWITCH_TO_24G_NOFORSCAN;
|
||||
break;
|
||||
|
||||
case BAND_ON_5G:
|
||||
type = BTC_SWITCH_TO_5G;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != BTC_NOT_SWITCH)
|
||||
exhalbtc_switch_band_notify(btcoexist, type);
|
||||
}
|
||||
|
||||
void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
|
||||
bool scanning)
|
||||
{
|
||||
struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
|
||||
u8 is_5g = (band_type == BAND_ON_5G);
|
||||
|
||||
if (!wifionly_cfg)
|
||||
return;
|
||||
|
||||
exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g);
|
||||
}
|
||||
|
||||
struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
|
||||
{
|
||||
return &rtl_btc_operation;
|
||||
|
@ -28,13 +28,16 @@
|
||||
#include "halbt_precomp.h"
|
||||
|
||||
void rtl_btc_init_variables(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
|
||||
void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type);
|
||||
void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
|
||||
void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype);
|
||||
void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
|
||||
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
|
||||
enum rt_media_status mstatus);
|
||||
@ -46,6 +49,10 @@ bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
|
||||
bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
|
||||
bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
|
||||
void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type);
|
||||
void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
|
||||
bool scanning);
|
||||
void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
|
||||
bool scanning);
|
||||
void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m);
|
||||
void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len);
|
||||
u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv);
|
||||
|
@ -1453,6 +1453,9 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw,
|
||||
|
||||
if (rtlpriv->cfg->ops->get_btc_status())
|
||||
rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1);
|
||||
else if (rtlpriv->btcoexist.btc_ops)
|
||||
rtlpriv->btcoexist.btc_ops->btc_scan_notify_wifi_only(rtlpriv,
|
||||
1);
|
||||
|
||||
if (rtlpriv->dm.supp_phymode_switch) {
|
||||
if (rtlpriv->cfg->ops->chk_switch_dmdp)
|
||||
@ -1508,6 +1511,9 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw,
|
||||
rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
|
||||
if (rtlpriv->cfg->ops->get_btc_status())
|
||||
rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0);
|
||||
else if (rtlpriv->btcoexist.btc_ops)
|
||||
rtlpriv->btcoexist.btc_ops->btc_scan_notify_wifi_only(rtlpriv,
|
||||
0);
|
||||
}
|
||||
|
||||
static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
|
@ -1794,6 +1794,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
|
||||
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
|
||||
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
||||
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
|
||||
struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops;
|
||||
|
||||
int err;
|
||||
|
||||
@ -1803,9 +1804,12 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
|
||||
if (rtlpriv->cfg->ops->get_btc_status &&
|
||||
rtlpriv->cfg->ops->get_btc_status()) {
|
||||
rtlpriv->btcoexist.btc_info.ap_num = 36;
|
||||
rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv);
|
||||
rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv);
|
||||
btc_ops->btc_init_variables(rtlpriv);
|
||||
btc_ops->btc_init_hal_vars(rtlpriv);
|
||||
} else if (btc_ops) {
|
||||
btc_ops->btc_init_variables_wifi_only(rtlpriv);
|
||||
}
|
||||
|
||||
err = rtlpriv->cfg->ops->hw_init(hw);
|
||||
if (err) {
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
|
||||
|
@ -873,6 +873,24 @@ enum ratr_table_mode {
|
||||
RATR_INX_WIRELESS_AC_24N = 9,
|
||||
};
|
||||
|
||||
enum ratr_table_mode_new {
|
||||
RATEID_IDX_BGN_40M_2SS = 0,
|
||||
RATEID_IDX_BGN_40M_1SS = 1,
|
||||
RATEID_IDX_BGN_20M_2SS_BN = 2,
|
||||
RATEID_IDX_BGN_20M_1SS_BN = 3,
|
||||
RATEID_IDX_GN_N2SS = 4,
|
||||
RATEID_IDX_GN_N1SS = 5,
|
||||
RATEID_IDX_BG = 6,
|
||||
RATEID_IDX_G = 7,
|
||||
RATEID_IDX_B = 8,
|
||||
RATEID_IDX_VHT_2SS = 9,
|
||||
RATEID_IDX_VHT_1SS = 10,
|
||||
RATEID_IDX_MIX1 = 11,
|
||||
RATEID_IDX_MIX2 = 12,
|
||||
RATEID_IDX_VHT_3SS = 13,
|
||||
RATEID_IDX_BGN_3SS = 14,
|
||||
};
|
||||
|
||||
enum rtl_link_state {
|
||||
MAC80211_NOLINK = 0,
|
||||
MAC80211_LINKING = 1,
|
||||
@ -931,6 +949,10 @@ enum package_type {
|
||||
PACKAGE_TFBGA79
|
||||
};
|
||||
|
||||
enum rtl_spec_ver {
|
||||
RTL_SPEC_NEW_RATEID = BIT(0), /* use ratr_table_mode_new */
|
||||
};
|
||||
|
||||
struct octet_string {
|
||||
u8 *octet;
|
||||
u16 length;
|
||||
@ -2315,6 +2337,7 @@ struct rtl_hal_cfg {
|
||||
struct rtl_hal_ops *ops;
|
||||
struct rtl_mod_params *mod_params;
|
||||
struct rtl_hal_usbint_cfg *usb_interface_cfg;
|
||||
enum rtl_spec_ver spec_ver;
|
||||
|
||||
/*this map used for some registers or vars
|
||||
defined int HAL but used in MAIN */
|
||||
@ -2502,6 +2525,7 @@ struct bt_coexist_info {
|
||||
struct rtl_btc_info btc_info;
|
||||
/* btc context */
|
||||
void *btc_context;
|
||||
void *wifi_only_context;
|
||||
/* EEPROM BT info. */
|
||||
u8 eeprom_bt_coexist;
|
||||
u8 eeprom_bt_type;
|
||||
@ -2558,13 +2582,17 @@ struct bt_coexist_info {
|
||||
|
||||
struct rtl_btc_ops {
|
||||
void (*btc_init_variables) (struct rtl_priv *rtlpriv);
|
||||
void (*btc_init_variables_wifi_only)(struct rtl_priv *rtlpriv);
|
||||
void (*btc_deinit_variables)(struct rtl_priv *rtlpriv);
|
||||
void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
|
||||
void (*btc_power_on_setting)(struct rtl_priv *rtlpriv);
|
||||
void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
|
||||
void (*btc_init_hw_config_wifi_only)(struct rtl_priv *rtlpriv);
|
||||
void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
|
||||
void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
|
||||
void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
|
||||
void (*btc_scan_notify_wifi_only)(struct rtl_priv *rtlpriv,
|
||||
u8 scantype);
|
||||
void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
|
||||
void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
|
||||
enum rt_media_status mstatus);
|
||||
@ -2579,6 +2607,10 @@ struct rtl_btc_ops {
|
||||
bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
|
||||
void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
|
||||
u8 pkt_type);
|
||||
void (*btc_switch_band_notify)(struct rtl_priv *rtlpriv, u8 type,
|
||||
bool scanning);
|
||||
void (*btc_switch_band_notify_wifi_only)(struct rtl_priv *rtlpriv,
|
||||
u8 type, bool scanning);
|
||||
void (*btc_display_bt_coex_info)(struct rtl_priv *rtlpriv,
|
||||
struct seq_file *m);
|
||||
void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len);
|
||||
|
Loading…
Reference in New Issue
Block a user