146 lines
3.5 KiB
C
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);
|
|
}
|