Commit f7a61170 authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for 4.16. Major changes:

wil6210

* add PCI device id for Talyn

* support flashless device

ath9k

* improve RSSI/signal accuracy on AR9003 series
parents f2f6026a d0bb950b
...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment