linux/drivers/net/wireless/realtek/rtw88/sec.c
Ping-Ke Shih 504e2b2882 rtw88: fill zeros to words 0x06 and 0x07 of security cam entry
8723D adds some experimental features to word 0x06 of cam entry, so fill
zeros to initialize them to off state. For existing chips, these two words
are reserved and always zeros, so this change is harmless for them.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200512102621.5148-9-yhchuang@realtek.com
2020-05-13 18:48:52 +03:00

146 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "sec.h"
#include "reg.h"
int rtw_sec_get_free_cam(struct rtw_sec_desc *sec)
{
/* if default key search is enabled, the first 4 cam entries
* are used to direct map to group key with its key->key_idx, so
* driver should use cam entries after 4 to install pairwise key
*/
if (sec->default_key_search)
return find_next_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM,
RTW_SEC_DEFAULT_KEY_NUM);
return find_first_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM);
}
void rtw_sec_write_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
u8 hw_key_type, u8 hw_key_idx)
{
struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx];
u32 write_cmd;
u32 command;
u32 content;
u32 addr;
int i, j;
set_bit(hw_key_idx, sec->cam_map);
cam->valid = true;
cam->group = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
cam->hw_key_type = hw_key_type;
cam->key = key;
if (sta)
ether_addr_copy(cam->addr, sta->addr);
else
eth_broadcast_addr(cam->addr);
write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING;
addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT;
for (i = 7; i >= 0; i--) {
switch (i) {
case 0:
content = ((key->keyidx & 0x3)) |
((hw_key_type & 0x7) << 2) |
(cam->group << 6) |
(cam->valid << 15) |
(cam->addr[0] << 16) |
(cam->addr[1] << 24);
break;
case 1:
content = (cam->addr[2]) |
(cam->addr[3] << 8) |
(cam->addr[4] << 16) |
(cam->addr[5] << 24);
break;
case 6:
case 7:
content = 0;
break;
default:
j = (i - 2) << 2;
content = (key->key[j]) |
(key->key[j + 1] << 8) |
(key->key[j + 2] << 16) |
(key->key[j + 3] << 24);
break;
}
command = write_cmd | (addr + i);
rtw_write32(rtwdev, RTW_SEC_WRITE_REG, content);
rtw_write32(rtwdev, RTW_SEC_CMD_REG, command);
}
}
void rtw_sec_clear_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
u8 hw_key_idx)
{
struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx];
u32 write_cmd;
u32 command;
u32 addr;
clear_bit(hw_key_idx, sec->cam_map);
cam->valid = false;
cam->key = NULL;
eth_zero_addr(cam->addr);
write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING;
addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT;
command = write_cmd | addr;
rtw_write32(rtwdev, RTW_SEC_WRITE_REG, 0);
rtw_write32(rtwdev, RTW_SEC_CMD_REG, command);
}
u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
u8 offset = 0;
u8 count, n;
if (!used_cam)
return 0;
for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) {
n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset);
if (n == RTW_MAX_SEC_CAM_NUM)
break;
used_cam[count] = n;
offset = n + 1;
}
return count;
}
void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
u16 ctrl_reg;
u16 sec_config;
/* default use default key search for now */
sec->default_key_search = true;
ctrl_reg = rtw_read16(rtwdev, REG_CR);
ctrl_reg |= RTW_SEC_ENGINE_EN;
rtw_write16(rtwdev, REG_CR, ctrl_reg);
sec_config = rtw_read16(rtwdev, RTW_SEC_CONFIG);
sec_config |= RTW_SEC_TX_DEC_EN | RTW_SEC_RX_DEC_EN;
if (sec->default_key_search)
sec_config |= RTW_SEC_TX_UNI_USE_DK | RTW_SEC_RX_UNI_USE_DK |
RTW_SEC_TX_BC_USE_DK | RTW_SEC_RX_BC_USE_DK;
rtw_write16(rtwdev, RTW_SEC_CONFIG, sec_config);
}