aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/net/wireless/realtek/rtw88/sec.c
blob: ce46e5b4a60a2c266084c507410df8e8cb46d39c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 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);
}