diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2018-01-25 18:39:07 +0100 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2018-01-25 18:39:07 +0100 |
commit | f7a611707b2755e2658a80c96e276e9506e674c4 (patch) | |
tree | 4f80ed729f555a74553040820d22844eafa77591 /drivers/net/wireless | |
parent | rtlwifi: btcoex: Fix some static warnings from Sparse (diff) | |
parent | wcn36xx: release DMA memory in case of error (diff) | |
download | linux-f7a611707b2755e2658a80c96e276e9506e674c4.tar.xz linux-f7a611707b2755e2658a80c96e276e9506e674c4.zip |
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
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 133 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/calib.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/dxe.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/boot_loader.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/fw.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/fw_inc.c | 167 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/interrupt.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 217 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/pcie_bus.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 55 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 90 |
14 files changed, 752 insertions, 89 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c2e210c0a770..f019a20e5a1f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3310,6 +3310,12 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; + cptr = AR9300_BASE_ADDR_4K; + ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", + cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + cptr = AR9300_BASE_ADDR_512; ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", cptr); @@ -3430,6 +3436,60 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, return len; } +static u32 ar9003_dump_cal_data(struct ath_hw *ah, char *buf, u32 len, u32 size, + bool is_2g) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase; + struct ar9300_cal_data_per_freq_op_loop *cal_pier; + int cal_pier_nr; + int freq; + int i, j; + + pBase = &eep->baseEepHeader; + + if (is_2g) + cal_pier_nr = AR9300_NUM_2G_CAL_PIERS; + else + cal_pier_nr = AR9300_NUM_5G_CAL_PIERS; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!((pBase->txrxMask >> i) & 1)) + continue; + + len += snprintf(buf + len, size - len, "Chain %d\n", i); + + len += snprintf(buf + len, size - len, + "Freq\t ref\tvolt\ttemp\tnf_cal\tnf_pow\trx_temp\n"); + + for (j = 0; j < cal_pier_nr; j++) { + if (is_2g) { + cal_pier = &eep->calPierData2G[i][j]; + freq = 2300 + eep->calFreqPier2G[j]; + } else { + cal_pier = &eep->calPierData5G[i][j]; + freq = 4800 + eep->calFreqPier5G[j] * 5; + } + + len += snprintf(buf + len, size - len, + "%d\t", freq); + + len += snprintf(buf + len, size - len, + "%d\t%d\t%d\t%d\t%d\t%d\n", + cal_pier->refPower, + cal_pier->voltMeas, + cal_pier->tempMeas, + cal_pier->rxTempMeas ? + N2DBM(cal_pier->rxNoisefloorCal) : 0, + cal_pier->rxTempMeas ? + N2DBM(cal_pier->rxNoisefloorPower) : 0, + cal_pier->rxTempMeas); + } + } + + return len; +} + static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, u8 *buf, u32 len, u32 size) { @@ -3441,10 +3501,18 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, "%20s :\n", "2GHz modal Header"); len = ar9003_dump_modal_eeprom(buf, len, size, &eep->modalHeader2G); - len += scnprintf(buf + len, size - len, + + len += scnprintf(buf + len, size - len, "Calibration data\n"); + len = ar9003_dump_cal_data(ah, buf, len, size, true); + + len += snprintf(buf + len, size - len, "%20s :\n", "5GHz modal Header"); len = ar9003_dump_modal_eeprom(buf, len, size, &eep->modalHeader5G); + + len += snprintf(buf + len, size - len, "Calibration data\n"); + len = ar9003_dump_cal_data(ah, buf, len, size, false); + goto out; } @@ -4683,7 +4751,8 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, int ichain, int *pfrequency, int *pcorrection, - int *ptemperature, int *pvoltage) + int *ptemperature, int *pvoltage, + int *pnf_cal, int *pnf_power) { u8 *pCalPier; struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct; @@ -4725,6 +4794,10 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, *pcorrection = pCalPierStruct->refPower; *ptemperature = pCalPierStruct->tempMeas; *pvoltage = pCalPierStruct->voltMeas; + *pnf_cal = pCalPierStruct->rxTempMeas ? + N2DBM(pCalPierStruct->rxNoisefloorCal) : 0; + *pnf_power = pCalPierStruct->rxTempMeas ? + N2DBM(pCalPierStruct->rxNoisefloorPower) : 0; return 0; } @@ -4889,14 +4962,18 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) int mode; int lfrequency[AR9300_MAX_CHAINS], lcorrection[AR9300_MAX_CHAINS], - ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS]; + ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS], + lnf_cal[AR9300_MAX_CHAINS], lnf_pwr[AR9300_MAX_CHAINS]; int hfrequency[AR9300_MAX_CHAINS], hcorrection[AR9300_MAX_CHAINS], - htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS]; + htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS], + hnf_cal[AR9300_MAX_CHAINS], hnf_pwr[AR9300_MAX_CHAINS]; int fdiff; int correction[AR9300_MAX_CHAINS], - voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS]; - int pfrequency, pcorrection, ptemperature, pvoltage; + voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS], + nf_cal[AR9300_MAX_CHAINS], nf_pwr[AR9300_MAX_CHAINS]; + int pfrequency, pcorrection, ptemperature, pvoltage, + pnf_cal, pnf_pwr; struct ath_common *common = ath9k_hw_common(ah); mode = (frequency >= 4000); @@ -4914,7 +4991,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) for (ipier = 0; ipier < npier; ipier++) { if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain, &pfrequency, &pcorrection, - &ptemperature, &pvoltage)) { + &ptemperature, &pvoltage, + &pnf_cal, &pnf_pwr)) { fdiff = frequency - pfrequency; /* @@ -4936,6 +5014,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) htemperature[ichain] = ptemperature; hvoltage[ichain] = pvoltage; + hnf_cal[ichain] = pnf_cal; + hnf_pwr[ichain] = pnf_pwr; } } if (fdiff >= 0) { @@ -4952,6 +5032,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ltemperature[ichain] = ptemperature; lvoltage[ichain] = pvoltage; + lnf_cal[ichain] = pnf_cal; + lnf_pwr[ichain] = pnf_pwr; } } } @@ -4960,15 +5042,20 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) /* interpolate */ for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { - ath_dbg(common, EEPROM, "ch=%d f=%d low=%d %d h=%d %d\n", + ath_dbg(common, EEPROM, + "ch=%d f=%d low=%d %d h=%d %d n=%d %d p=%d %d\n", ichain, frequency, lfrequency[ichain], lcorrection[ichain], hfrequency[ichain], - hcorrection[ichain]); + hcorrection[ichain], lnf_cal[ichain], + hnf_cal[ichain], lnf_pwr[ichain], + hnf_pwr[ichain]); /* they're the same, so just pick one */ if (hfrequency[ichain] == lfrequency[ichain]) { correction[ichain] = lcorrection[ichain]; voltage[ichain] = lvoltage[ichain]; temperature[ichain] = ltemperature[ichain]; + nf_cal[ichain] = lnf_cal[ichain]; + nf_pwr[ichain] = lnf_pwr[ichain]; } /* the low frequency is good */ else if (frequency - lfrequency[ichain] < 1000) { @@ -4992,12 +5079,26 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) hfrequency[ichain], lvoltage[ichain], hvoltage[ichain]); + + nf_cal[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lnf_cal[ichain], + hnf_cal[ichain]); + + nf_pwr[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lnf_pwr[ichain], + hnf_pwr[ichain]); } /* only low is good, use it */ else { correction[ichain] = lcorrection[ichain]; temperature[ichain] = ltemperature[ichain]; voltage[ichain] = lvoltage[ichain]; + nf_cal[ichain] = lnf_cal[ichain]; + nf_pwr[ichain] = lnf_pwr[ichain]; } } /* only high is good, use it */ @@ -5005,10 +5106,14 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) correction[ichain] = hcorrection[ichain]; temperature[ichain] = htemperature[ichain]; voltage[ichain] = hvoltage[ichain]; + nf_cal[ichain] = hnf_cal[ichain]; + nf_pwr[ichain] = hnf_pwr[ichain]; } else { /* nothing is good, presume 0???? */ correction[ichain] = 0; temperature[ichain] = 0; voltage[ichain] = 0; + nf_cal[ichain] = 0; + nf_pwr[ichain] = 0; } } @@ -5019,6 +5124,16 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) "for frequency=%d, calibration correction = %d %d %d\n", frequency, correction[0], correction[1], correction[2]); + /* Store calibrated noise floor values */ + for (ichain = 0; ichain < AR5416_MAX_CHAINS; ichain++) + if (mode) { + ah->nf_5g.cal[ichain] = nf_cal[ichain]; + ah->nf_5g.pwr[ichain] = nf_pwr[ichain]; + } else { + ah->nf_2g.cal[ichain] = nf_cal[ichain]; + ah->nf_2g.pwr[ichain] = nf_pwr[ichain]; + } + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index bd2269c7de6b..e8fda54acfe3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -62,6 +62,16 @@ */ #define AR9300_PWR_TABLE_OFFSET 0 +/* Noise power data definitions + * units are: 4 x dBm - NOISE_PWR_DATA_OFFSET + * (e.g. -25 = (-25/4 - 90) = -96.25 dBm) + * range (for 6 signed bits) is (-32 to 31) + offset => -122dBm to -59dBm + * resolution (2 bits) is 0.25dBm + */ +#define NOISE_PWR_DATA_OFFSET -90 +#define NOISE_PWR_DBM_2_INT(_p) ((((_p) + 3) >> 2) + NOISE_PWR_DATA_OFFSET) +#define N2DBM(_p) NOISE_PWR_DBM_2_INT(_p) + /* byte addressable */ #define AR9300_EEPROM_SIZE (16*1024) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 13ab6bc46775..3d9447e21025 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -58,19 +58,25 @@ static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah, } static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, - struct ath9k_channel *chan) + struct ath9k_channel *chan, + int chain) { - 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 nf) { - s8 noise = ATH_DEFAULT_NOISE_FLOOR; + s8 noise = ath9k_hw_get_default_nf(ah, chan, 0); if (nf) { s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH - - ath9k_hw_get_default_nf(ah, chan); + ath9k_hw_get_default_nf(ah, chan, 0); if (delta > 0) noise += delta; } @@ -240,7 +246,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) unsigned i, j; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); - s16 default_nf = ath9k_hw_get_default_nf(ah, chan); + s16 default_nf = ath9k_hw_get_nf_limits(ah, chan)->nominal; u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL); if (ah->caldata) @@ -258,8 +264,13 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) nfval = ah->nf_override; else if (h) nfval = h[i].privNF; - else - nfval = default_nf; + else { + /* Try to get calibrated noise floor value */ + nfval = + ath9k_hw_get_nf_limits(ah, chan)->cal[i]; + if (nfval > -60 || nfval < -127) + nfval = default_nf; + } REG_RMW(ah, ah->nf_regs[i], (((u32) nfval << 1) & 0x1ff), 0x1ff); @@ -429,20 +440,19 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h; - s16 default_nf; - int i, j; + int i, j, k = 0; ah->caldata->channel = chan->channel; ah->caldata->channelFlags = chan->channelFlags; h = ah->caldata->nfCalHist; - default_nf = ath9k_hw_get_default_nf(ah, chan); for (i = 0; i < NUM_NF_READINGS; i++) { h[i].currIndex = 0; - h[i].privNF = default_nf; + h[i].privNF = ath9k_hw_get_default_nf(ah, chan, k); h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - h[i].nfCalBuffer[j] = default_nf; - } + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) + h[i].nfCalBuffer[j] = h[i].privNF; + if (++k >= AR5416_MAX_CHAINS) + k = 0; } } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0d6c07c77372..9804a24a2dc0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -754,6 +754,8 @@ struct ath_nf_limits { s16 max; s16 min; s16 nominal; + s16 cal[AR5416_MAX_CHAINS]; + s16 pwr[AR5416_MAX_CHAINS]; }; enum ath_cal_list { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2197aee2bb72..a8ac42c96d71 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -826,9 +826,9 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, sc->rx.discard_next = false; /* - * Discard zero-length packets. + * Discard zero-length packets and packets smaller than an ACK */ - if (!rx_stats->rs_datalen) { + if (rx_stats->rs_datalen < 10) { RX_STAT_INC(rx_len_err); goto corrupt; } diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index d5c810a8cc52..a3f1f7d042a4 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -236,6 +236,14 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn return 0; } +static void wcn36xx_dxe_deinit_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn_ch) +{ + size_t size; + + size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc); + dma_free_coherent(dev, size,wcn_ch->cpu_addr, wcn_ch->dma_addr); +} + static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch, struct wcn36xx_dxe_mem_pool *pool) { @@ -722,7 +730,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /***************************************/ /* Init descriptors for TX LOW channel */ /***************************************/ - wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch); + ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch); + if (ret) { + dev_err(wcn->dev, "Error allocating descriptor\n"); + return ret; + } wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool); /* Write channel head to a NEXT register */ @@ -740,7 +752,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /***************************************/ /* Init descriptors for TX HIGH channel */ /***************************************/ - wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch); + ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch); + if (ret) { + dev_err(wcn->dev, "Error allocating descriptor\n"); + goto out_err_txh_ch; + } + wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool); /* Write channel head to a NEXT register */ @@ -760,7 +777,12 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /***************************************/ /* Init descriptors for RX LOW channel */ /***************************************/ - wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch); + ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch); + if (ret) { + dev_err(wcn->dev, "Error allocating descriptor\n"); + goto out_err_rxl_ch; + } + /* For RX we need to preallocated buffers */ wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch); @@ -790,7 +812,11 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /***************************************/ /* Init descriptors for RX HIGH channel */ /***************************************/ - wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch); + ret = wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch); + if (ret) { + dev_err(wcn->dev, "Error allocating descriptor\n"); + goto out_err_rxh_ch; + } /* For RX we need to prealocat buffers */ wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch); @@ -819,11 +845,19 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) ret = wcn36xx_dxe_request_irqs(wcn); if (ret < 0) - goto out_err; + goto out_err_irq; return 0; -out_err: +out_err_irq: + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_h_ch); +out_err_rxh_ch: + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_l_ch); +out_err_rxl_ch: + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_h_ch); +out_err_txh_ch: + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_l_ch); + return ret; } diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h index c131b5e1292f..d32c1f4e533a 100644 --- a/drivers/net/wireless/ath/wil6210/boot_loader.h +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -1,4 +1,5 @@ /* Copyright (c) 2015 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 { /* valid only for version 2 and above */ __le32 bl_assert_code; /* 0x880A58 BL Assert code */ __le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ - __le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */ + __le32 bl_shutdown_handshake; /* 0x880A60 BL cleaner shutdown */ + __le32 bl_reserved[21]; /* 0x880A64 - 0x880AB4 */ __le32 bl_magic_number; /* 0x880AB8 BL Magic number */ } __packed; @@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 { u8 mac_address[6]; /* 0x880A4c BL mac address */ } __packed; +/* bits for bl_shutdown_handshake */ +#define BL_SHUTDOWN_HS_GRTD BIT(0) +#define BL_SHUTDOWN_HS_RTD BIT(1) +#define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31) + #endif /* BOOT_LOADER_EXPORT_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index 2f2b910501ba..2c7b24f61587 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2014,2016 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,15 +59,30 @@ struct wil_fw_record_comment { /* type == wil_fw_type_comment */ u8 data[0]; /* free-form data [data_size], see above */ } __packed; +/* Comment header - common for all comment record types */ +struct wil_fw_record_comment_hdr { + __le32 magic; +}; + /* FW capabilities encoded inside a comment record */ #define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba) struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */ /* identifies capabilities record */ - __le32 magic; + struct wil_fw_record_comment_hdr hdr; /* capabilities (variable size), see enum wmi_fw_capability */ u8 capabilities[0]; }; +/* brd file info encoded inside a comment record */ +#define WIL_BRD_FILE_MAGIC (0xabcddcbb) +struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */ + /* identifies brd file record */ + struct wil_fw_record_comment_hdr hdr; + __le32 version; + __le32 base_addr; + __le32 max_size_bytes; +} __packed; + /* perform action * data_size = @head.size - offsetof(struct wil_fw_record_action, data) */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 77d1902947e3..914c0106e94b 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -128,14 +129,13 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data, } static int -fw_handle_comment(struct wil6210_priv *wil, const void *data, - size_t size) +fw_handle_capabilities(struct wil6210_priv *wil, const void *data, + size_t size) { const struct wil_fw_record_capabilities *rec = data; size_t capa_size; - if (size < sizeof(*rec) || - le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) { + if (size < sizeof(*rec)) { wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true); return 0; @@ -151,8 +151,56 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data, return 0; } -static int fw_handle_data(struct wil6210_priv *wil, const void *data, - size_t size) +static int +fw_handle_brd_file(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_brd_file *rec = data; + + if (size < sizeof(*rec)) { + wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, + data, size, true); + return 0; + } + + wil->brd_file_addr = le32_to_cpu(rec->base_addr); + wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes); + + wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n", + wil->brd_file_addr, wil->brd_file_max_size); + + return 0; +} + +static int +fw_handle_comment(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_comment_hdr *hdr = data; + u32 magic; + int rc = 0; + + if (size < sizeof(*hdr)) + return 0; + + magic = le32_to_cpu(hdr->magic); + + switch (magic) { + case WIL_FW_CAPABILITIES_MAGIC: + wil_dbg_fw(wil, "magic is WIL_FW_CAPABILITIES_MAGIC\n"); + rc = fw_handle_capabilities(wil, data, size); + break; + case WIL_BRD_FILE_MAGIC: + wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n"); + rc = fw_handle_brd_file(wil, data, size); + break; + } + + return rc; +} + +static int __fw_handle_data(struct wil6210_priv *wil, const void *data, + size_t size, __le32 addr) { const struct wil_fw_record_data *d = data; void __iomem *dst; @@ -163,16 +211,23 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data, return -EINVAL; } - if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) + if (!wil_fw_addr_check(wil, &dst, addr, s, "address")) return -EINVAL; - wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), - s); + wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s); wil_memcpy_toio_32(dst, d->data, s); wmb(); /* finish before processing next record */ return 0; } +static int fw_handle_data(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_data *d = data; + + return __fw_handle_data(wil, data, size, d->addr); +} + static int fw_handle_fill(struct wil6210_priv *wil, const void *data, size_t size) { @@ -552,6 +607,100 @@ out: } /** + * 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: driver context diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index dcf87a7f99da..1835187ea075 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -395,8 +396,9 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) wil6210_mask_irq_misc(wil, false); if (isr & ISR_MISC_FW_ERROR) { - u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE); - u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE); + u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr); + u32 ucode_assert_code = + wil_r(wil, wil->rgf_ucode_assert_code_addr); wil_err(wil, "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n", diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index aa6f9c4a21f1..0c61a6c13991 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -637,6 +638,98 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } +static void wil_shutdown_bl(struct wil6210_priv *wil) +{ + u32 val; + + wil_s(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD); + + usleep_range(100, 150); + + val = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_shutdown_handshake)); + if (val & BL_SHUTDOWN_HS_RTD) { + wil_dbg_misc(wil, "BL is ready for halt\n"); + return; + } + + wil_err(wil, "BL did not report ready for halt\n"); +} + +/* this format is used by ARC embedded CPU for instruction memory */ +static inline u32 ARC_me_imm32(u32 d) +{ + return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16); +} + +/* defines access to interrupt vectors for wil_freeze_bl */ +#define ARC_IRQ_VECTOR_OFFSET(N) ((N) * 8) +/* ARC long jump instruction */ +#define ARC_JAL_INST (0x20200f80) + +static void wil_freeze_bl(struct wil6210_priv *wil) +{ + u32 jal, upc, saved; + u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3); + + jal = wil_r(wil, wil->iccm_base + ivt3); + if (jal != ARC_me_imm32(ARC_JAL_INST)) { + wil_dbg_misc(wil, "invalid IVT entry found, skipping\n"); + return; + } + + /* prevent the target from entering deep sleep + * and disabling memory access + */ + saved = wil_r(wil, RGF_USER_USAGE_8); + wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP); + usleep_range(20, 25); /* let the BL process the bit */ + + /* redirect to endless loop in the INT_L1 context and let it trap */ + wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3)); + usleep_range(20, 25); /* let the BL get into the trap */ + + /* verify the BL is frozen */ + upc = wil_r(wil, RGF_USER_CPU_PC); + if (upc < ivt3 || (upc > (ivt3 + 8))) + wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc); + + wil_w(wil, RGF_USER_USAGE_8, saved); +} + +static void wil_bl_prepare_halt(struct wil6210_priv *wil) +{ + u32 tmp, ver; + + /* before halting device CPU driver must make sure BL is not accessing + * host memory. This is done differently depending on BL version: + * 1. For very old BL versions the procedure is skipped + * (not supported). + * 2. For old BL version we use a special trick to freeze the BL + * 3. For new BL versions we shutdown the BL using handshake procedure. + */ + tmp = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); + if (!tmp) { + wil_dbg_misc(wil, "old BL, skipping halt preperation\n"); + return; + } + + tmp = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_shutdown_handshake)); + ver = BL_SHUTDOWN_HS_PROT_VER(tmp); + + if (ver > 0) + wil_shutdown_bl(wil); + else + wil_freeze_bl(wil); +} + static inline void wil_halt_cpu(struct wil6210_priv *wil) { wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); @@ -670,7 +763,7 @@ static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode) } } -static int wil_target_reset(struct wil6210_priv *wil) +static int wil_target_reset(struct wil6210_priv *wil, int no_flash) { int delay = 0; u32 x, x1 = 0; @@ -684,9 +777,16 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); - /* clear all boot loader "ready" bits */ - wil_w(wil, RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); + if (!no_flash) { + /* clear all boot loader "ready" bits */ + wil_w(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready), 0); + /* this should be safe to write even with old BLs */ + wil_w(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_shutdown_handshake), 0); + } /* Clear Fw Download notification */ wil_c(wil, RGF_USER_USAGE_6, BIT(0)); @@ -727,21 +827,33 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ - do { - msleep(RST_DELAY); - x = wil_r(wil, RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, - boot_loader_ready)); - if (x1 != x) { - wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); - x1 = x; - } - if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", - x); - return -ETIME; - } - } while (x != BL_READY); + if (no_flash) + do { + msleep(RST_DELAY); + x = wil_r(wil, USER_EXT_USER_PMU_3); + if (delay++ > RST_COUNT) { + wil_err(wil, "Reset not completed, PMU_3 0x%08x\n", + x); + return -ETIME; + } + } while ((x & BIT_PMU_DEVICE_RDY) == 0); + else + do { + msleep(RST_DELAY); + x = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); + if (x1 != x) { + wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", + x1, x); + 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); @@ -749,6 +861,21 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + if (no_flash) { + /* Reset OTP HW vectors to fit 40MHz */ + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001); + wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001); + wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57); + } + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } @@ -906,6 +1033,27 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) } } +static int wil_get_otp_info(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct wiphy *wiphy = wil_to_wiphy(wil); + u8 mac[8]; + + wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC), + sizeof(mac)); + if (!is_valid_ether_addr(mac)) { + wil_err(wil, "Invalid MAC %pM\n", mac); + return -EINVAL; + } + + ether_addr_copy(ndev->perm_addr, mac); + ether_addr_copy(wiphy->perm_addr, mac); + if (!is_valid_ether_addr(ndev->dev_addr)) + ether_addr_copy(ndev->dev_addr, mac); + + return 0; +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -999,6 +1147,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; unsigned long status_flags = BIT(wil_status_resetting); + int no_flash; wil_dbg_misc(wil, "reset\n"); @@ -1074,20 +1223,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); - 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); - rc = wil_target_reset(wil); + rc = wil_target_reset(wil, no_flash); wil6210_clear_irq(wil); wil_enable_irq(wil); wil_rx_fini(wil); if (rc) { - wil_bl_crash_info(wil, true); + if (!no_flash) + wil_bl_crash_info(wil, true); goto out; } - rc = wil_get_bl_info(wil); - if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ - rc = 0; + if (no_flash) { + rc = wil_get_otp_info(wil); + } else { + rc = wil_get_bl_info(wil); + if (rc == -EAGAIN && !load_fw) + /* ignore RF error if not going up */ + rc = 0; + } if (rc) goto out; @@ -1096,13 +1253,21 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_info(wil, "Use firmware <%s> + board <%s>\n", wil->wil_fw_name, WIL_BOARD_FILE_NAME); + if (!no_flash) + wil_bl_prepare_halt(wil); + wil_halt_cpu(wil); memset(wil->fw_version, 0, sizeof(wil->fw_version)); /* Loading f/w from the file */ rc = wil_request_firmware(wil, wil->wil_fw_name, true); if (rc) goto out; - rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true); + if (wil->brd_file_addr) + rc = wil_request_board(wil, WIL_BOARD_FILE_NAME); + else + rc = wil_request_firmware(wil, + WIL_BOARD_FILE_NAME, + true); if (rc) goto out; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 0c401bf151a2..809092a49192 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,15 +36,16 @@ static int wil6210_pm_notify(struct notifier_block *notify_block, unsigned long mode, void *unused); static -void wil_set_capabilities(struct wil6210_priv *wil) +int wil_set_capabilities(struct wil6210_priv *wil) { const char *wil_fw_name; u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & RGF_USER_REVISION_ID_MASK); int platform_capa; + struct fw_map *iccm_section, *sct; - bitmap_zero(wil->hw_capabilities, hw_capability_last); + bitmap_zero(wil->hw_capa, hw_capa_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX); wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : @@ -52,6 +54,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) switch (jtag_id) { case JTAG_DEV_ID_SPARROW: + memcpy(fw_mapping, sparrow_fw_mapping, + sizeof(sparrow_fw_mapping)); switch (chip_revision) { case REVISION_ID_SPARROW_D0: wil->hw_name = "Sparrow D0"; @@ -61,6 +65,12 @@ void wil_set_capabilities(struct wil6210_priv *wil) if (wil_fw_verify_file_exists(wil, wil_fw_name)) wil->wil_fw_name = wil_fw_name; + sct = wil_find_fw_mapping("mac_rgf_ext"); + if (!sct) { + wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n"); + return -EINVAL; + } + memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct)); break; case REVISION_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; @@ -71,15 +81,36 @@ void wil_set_capabilities(struct wil6210_priv *wil) wil->hw_version = HW_VER_UNKNOWN; break; } + wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE; + wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE; + break; + case JTAG_DEV_ID_TALYN: + wil->hw_name = "Talyn"; + wil->hw_version = HW_VER_TALYN; + memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping)); + wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; + wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; + if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) & + BIT_NO_FLASH_INDICATION) + set_bit(hw_capa_no_flash, wil->hw_capa); break; default: wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", jtag_id, chip_revision); wil->hw_name = "Unknown"; wil->hw_version = HW_VER_UNKNOWN; + return -EINVAL; + } + + 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 */ if (wil->platform_ops.get_capa) { @@ -92,6 +123,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); wil_refresh_fw_capabilities(wil); + + return 0; } void wil_disable_irq(struct wil6210_priv *wil) @@ -302,7 +335,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* rollback to err_iounmap */ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); - wil_set_capabilities(wil); + rc = wil_set_capabilities(wil); + if (rc) { + wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc); + goto err_iounmap; + } wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ @@ -378,6 +415,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) static const struct pci_device_id wil6210_pcie_ids[] = { { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ + { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */ { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0a0766b2c80a..0df2aada6659 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -169,6 +170,7 @@ struct RGF_ICR { #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */ +#define RGF_USER_CPU_PC (0x8801e8) #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) @@ -194,6 +196,19 @@ struct RGF_ICR { #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) #define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) +#define RGF_USER_OTP_HW_RD_MACHINE_1 (0x880ce0) + #define BIT_NO_FLASH_INDICATION BIT(8) +#define RGF_USER_XPM_IFC_RD_TIME1 (0x880cec) +#define RGF_USER_XPM_IFC_RD_TIME2 (0x880cf0) +#define RGF_USER_XPM_IFC_RD_TIME3 (0x880cf4) +#define RGF_USER_XPM_IFC_RD_TIME4 (0x880cf8) +#define RGF_USER_XPM_IFC_RD_TIME5 (0x880cfc) +#define RGF_USER_XPM_IFC_RD_TIME6 (0x880d00) +#define RGF_USER_XPM_IFC_RD_TIME7 (0x880d04) +#define RGF_USER_XPM_IFC_RD_TIME8 (0x880d08) +#define RGF_USER_XPM_IFC_RD_TIME9 (0x880d0c) +#define RGF_USER_XPM_IFC_RD_TIME10 (0x880d10) +#define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -284,22 +299,33 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) +#define USER_EXT_USER_PMU_3 (0x88d00c) + #define BIT_PMU_DEVICE_RDY BIT(0) + #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ #define JTAG_DEV_ID_SPARROW (0x2632072f) + #define JTAG_DEV_ID_TALYN (0x7e0e1) #define RGF_USER_REVISION_ID (0x88afe4) #define RGF_USER_REVISION_ID_MASK (3) #define REVISION_ID_SPARROW_B0 (0x0) #define REVISION_ID_SPARROW_D0 (0x3) +#define RGF_OTP_MAC (0x8a0620) + /* crash codes for FW/Ucode stored here */ -#define RGF_FW_ASSERT_CODE (0x91f020) -#define RGF_UCODE_ASSERT_CODE (0x91f028) + +/* ASSERT RGFs */ +#define SPARROW_RGF_FW_ASSERT_CODE (0x91f020) +#define SPARROW_RGF_UCODE_ASSERT_CODE (0x91f028) +#define TALYN_RGF_FW_ASSERT_CODE (0xa37020) +#define TALYN_RGF_UCODE_ASSERT_CODE (0xa37028) enum { HW_VER_UNKNOWN, HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */ HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */ + HW_VER_TALYN, /* JTAG_DEV_ID_TALYN */ }; /* popular locations */ @@ -315,6 +341,10 @@ enum { #define WIL_DATA_COMPLETION_TO_MS 200 /* Hardware definitions end */ +#define SPARROW_FW_MAPPING_TABLE_SIZE 10 +#define TALYN_FW_MAPPING_TABLE_SIZE 13 +#define MAX_FW_MAPPING_TABLE_SIZE 13 + struct fw_map { u32 from; /* linker address - from, inclusive */ u32 to; /* linker address - to, exclusive */ @@ -324,7 +354,10 @@ struct fw_map { }; /* array size should be in sync with actual definition in the wmi.c */ -extern const struct fw_map fw_mapping[10]; +extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE]; +extern const struct fw_map sparrow_d0_mac_rgf_ext; +extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE]; +extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE]; /** * mk_cidxtid - construct @cidxtid field @@ -570,7 +603,8 @@ enum { }; enum { - hw_capability_last + hw_capa_no_flash, + hw_capa_last }; struct wil_probe_client_req { @@ -646,7 +680,10 @@ struct wil6210_priv { u8 chip_revision; const char *hw_name; const char *wil_fw_name; - DECLARE_BITMAP(hw_capabilities, hw_capability_last); + char *board_file; + u32 brd_file_addr; + u32 brd_file_max_size; + DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); u8 n_mids; /* number of additional MIDs as reported by FW */ @@ -720,7 +757,7 @@ struct wil6210_priv { atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; - struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; + struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE]; u8 discovery_mode; u8 abft_len; u8 wakeup_trigger; @@ -755,6 +792,10 @@ struct wil6210_priv { bool suspend_resp_comp; u32 bus_request_kbps; u32 bus_request_kbps_pre_suspend; + + u32 rgf_fw_assert_code_addr; + u32 rgf_ucode_assert_code_addr; + u32 iccm_base; }; #define wil_to_wiphy(i) (i->wdev->wiphy) @@ -880,6 +921,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); +struct fw_map *wil_find_fw_mapping(const char *section); void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); @@ -1013,6 +1055,7 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_request_firmware(struct wil6210_priv *wil, const char *name, bool load); +int wil_request_board(struct wil6210_priv *wil, const char *name); bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); void wil_pm_runtime_allow(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 2ab71bb32327..b31e2514f8c2 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -70,23 +71,23 @@ MODULE_PARM_DESC(led_id, * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing * AHB addresses starting from 0x880000 * - * Internally, firmware uses addresses that allows faster access but + * Internally, firmware uses addresses that allow faster access but * are invisible from the host. To read from these addresses, alternative * AHB address must be used. - * - * Memory mapping - * Linker address PCI/Host address - * 0x880000 .. 0xa80000 2Mb BAR0 - * 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM - * 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH */ /** - * @fw_mapping provides memory remapping table + * @sparrow_fw_mapping provides memory remapping table for sparrow * * array size should be in sync with the declaration in the wil6210.h + * + * Sparrow memory mapping: + * Linker address PCI/Host address + * 0x880000 .. 0xa80000 2Mb BAR0 + * 0x800000 .. 0x808000 0x900000 .. 0x908000 32k DCCM + * 0x840000 .. 0x860000 0x908000 .. 0x928000 128k PERIPH */ -const struct fw_map fw_mapping[] = { +const struct fw_map sparrow_fw_mapping[] = { /* FW code RAM 256k */ {0x000000, 0x040000, 0x8c0000, "fw_code", true}, /* FW data RAM 32k */ @@ -112,6 +113,59 @@ const struct fw_map fw_mapping[] = { {0x800000, 0x804000, 0x940000, "uc_data", false}, }; +/** + * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0 + * it is a bit larger to support extra features + */ +const struct fw_map sparrow_d0_mac_rgf_ext = { + 0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true +}; + +/** + * @talyn_fw_mapping provides memory remapping table for Talyn + * + * array size should be in sync with the declaration in the wil6210.h + * + * Talyn memory mapping: + * Linker address PCI/Host address + * 0x880000 .. 0xc80000 4Mb BAR0 + * 0x800000 .. 0x820000 0xa00000 .. 0xa20000 128k DCCM + * 0x840000 .. 0x858000 0xa20000 .. 0xa38000 96k PERIPH + */ +const struct fw_map talyn_fw_mapping[] = { + /* FW code RAM 1M */ + {0x000000, 0x100000, 0x900000, "fw_code", true}, + /* FW data RAM 128k */ + {0x800000, 0x820000, 0xa00000, "fw_data", true}, + /* periph. data RAM 96k */ + {0x840000, 0x858000, 0xa20000, "fw_peri", true}, + /* various RGF 40k */ + {0x880000, 0x88a000, 0x880000, "rgf", true}, + /* AGC table 4k */ + {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true}, + /* Pcie_ext_rgf 4k */ + {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true}, + /* mac_ext_rgf 1344b */ + {0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true}, + /* ext USER RGF 4k */ + {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true}, + /* OTP 4k */ + {0x8a0000, 0x8a1000, 0x8a0000, "otp", true}, + /* DMA EXT RGF 64k */ + {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true}, + /* upper area 1536k */ + {0x900000, 0xa80000, 0x900000, "upper", true}, + /* UCODE areas - accessible by debugfs blobs but not by + * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas! + */ + /* ucode code RAM 256k */ + {0x000000, 0x040000, 0xa38000, "uc_code", false}, + /* ucode data RAM 32k */ + {0x800000, 0x808000, 0xa78000, "uc_data", false}, +}; + +struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE]; + struct blink_on_off_time led_blink_time[] = { {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS}, {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS}, @@ -139,6 +193,24 @@ static u32 wmi_addr_remap(u32 x) } /** + * find fw_mapping entry by section name + * @section - section name + * + * Return pointer to section or NULL if not found + */ +struct fw_map *wil_find_fw_mapping(const char *section) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) + if (fw_mapping[i].name && + !strcmp(section, fw_mapping[i].name)) + return &fw_mapping[i]; + + return NULL; +} + +/** * Check address validity for WMI buffer; remap if needed * @ptr - internal (linker) fw/ucode address * @size - if non zero, validate the block does not |