提交 868c36dc 编写于 作者: D David S. Miller

Merge tag 'wireless-drivers-next-for-davem-2018-01-26' of...

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: NDavid S. Miller <davem@davemloft.net>
...@@ -3310,6 +3310,12 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, ...@@ -3310,6 +3310,12 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
if (ar9300_check_eeprom_header(ah, read, cptr)) if (ar9300_check_eeprom_header(ah, read, cptr))
goto found; 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; cptr = AR9300_BASE_ADDR_512;
ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n",
cptr); cptr);
...@@ -3430,6 +3436,60 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, ...@@ -3430,6 +3436,60 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
return len; 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, static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
u8 *buf, u32 len, u32 size) 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, ...@@ -3441,10 +3501,18 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
"%20s :\n", "2GHz modal Header"); "%20s :\n", "2GHz modal Header");
len = ar9003_dump_modal_eeprom(buf, len, size, len = ar9003_dump_modal_eeprom(buf, len, size,
&eep->modalHeader2G); &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"); "%20s :\n", "5GHz modal Header");
len = ar9003_dump_modal_eeprom(buf, len, size, len = ar9003_dump_modal_eeprom(buf, len, size,
&eep->modalHeader5G); &eep->modalHeader5G);
len += snprintf(buf + len, size - len, "Calibration data\n");
len = ar9003_dump_cal_data(ah, buf, len, size, false);
goto out; goto out;
} }
...@@ -4683,7 +4751,8 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, ...@@ -4683,7 +4751,8 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
int ichain, int ichain,
int *pfrequency, int *pfrequency,
int *pcorrection, int *pcorrection,
int *ptemperature, int *pvoltage) int *ptemperature, int *pvoltage,
int *pnf_cal, int *pnf_power)
{ {
u8 *pCalPier; u8 *pCalPier;
struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct; struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct;
...@@ -4725,6 +4794,10 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, ...@@ -4725,6 +4794,10 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
*pcorrection = pCalPierStruct->refPower; *pcorrection = pCalPierStruct->refPower;
*ptemperature = pCalPierStruct->tempMeas; *ptemperature = pCalPierStruct->tempMeas;
*pvoltage = pCalPierStruct->voltMeas; *pvoltage = pCalPierStruct->voltMeas;
*pnf_cal = pCalPierStruct->rxTempMeas ?
N2DBM(pCalPierStruct->rxNoisefloorCal) : 0;
*pnf_power = pCalPierStruct->rxTempMeas ?
N2DBM(pCalPierStruct->rxNoisefloorPower) : 0;
return 0; return 0;
} }
...@@ -4889,14 +4962,18 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -4889,14 +4962,18 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
int mode; int mode;
int lfrequency[AR9300_MAX_CHAINS], int lfrequency[AR9300_MAX_CHAINS],
lcorrection[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], int hfrequency[AR9300_MAX_CHAINS],
hcorrection[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 fdiff;
int correction[AR9300_MAX_CHAINS], int correction[AR9300_MAX_CHAINS],
voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS]; voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS],
int pfrequency, pcorrection, ptemperature, pvoltage; 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); struct ath_common *common = ath9k_hw_common(ah);
mode = (frequency >= 4000); mode = (frequency >= 4000);
...@@ -4914,7 +4991,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -4914,7 +4991,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
for (ipier = 0; ipier < npier; ipier++) { for (ipier = 0; ipier < npier; ipier++) {
if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain, if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain,
&pfrequency, &pcorrection, &pfrequency, &pcorrection,
&ptemperature, &pvoltage)) { &ptemperature, &pvoltage,
&pnf_cal, &pnf_pwr)) {
fdiff = frequency - pfrequency; fdiff = frequency - pfrequency;
/* /*
...@@ -4936,6 +5014,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -4936,6 +5014,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
htemperature[ichain] = htemperature[ichain] =
ptemperature; ptemperature;
hvoltage[ichain] = pvoltage; hvoltage[ichain] = pvoltage;
hnf_cal[ichain] = pnf_cal;
hnf_pwr[ichain] = pnf_pwr;
} }
} }
if (fdiff >= 0) { if (fdiff >= 0) {
...@@ -4952,6 +5032,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -4952,6 +5032,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
ltemperature[ichain] = ltemperature[ichain] =
ptemperature; ptemperature;
lvoltage[ichain] = pvoltage; 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) ...@@ -4960,15 +5042,20 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
/* interpolate */ /* interpolate */
for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 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], ichain, frequency, lfrequency[ichain],
lcorrection[ichain], hfrequency[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 */ /* they're the same, so just pick one */
if (hfrequency[ichain] == lfrequency[ichain]) { if (hfrequency[ichain] == lfrequency[ichain]) {
correction[ichain] = lcorrection[ichain]; correction[ichain] = lcorrection[ichain];
voltage[ichain] = lvoltage[ichain]; voltage[ichain] = lvoltage[ichain];
temperature[ichain] = ltemperature[ichain]; temperature[ichain] = ltemperature[ichain];
nf_cal[ichain] = lnf_cal[ichain];
nf_pwr[ichain] = lnf_pwr[ichain];
} }
/* the low frequency is good */ /* the low frequency is good */
else if (frequency - lfrequency[ichain] < 1000) { else if (frequency - lfrequency[ichain] < 1000) {
...@@ -4992,12 +5079,26 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -4992,12 +5079,26 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
hfrequency[ichain], hfrequency[ichain],
lvoltage[ichain], lvoltage[ichain],
hvoltage[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 */ /* only low is good, use it */
else { else {
correction[ichain] = lcorrection[ichain]; correction[ichain] = lcorrection[ichain];
temperature[ichain] = ltemperature[ichain]; temperature[ichain] = ltemperature[ichain];
voltage[ichain] = lvoltage[ichain]; voltage[ichain] = lvoltage[ichain];
nf_cal[ichain] = lnf_cal[ichain];
nf_pwr[ichain] = lnf_pwr[ichain];
} }
} }
/* only high is good, use it */ /* only high is good, use it */
...@@ -5005,10 +5106,14 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ...@@ -5005,10 +5106,14 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
correction[ichain] = hcorrection[ichain]; correction[ichain] = hcorrection[ichain];
temperature[ichain] = htemperature[ichain]; temperature[ichain] = htemperature[ichain];
voltage[ichain] = hvoltage[ichain]; voltage[ichain] = hvoltage[ichain];
nf_cal[ichain] = hnf_cal[ichain];
nf_pwr[ichain] = hnf_pwr[ichain];
} else { /* nothing is good, presume 0???? */ } else { /* nothing is good, presume 0???? */
correction[ichain] = 0; correction[ichain] = 0;
temperature[ichain] = 0; temperature[ichain] = 0;
voltage[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) ...@@ -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", "for frequency=%d, calibration correction = %d %d %d\n",
frequency, correction[0], correction[1], correction[2]); 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; return 0;
} }
......
...@@ -62,6 +62,16 @@ ...@@ -62,6 +62,16 @@
*/ */
#define AR9300_PWR_TABLE_OFFSET 0 #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 */ /* byte addressable */
#define AR9300_EEPROM_SIZE (16*1024) #define AR9300_EEPROM_SIZE (16*1024)
......
...@@ -58,19 +58,25 @@ static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah, ...@@ -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, static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan,
int chain)
{ {
return ath9k_hw_get_nf_limits(ah, chan)->nominal; 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 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
s16 nf) s16 nf)
{ {
s8 noise = ATH_DEFAULT_NOISE_FLOOR; s8 noise = ath9k_hw_get_default_nf(ah, chan, 0);
if (nf) { if (nf) {
s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH - 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) if (delta > 0)
noise += delta; noise += delta;
} }
...@@ -240,7 +246,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -240,7 +246,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
unsigned i, j; unsigned i, j;
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
struct ath_common *common = ath9k_hw_common(ah); 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); u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
if (ah->caldata) if (ah->caldata)
...@@ -258,8 +264,13 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -258,8 +264,13 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
nfval = ah->nf_override; nfval = ah->nf_override;
else if (h) else if (h)
nfval = h[i].privNF; nfval = h[i].privNF;
else else {
nfval = default_nf; /* 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], REG_RMW(ah, ah->nf_regs[i],
(((u32) nfval << 1) & 0x1ff), 0x1ff); (((u32) nfval << 1) & 0x1ff), 0x1ff);
...@@ -429,20 +440,19 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, ...@@ -429,20 +440,19 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan)
{ {
struct ath9k_nfcal_hist *h; struct ath9k_nfcal_hist *h;
s16 default_nf; int i, j, k = 0;
int i, j;
ah->caldata->channel = chan->channel; ah->caldata->channel = chan->channel;
ah->caldata->channelFlags = chan->channelFlags; ah->caldata->channelFlags = chan->channelFlags;
h = ah->caldata->nfCalHist; h = ah->caldata->nfCalHist;
default_nf = ath9k_hw_get_default_nf(ah, chan);
for (i = 0; i < NUM_NF_READINGS; i++) { for (i = 0; i < NUM_NF_READINGS; i++) {
h[i].currIndex = 0; 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; h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++)
h[i].nfCalBuffer[j] = default_nf; h[i].nfCalBuffer[j] = h[i].privNF;
} if (++k >= AR5416_MAX_CHAINS)
k = 0;
} }
} }
......
...@@ -754,6 +754,8 @@ struct ath_nf_limits { ...@@ -754,6 +754,8 @@ struct ath_nf_limits {
s16 max; s16 max;
s16 min; s16 min;
s16 nominal; s16 nominal;
s16 cal[AR5416_MAX_CHAINS];
s16 pwr[AR5416_MAX_CHAINS];
}; };
enum ath_cal_list { enum ath_cal_list {
......
...@@ -826,9 +826,9 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ...@@ -826,9 +826,9 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
sc->rx.discard_next = false; 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); RX_STAT_INC(rx_len_err);
goto corrupt; goto corrupt;
} }
......
...@@ -236,6 +236,14 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn ...@@ -236,6 +236,14 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn
return 0; 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, static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch,
struct wcn36xx_dxe_mem_pool *pool) struct wcn36xx_dxe_mem_pool *pool)
{ {
...@@ -722,7 +730,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ...@@ -722,7 +730,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/ /***************************************/
/* Init descriptors for TX LOW channel */ /* 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); wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool);
/* Write channel head to a NEXT register */ /* Write channel head to a NEXT register */
...@@ -740,7 +752,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ...@@ -740,7 +752,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/ /***************************************/
/* Init descriptors for TX HIGH channel */ /* 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); wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool);
/* Write channel head to a NEXT register */ /* Write channel head to a NEXT register */
...@@ -760,7 +777,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ...@@ -760,7 +777,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/ /***************************************/
/* Init descriptors for RX LOW channel */ /* 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 */ /* For RX we need to preallocated buffers */
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch); wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch);
...@@ -790,7 +812,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ...@@ -790,7 +812,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/ /***************************************/
/* Init descriptors for RX HIGH channel */ /* 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 */ /* For RX we need to prealocat buffers */
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch); wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch);
...@@ -819,11 +845,19 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ...@@ -819,11 +845,19 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
ret = wcn36xx_dxe_request_irqs(wcn); ret = wcn36xx_dxe_request_irqs(wcn);
if (ret < 0) if (ret < 0)
goto out_err; goto out_err_irq;
return 0; 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; return ret;
} }
......
/* Copyright (c) 2015 Qualcomm Atheros, Inc. /* 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 { ...@@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 {
/* valid only for version 2 and above */ /* valid only for version 2 and above */
__le32 bl_assert_code; /* 0x880A58 BL Assert code */ __le32 bl_assert_code; /* 0x880A58 BL Assert code */
__le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ __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 */ __le32 bl_magic_number; /* 0x880AB8 BL Magic number */
} __packed; } __packed;
...@@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 { ...@@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 {
u8 mac_address[6]; /* 0x880A4c BL mac address */ u8 mac_address[6]; /* 0x880A4c BL mac address */
} __packed; } __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_ */ #endif /* BOOT_LOADER_EXPORT_H_ */
/* /*
* Copyright (c) 2014,2016 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 */ ...@@ -58,15 +59,30 @@ struct wil_fw_record_comment { /* type == wil_fw_type_comment */
u8 data[0]; /* free-form data [data_size], see above */ u8 data[0]; /* free-form data [data_size], see above */
} __packed; } __packed;
/* Comment header - common for all comment record types */
struct wil_fw_record_comment_hdr {
__le32 magic;
};
/* FW capabilities encoded inside a comment record */ /* FW capabilities encoded inside a comment record */
#define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba) #define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba)
struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
/* identifies capabilities record */ /* identifies capabilities record */
__le32 magic; struct wil_fw_record_comment_hdr hdr;
/* capabilities (variable size), see enum wmi_fw_capability */ /* capabilities (variable size), see enum wmi_fw_capability */
u8 capabilities[0]; 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 /* perform action
* data_size = @head.size - offsetof(struct wil_fw_record_action, data) * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
*/ */
......
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -128,14 +129,13 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
} }
static int 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) size_t size)
{ {
const struct wil_fw_record_capabilities *rec = data; const struct wil_fw_record_capabilities *rec = data;
size_t capa_size; size_t capa_size;
if (size < sizeof(*rec) || if (size < sizeof(*rec)) {
le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
data, size, true); data, size, true);
return 0; return 0;
...@@ -151,8 +151,56 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data, ...@@ -151,8 +151,56 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
return 0; return 0;
} }
static int fw_handle_data(struct wil6210_priv *wil, const void *data, static int
size_t size) 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; const struct wil_fw_record_data *d = data;
void __iomem *dst; void __iomem *dst;
...@@ -163,16 +211,23 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data, ...@@ -163,16 +211,23 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
return -EINVAL; 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; return -EINVAL;
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s);
s);
wil_memcpy_toio_32(dst, d->data, s); wil_memcpy_toio_32(dst, d->data, s);
wmb(); /* finish before processing next record */ wmb(); /* finish before processing next record */
return 0; 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, static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
size_t size) size_t size)
{ {
...@@ -551,6 +606,100 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name, ...@@ -551,6 +606,100 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
return rc; 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 * wil_fw_verify_file_exists - checks if firmware file exist
* *
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) ...@@ -395,8 +396,9 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
wil6210_mask_irq_misc(wil, false); wil6210_mask_irq_misc(wil, false);
if (isr & ISR_MISC_FW_ERROR) { if (isr & ISR_MISC_FW_ERROR) {
u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE); u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE); u32 ucode_assert_code =
wil_r(wil, wil->rgf_ucode_assert_code_addr);
wil_err(wil, wil_err(wil,
"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n", "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -637,6 +638,98 @@ void wil_priv_deinit(struct wil6210_priv *wil) ...@@ -637,6 +638,98 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq); 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) static inline void wil_halt_cpu(struct wil6210_priv *wil)
{ {
wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); 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) ...@@ -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; int delay = 0;
u32 x, x1 = 0; u32 x, x1 = 0;
...@@ -684,9 +777,16 @@ static int wil_target_reset(struct wil6210_priv *wil) ...@@ -684,9 +777,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
wil_halt_cpu(wil); wil_halt_cpu(wil);
/* clear all boot loader "ready" bits */ if (!no_flash) {
wil_w(wil, RGF_USER_BL + /* clear all boot loader "ready" bits */
offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); wil_w(wil, RGF_USER_BL +
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 */ /* Clear Fw Download notification */
wil_c(wil, RGF_USER_USAGE_6, BIT(0)); wil_c(wil, RGF_USER_USAGE_6, BIT(0));
...@@ -727,21 +827,33 @@ static int wil_target_reset(struct wil6210_priv *wil) ...@@ -727,21 +827,33 @@ static int wil_target_reset(struct wil6210_priv *wil)
wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
/* wait until device ready. typical time is 20..80 msec */ /* wait until device ready. typical time is 20..80 msec */
do { if (no_flash)
msleep(RST_DELAY); do {
x = wil_r(wil, RGF_USER_BL + msleep(RST_DELAY);
offsetof(struct bl_dedicated_registers_v0, x = wil_r(wil, USER_EXT_USER_PMU_3);
boot_loader_ready)); if (delay++ > RST_COUNT) {
if (x1 != x) { wil_err(wil, "Reset not completed, PMU_3 0x%08x\n",
wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x);
x1 = x; return -ETIME;
} }
if (delay++ > RST_COUNT) { } while ((x & BIT_PMU_DEVICE_RDY) == 0);
wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", else
x); do {
return -ETIME; msleep(RST_DELAY);
} x = wil_r(wil, RGF_USER_BL +
} while (x != BL_READY); 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);
x1 = x;
}
if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
x);
return -ETIME;
}
} while (x != BL_READY);
wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
...@@ -749,6 +861,21 @@ static int wil_target_reset(struct wil6210_priv *wil) ...@@ -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 | 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); 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); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
return 0; return 0;
} }
...@@ -906,6 +1033,27 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) ...@@ -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) static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{ {
ulong to = msecs_to_jiffies(1000); ulong to = msecs_to_jiffies(1000);
...@@ -999,6 +1147,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -999,6 +1147,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
{ {
int rc; int rc;
unsigned long status_flags = BIT(wil_status_resetting); unsigned long status_flags = BIT(wil_status_resetting);
int no_flash;
wil_dbg_misc(wil, "reset\n"); wil_dbg_misc(wil, "reset\n");
...@@ -1074,20 +1223,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1074,20 +1223,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
flush_workqueue(wil->wq_service); flush_workqueue(wil->wq_service);
flush_workqueue(wil->wmi_wq); flush_workqueue(wil->wmi_wq);
wil_bl_crash_info(wil, false); no_flash = test_bit(hw_capa_no_flash, wil->hw_capa);
if (!no_flash)
wil_bl_crash_info(wil, false);
wil_disable_irq(wil); wil_disable_irq(wil);
rc = wil_target_reset(wil); rc = wil_target_reset(wil, no_flash);
wil6210_clear_irq(wil); wil6210_clear_irq(wil);
wil_enable_irq(wil); wil_enable_irq(wil);
wil_rx_fini(wil); wil_rx_fini(wil);
if (rc) { if (rc) {
wil_bl_crash_info(wil, true); if (!no_flash)
wil_bl_crash_info(wil, true);
goto out; goto out;
} }
rc = wil_get_bl_info(wil); if (no_flash) {
if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ rc = wil_get_otp_info(wil);
rc = 0; } else {
rc = wil_get_bl_info(wil);
if (rc == -EAGAIN && !load_fw)
/* ignore RF error if not going up */
rc = 0;
}
if (rc) if (rc)
goto out; goto out;
...@@ -1096,13 +1253,21 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1096,13 +1253,21 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_info(wil, "Use firmware <%s> + board <%s>\n", wil_info(wil, "Use firmware <%s> + board <%s>\n",
wil->wil_fw_name, WIL_BOARD_FILE_NAME); wil->wil_fw_name, WIL_BOARD_FILE_NAME);
if (!no_flash)
wil_bl_prepare_halt(wil);
wil_halt_cpu(wil); wil_halt_cpu(wil);
memset(wil->fw_version, 0, sizeof(wil->fw_version)); memset(wil->fw_version, 0, sizeof(wil->fw_version));
/* Loading f/w from the file */ /* Loading f/w from the file */
rc = wil_request_firmware(wil, wil->wil_fw_name, true); rc = wil_request_firmware(wil, wil->wil_fw_name, true);
if (rc) if (rc)
goto out; 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) if (rc)
goto out; goto out;
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -35,15 +36,16 @@ static int wil6210_pm_notify(struct notifier_block *notify_block,
unsigned long mode, void *unused); unsigned long mode, void *unused);
static static
void wil_set_capabilities(struct wil6210_priv *wil) int wil_set_capabilities(struct wil6210_priv *wil)
{ {
const char *wil_fw_name; const char *wil_fw_name;
u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
RGF_USER_REVISION_ID_MASK); RGF_USER_REVISION_ID_MASK);
int platform_capa; 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->fw_capabilities, WMI_FW_CAPABILITY_MAX);
bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX); bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
...@@ -52,6 +54,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -52,6 +54,8 @@ void wil_set_capabilities(struct wil6210_priv *wil)
switch (jtag_id) { switch (jtag_id) {
case JTAG_DEV_ID_SPARROW: case JTAG_DEV_ID_SPARROW:
memcpy(fw_mapping, sparrow_fw_mapping,
sizeof(sparrow_fw_mapping));
switch (chip_revision) { switch (chip_revision) {
case REVISION_ID_SPARROW_D0: case REVISION_ID_SPARROW_D0:
wil->hw_name = "Sparrow D0"; wil->hw_name = "Sparrow D0";
...@@ -61,6 +65,12 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -61,6 +65,12 @@ void wil_set_capabilities(struct wil6210_priv *wil)
if (wil_fw_verify_file_exists(wil, wil_fw_name)) if (wil_fw_verify_file_exists(wil, wil_fw_name))
wil->wil_fw_name = 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; break;
case REVISION_ID_SPARROW_B0: case REVISION_ID_SPARROW_B0:
wil->hw_name = "Sparrow B0"; wil->hw_name = "Sparrow B0";
...@@ -71,15 +81,36 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -71,15 +81,36 @@ void wil_set_capabilities(struct wil6210_priv *wil)
wil->hw_version = HW_VER_UNKNOWN; wil->hw_version = HW_VER_UNKNOWN;
break; 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; break;
default: default:
wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
jtag_id, chip_revision); jtag_id, chip_revision);
wil->hw_name = "Unknown"; wil->hw_name = "Unknown";
wil->hw_version = HW_VER_UNKNOWN; wil->hw_version = HW_VER_UNKNOWN;
return -EINVAL;
}
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\n", wil->hw_name); 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 */ /* Get platform capabilities */
if (wil->platform_ops.get_capa) { if (wil->platform_ops.get_capa) {
...@@ -92,6 +123,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -92,6 +123,8 @@ void wil_set_capabilities(struct wil6210_priv *wil)
/* extract FW capabilities from file without loading the FW */ /* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, wil->wil_fw_name, false); wil_request_firmware(wil, wil->wil_fw_name, false);
wil_refresh_fw_capabilities(wil); wil_refresh_fw_capabilities(wil);
return 0;
} }
void wil_disable_irq(struct wil6210_priv *wil) 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) ...@@ -302,7 +335,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* rollback to err_iounmap */ /* rollback to err_iounmap */
wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); 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); wil6210_clear_irq(wil);
/* FW should raise IRQ when ready */ /* FW should raise IRQ when ready */
...@@ -378,6 +415,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) ...@@ -378,6 +415,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
static const struct pci_device_id wil6210_pcie_ids[] = { static const struct pci_device_id wil6210_pcie_ids[] = {
{ PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0310) },
{ PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
{ PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */
{ /* end: all zeroes */ }, { /* end: all zeroes */ },
}; };
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -169,6 +170,7 @@ struct RGF_ICR { ...@@ -169,6 +170,7 @@ struct RGF_ICR {
#define HW_MACHINE_BOOT_DONE (0x3fffffd) #define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0) #define RGF_USER_USER_CPU_0 (0x8801e0)
#define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */ #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 RGF_USER_MAC_CPU_0 (0x8801fc)
#define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) #define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
...@@ -194,6 +196,19 @@ struct RGF_ICR { ...@@ -194,6 +196,19 @@ struct RGF_ICR {
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
#define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ #define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */
#define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) #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 RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
...@@ -284,22 +299,33 @@ struct RGF_ICR { ...@@ -284,22 +299,33 @@ struct RGF_ICR {
#define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #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 RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
#define JTAG_DEV_ID_SPARROW (0x2632072f) #define JTAG_DEV_ID_SPARROW (0x2632072f)
#define JTAG_DEV_ID_TALYN (0x7e0e1)
#define RGF_USER_REVISION_ID (0x88afe4) #define RGF_USER_REVISION_ID (0x88afe4)
#define RGF_USER_REVISION_ID_MASK (3) #define RGF_USER_REVISION_ID_MASK (3)
#define REVISION_ID_SPARROW_B0 (0x0) #define REVISION_ID_SPARROW_B0 (0x0)
#define REVISION_ID_SPARROW_D0 (0x3) #define REVISION_ID_SPARROW_D0 (0x3)
#define RGF_OTP_MAC (0x8a0620)
/* crash codes for FW/Ucode stored here */ /* 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 { enum {
HW_VER_UNKNOWN, HW_VER_UNKNOWN,
HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */ HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */ HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
HW_VER_TALYN, /* JTAG_DEV_ID_TALYN */
}; };
/* popular locations */ /* popular locations */
...@@ -315,6 +341,10 @@ enum { ...@@ -315,6 +341,10 @@ enum {
#define WIL_DATA_COMPLETION_TO_MS 200 #define WIL_DATA_COMPLETION_TO_MS 200
/* Hardware definitions end */ /* 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 { struct fw_map {
u32 from; /* linker address - from, inclusive */ u32 from; /* linker address - from, inclusive */
u32 to; /* linker address - to, exclusive */ u32 to; /* linker address - to, exclusive */
...@@ -324,7 +354,10 @@ struct fw_map { ...@@ -324,7 +354,10 @@ struct fw_map {
}; };
/* array size should be in sync with actual definition in the wmi.c */ /* 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 * mk_cidxtid - construct @cidxtid field
...@@ -570,7 +603,8 @@ enum { ...@@ -570,7 +603,8 @@ enum {
}; };
enum { enum {
hw_capability_last hw_capa_no_flash,
hw_capa_last
}; };
struct wil_probe_client_req { struct wil_probe_client_req {
...@@ -646,7 +680,10 @@ struct wil6210_priv { ...@@ -646,7 +680,10 @@ struct wil6210_priv {
u8 chip_revision; u8 chip_revision;
const char *hw_name; const char *hw_name;
const char *wil_fw_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(fw_capabilities, WMI_FW_CAPABILITY_MAX);
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
u8 n_mids; /* number of additional MIDs as reported by FW */ u8 n_mids; /* number of additional MIDs as reported by FW */
...@@ -720,7 +757,7 @@ struct wil6210_priv { ...@@ -720,7 +757,7 @@ struct wil6210_priv {
atomic_t isr_count_rx, isr_count_tx; atomic_t isr_count_rx, isr_count_tx;
/* debugfs */ /* debugfs */
struct dentry *debug; 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 discovery_mode;
u8 abft_len; u8 abft_len;
u8 wakeup_trigger; u8 wakeup_trigger;
...@@ -755,6 +792,10 @@ struct wil6210_priv { ...@@ -755,6 +792,10 @@ struct wil6210_priv {
bool suspend_resp_comp; bool suspend_resp_comp;
u32 bus_request_kbps; u32 bus_request_kbps;
u32 bus_request_kbps_pre_suspend; 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) #define wil_to_wiphy(i) (i->wdev->wiphy)
...@@ -880,6 +921,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); ...@@ -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); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
void wil_set_ethtoolops(struct net_device *ndev); 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_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
...@@ -1013,6 +1055,7 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type); ...@@ -1013,6 +1055,7 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type);
int wil_request_firmware(struct wil6210_priv *wil, const char *name, int wil_request_firmware(struct wil6210_priv *wil, const char *name,
bool load); 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); bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
void wil_pm_runtime_allow(struct wil6210_priv *wil); void wil_pm_runtime_allow(struct wil6210_priv *wil);
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -70,23 +71,23 @@ MODULE_PARM_DESC(led_id, ...@@ -70,23 +71,23 @@ MODULE_PARM_DESC(led_id,
* On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
* AHB addresses starting from 0x880000 * 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 * are invisible from the host. To read from these addresses, alternative
* AHB address must be used. * 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 * 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 */ /* FW code RAM 256k */
{0x000000, 0x040000, 0x8c0000, "fw_code", true}, {0x000000, 0x040000, 0x8c0000, "fw_code", true},
/* FW data RAM 32k */ /* FW data RAM 32k */
...@@ -112,6 +113,59 @@ const struct fw_map fw_mapping[] = { ...@@ -112,6 +113,59 @@ const struct fw_map fw_mapping[] = {
{0x800000, 0x804000, 0x940000, "uc_data", false}, {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[] = { struct blink_on_off_time led_blink_time[] = {
{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS}, {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS}, {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
...@@ -138,6 +192,24 @@ static u32 wmi_addr_remap(u32 x) ...@@ -138,6 +192,24 @@ static u32 wmi_addr_remap(u32 x)
return 0; 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 * Check address validity for WMI buffer; remap if needed
* @ptr - internal (linker) fw/ucode address * @ptr - internal (linker) fw/ucode address
......
...@@ -165,7 +165,7 @@ static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) ...@@ -165,7 +165,7 @@ static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
static int static int
brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 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_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 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, ...@@ -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); brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
*fwerr = 0;
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
if (ret < 0) { if (ret < 0) {
brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", 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, ...@@ -211,25 +212,27 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
memcpy(buf, info, len); memcpy(buf, info, len);
} }
ret = 0;
/* Check the ERROR flag */ /* Check the ERROR flag */
if (flags & BCDC_DCMD_ERROR) if (flags & BCDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status); *fwerr = le32_to_cpu(msg->status);
done: done:
return ret; return ret;
} }
static int static int
brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 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_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
int ret = 0; int ret;
u32 flags, id; u32 flags, id;
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
*fwerr = 0;
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
if (ret < 0) if (ret < 0)
goto done; goto done;
...@@ -249,9 +252,11 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, ...@@ -249,9 +252,11 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
goto done; goto done;
} }
ret = 0;
/* Check the ERROR flag */ /* Check the ERROR flag */
if (flags & BCDC_DCMD_ERROR) if (flags & BCDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status); *fwerr = le32_to_cpu(msg->status);
done: done:
return ret; return ret;
......
...@@ -107,7 +107,7 @@ static s32 ...@@ -107,7 +107,7 @@ static s32
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
{ {
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
s32 err; s32 err, fwerr;
if (drvr->bus_if->state != BRCMF_BUS_UP) { if (drvr->bus_if->state != BRCMF_BUS_UP) {
brcmf_err("bus is down. we have nothing to do.\n"); 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) ...@@ -117,16 +117,20 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
if (data != NULL) if (data != NULL)
len = min_t(uint, len, BRCMF_DCMD_MAXLEN); len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
if (set) 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 else
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len); err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
data, len, &fwerr);
if (err >= 0)
return 0; if (err) {
brcmf_dbg(FIL, "Failed: %s (%d)\n",
brcmf_dbg(FIL, "Failed: %s (%d)\n", brcmf_fil_get_errstr((u32)(-err)), err);
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; return err;
} }
......
...@@ -477,7 +477,7 @@ static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf) ...@@ -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, 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 brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
...@@ -485,6 +485,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, ...@@ -485,6 +485,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
int err; int err;
brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len); brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);
*fwerr = 0;
msgbuf->ctl_completed = false; msgbuf->ctl_completed = false;
err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len); err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);
if (err) if (err)
...@@ -508,14 +509,15 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, ...@@ -508,14 +509,15 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
} }
brcmu_pkt_buf_free_skb(skb); 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, 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 { ...@@ -30,9 +30,9 @@ struct brcmf_proto {
int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
struct sk_buff *skb, struct brcmf_if **ifp); struct sk_buff *skb, struct brcmf_if **ifp);
int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, 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, 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, int (*tx_queue_data)(struct brcmf_pub *drvr, int ifidx,
struct sk_buff *skb); struct sk_buff *skb);
int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset, 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, ...@@ -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); return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
} }
static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx, 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, 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, static inline int brcmf_proto_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
......
...@@ -2,7 +2,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o ...@@ -2,7 +2,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o
obj-$(CONFIG_MT76x2E) += mt76x2e.o obj-$(CONFIG_MT76x2E) += mt76x2e.o
mt76-y := \ 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) CFLAGS_trace.o := -I$(src)
......
/*
* 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 ...@@ -387,17 +387,25 @@ static int
mt76_dma_rx_poll(struct napi_struct *napi, int budget) mt76_dma_rx_poll(struct napi_struct *napi, int budget)
{ {
struct mt76_dev *dev; struct mt76_dev *dev;
int qid, done; int qid, done = 0, cur;
dev = container_of(napi->dev, struct mt76_dev, napi_dev); dev = container_of(napi->dev, struct mt76_dev, napi_dev);
qid = napi - dev->napi; 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) { if (done < budget) {
napi_complete(napi); napi_complete(napi);
dev->drv->rx_poll_complete(dev, qid); dev->drv->rx_poll_complete(dev, qid);
} }
mt76_rx_complete(dev, qid);
return done; return done;
} }
......
...@@ -384,10 +384,122 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, ...@@ -384,10 +384,122 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
} }
EXPORT_SYMBOL_GPL(mt76_get_survey); 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;
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; struct sk_buff *skb;
__skb_queue_head_init(&frames);
while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL)
ieee80211_rx_napi(dev->hw, NULL, skb, &dev->napi[q]); mt76_rx_aggr_reorder(skb, &frames);
mt76_rx_complete(dev, &frames, q);
} }
...@@ -122,13 +122,23 @@ struct mt76_queue_ops { ...@@ -122,13 +122,23 @@ struct mt76_queue_ops {
}; };
struct mt76_wcid { struct mt76_wcid {
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
struct work_struct aggr_work;
u8 idx; u8 idx;
u8 hw_key_idx; u8 hw_key_idx;
u8 sta:1;
u8 rx_check_pn;
u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
__le16 tx_rate; __le16 tx_rate;
bool tx_rate_set; bool tx_rate_set;
u8 tx_rate_nss; u8 tx_rate_nss;
s8 max_txpwr_adj; s8 max_txpwr_adj;
bool sw_iv;
}; };
struct mt76_txq { struct mt76_txq {
...@@ -149,6 +159,24 @@ struct mt76_txwi_cache { ...@@ -149,6 +159,24 @@ struct mt76_txwi_cache {
struct list_head list; 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 { enum {
MT76_STATE_INITIALIZED, MT76_STATE_INITIALIZED,
MT76_STATE_RUNNING, MT76_STATE_RUNNING,
...@@ -249,6 +277,29 @@ struct mt76_rate_power { ...@@ -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_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((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__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__)
...@@ -329,6 +380,17 @@ mtxq_to_txq(struct mt76_txq *mtxq) ...@@ -329,6 +380,17 @@ mtxq_to_txq(struct mt76_txq *mtxq)
return container_of(ptr, struct ieee80211_txq, drv_priv); 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, int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid, struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
...@@ -352,9 +414,19 @@ void mt76_set_channel(struct mt76_dev *dev); ...@@ -352,9 +414,19 @@ void mt76_set_channel(struct mt76_dev *dev);
int mt76_get_survey(struct ieee80211_hw *hw, int idx, int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey); 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 */ /* internal */
void mt76_tx_free(struct mt76_dev *dev); void mt76_tx_free(struct mt76_dev *dev);
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t); 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 #endif
...@@ -144,6 +144,7 @@ struct mt76x2_vif { ...@@ -144,6 +144,7 @@ struct mt76x2_vif {
struct mt76x2_sta { struct mt76x2_sta {
struct mt76_wcid wcid; /* must be first */ struct mt76_wcid wcid; /* must be first */
struct mt76x2_vif *vif;
struct mt76x2_tx_status status; struct mt76x2_tx_status status;
int n_frames; int n_frames;
}; };
......
...@@ -460,8 +460,8 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) ...@@ -460,8 +460,8 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
{ {
struct cfg80211_chan_def *chandef = &dev->mt76.chandef; 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); mt76x2_dfs_set_bbp_params(dev);
/* enable debug mode */ /* enable debug mode */
mt76x2_dfs_set_capture_mode_ctrl(dev, true); mt76x2_dfs_set_capture_mode_ctrl(dev, true);
...@@ -491,3 +491,16 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) ...@@ -491,3 +491,16 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev)
(unsigned long)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 { ...@@ -76,5 +76,7 @@ struct mt76x2_dfs_pattern_detector {
void mt76x2_dfs_init_params(struct mt76x2_dev *dev); void mt76x2_dfs_init_params(struct mt76x2_dev *dev);
void mt76x2_dfs_init_detector(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_adjust_agc(struct mt76x2_dev *dev);
void mt76x2_dfs_set_domain(struct mt76x2_dev *dev,
enum nl80211_dfs_regions region);
#endif /* __MT76x2_DFS_H */ #endif /* __MT76x2_DFS_H */
...@@ -55,6 +55,7 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, ...@@ -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->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
q->ndesc = n_desc; q->ndesc = n_desc;
q->hw_idx = idx;
ret = mt76_queue_alloc(dev, q); ret = mt76_queue_alloc(dev, q);
if (ret) if (ret)
......
...@@ -131,7 +131,7 @@ mt76_write_mac_initvals(struct mt76x2_dev *dev) ...@@ -131,7 +131,7 @@ mt76_write_mac_initvals(struct mt76x2_dev *dev)
{ MT_RX_FILTR_CFG, 0x00015f97 }, { MT_RX_FILTR_CFG, 0x00015f97 },
{ MT_LEGACY_BASIC_RATE, 0x0000017f }, { MT_LEGACY_BASIC_RATE, 0x0000017f },
{ MT_HT_BASIC_RATE, 0x00004003 }, { MT_HT_BASIC_RATE, 0x00004003 },
{ MT_PN_PAD_MODE, 0x00000002 }, { MT_PN_PAD_MODE, 0x00000003 },
{ MT_TXOP_HLDR_ET, 0x00000002 }, { MT_TXOP_HLDR_ET, 0x00000002 },
{ 0xa44, 0x00000000 }, { 0xa44, 0x00000000 },
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
...@@ -614,6 +614,8 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev) ...@@ -614,6 +614,8 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev)
void mt76x2_cleanup(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_stop_hardware(dev);
mt76x2_dma_cleanup(dev); mt76x2_dma_cleanup(dev);
mt76x2_mcu_cleanup(dev); mt76x2_mcu_cleanup(dev);
...@@ -652,7 +654,7 @@ static void mt76x2_regd_notifier(struct wiphy *wiphy, ...@@ -652,7 +654,7 @@ static void mt76x2_regd_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt76x2_dev *dev = hw->priv; 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) { \ #define CCK_RATE(_idx, _rate) { \
...@@ -840,6 +842,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev) ...@@ -840,6 +842,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 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->cal_work, mt76x2_phy_calibrate);
INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); 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) ...@@ -29,7 +29,7 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr)
} }
static int 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); 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, ...@@ -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_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0]; 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 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
u16 txwi_flags = 0; u16 txwi_flags = 0;
u8 nss; u8 nss;
s8 txpwr_adj, max_txpwr_adj; s8 txpwr_adj, max_txpwr_adj;
u8 ccmp_pn[8];
memset(txwi, 0, sizeof(*txwi)); memset(txwi, 0, sizeof(*txwi));
...@@ -185,6 +188,20 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, ...@@ -185,6 +188,20 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
txwi->pktid = 1; 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); spin_lock_bh(&dev->mt76.lock);
if (wcid && (rate->idx < 0 || !rate->count)) { if (wcid && (rate->idx < 0 || !rate->count)) {
txwi->rate = wcid->tx_rate; txwi->rate = wcid->tx_rate;
...@@ -232,36 +249,101 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, ...@@ -232,36 +249,101 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
sta->ht_cap.ampdu_density); 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->flags |= cpu_to_le16(txwi_flags);
txwi->len_ctl = cpu_to_le16(skb->len); 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 hdrlen;
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)
{ {
int len = ieee80211_get_hdrlen_from_skb(skb); struct mt76x2_sta *sta;
struct mt76_wcid *wcid;
memmove(skb->data + 2, skb->data, len); if (idx >= ARRAY_SIZE(dev->wcid))
skb_pull(skb, 2); 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, int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
void *rxi) 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; struct mt76x2_rxwi *rxwi = rxi;
u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
u32 ctl = le32_to_cpu(rxwi->ctl); u32 ctl = le32_to_cpu(rxwi->ctl);
u16 rate = le16_to_cpu(rxwi->rate); 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; int len;
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) if (rxinfo & MT_RXINFO_L2PAD)
mt76x2_remove_hdr_pad(skb); 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_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); 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)) if (WARN_ON_ONCE(len > skb->len))
return -EINVAL; return -EINVAL;
...@@ -273,6 +355,9 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, ...@@ -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->freq = dev->mt76.chandef.chan->center_freq;
status->band = dev->mt76.chandef.chan->band; 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); return mt76x2_mac_process_rate(status, rate);
} }
...@@ -618,7 +703,6 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) ...@@ -618,7 +703,6 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
return -ENOSPC; return -ENOSPC;
mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL); 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)); mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
offset += sizeof(txwi); offset += sizeof(txwi);
......
...@@ -127,6 +127,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) ...@@ -127,6 +127,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
mt76_set_channel(&dev->mt76); mt76_set_channel(&dev->mt76);
tasklet_disable(&dev->pre_tbtt_tasklet); tasklet_disable(&dev->pre_tbtt_tasklet);
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->cal_work);
mt76x2_mac_stop(dev, true); mt76x2_mac_stop(dev, true);
...@@ -139,6 +140,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) ...@@ -139,6 +140,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
mt76x2_dfs_init_params(dev); mt76x2_dfs_init_params(dev);
mt76x2_mac_resume(dev); mt76x2_mac_resume(dev);
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
tasklet_enable(&dev->pre_tbtt_tasklet); tasklet_enable(&dev->pre_tbtt_tasklet);
return ret; return ret;
...@@ -271,6 +273,8 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -271,6 +273,8 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out; goto out;
} }
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx; msta->wcid.idx = idx;
msta->wcid.hw_key_idx = -1; msta->wcid.hw_key_idx = -1;
mt76x2_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); 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, ...@@ -355,12 +359,19 @@ mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (cmd == SET_KEY) { if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx; key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = 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 { } else {
if (idx == wcid->hw_key_idx) if (idx == wcid->hw_key_idx) {
wcid->hw_key_idx = -1; wcid->hw_key_idx = -1;
wcid->sw_iv = true;
}
key = NULL; key = NULL;
} }
mt76_wcid_key_setup(&dev->mt76, wcid, key);
if (!msta) { if (!msta) {
if (key || wcid->hw_key_idx == idx) { if (key || wcid->hw_key_idx == idx) {
...@@ -380,9 +391,11 @@ mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, ...@@ -380,9 +391,11 @@ mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct mt76x2_dev *dev = hw->priv; struct mt76x2_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10; u8 cw_min = 5, cw_max = 10, qid;
u32 val; u32 val;
qid = dev->mt76.q_tx[queue].hw_idx;
if (params->cw_min) if (params->cw_min)
cw_min = fls(params->cw_min); cw_min = fls(params->cw_min);
if (params->cw_max) if (params->cw_max)
...@@ -392,26 +405,26 @@ mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, ...@@ -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_AIFSN, params->aifs) |
FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); 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 = mt76_rr(dev, MT_WMM_TXOP(qid));
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(queue)); val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
val |= params->txop << MT_WMM_TXOP_SHIFT(queue); val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
mt76_wr(dev, MT_WMM_TXOP(queue), val); mt76_wr(dev, MT_WMM_TXOP(qid), val);
val = mt76_rr(dev, MT_WMM_AIFSN); val = mt76_rr(dev, MT_WMM_AIFSN);
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(queue)); val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
val |= params->aifs << MT_WMM_AIFSN_SHIFT(queue); val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
mt76_wr(dev, MT_WMM_AIFSN, val); mt76_wr(dev, MT_WMM_AIFSN, val);
val = mt76_rr(dev, MT_WMM_CWMIN); val = mt76_rr(dev, MT_WMM_CWMIN);
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(queue)); val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
val |= cw_min << MT_WMM_CWMIN_SHIFT(queue); val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
mt76_wr(dev, MT_WMM_CWMIN, val); mt76_wr(dev, MT_WMM_CWMIN, val);
val = mt76_rr(dev, MT_WMM_CWMAX); val = mt76_rr(dev, MT_WMM_CWMAX);
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(queue)); val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
val |= cw_max << MT_WMM_CWMAX_SHIFT(queue); val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
mt76_wr(dev, MT_WMM_CWMAX, val); mt76_wr(dev, MT_WMM_CWMAX, val);
return 0; return 0;
...@@ -476,9 +489,11 @@ mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -476,9 +489,11 @@ mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: 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)); mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break; break;
case IEEE80211_AMPDU_RX_STOP: case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
BIT(16 + tid)); BIT(16 + tid));
break; break;
......
...@@ -36,7 +36,9 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, ...@@ -36,7 +36,9 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
msta = (struct mt76x2_sta *) control->sta->drv_priv; msta = (struct mt76x2_sta *) control->sta->drv_priv;
wcid = &msta->wcid; wcid = &msta->wcid;
} else if (vif) { }
if (vif || (!info->control.hw_key && wcid->hw_key_idx != -1)) {
struct mt76x2_vif *mvif; struct mt76x2_vif *mvif;
mvif = (struct mt76x2_vif *) vif->drv_priv; mvif = (struct mt76x2_vif *) vif->drv_priv;
...@@ -166,7 +168,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, ...@@ -166,7 +168,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
*tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
MT_TXD_INFO_80211; 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; *tx_info |= MT_TXD_INFO_WIV;
return 0; return 0;
......
...@@ -80,6 +80,41 @@ qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = { ...@@ -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, &params);
return ret;
}
static int static int
qtnf_change_virtual_intf(struct wiphy *wiphy, qtnf_change_virtual_intf(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
...@@ -90,6 +125,13 @@ qtnf_change_virtual_intf(struct wiphy *wiphy, ...@@ -90,6 +125,13 @@ qtnf_change_virtual_intf(struct wiphy *wiphy,
u8 *mac_addr; u8 *mac_addr;
int ret; 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) if (params)
mac_addr = params->macaddr; mac_addr = params->macaddr;
else else
...@@ -120,10 +162,6 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -120,10 +162,6 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
qtnf_scan_done(vif->mac, true); 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 */ /* Stop data */
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
if (netif_carrier_ok(netdev)) if (netif_carrier_ok(netdev))
...@@ -132,6 +170,10 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -132,6 +170,10 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (netdev->reg_state == NETREG_REGISTERED) if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(netdev); 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->ieee80211_ptr = NULL;
vif->netdev = NULL; vif->netdev = NULL;
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
...@@ -150,12 +192,20 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, ...@@ -150,12 +192,20 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
struct qtnf_wmac *mac; struct qtnf_wmac *mac;
struct qtnf_vif *vif; struct qtnf_vif *vif;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
int ret;
mac = wiphy_priv(wiphy); mac = wiphy_priv(wiphy);
if (!mac) if (!mac)
return ERR_PTR(-EFAULT); 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) { switch (type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -545,19 +595,13 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev, ...@@ -545,19 +595,13 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev,
return ret; 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 static int
qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{ {
struct qtnf_wmac *mac = wiphy_priv(wiphy); struct qtnf_wmac *mac = wiphy_priv(wiphy);
cancel_delayed_work_sync(&mac->scan_timeout);
mac->scan_req = request; mac->scan_req = request;
if (qtnf_cmd_send_scan(mac)) { if (qtnf_cmd_send_scan(mac)) {
...@@ -566,9 +610,8 @@ qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) ...@@ -566,9 +610,8 @@ qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
return -EFAULT; return -EFAULT;
} }
mac->scan_timeout.function = qtnf_scan_timeout; queue_delayed_work(mac->bus->workqueue, &mac->scan_timeout,
mod_timer(&mac->scan_timeout, QTNF_SCAN_TIMEOUT_SEC * HZ);
jiffies + QTNF_SCAN_TIMEOUT_SEC * HZ);
return 0; return 0;
} }
...@@ -629,7 +672,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, ...@@ -629,7 +672,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,
return ret; return ret;
} }
vif->sta_state = QTNF_STA_DISCONNECTED;
return 0; return 0;
} }
...@@ -876,29 +918,29 @@ struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus) ...@@ -876,29 +918,29 @@ struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus)
return wiphy; return wiphy;
} }
static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, static int
struct ieee80211_iface_combination *if_comb, qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, struct qtnf_mac_info *mac_info)
const 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; u16 interface_modes = 0;
size_t i; size_t i, j;
if_comb = mac_info->if_comb;
n_if_comb = mac_info->n_if_comb;
if (unlikely(!mac_info->limits || !mac_info->n_limits)) if (!if_comb || !n_if_comb)
return -ENOENT; return -ENOENT;
if_comb->limits = mac_info->limits; for (i = 0; i < n_if_comb; i++) {
if_comb->n_limits = mac_info->n_limits; if_comb[i].radar_detect_widths = mac_info->radar_detect_widths;
for (i = 0; i < mac_info->n_limits; i++) { for (j = 0; j < if_comb[i].n_limits; j++)
max_interfaces += mac_info->limits[i].max; interface_modes |= if_comb[i].limits[j].types;
interface_modes |= mac_info->limits[i].types;
} }
if_comb->num_different_channels = 1; wiphy->iface_combinations = if_comb;
if_comb->beacon_int_infra_match = true; wiphy->n_iface_combinations = n_if_comb;
if_comb->max_interfaces = max_interfaces;
if_comb->radar_detect_widths = mac_info->radar_detect_widths;
wiphy->interface_modes = interface_modes; wiphy->interface_modes = interface_modes;
return 0; return 0;
...@@ -907,7 +949,6 @@ static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, ...@@ -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) int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
{ {
struct wiphy *wiphy = priv_to_wiphy(mac); struct wiphy *wiphy = priv_to_wiphy(mac);
struct ieee80211_iface_combination *iface_comb = NULL;
int ret; int ret;
if (!wiphy) { if (!wiphy) {
...@@ -915,14 +956,6 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) ...@@ -915,14 +956,6 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
return -EFAULT; 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->frag_threshold = mac->macinfo.frag_thr;
wiphy->rts_threshold = mac->macinfo.rts_thr; wiphy->rts_threshold = mac->macinfo.rts_thr;
wiphy->retry_short = mac->macinfo.sretry_limit; 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) ...@@ -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->mgmt_stypes = qtnf_mgmt_stypes;
wiphy->max_remain_on_channel_duration = 5000; wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_acl_mac_addrs = mac->macinfo.max_acl_mac_addrs; 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; wiphy->max_num_csa_counters = 2;
ret = qtnf_wiphy_setup_if_comb(wiphy, &mac->macinfo);
if (ret)
goto out;
/* Initialize cipher suits */ /* Initialize cipher suits */
wiphy->cipher_suites = qtnf_cipher_suites; wiphy->cipher_suites = qtnf_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(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) ...@@ -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; 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); ret = wiphy_register(wiphy);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -983,12 +1021,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) ...@@ -983,12 +1021,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
ret = regulatory_hint(wiphy, hw_info->rd->alpha2); ret = regulatory_hint(wiphy, hw_info->rd->alpha2);
out: out:
if (ret) { return ret;
kfree(iface_comb);
return ret;
}
return 0;
} }
void qtnf_netdev_updown(struct net_device *ndev, bool up) void qtnf_netdev_updown(struct net_device *ndev, bool up)
......
...@@ -28,23 +28,4 @@ void qtnf_band_init_rates(struct ieee80211_supported_band *band); ...@@ -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, void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo,
struct ieee80211_supported_band *band); 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_ */ #endif /* _QTN_FMAC_CFG80211_H_ */
...@@ -187,7 +187,8 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif, ...@@ -187,7 +187,8 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
len += sizeof(struct qlink_tlv_chandef); len += sizeof(struct qlink_tlv_chandef);
if (s->acl) 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)) { if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
pr_err("VIF%u.%u: can not fit AP settings: %u\n", 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, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_START_AP, QLINK_CMD_START_AP,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct qlink_cmd_start_ap *)cmd_skb->data; cmd = (struct qlink_cmd_start_ap *)cmd_skb->data;
...@@ -334,7 +335,7 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_STOP_AP, QLINK_CMD_STOP_AP,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); 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) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_REGISTER_MGMT, QLINK_CMD_REGISTER_MGMT,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -411,7 +412,7 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SEND_MGMT_FRAME, QLINK_CMD_SEND_MGMT_FRAME,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -457,7 +458,7 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_MGMT_SET_APPIE, QLINK_CMD_MGMT_SET_APPIE,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len); 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, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_GET_STA_INFO, QLINK_CMD_GET_STA_INFO,
sizeof(*cmd)); sizeof(*cmd));
if (!cmd_skb)
if (unlikely(!cmd_skb))
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -778,7 +778,7 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, ...@@ -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_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
cmd_type, cmd_type,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -851,7 +851,7 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_INTF, QLINK_CMD_DEL_INTF,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -948,6 +948,16 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, ...@@ -948,6 +948,16 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
struct qtnf_hw_info *hwinfo = &bus->hw_info; struct qtnf_hw_info *hwinfo = &bus->hw_info;
const struct qlink_tlv_hdr *tlv; const struct qlink_tlv_hdr *tlv;
const struct qlink_tlv_reg_rule *tlv_rule; 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; struct ieee80211_reg_rule *rule;
u16 tlv_type; u16 tlv_type;
u16 tlv_value_len; u16 tlv_value_len;
...@@ -974,6 +984,10 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, ...@@ -974,6 +984,10 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
hwinfo->rd->alpha2[0] = resp->alpha2[0]; hwinfo->rd->alpha2[0] = resp->alpha2[0];
hwinfo->rd->alpha2[1] = resp->alpha2[1]; 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) { switch (resp->dfs_region) {
case QLINK_DFS_FCC: case QLINK_DFS_FCC:
hwinfo->rd->dfs_region = NL80211_DFS_FCC; hwinfo->rd->dfs_region = NL80211_DFS_FCC;
...@@ -1034,6 +1048,27 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, ...@@ -1034,6 +1048,27 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
rule->flags = qtnf_cmd_resp_reg_rule_flags_parse( rule->flags = qtnf_cmd_resp_reg_rule_flags_parse(
le32_to_cpu(tlv_rule->flags)); le32_to_cpu(tlv_rule->flags));
break; 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: default:
break; break;
} }
...@@ -1056,25 +1091,46 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, ...@@ -1056,25 +1091,46 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
hwinfo->total_tx_chain, hwinfo->total_rx_chain, hwinfo->total_tx_chain, hwinfo->total_rx_chain,
hwinfo->hw_capab); 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; return 0;
} }
static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
const u8 *tlv_buf, size_t tlv_buf_size) const u8 *tlv_buf, size_t tlv_buf_size)
{ {
struct ieee80211_iface_limit *limits = NULL; struct ieee80211_iface_combination *comb = NULL;
const struct qlink_iface_limit *limit_record; size_t n_comb = 0;
size_t record_count = 0, rec = 0; struct ieee80211_iface_limit *limits;
u16 tlv_type, tlv_value_len; const struct qlink_iface_comb_num *comb_num;
struct qlink_iface_comb_num *comb; 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; size_t tlv_full_len;
const struct qlink_tlv_hdr *tlv; const struct qlink_tlv_hdr *tlv;
u8 *ext_capa = NULL; u8 *ext_capa = NULL;
u8 *ext_capa_mask = NULL; u8 *ext_capa_mask = NULL;
u8 ext_capa_len = 0; u8 ext_capa_len = 0;
u8 ext_capa_mask_len = 0; u8 ext_capa_mask_len = 0;
int i = 0;
mac->macinfo.n_limits = 0;
tlv = (const struct qlink_tlv_hdr *)tlv_buf; tlv = (const struct qlink_tlv_hdr *)tlv_buf;
while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) { while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) {
...@@ -1089,52 +1145,77 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, ...@@ -1089,52 +1145,77 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
switch (tlv_type) { switch (tlv_type) {
case QTN_TLV_ID_NUM_IFACE_COMB: case QTN_TLV_ID_NUM_IFACE_COMB:
if (unlikely(tlv_value_len != sizeof(*comb))) if (tlv_value_len != sizeof(*comb_num))
return -EINVAL; return -EINVAL;
comb = (void *)tlv->val; comb_num = (void *)tlv->val;
record_count = le16_to_cpu(comb->iface_comb_num);
/* free earlier iface comb memory */
qtnf_mac_iface_comb_free(mac);
mac->macinfo.n_if_comb =
le32_to_cpu(comb_num->iface_comb_num);
mac->macinfo.n_limits = record_count; mac->macinfo.if_comb =
/* free earlier iface limits memory */ kcalloc(mac->macinfo.n_if_comb,
kfree(mac->macinfo.limits); sizeof(*mac->macinfo.if_comb),
mac->macinfo.limits = GFP_KERNEL);
kzalloc(sizeof(*mac->macinfo.limits) *
record_count, GFP_KERNEL);
if (unlikely(!mac->macinfo.limits)) if (!mac->macinfo.if_comb)
return -ENOMEM; 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; break;
case QTN_TLV_ID_IFACE_LIMIT: case QTN_TLV_ID_IFACE_LIMIT:
if (unlikely(!limits)) { if (unlikely(!comb)) {
pr_warn("MAC%u: limits are not inited\n", pr_warn("MAC%u: no combinations advertised\n",
mac->macid); mac->macid);
return -EINVAL; return -EINVAL;
} }
if (unlikely(tlv_value_len != sizeof(*limit_record))) { if (n_comb >= mac->macinfo.n_if_comb) {
pr_warn("MAC%u: record size mismatch\n", pr_warn("MAC%u: combinations count exceeded\n",
mac->macid); mac->macid);
return -EINVAL; n_comb++;
break;
} }
limit_record = (void *)tlv->val; rec = (void *)tlv->val;
limits[rec].max = le16_to_cpu(limit_record->max_num); rec_len = sizeof(*rec) + rec->n_limits * sizeof(*lim);
limits[rec].types = qlink_iface_type_to_nl_mask(
le16_to_cpu(limit_record->type));
/* supported modes: STA, AP */ if (unlikely(tlv_value_len != rec_len)) {
limits[rec].types &= BIT(NL80211_IFTYPE_AP) | pr_warn("MAC%u: record %zu size mismatch\n",
BIT(NL80211_IFTYPE_AP_VLAN) | mac->macid, n_comb);
BIT(NL80211_IFTYPE_STATION); return -EINVAL;
}
pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid, limits = kzalloc(sizeof(*limits) * rec->n_limits,
limits[rec].max, limits[rec].types); GFP_KERNEL);
if (!limits)
return -ENOMEM;
if (limits[rec].types) comb[n_comb].num_different_channels =
rec++; 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;
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);
}
n_comb++;
break; break;
case WLAN_EID_EXT_CAPABILITY: case WLAN_EID_EXT_CAPABILITY:
if (unlikely(tlv_value_len > U8_MAX)) if (unlikely(tlv_value_len > U8_MAX))
...@@ -1162,9 +1243,9 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, ...@@ -1162,9 +1243,9 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
return -EINVAL; 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", 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; return -EINVAL;
} }
...@@ -1575,7 +1656,7 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
QLINK_CMD_MAC_INFO, QLINK_CMD_MAC_INFO,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(mac->bus); qtnf_bus_lock(mac->bus);
...@@ -1613,7 +1694,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
QLINK_CMD_GET_HW_INFO, QLINK_CMD_GET_HW_INFO,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(bus); qtnf_bus_lock(bus);
...@@ -1793,7 +1874,7 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
QLINK_CMD_FW_INIT, QLINK_CMD_FW_INIT,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(bus); qtnf_bus_lock(bus);
...@@ -1842,7 +1923,7 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_ADD_KEY, QLINK_CMD_ADD_KEY,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); 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, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_KEY, QLINK_CMD_DEL_KEY,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -1936,7 +2017,7 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SET_DEFAULT_KEY, QLINK_CMD_SET_DEFAULT_KEY,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); 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) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SET_DEFAULT_MGMT_KEY, QLINK_CMD_SET_DEFAULT_MGMT_KEY,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -2026,7 +2107,7 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CHANGE_STA, QLINK_CMD_CHANGE_STA,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -2078,7 +2159,7 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_STA, QLINK_CMD_DEL_STA,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -2148,7 +2229,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
QLINK_CMD_SCAN, QLINK_CMD_SCAN,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(mac->bus); qtnf_bus_lock(mac->bus);
...@@ -2218,7 +2299,7 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CONNECT, QLINK_CMD_CONNECT,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct qlink_cmd_connect *)cmd_skb->data; cmd = (struct qlink_cmd_connect *)cmd_skb->data;
...@@ -2320,7 +2401,7 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DISCONNECT, QLINK_CMD_DISCONNECT,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(vif->mac->bus); qtnf_bus_lock(vif->mac->bus);
...@@ -2354,7 +2435,7 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_UPDOWN_INTF, QLINK_CMD_UPDOWN_INTF,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct qlink_cmd_updown *)cmd_skb->data; cmd = (struct qlink_cmd_updown *)cmd_skb->data;
...@@ -2515,8 +2596,7 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
QLINK_CMD_CHAN_SWITCH, QLINK_CMD_CHAN_SWITCH,
sizeof(*cmd)); sizeof(*cmd));
if (!cmd_skb)
if (unlikely(!cmd_skb))
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(mac->bus); qtnf_bus_lock(mac->bus);
...@@ -2568,7 +2648,7 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef) ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CHAN_GET, QLINK_CMD_CHAN_GET,
sizeof(struct qlink_cmd)); sizeof(struct qlink_cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
qtnf_bus_lock(bus); qtnf_bus_lock(bus);
...@@ -2607,7 +2687,7 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, ...@@ -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, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_START_CAC, QLINK_CMD_START_CAC,
sizeof(*cmd)); sizeof(*cmd));
if (unlikely(!cmd_skb)) if (!cmd_skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct qlink_cmd_start_cac *)cmd_skb->data; cmd = (struct qlink_cmd_start_cac *)cmd_skb->data;
...@@ -2637,19 +2717,21 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, ...@@ -2637,19 +2717,21 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
{ {
struct qtnf_bus *bus = vif->mac->bus; struct qtnf_bus *bus = vif->mac->bus;
struct sk_buff *cmd_skb; 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; u16 res_code;
int ret; int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SET_MAC_ACL, QLINK_CMD_SET_MAC_ACL,
sizeof(*cmd) + sizeof(struct qlink_cmd));
qtnf_cmd_acl_data_size(params)); if (!cmd_skb)
if (unlikely(!cmd_skb))
return -ENOMEM; return -ENOMEM;
cmd = (struct qlink_cmd_set_mac_acl *)cmd_skb->data; tlv = skb_put(cmd_skb, sizeof(*tlv) + acl_size);
qlink_acl_data_cfg2q(params, &cmd->acl); 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); qtnf_bus_lock(bus);
ret = qtnf_cmd_send(bus, cmd_skb, &res_code); 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) ...@@ -119,9 +119,38 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Netdev handler for getting stats. /* 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. /* Netdev handler for transmission timeout.
...@@ -156,7 +185,7 @@ const struct net_device_ops qtnf_netdev_ops = { ...@@ -156,7 +185,7 @@ const struct net_device_ops qtnf_netdev_ops = {
.ndo_stop = qtnf_netdev_close, .ndo_stop = qtnf_netdev_close,
.ndo_start_xmit = qtnf_netdev_hard_start_xmit, .ndo_start_xmit = qtnf_netdev_hard_start_xmit,
.ndo_tx_timeout = qtnf_netdev_tx_timeout, .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, 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) ...@@ -233,6 +262,23 @@ struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac)
return vif; 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) static void qtnf_vif_reset_handler(struct work_struct *work)
{ {
struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_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) ...@@ -265,6 +311,37 @@ static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac)
vif->cons_tx_timeout_cnt = 0; 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, static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
unsigned int macid) unsigned int macid)
{ {
...@@ -288,7 +365,12 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, ...@@ -288,7 +365,12 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
mac->iflist[i].vifid = i; mac->iflist[i].vifid = i;
qtnf_sta_list_init(&mac->iflist[i].sta_list); qtnf_sta_list_init(&mac->iflist[i].sta_list);
mutex_init(&mac->mac_lock); 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); qtnf_mac_init_primary_intf(mac);
...@@ -297,6 +379,10 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, ...@@ -297,6 +379,10 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
return mac; 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, int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
const char *name, unsigned char name_assign_type) 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, ...@@ -324,6 +410,7 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
dev->flags |= IFF_BROADCAST | IFF_MULTICAST; dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT; dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT;
dev->tx_queue_len = 100; dev->tx_queue_len = 100;
dev->ethtool_ops = &qtnf_ethtool_ops;
qdev_vif = netdev_priv(dev); qdev_vif = netdev_priv(dev);
*((void **)qdev_vif) = vif; *((void **)qdev_vif) = vif;
...@@ -364,6 +451,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) ...@@ -364,6 +451,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
} }
rtnl_unlock(); rtnl_unlock();
qtnf_sta_list_free(&vif->sta_list); qtnf_sta_list_free(&vif->sta_list);
free_percpu(vif->stats64);
} }
if (mac->wiphy_registered) if (mac->wiphy_registered)
...@@ -380,10 +468,9 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) ...@@ -380,10 +468,9 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
wiphy->bands[band] = NULL; wiphy->bands[band] = NULL;
} }
kfree(mac->macinfo.limits); qtnf_mac_iface_comb_free(mac);
kfree(mac->macinfo.extended_capabilities); kfree(mac->macinfo.extended_capabilities);
kfree(mac->macinfo.extended_capabilities_mask); kfree(mac->macinfo.extended_capabilities_mask);
kfree(wiphy->iface_combinations);
wiphy_free(wiphy); wiphy_free(wiphy);
bus->mac[macid] = NULL; bus->mac[macid] = NULL;
} }
...@@ -643,6 +730,46 @@ void qtnf_wake_all_queues(struct net_device *ndev) ...@@ -643,6 +730,46 @@ void qtnf_wake_all_queues(struct net_device *ndev)
} }
EXPORT_SYMBOL_GPL(qtnf_wake_all_queues); 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_AUTHOR("Quantenna Communications");
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver."); MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -89,6 +89,8 @@ struct qtnf_vif { ...@@ -89,6 +89,8 @@ struct qtnf_vif {
struct qtnf_sta_list sta_list; struct qtnf_sta_list sta_list;
unsigned long cons_tx_timeout_cnt; unsigned long cons_tx_timeout_cnt;
int generation; int generation;
struct pcpu_sw_netstats __percpu *stats64;
}; };
struct qtnf_mac_info { struct qtnf_mac_info {
...@@ -106,8 +108,8 @@ struct qtnf_mac_info { ...@@ -106,8 +108,8 @@ struct qtnf_mac_info {
u32 max_acl_mac_addrs; u32 max_acl_mac_addrs;
struct ieee80211_ht_cap ht_cap_mod_mask; struct ieee80211_ht_cap ht_cap_mod_mask;
struct ieee80211_vht_cap vht_cap_mod_mask; struct ieee80211_vht_cap vht_cap_mod_mask;
struct ieee80211_iface_limit *limits; struct ieee80211_iface_combination *if_comb;
size_t n_limits; size_t n_if_comb;
u8 *extended_capabilities; u8 *extended_capabilities;
u8 *extended_capabilities_mask; u8 *extended_capabilities_mask;
u8 extended_capabilities_len; u8 extended_capabilities_len;
...@@ -131,7 +133,7 @@ struct qtnf_wmac { ...@@ -131,7 +133,7 @@ struct qtnf_wmac {
struct qtnf_vif iflist[QTNF_MAX_INTF]; struct qtnf_vif iflist[QTNF_MAX_INTF];
struct cfg80211_scan_request *scan_req; struct cfg80211_scan_request *scan_req;
struct mutex mac_lock; /* lock during wmac speicific ops */ struct mutex mac_lock; /* lock during wmac speicific ops */
struct timer_list scan_timeout; struct delayed_work scan_timeout;
}; };
struct qtnf_hw_info { struct qtnf_hw_info {
...@@ -143,10 +145,13 @@ struct qtnf_hw_info { ...@@ -143,10 +145,13 @@ struct qtnf_hw_info {
struct ieee80211_regdomain *rd; struct ieee80211_regdomain *rd;
u8 total_tx_chain; u8 total_tx_chain;
u8 total_rx_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_free_vif(struct qtnf_wmac *mac);
struct qtnf_vif *qtnf_mac_get_base_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); struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv, int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,
const char *name, unsigned char name_assign_type); const char *name, unsigned char name_assign_type);
...@@ -157,9 +162,13 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac); ...@@ -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 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); 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_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_virtual_intf_cleanup(struct net_device *ndev);
void qtnf_netdev_updown(struct net_device *ndev, bool up); 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) 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, ...@@ -541,9 +541,9 @@ static int qtnf_event_process_skb(struct qtnf_bus *bus,
if (unlikely(!mac)) if (unlikely(!mac))
return -ENXIO; return -ENXIO;
qtnf_bus_lock(bus); rtnl_lock();
res = qtnf_event_parse(mac, skb); res = qtnf_event_parse(mac, skb);
qtnf_bus_unlock(bus); rtnl_unlock();
return res; return res;
} }
......
...@@ -615,8 +615,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) ...@@ -615,8 +615,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv)
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (skb->dev) { if (skb->dev) {
skb->dev->stats.tx_packets++; qtnf_update_tx_stats(skb->dev, skb);
skb->dev->stats.tx_bytes += skb->len;
if (unlikely(priv->tx_stopped)) { if (unlikely(priv->tx_stopped)) {
qtnf_wake_all_queues(skb->dev); qtnf_wake_all_queues(skb->dev);
priv->tx_stopped = 0; priv->tx_stopped = 0;
...@@ -855,9 +854,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) ...@@ -855,9 +854,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget)
skb_put(skb, psize); skb_put(skb, psize);
ndev = qtnf_classify_skb(bus, skb); ndev = qtnf_classify_skb(bus, skb);
if (likely(ndev)) { if (likely(ndev)) {
ndev->stats.rx_packets++; qtnf_update_rx_stats(ndev, skb);
ndev->stats.rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
napi_gro_receive(napi, skb); napi_gro_receive(napi, skb);
} else { } else {
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#define QLINK_PROTO_VER 10 #define QLINK_PROTO_VER 11
#define QLINK_MACID_RSVD 0xFF #define QLINK_MACID_RSVD 0xFF
#define QLINK_VIFID_RSVD 0xFF #define QLINK_VIFID_RSVD 0xFF
...@@ -663,16 +663,6 @@ struct qlink_acl_data { ...@@ -663,16 +663,6 @@ struct qlink_acl_data {
struct qlink_mac_address mac_addrs[0]; struct qlink_mac_address mac_addrs[0];
} __packed; } __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 /* QLINK Command Responses messages related definitions
*/ */
...@@ -774,6 +764,9 @@ struct qlink_resp_get_hw_info { ...@@ -774,6 +764,9 @@ struct qlink_resp_get_hw_info {
struct qlink_resp rhdr; struct qlink_resp rhdr;
__le32 fw_ver; __le32 fw_ver;
__le32 hw_capab; __le32 hw_capab;
__le32 bld_tmstamp;
__le32 plat_id;
__le32 hw_ver;
__le16 ql_proto_ver; __le16 ql_proto_ver;
u8 num_mac; u8 num_mac;
u8 mac_bitmap; u8 mac_bitmap;
...@@ -1084,6 +1077,13 @@ enum qlink_tlv_id { ...@@ -1084,6 +1077,13 @@ enum qlink_tlv_id {
QTN_TLV_ID_IE_SET = 0x0305, QTN_TLV_ID_IE_SET = 0x0305,
QTN_TLV_ID_EXT_CAPABILITY_MASK = 0x0306, QTN_TLV_ID_EXT_CAPABILITY_MASK = 0x0306,
QTN_TLV_ID_ACL_DATA = 0x0307, 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 { struct qlink_tlv_hdr {
...@@ -1092,13 +1092,20 @@ struct qlink_tlv_hdr { ...@@ -1092,13 +1092,20 @@ struct qlink_tlv_hdr {
u8 val[0]; u8 val[0];
} __packed; } __packed;
struct qlink_iface_comb_num {
__le32 iface_comb_num;
} __packed;
struct qlink_iface_limit { struct qlink_iface_limit {
__le16 max_num; __le16 max_num;
__le16 type; __le16 type;
} __packed; } __packed;
struct qlink_iface_comb_num { struct qlink_iface_limit_record {
__le16 iface_comb_num; __le16 max_interfaces;
u8 num_different_channels;
u8 n_limits;
struct qlink_iface_limit limits[0];
} __packed; } __packed;
#define QLINK_RSSI_OFFSET 120 #define QLINK_RSSI_OFFSET 120
......
...@@ -1172,7 +1172,7 @@ struct rtl8723bu_c2h { ...@@ -1172,7 +1172,7 @@ struct rtl8723bu_c2h {
u8 basic_rate:1; u8 basic_rate:1;
u8 bt_has_reset:1; u8 bt_has_reset:1;
u8 dummy4_1:1;; u8 dummy4_1:1;
u8 ignore_wlan:1; u8 ignore_wlan:1;
u8 auto_report:1; u8 auto_report:1;
u8 dummy4_2:3; u8 dummy4_2:3;
......
...@@ -244,7 +244,8 @@ static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw, ...@@ -244,7 +244,8 @@ static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv); 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; u16 mcs_map;
vht_cap->vht_supported = true; vht_cap->vht_supported = true;
...@@ -697,14 +698,94 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw, ...@@ -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, static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct rtl_tcb_desc *tcb_desc) 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_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_sta_info *sta_entry = NULL; struct rtl_sta_info *sta_entry = NULL;
u8 ratr_index = 7; u8 ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC);
if (sta) { if (sta) {
sta_entry = (struct rtl_sta_info *) sta->drv_priv; sta_entry = (struct rtl_sta_info *) sta->drv_priv;
...@@ -719,7 +800,8 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, ...@@ -719,7 +800,8 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
tcb_desc->hw_rate = tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
tcb_desc->use_driver_rate = 1; 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 { } else {
tcb_desc->ratr_index = ratr_index; tcb_desc->ratr_index = ratr_index;
} }
...@@ -735,22 +817,30 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, ...@@ -735,22 +817,30 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
mac->opmode == NL80211_IFTYPE_MESH_POINT) { mac->opmode == NL80211_IFTYPE_MESH_POINT) {
tcb_desc->mac_id = 0; 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 = 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) else if (mac->mode == WIRELESS_MODE_AC_24G)
tcb_desc->ratr_index = 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) 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) 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) 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) 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) 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 || } else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC) { mac->opmode == NL80211_IFTYPE_ADHOC) {
...@@ -764,6 +854,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, ...@@ -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, static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
...@@ -1140,9 +1231,19 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, ...@@ -1140,9 +1231,19 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) 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_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
struct ieee80211_hdr *hdr = rtl_get_hdr(skb); 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); __le16 fc = rtl_get_fc(skb);
...@@ -1165,7 +1266,8 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, ...@@ -1165,7 +1266,8 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
if (info->control.rates[0].idx == 0 || if (info->control.rates[0].idx == 0 ||
ieee80211_is_nullfunc(fc)) { ieee80211_is_nullfunc(fc)) {
tcb_desc->use_driver_rate = true; 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->disable_ratefallback = 1;
} else { } else {
...@@ -1207,11 +1309,12 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, ...@@ -1207,11 +1309,12 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
_rtl_query_protection_mode(hw, tcb_desc, info); _rtl_query_protection_mode(hw, tcb_desc, info);
} else { } else {
tcb_desc->use_driver_rate = true; 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->disable_ratefallback = 1;
tcb_desc->mac_id = 0; tcb_desc->mac_id = 0;
tcb_desc->packet_bw = false; tcb_desc->packet_bw = false;
} }
#undef SET_RATE_ID
} }
EXPORT_SYMBOL(rtl_get_tcb_desc); EXPORT_SYMBOL(rtl_get_tcb_desc);
......
...@@ -162,6 +162,8 @@ void rtl_c2hcmd_wq_callback(void *data); ...@@ -162,6 +162,8 @@ void rtl_c2hcmd_wq_callback(void *data);
void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec); void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec);
void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val); 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, void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* Debug related function * Debug related function
***************************************************/ ***************************************************/
const char *const gl_btc_wifi_bw_string[] = { static const char *const gl_btc_wifi_bw_string[] = {
"11bg", "11bg",
"HT20", "HT20",
"HT40", "HT40",
...@@ -37,7 +37,7 @@ const char *const gl_btc_wifi_bw_string[] = { ...@@ -37,7 +37,7 @@ const char *const gl_btc_wifi_bw_string[] = {
"HT160" "HT160"
}; };
const char *const gl_btc_wifi_freq_string[] = { static const char *const gl_btc_wifi_freq_string[] = {
"2.4G", "2.4G",
"5G" "5G"
}; };
...@@ -95,21 +95,6 @@ static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist) ...@@ -95,21 +95,6 @@ static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist)
return false; 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) static bool halbtc_legacy(struct rtl_priv *adapter)
{ {
struct rtl_priv *rtlpriv = adapter; struct rtl_priv *rtlpriv = adapter;
...@@ -135,18 +120,26 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter) ...@@ -135,18 +120,26 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter)
static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist) static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist)
{ {
struct rtl_priv *rtlpriv = struct rtl_priv *rtlpriv = btcoexist->adapter;
(struct rtl_priv *)btcoexist->adapter; struct rtl_phy *rtlphy = &rtlpriv->phy;
u32 wifi_bw = BTC_WIFI_BW_HT20; u32 wifi_bw = BTC_WIFI_BW_HT20;
if (halbtc_is_bt40(rtlpriv)) { if (halbtc_legacy(rtlpriv)) {
wifi_bw = BTC_WIFI_BW_HT40; wifi_bw = BTC_WIFI_BW_LEGACY;
} else { } else {
if (halbtc_legacy(rtlpriv)) switch (rtlphy->current_chan_bw) {
wifi_bw = BTC_WIFI_BW_LEGACY; case HT_CHANNEL_WIDTH_20:
else
wifi_bw = BTC_WIFI_BW_HT20; 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; return wifi_bw;
} }
...@@ -163,7 +156,7 @@ static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist) ...@@ -163,7 +156,7 @@ static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist)
return chnl; 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; 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) ...@@ -178,12 +171,12 @@ u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
return rtlpriv->btcoexist.btc_info.single_ant_path; 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; 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; struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
u8 num; u8 num;
...@@ -200,7 +193,7 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv) ...@@ -200,7 +193,7 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
return num; 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); struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
...@@ -511,7 +504,7 @@ static u32 halbtc_get_bt_forbidden_slot_val(void *btc_context) ...@@ -511,7 +504,7 @@ static u32 halbtc_get_bt_forbidden_slot_val(void *btc_context)
return btcoexist->bt_info.bt_forb_slot_val; 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: /* return value:
* [31:16] => connected port number * [31:16] => connected port number
...@@ -987,7 +980,8 @@ static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) ...@@ -987,7 +980,8 @@ static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data)
rtl_write_dword(rtlpriv, reg_addr, 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 btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
struct rtl_priv *rtlpriv = btcoexist->adapter; struct rtl_priv *rtlpriv = btcoexist->adapter;
...@@ -1000,22 +994,6 @@ void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, u8 data) ...@@ -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); 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, static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask,
u32 data) u32 data)
{ {
...@@ -1061,6 +1039,7 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, ...@@ -1061,6 +1039,7 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id,
cmd_len, cmd_buf); cmd_len, cmd_buf);
} }
static
void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val) 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; 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, ...@@ -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_priv *rtlpriv = btcoexist->adapter;
struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
...@@ -1254,6 +1233,40 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv) ...@@ -1254,6 +1233,40 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv)
return true; 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) bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
{ {
struct rtl_priv *rtlpriv = adapter; struct rtl_priv *rtlpriv = adapter;
...@@ -1317,6 +1330,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter) ...@@ -1317,6 +1330,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
"[BTCoex], Package Type = Non-TFBGA\n"); "[BTCoex], Package Type = Non-TFBGA\n");
btcoexist->board_info.rfe_type = rtl_get_hwpg_rfe_type(rtlpriv); btcoexist->board_info.rfe_type = rtl_get_hwpg_rfe_type(rtlpriv);
btcoexist->board_info.ant_div_cfg = 0;
return true; return true;
} }
...@@ -1374,6 +1388,10 @@ void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only) ...@@ -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) void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
{ {
if (!halbtc_is_bt_coexist_available(btcoexist)) if (!halbtc_is_bt_coexist_available(btcoexist))
...@@ -1500,6 +1518,11 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) ...@@ -1500,6 +1518,11 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_normal_low_power(btcoexist); 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) void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
{ {
u8 asso_type; u8 asso_type;
...@@ -1917,3 +1940,21 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist, ...@@ -1917,3 +1940,21 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist,
halbtc_normal_low_power(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 { ...@@ -153,6 +153,7 @@ struct btc_board_info {
bool tfbga_package; bool tfbga_package;
u8 rfe_type; u8 rfe_type;
u8 ant_div_cfg;
}; };
enum btc_dbg_opcode { enum btc_dbg_opcode {
...@@ -190,6 +191,7 @@ enum btc_wifi_bw_mode { ...@@ -190,6 +191,7 @@ enum btc_wifi_bw_mode {
BTC_WIFI_BW_LEGACY = 0x0, BTC_WIFI_BW_LEGACY = 0x0,
BTC_WIFI_BW_HT20 = 0x1, BTC_WIFI_BW_HT20 = 0x1,
BTC_WIFI_BW_HT40 = 0x2, BTC_WIFI_BW_HT40 = 0x2,
BTC_WIFI_BW_HT80 = 0x3,
BTC_WIFI_BW_MAX BTC_WIFI_BW_MAX
}; };
...@@ -384,6 +386,14 @@ enum btc_notify_type_scan { ...@@ -384,6 +386,14 @@ enum btc_notify_type_scan {
BTC_SCAN_MAX 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 { enum btc_notify_type_associate {
BTC_ASSOCIATE_FINISH = 0x0, BTC_ASSOCIATE_FINISH = 0x0,
BTC_ASSOCIATE_START = 0x1, BTC_ASSOCIATE_START = 0x1,
...@@ -573,6 +583,8 @@ struct btc_coexist { ...@@ -573,6 +583,8 @@ struct btc_coexist {
*/ */
bool auto_report_1ant; bool auto_report_1ant;
bool auto_report_2ant; bool auto_report_2ant;
bool dbg_mode_1ant;
bool dbg_mode_2ant;
bool initilized; bool initilized;
bool stop_coex_dm; bool stop_coex_dm;
bool manual_control; bool manual_control;
...@@ -626,21 +638,31 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); ...@@ -626,21 +638,31 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter);
#define rtl_btc_coexist(rtlpriv) \ #define rtl_btc_coexist(rtlpriv) \
((struct btc_coexist *)((rtlpriv)->btcoexist.btc_context)) ((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(struct rtl_priv *rtlpriv);
bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv);
bool exhalbtc_bind_bt_coex_withadapter(void *adapter); bool exhalbtc_bind_bt_coex_withadapter(void *adapter);
void exhalbtc_power_on_setting(struct btc_coexist *btcoexist); 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(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_init_coex_dm(struct btc_coexist *btcoexist);
void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_lps_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(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_connect_notify(struct btc_coexist *btcoexist, u8 action);
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
enum rt_media_status media_status); enum rt_media_status media_status);
void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length); 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_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist); void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
...@@ -648,6 +670,8 @@ void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); ...@@ -648,6 +670,8 @@ void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
void exhalbtc_periodical(struct btc_coexist *btcoexist); void exhalbtc_periodical(struct btc_coexist *btcoexist);
void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
u8 *data); 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_stack_update_profile_info(void);
void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version); void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version);
void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, 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); ...@@ -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_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num);
void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist, void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist,
struct seq_file *m); 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, void exhalbtc_signal_compensation(struct btc_coexist *btcoexist,
u8 *rssi_wifi, u8 *rssi_bt); u8 *rssi_wifi, u8 *rssi_bt);
void exhalbtc_lps_leave(struct btc_coexist *btcoexist); void exhalbtc_lps_leave(struct btc_coexist *btcoexist);
...@@ -665,4 +692,41 @@ void exhalbtc_low_wifi_traffic_notify(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, void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist,
u8 single_ant_path); 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 #endif
...@@ -31,13 +31,16 @@ ...@@ -31,13 +31,16 @@
static struct rtl_btc_ops rtl_btc_operation = { static struct rtl_btc_ops rtl_btc_operation = {
.btc_init_variables = rtl_btc_init_variables, .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_deinit_variables = rtl_btc_deinit_variables,
.btc_init_hal_vars = rtl_btc_init_hal_vars, .btc_init_hal_vars = rtl_btc_init_hal_vars,
.btc_power_on_setting = rtl_btc_power_on_setting, .btc_power_on_setting = rtl_btc_power_on_setting,
.btc_init_hw_config = rtl_btc_init_hw_config, .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_ips_notify = rtl_btc_ips_notify,
.btc_lps_notify = rtl_btc_lps_notify, .btc_lps_notify = rtl_btc_lps_notify,
.btc_scan_notify = rtl_btc_scan_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_connect_notify = rtl_btc_connect_notify,
.btc_mediastatus_notify = rtl_btc_mediastatus_notify, .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
.btc_periodical = rtl_btc_periodical, .btc_periodical = rtl_btc_periodical,
...@@ -48,6 +51,8 @@ static struct rtl_btc_ops rtl_btc_operation = { ...@@ -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_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
.btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
.btc_special_packet_notify = rtl_btc_special_packet_notify, .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_record_pwr_mode = rtl_btc_record_pwr_mode,
.btc_get_lps_val = rtl_btc_get_lps_val, .btc_get_lps_val = rtl_btc_get_lps_val,
.btc_get_rpwm_val = rtl_btc_get_rpwm_val, .btc_get_rpwm_val = rtl_btc_get_rpwm_val,
...@@ -146,7 +151,11 @@ void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, ...@@ -146,7 +151,11 @@ 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) static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only)
{ {
rtlpriv->btcoexist.btc_context = 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); kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);
} }
...@@ -154,6 +163,9 @@ static void rtl_btc_free_variable(struct rtl_priv *rtlpriv) ...@@ -154,6 +163,9 @@ static void rtl_btc_free_variable(struct rtl_priv *rtlpriv)
{ {
kfree(rtlpriv->btcoexist.btc_context); kfree(rtlpriv->btcoexist.btc_context);
rtlpriv->btcoexist.btc_context = NULL; 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) void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
...@@ -164,6 +176,13 @@ 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); 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) void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)
{ {
rtl_btc_free_variable(rtlpriv); rtl_btc_free_variable(rtlpriv);
...@@ -203,6 +222,16 @@ void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) ...@@ -203,6 +222,16 @@ void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
exhalbtc_init_coex_dm(btcoexist); 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) void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
{ {
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
...@@ -211,6 +240,14 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) ...@@ -211,6 +240,14 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
return; return;
exhalbtc_ips_notify(btcoexist, type); 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) 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) ...@@ -233,6 +270,18 @@ void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
exhalbtc_scan_notify(btcoexist, 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) void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
{ {
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); 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) ...@@ -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); 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) struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
{ {
return &rtl_btc_operation; return &rtl_btc_operation;
......
...@@ -28,13 +28,16 @@ ...@@ -28,13 +28,16 @@
#include "halbt_precomp.h" #include "halbt_precomp.h"
void rtl_btc_init_variables(struct rtl_priv *rtlpriv); 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_deinit_variables(struct rtl_priv *rtlpriv);
void rtl_btc_init_hal_vars(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_power_on_setting(struct rtl_priv *rtlpriv);
void rtl_btc_init_hw_config(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_ips_notify(struct rtl_priv *rtlpriv, u8 type);
void rtl_btc_lps_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(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_connect_notify(struct rtl_priv *rtlpriv, u8 action);
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
enum rt_media_status mstatus); enum rt_media_status mstatus);
...@@ -46,6 +49,10 @@ bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); ...@@ -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_disable_edca_turbo(struct rtl_priv *rtlpriv);
bool rtl_btc_is_bt_disabled(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_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_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); void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len);
u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv); 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, ...@@ -1453,6 +1453,9 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->get_btc_status()) if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1); 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->dm.supp_phymode_switch) {
if (rtlpriv->cfg->ops->chk_switch_dmdp) if (rtlpriv->cfg->ops->chk_switch_dmdp)
...@@ -1508,6 +1511,9 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, ...@@ -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); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
if (rtlpriv->cfg->ops->get_btc_status()) if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0); 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, 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) ...@@ -1794,6 +1794,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops;
int err; int err;
...@@ -1803,9 +1804,12 @@ static int rtl_pci_start(struct ieee80211_hw *hw) ...@@ -1803,9 +1804,12 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
if (rtlpriv->cfg->ops->get_btc_status && if (rtlpriv->cfg->ops->get_btc_status &&
rtlpriv->cfg->ops->get_btc_status()) { rtlpriv->cfg->ops->get_btc_status()) {
rtlpriv->btcoexist.btc_info.ap_num = 36; rtlpriv->btcoexist.btc_info.ap_num = 36;
rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); btc_ops->btc_init_variables(rtlpriv);
rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(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); err = rtlpriv->cfg->ops->hw_init(hw);
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
......
...@@ -873,6 +873,24 @@ enum ratr_table_mode { ...@@ -873,6 +873,24 @@ enum ratr_table_mode {
RATR_INX_WIRELESS_AC_24N = 9, 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 { enum rtl_link_state {
MAC80211_NOLINK = 0, MAC80211_NOLINK = 0,
MAC80211_LINKING = 1, MAC80211_LINKING = 1,
...@@ -931,6 +949,10 @@ enum package_type { ...@@ -931,6 +949,10 @@ enum package_type {
PACKAGE_TFBGA79 PACKAGE_TFBGA79
}; };
enum rtl_spec_ver {
RTL_SPEC_NEW_RATEID = BIT(0), /* use ratr_table_mode_new */
};
struct octet_string { struct octet_string {
u8 *octet; u8 *octet;
u16 length; u16 length;
...@@ -2315,6 +2337,7 @@ struct rtl_hal_cfg { ...@@ -2315,6 +2337,7 @@ struct rtl_hal_cfg {
struct rtl_hal_ops *ops; struct rtl_hal_ops *ops;
struct rtl_mod_params *mod_params; struct rtl_mod_params *mod_params;
struct rtl_hal_usbint_cfg *usb_interface_cfg; struct rtl_hal_usbint_cfg *usb_interface_cfg;
enum rtl_spec_ver spec_ver;
/*this map used for some registers or vars /*this map used for some registers or vars
defined int HAL but used in MAIN */ defined int HAL but used in MAIN */
...@@ -2502,6 +2525,7 @@ struct bt_coexist_info { ...@@ -2502,6 +2525,7 @@ struct bt_coexist_info {
struct rtl_btc_info btc_info; struct rtl_btc_info btc_info;
/* btc context */ /* btc context */
void *btc_context; void *btc_context;
void *wifi_only_context;
/* EEPROM BT info. */ /* EEPROM BT info. */
u8 eeprom_bt_coexist; u8 eeprom_bt_coexist;
u8 eeprom_bt_type; u8 eeprom_bt_type;
...@@ -2558,13 +2582,17 @@ struct bt_coexist_info { ...@@ -2558,13 +2582,17 @@ struct bt_coexist_info {
struct rtl_btc_ops { struct rtl_btc_ops {
void (*btc_init_variables) (struct rtl_priv *rtlpriv); 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_deinit_variables)(struct rtl_priv *rtlpriv);
void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
void (*btc_power_on_setting)(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) (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_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
void (*btc_lps_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) (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_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv, void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
enum rt_media_status mstatus); enum rt_media_status mstatus);
...@@ -2579,6 +2607,10 @@ struct rtl_btc_ops { ...@@ -2579,6 +2607,10 @@ struct rtl_btc_ops {
bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
u8 pkt_type); 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, void (*btc_display_bt_coex_info)(struct rtl_priv *rtlpriv,
struct seq_file *m); struct seq_file *m);
void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册