Newer
Older
if (!rt2x00_rf(rt2x00dev, RF2020))
spec->ht.ht_supported = true;
else
spec->ht.ht_supported = false;
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40;
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) >= 2)
spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) <<
IEEE80211_HT_CAP_RX_STBC_SHIFT;
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
((rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
switch (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
break;
}
/*
* Create channel information array
*/
info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
for (i = 0; i < 14; i++) {
info[i].default_power1 = default_power1[i];
info[i].default_power2 = default_power2[i];
}
if (spec->num_channels > 14) {
default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
for (i = 14; i < spec->num_channels; i++) {
info[i].default_power1 = default_power1[i];
info[i].default_power2 = default_power2[i];
}
}
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
/*
* IEEE80211 stack callback functions.
*/
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u16 *iv16)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct mac_iveiv_entry iveiv_entry;
u32 offset;
offset = MAC_IVEIV_ENTRY(hw_key_idx);
rt2800_register_multiread(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u32 reg;
bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD);
rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®);
rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value);
rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg);
rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®);
rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®);
rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®);
rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®);
rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®);
rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®);
rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled);
rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
struct rt2x00_field32 field;
int retval;
u32 reg;
u32 offset;
/*
* First pass the configuration through rt2x00lib, that will
* update the queue settings and validate the input. After that
* we are free to update the registers based on the value
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
if (retval)
return retval;
/*
* We only need to perform additional register initialization
* for WMM queues/
*/
if (queue_idx >= 4)
return 0;
queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
/* Update WMM TXOP register */
offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2)));
field.bit_offset = (queue_idx & 1) * 16;
field.bit_mask = 0xffff << field.bit_offset;
rt2800_register_read(rt2x00dev, offset, ®);
rt2x00_set_field32(®, field, queue->txop);
rt2800_register_write(rt2x00dev, offset, reg);
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®);
rt2x00_set_field32(®, field, queue->aifs);
rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg);
rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®);
rt2x00_set_field32(®, field, queue->cw_min);
rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg);
rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®);
rt2x00_set_field32(®, field, queue->cw_max);
rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg);
/* Update EDCA registers */
offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
rt2800_register_read(rt2x00dev, offset, ®);
rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop);
rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs);
rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min);
rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max);
rt2800_register_write(rt2x00dev, offset, reg);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_conf_tx);
u64 rt2800_get_tsf(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
u32 reg;
rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®);
tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32;
rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®);
tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD);
return tsf;
}
EXPORT_SYMBOL_GPL(rt2800_get_tsf);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
int ret = 0;
switch (action) {
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
/*
* The hw itself takes care of setting up BlockAck mechanisms.
* So, we only have to allow mac80211 to nagotiate a BlockAck
* agreement. Once that is done, the hw will BlockAck incoming
* AMPDUs without further setup.
*/
break;
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
break;
default:
WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");
EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
u32 idle, busy, busy_ext;
if (idx != 0)
return -ENOENT;
survey->channel = conf->channel;
rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
if (idle || busy) {
survey->filled = SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
survey->channel_time = (idle + busy) / 1000;
survey->channel_time_busy = busy / 1000;
survey->channel_time_ext_busy = busy_ext / 1000;
}
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_get_survey);
MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 library");
MODULE_LICENSE("GPL");