diff options
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 302 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 12 |
3 files changed, 317 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 3721c43e2941..ade1781c7186 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
| @@ -253,6 +253,9 @@ struct ath10k_vif { | |||
| 253 | u8 bssid[ETH_ALEN]; | 253 | u8 bssid[ETH_ALEN]; |
| 254 | } ibss; | 254 | } ibss; |
| 255 | } u; | 255 | } u; |
| 256 | |||
| 257 | u8 fixed_rate; | ||
| 258 | u8 fixed_nss; | ||
| 256 | }; | 259 | }; |
| 257 | 260 | ||
| 258 | struct ath10k_vif_iter { | 261 | struct ath10k_vif_iter { |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ce0f1db24731..7aa6c4d702d6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
| @@ -3339,6 +3339,307 @@ exit: | |||
| 3339 | return ret; | 3339 | return ret; |
| 3340 | } | 3340 | } |
| 3341 | 3341 | ||
| 3342 | /* Helper table for legacy fixed_rate/bitrate_mask */ | ||
| 3343 | static const u8 cck_ofdm_rate[] = { | ||
| 3344 | /* CCK */ | ||
| 3345 | 3, /* 1Mbps */ | ||
| 3346 | 2, /* 2Mbps */ | ||
| 3347 | 1, /* 5.5Mbps */ | ||
| 3348 | 0, /* 11Mbps */ | ||
| 3349 | /* OFDM */ | ||
| 3350 | 3, /* 6Mbps */ | ||
| 3351 | 7, /* 9Mbps */ | ||
| 3352 | 2, /* 12Mbps */ | ||
| 3353 | 6, /* 18Mbps */ | ||
| 3354 | 1, /* 24Mbps */ | ||
| 3355 | 5, /* 36Mbps */ | ||
| 3356 | 0, /* 48Mbps */ | ||
| 3357 | 4, /* 54Mbps */ | ||
| 3358 | }; | ||
| 3359 | |||
| 3360 | /* Check if only one bit set */ | ||
| 3361 | static int ath10k_check_single_mask(u32 mask) | ||
| 3362 | { | ||
| 3363 | int bit; | ||
| 3364 | |||
| 3365 | bit = ffs(mask); | ||
| 3366 | if (!bit) | ||
| 3367 | return 0; | ||
| 3368 | |||
| 3369 | mask &= ~BIT(bit - 1); | ||
| 3370 | if (mask) | ||
| 3371 | return 2; | ||
| 3372 | |||
| 3373 | return 1; | ||
| 3374 | } | ||
| 3375 | |||
| 3376 | static bool | ||
| 3377 | ath10k_default_bitrate_mask(struct ath10k *ar, | ||
| 3378 | enum ieee80211_band band, | ||
| 3379 | const struct cfg80211_bitrate_mask *mask) | ||
| 3380 | { | ||
| 3381 | u32 legacy = 0x00ff; | ||
| 3382 | u8 ht = 0xff, i; | ||
| 3383 | u16 vht = 0x3ff; | ||
| 3384 | |||
| 3385 | switch (band) { | ||
| 3386 | case IEEE80211_BAND_2GHZ: | ||
| 3387 | legacy = 0x00fff; | ||
| 3388 | vht = 0; | ||
| 3389 | break; | ||
| 3390 | case IEEE80211_BAND_5GHZ: | ||
| 3391 | break; | ||
| 3392 | default: | ||
| 3393 | return false; | ||
| 3394 | } | ||
| 3395 | |||
| 3396 | if (mask->control[band].legacy != legacy) | ||
| 3397 | return false; | ||
| 3398 | |||
| 3399 | for (i = 0; i < ar->num_rf_chains; i++) | ||
| 3400 | if (mask->control[band].ht_mcs[i] != ht) | ||
| 3401 | return false; | ||
| 3402 | |||
| 3403 | for (i = 0; i < ar->num_rf_chains; i++) | ||
| 3404 | if (mask->control[band].vht_mcs[i] != vht) | ||
| 3405 | return false; | ||
| 3406 | |||
| 3407 | return true; | ||
| 3408 | } | ||
| 3409 | |||
| 3410 | static bool | ||
| 3411 | ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask, | ||
| 3412 | enum ieee80211_band band, | ||
| 3413 | u8 *fixed_nss) | ||
| 3414 | { | ||
| 3415 | int ht_nss = 0, vht_nss = 0, i; | ||
| 3416 | |||
| 3417 | /* check legacy */ | ||
| 3418 | if (ath10k_check_single_mask(mask->control[band].legacy)) | ||
| 3419 | return false; | ||
| 3420 | |||
| 3421 | /* check HT */ | ||
| 3422 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { | ||
| 3423 | if (mask->control[band].ht_mcs[i] == 0xff) | ||
| 3424 | continue; | ||
| 3425 | else if (mask->control[band].ht_mcs[i] == 0x00) | ||
| 3426 | break; | ||
| 3427 | else | ||
| 3428 | return false; | ||
| 3429 | } | ||
| 3430 | |||
| 3431 | ht_nss = i; | ||
| 3432 | |||
| 3433 | /* check VHT */ | ||
| 3434 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
| 3435 | if (mask->control[band].vht_mcs[i] == 0x03ff) | ||
| 3436 | continue; | ||
| 3437 | else if (mask->control[band].vht_mcs[i] == 0x0000) | ||
| 3438 | break; | ||
| 3439 | else | ||
| 3440 | return false; | ||
| 3441 | } | ||
| 3442 | |||
| 3443 | vht_nss = i; | ||
| 3444 | |||
| 3445 | if (ht_nss > 0 && vht_nss > 0) | ||
| 3446 | return false; | ||
| 3447 | |||
| 3448 | if (ht_nss) | ||
| 3449 | *fixed_nss = ht_nss; | ||
| 3450 | else if (vht_nss) | ||
| 3451 | *fixed_nss = vht_nss; | ||
| 3452 | else | ||
| 3453 | return false; | ||
| 3454 | |||
| 3455 | return true; | ||
| 3456 | } | ||
| 3457 | |||
| 3458 | static bool | ||
| 3459 | ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask, | ||
| 3460 | enum ieee80211_band band, | ||
| 3461 | enum wmi_rate_preamble *preamble) | ||
| 3462 | { | ||
| 3463 | int legacy = 0, ht = 0, vht = 0, i; | ||
| 3464 | |||
| 3465 | *preamble = WMI_RATE_PREAMBLE_OFDM; | ||
| 3466 | |||
| 3467 | /* check legacy */ | ||
| 3468 | legacy = ath10k_check_single_mask(mask->control[band].legacy); | ||
| 3469 | if (legacy > 1) | ||
| 3470 | return false; | ||
| 3471 | |||
| 3472 | /* check HT */ | ||
| 3473 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||
| 3474 | ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]); | ||
| 3475 | if (ht > 1) | ||
| 3476 | return false; | ||
| 3477 | |||
| 3478 | /* check VHT */ | ||
| 3479 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
| 3480 | vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]); | ||
| 3481 | if (vht > 1) | ||
| 3482 | return false; | ||
| 3483 | |||
| 3484 | /* Currently we support only one fixed_rate */ | ||
| 3485 | if ((legacy + ht + vht) != 1) | ||
| 3486 | return false; | ||
| 3487 | |||
| 3488 | if (ht) | ||
| 3489 | *preamble = WMI_RATE_PREAMBLE_HT; | ||
| 3490 | else if (vht) | ||
| 3491 | *preamble = WMI_RATE_PREAMBLE_VHT; | ||
| 3492 | |||
| 3493 | return true; | ||
| 3494 | } | ||
| 3495 | |||
| 3496 | static bool | ||
| 3497 | ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, | ||
| 3498 | enum ieee80211_band band, | ||
| 3499 | u8 *fixed_rate, | ||
| 3500 | u8 *fixed_nss) | ||
| 3501 | { | ||
| 3502 | u8 rate = 0, pream = 0, nss = 0, i; | ||
| 3503 | enum wmi_rate_preamble preamble; | ||
| 3504 | |||
| 3505 | /* Check if single rate correct */ | ||
| 3506 | if (!ath10k_bitrate_mask_correct(mask, band, &preamble)) | ||
| 3507 | return false; | ||
| 3508 | |||
| 3509 | pream = preamble; | ||
| 3510 | |||
| 3511 | switch (preamble) { | ||
| 3512 | case WMI_RATE_PREAMBLE_CCK: | ||
| 3513 | case WMI_RATE_PREAMBLE_OFDM: | ||
| 3514 | i = ffs(mask->control[band].legacy) - 1; | ||
| 3515 | |||
| 3516 | if (band == IEEE80211_BAND_2GHZ && i < 4) | ||
| 3517 | pream = WMI_RATE_PREAMBLE_CCK; | ||
| 3518 | |||
| 3519 | if (band == IEEE80211_BAND_5GHZ) | ||
| 3520 | i += 4; | ||
| 3521 | |||
| 3522 | if (i >= ARRAY_SIZE(cck_ofdm_rate)) | ||
| 3523 | return false; | ||
| 3524 | |||
| 3525 | rate = cck_ofdm_rate[i]; | ||
| 3526 | break; | ||
| 3527 | case WMI_RATE_PREAMBLE_HT: | ||
| 3528 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||
| 3529 | if (mask->control[band].ht_mcs[i]) | ||
| 3530 | break; | ||
| 3531 | |||
| 3532 | if (i == IEEE80211_HT_MCS_MASK_LEN) | ||
| 3533 | return false; | ||
| 3534 | |||
| 3535 | rate = ffs(mask->control[band].ht_mcs[i]) - 1; | ||
| 3536 | nss = i; | ||
| 3537 | break; | ||
| 3538 | case WMI_RATE_PREAMBLE_VHT: | ||
| 3539 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
| 3540 | if (mask->control[band].vht_mcs[i]) | ||
| 3541 | break; | ||
| 3542 | |||
| 3543 | if (i == NL80211_VHT_NSS_MAX) | ||
| 3544 | return false; | ||
| 3545 | |||
| 3546 | rate = ffs(mask->control[band].vht_mcs[i]) - 1; | ||
| 3547 | nss = i; | ||
| 3548 | break; | ||
| 3549 | } | ||
| 3550 | |||
| 3551 | *fixed_nss = nss + 1; | ||
| 3552 | nss <<= 4; | ||
| 3553 | pream <<= 6; | ||
| 3554 | |||
| 3555 | ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", | ||
| 3556 | pream, nss, rate); | ||
| 3557 | |||
| 3558 | *fixed_rate = pream | nss | rate; | ||
| 3559 | |||
| 3560 | return true; | ||
| 3561 | } | ||
| 3562 | |||
| 3563 | static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, | ||
| 3564 | enum ieee80211_band band, | ||
| 3565 | u8 *fixed_rate, | ||
| 3566 | u8 *fixed_nss) | ||
| 3567 | { | ||
| 3568 | /* First check full NSS mask, if we can simply limit NSS */ | ||
| 3569 | if (ath10k_bitrate_mask_nss(mask, band, fixed_nss)) | ||
| 3570 | return true; | ||
| 3571 | |||
| 3572 | /* Next Check single rate is set */ | ||
| 3573 | return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss); | ||
| 3574 | } | ||
| 3575 | |||
| 3576 | static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, | ||
| 3577 | u8 fixed_rate, | ||
| 3578 | u8 fixed_nss) | ||
| 3579 | { | ||
| 3580 | struct ath10k *ar = arvif->ar; | ||
| 3581 | u32 vdev_param; | ||
| 3582 | int ret = 0; | ||
| 3583 | |||
| 3584 | mutex_lock(&ar->conf_mutex); | ||
| 3585 | |||
| 3586 | if (arvif->fixed_rate == fixed_rate && | ||
| 3587 | arvif->fixed_nss == fixed_nss) | ||
| 3588 | goto exit; | ||
| 3589 | |||
| 3590 | if (fixed_rate == WMI_FIXED_RATE_NONE) | ||
| 3591 | ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); | ||
| 3592 | |||
| 3593 | vdev_param = ar->wmi.vdev_param->fixed_rate; | ||
| 3594 | ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||
| 3595 | vdev_param, fixed_rate); | ||
| 3596 | if (ret) { | ||
| 3597 | ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n", | ||
| 3598 | fixed_rate, ret); | ||
| 3599 | ret = -EINVAL; | ||
| 3600 | goto exit; | ||
| 3601 | } | ||
| 3602 | |||
| 3603 | arvif->fixed_rate = fixed_rate; | ||
| 3604 | |||
| 3605 | vdev_param = ar->wmi.vdev_param->nss; | ||
| 3606 | ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||
| 3607 | vdev_param, fixed_nss); | ||
| 3608 | |||
| 3609 | if (ret) { | ||
| 3610 | ath10k_warn("Could not set fixed_nss param %d: %d\n", | ||
| 3611 | fixed_nss, ret); | ||
| 3612 | ret = -EINVAL; | ||
| 3613 | goto exit; | ||
| 3614 | } | ||
| 3615 | |||
| 3616 | arvif->fixed_nss = fixed_nss; | ||
| 3617 | |||
| 3618 | exit: | ||
| 3619 | mutex_unlock(&ar->conf_mutex); | ||
| 3620 | return ret; | ||
| 3621 | } | ||
| 3622 | |||
| 3623 | static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, | ||
| 3624 | struct ieee80211_vif *vif, | ||
| 3625 | const struct cfg80211_bitrate_mask *mask) | ||
| 3626 | { | ||
| 3627 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||
| 3628 | struct ath10k *ar = arvif->ar; | ||
| 3629 | enum ieee80211_band band = ar->hw->conf.chandef.chan->band; | ||
| 3630 | u8 fixed_rate = WMI_FIXED_RATE_NONE; | ||
| 3631 | u8 fixed_nss = ar->num_rf_chains; | ||
| 3632 | |||
| 3633 | if (!ath10k_default_bitrate_mask(ar, band, mask)) { | ||
| 3634 | if (!ath10k_get_fixed_rate_nss(mask, band, | ||
| 3635 | &fixed_rate, | ||
| 3636 | &fixed_nss)) | ||
| 3637 | return -EINVAL; | ||
| 3638 | } | ||
| 3639 | |||
| 3640 | return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); | ||
| 3641 | } | ||
| 3642 | |||
| 3342 | static const struct ieee80211_ops ath10k_ops = { | 3643 | static const struct ieee80211_ops ath10k_ops = { |
| 3343 | .tx = ath10k_tx, | 3644 | .tx = ath10k_tx, |
| 3344 | .start = ath10k_start, | 3645 | .start = ath10k_start, |
| @@ -3361,6 +3662,7 @@ static const struct ieee80211_ops ath10k_ops = { | |||
| 3361 | .tx_last_beacon = ath10k_tx_last_beacon, | 3662 | .tx_last_beacon = ath10k_tx_last_beacon, |
| 3362 | .restart_complete = ath10k_restart_complete, | 3663 | .restart_complete = ath10k_restart_complete, |
| 3363 | .get_survey = ath10k_get_survey, | 3664 | .get_survey = ath10k_get_survey, |
| 3665 | .set_bitrate_mask = ath10k_set_bitrate_mask, | ||
| 3364 | #ifdef CONFIG_PM | 3666 | #ifdef CONFIG_PM |
| 3365 | .suspend = ath10k_suspend, | 3667 | .suspend = ath10k_suspend, |
| 3366 | .resume = ath10k_resume, | 3668 | .resume = ath10k_resume, |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4aa1489f4eb2..4b5e7d3d32b6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
| @@ -3003,6 +3003,18 @@ struct wmi_vdev_install_key_arg { | |||
| 3003 | const void *key_data; | 3003 | const void *key_data; |
| 3004 | }; | 3004 | }; |
| 3005 | 3005 | ||
| 3006 | /* | ||
| 3007 | * vdev fixed rate format: | ||
| 3008 | * - preamble - b7:b6 - see WMI_RATE_PREMABLE_ | ||
| 3009 | * - nss - b5:b4 - ss number (0 mean 1ss) | ||
| 3010 | * - rate_mcs - b3:b0 - as below | ||
| 3011 | * CCK: 0 - 11Mbps, 1 - 5,5Mbps, 2 - 2Mbps, 3 - 1Mbps, | ||
| 3012 | * 4 - 11Mbps (s), 5 - 5,5Mbps (s), 6 - 2Mbps (s) | ||
| 3013 | * OFDM: 0 - 48Mbps, 1 - 24Mbps, 2 - 12Mbps, 3 - 6Mbps, | ||
| 3014 | * 4 - 54Mbps, 5 - 36Mbps, 6 - 18Mbps, 7 - 9Mbps | ||
| 3015 | * HT/VHT: MCS index | ||
| 3016 | */ | ||
| 3017 | |||
| 3006 | /* Preamble types to be used with VDEV fixed rate configuration */ | 3018 | /* Preamble types to be used with VDEV fixed rate configuration */ |
| 3007 | enum wmi_rate_preamble { | 3019 | enum wmi_rate_preamble { |
| 3008 | WMI_RATE_PREAMBLE_OFDM, | 3020 | WMI_RATE_PREAMBLE_OFDM, |
