162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2018-2019 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "main.h" 662306a36Sopenharmony_ci#include "sec.h" 762306a36Sopenharmony_ci#include "reg.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ciint rtw_sec_get_free_cam(struct rtw_sec_desc *sec) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci /* if default key search is enabled, the first 4 cam entries 1262306a36Sopenharmony_ci * are used to direct map to group key with its key->key_idx, so 1362306a36Sopenharmony_ci * driver should use cam entries after 4 to install pairwise key 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci if (sec->default_key_search) 1662306a36Sopenharmony_ci return find_next_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, 1762306a36Sopenharmony_ci RTW_SEC_DEFAULT_KEY_NUM); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci return find_first_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid rtw_sec_write_cam(struct rtw_dev *rtwdev, 2362306a36Sopenharmony_ci struct rtw_sec_desc *sec, 2462306a36Sopenharmony_ci struct ieee80211_sta *sta, 2562306a36Sopenharmony_ci struct ieee80211_key_conf *key, 2662306a36Sopenharmony_ci u8 hw_key_type, u8 hw_key_idx) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx]; 2962306a36Sopenharmony_ci u32 write_cmd; 3062306a36Sopenharmony_ci u32 command; 3162306a36Sopenharmony_ci u32 content; 3262306a36Sopenharmony_ci u32 addr; 3362306a36Sopenharmony_ci int i, j; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci set_bit(hw_key_idx, sec->cam_map); 3662306a36Sopenharmony_ci cam->valid = true; 3762306a36Sopenharmony_ci cam->group = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); 3862306a36Sopenharmony_ci cam->hw_key_type = hw_key_type; 3962306a36Sopenharmony_ci cam->key = key; 4062306a36Sopenharmony_ci if (sta) 4162306a36Sopenharmony_ci ether_addr_copy(cam->addr, sta->addr); 4262306a36Sopenharmony_ci else 4362306a36Sopenharmony_ci eth_broadcast_addr(cam->addr); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING; 4662306a36Sopenharmony_ci addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT; 4762306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 4862306a36Sopenharmony_ci switch (i) { 4962306a36Sopenharmony_ci case 0: 5062306a36Sopenharmony_ci content = ((key->keyidx & 0x3)) | 5162306a36Sopenharmony_ci ((hw_key_type & 0x7) << 2) | 5262306a36Sopenharmony_ci (cam->group << 6) | 5362306a36Sopenharmony_ci (cam->valid << 15) | 5462306a36Sopenharmony_ci (cam->addr[0] << 16) | 5562306a36Sopenharmony_ci (cam->addr[1] << 24); 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci case 1: 5862306a36Sopenharmony_ci content = (cam->addr[2]) | 5962306a36Sopenharmony_ci (cam->addr[3] << 8) | 6062306a36Sopenharmony_ci (cam->addr[4] << 16) | 6162306a36Sopenharmony_ci (cam->addr[5] << 24); 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case 6: 6462306a36Sopenharmony_ci case 7: 6562306a36Sopenharmony_ci content = 0; 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci default: 6862306a36Sopenharmony_ci j = (i - 2) << 2; 6962306a36Sopenharmony_ci content = (key->key[j]) | 7062306a36Sopenharmony_ci (key->key[j + 1] << 8) | 7162306a36Sopenharmony_ci (key->key[j + 2] << 16) | 7262306a36Sopenharmony_ci (key->key[j + 3] << 24); 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci command = write_cmd | (addr + i); 7762306a36Sopenharmony_ci rtw_write32(rtwdev, RTW_SEC_WRITE_REG, content); 7862306a36Sopenharmony_ci rtw_write32(rtwdev, RTW_SEC_CMD_REG, command); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid rtw_sec_clear_cam(struct rtw_dev *rtwdev, 8362306a36Sopenharmony_ci struct rtw_sec_desc *sec, 8462306a36Sopenharmony_ci u8 hw_key_idx) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx]; 8762306a36Sopenharmony_ci u32 write_cmd; 8862306a36Sopenharmony_ci u32 command; 8962306a36Sopenharmony_ci u32 addr; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci clear_bit(hw_key_idx, sec->cam_map); 9262306a36Sopenharmony_ci cam->valid = false; 9362306a36Sopenharmony_ci cam->key = NULL; 9462306a36Sopenharmony_ci eth_zero_addr(cam->addr); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING; 9762306a36Sopenharmony_ci addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT; 9862306a36Sopenharmony_ci command = write_cmd | addr; 9962306a36Sopenharmony_ci rtw_write32(rtwdev, RTW_SEC_WRITE_REG, 0); 10062306a36Sopenharmony_ci rtw_write32(rtwdev, RTW_SEC_CMD_REG, command); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciu8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct rtw_sec_desc *sec = &rtwdev->sec; 10662306a36Sopenharmony_ci u8 offset = 0; 10762306a36Sopenharmony_ci u8 count, n; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (!used_cam) 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) { 11362306a36Sopenharmony_ci n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset); 11462306a36Sopenharmony_ci if (n == RTW_MAX_SEC_CAM_NUM) 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci used_cam[count] = n; 11862306a36Sopenharmony_ci offset = n + 1; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return count; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct rtw_sec_desc *sec = &rtwdev->sec; 12762306a36Sopenharmony_ci u16 ctrl_reg; 12862306a36Sopenharmony_ci u16 sec_config; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* default use default key search for now */ 13162306a36Sopenharmony_ci sec->default_key_search = true; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ctrl_reg = rtw_read16(rtwdev, REG_CR); 13462306a36Sopenharmony_ci ctrl_reg |= RTW_SEC_ENGINE_EN; 13562306a36Sopenharmony_ci rtw_write16(rtwdev, REG_CR, ctrl_reg); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci sec_config = rtw_read16(rtwdev, RTW_SEC_CONFIG); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci sec_config |= RTW_SEC_TX_DEC_EN | RTW_SEC_RX_DEC_EN; 14062306a36Sopenharmony_ci if (sec->default_key_search) 14162306a36Sopenharmony_ci sec_config |= RTW_SEC_TX_UNI_USE_DK | RTW_SEC_RX_UNI_USE_DK | 14262306a36Sopenharmony_ci RTW_SEC_TX_BC_USE_DK | RTW_SEC_RX_BC_USE_DK; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci rtw_write16(rtwdev, RTW_SEC_CONFIG, sec_config); 14562306a36Sopenharmony_ci} 146