1// SPDX-License-Identifier: GPL-2.0-only
2/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
9 */
10
11#include <linux/delay.h>
12#include <linux/firmware.h>
13
14#include "r8169_firmware.h"
15
16enum rtl_fw_opcode {
17	PHY_READ		= 0x0,
18	PHY_DATA_OR		= 0x1,
19	PHY_DATA_AND		= 0x2,
20	PHY_BJMPN		= 0x3,
21	PHY_MDIO_CHG		= 0x4,
22	PHY_CLEAR_READCOUNT	= 0x7,
23	PHY_WRITE		= 0x8,
24	PHY_READCOUNT_EQ_SKIP	= 0x9,
25	PHY_COMP_EQ_SKIPN	= 0xa,
26	PHY_COMP_NEQ_SKIPN	= 0xb,
27	PHY_WRITE_PREVIOUS	= 0xc,
28	PHY_SKIPN		= 0xd,
29	PHY_DELAY_MS		= 0xe,
30};
31
32struct fw_info {
33	u32	magic;
34	char	version[RTL_VER_SIZE];
35	__le32	fw_start;
36	__le32	fw_len;
37	u8	chksum;
38} __packed;
39
40#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
41
42static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
43{
44	const struct firmware *fw = rtl_fw->fw;
45	struct fw_info *fw_info = (struct fw_info *)fw->data;
46	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
47
48	if (fw->size < FW_OPCODE_SIZE)
49		return false;
50
51	if (!fw_info->magic) {
52		size_t i, size, start;
53		u8 checksum = 0;
54
55		if (fw->size < sizeof(*fw_info))
56			return false;
57
58		for (i = 0; i < fw->size; i++)
59			checksum += fw->data[i];
60		if (checksum != 0)
61			return false;
62
63		start = le32_to_cpu(fw_info->fw_start);
64		if (start > fw->size)
65			return false;
66
67		size = le32_to_cpu(fw_info->fw_len);
68		if (size > (fw->size - start) / FW_OPCODE_SIZE)
69			return false;
70
71		strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
72
73		pa->code = (__le32 *)(fw->data + start);
74		pa->size = size;
75	} else {
76		if (fw->size % FW_OPCODE_SIZE)
77			return false;
78
79		strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
80
81		pa->code = (__le32 *)fw->data;
82		pa->size = fw->size / FW_OPCODE_SIZE;
83	}
84
85	return true;
86}
87
88static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
89{
90	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
91	size_t index;
92
93	for (index = 0; index < pa->size; index++) {
94		u32 action = le32_to_cpu(pa->code[index]);
95		u32 val = action & 0x0000ffff;
96		u32 regno = (action & 0x0fff0000) >> 16;
97
98		switch (action >> 28) {
99		case PHY_READ:
100		case PHY_DATA_OR:
101		case PHY_DATA_AND:
102		case PHY_CLEAR_READCOUNT:
103		case PHY_WRITE:
104		case PHY_WRITE_PREVIOUS:
105		case PHY_DELAY_MS:
106			break;
107
108		case PHY_MDIO_CHG:
109			if (val > 1)
110				goto out;
111			break;
112
113		case PHY_BJMPN:
114			if (regno > index)
115				goto out;
116			break;
117		case PHY_READCOUNT_EQ_SKIP:
118			if (index + 2 >= pa->size)
119				goto out;
120			break;
121		case PHY_COMP_EQ_SKIPN:
122		case PHY_COMP_NEQ_SKIPN:
123		case PHY_SKIPN:
124			if (index + 1 + regno >= pa->size)
125				goto out;
126			break;
127
128		default:
129			dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
130			return false;
131		}
132	}
133
134	return true;
135out:
136	dev_err(rtl_fw->dev, "Out of range of firmware\n");
137	return false;
138}
139
140void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
141{
142	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
143	rtl_fw_write_t fw_write = rtl_fw->phy_write;
144	rtl_fw_read_t fw_read = rtl_fw->phy_read;
145	int predata = 0, count = 0;
146	size_t index;
147
148	for (index = 0; index < pa->size; index++) {
149		u32 action = le32_to_cpu(pa->code[index]);
150		u32 data = action & 0x0000ffff;
151		u32 regno = (action & 0x0fff0000) >> 16;
152		enum rtl_fw_opcode opcode = action >> 28;
153
154		if (!action)
155			break;
156
157		switch (opcode) {
158		case PHY_READ:
159			predata = fw_read(tp, regno);
160			count++;
161			break;
162		case PHY_DATA_OR:
163			predata |= data;
164			break;
165		case PHY_DATA_AND:
166			predata &= data;
167			break;
168		case PHY_BJMPN:
169			index -= (regno + 1);
170			break;
171		case PHY_MDIO_CHG:
172			if (data) {
173				fw_write = rtl_fw->mac_mcu_write;
174				fw_read = rtl_fw->mac_mcu_read;
175			} else {
176				fw_write = rtl_fw->phy_write;
177				fw_read = rtl_fw->phy_read;
178			}
179
180			break;
181		case PHY_CLEAR_READCOUNT:
182			count = 0;
183			break;
184		case PHY_WRITE:
185			fw_write(tp, regno, data);
186			break;
187		case PHY_READCOUNT_EQ_SKIP:
188			if (count == data)
189				index++;
190			break;
191		case PHY_COMP_EQ_SKIPN:
192			if (predata == data)
193				index += regno;
194			break;
195		case PHY_COMP_NEQ_SKIPN:
196			if (predata != data)
197				index += regno;
198			break;
199		case PHY_WRITE_PREVIOUS:
200			fw_write(tp, regno, predata);
201			break;
202		case PHY_SKIPN:
203			index += regno;
204			break;
205		case PHY_DELAY_MS:
206			msleep(data);
207			break;
208		}
209	}
210}
211
212void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
213{
214	release_firmware(rtl_fw->fw);
215}
216
217int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
218{
219	int rc;
220
221	rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
222	if (rc < 0)
223		goto out;
224
225	if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
226		release_firmware(rtl_fw->fw);
227		rc = -EINVAL;
228		goto out;
229	}
230
231	return 0;
232out:
233	dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
234		rtl_fw->fw_name, rc);
235	return rc;
236}
237