brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · ed6e721 Raw
234 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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		switch (opcode) {155		case PHY_READ:156			predata = fw_read(tp, regno);157			count++;158			break;159		case PHY_DATA_OR:160			predata |= data;161			break;162		case PHY_DATA_AND:163			predata &= data;164			break;165		case PHY_BJMPN:166			index -= (regno + 1);167			break;168		case PHY_MDIO_CHG:169			if (data) {170				fw_write = rtl_fw->mac_mcu_write;171				fw_read = rtl_fw->mac_mcu_read;172			} else {173				fw_write = rtl_fw->phy_write;174				fw_read = rtl_fw->phy_read;175			}176 177			break;178		case PHY_CLEAR_READCOUNT:179			count = 0;180			break;181		case PHY_WRITE:182			fw_write(tp, regno, data);183			break;184		case PHY_READCOUNT_EQ_SKIP:185			if (count == data)186				index++;187			break;188		case PHY_COMP_EQ_SKIPN:189			if (predata == data)190				index += regno;191			break;192		case PHY_COMP_NEQ_SKIPN:193			if (predata != data)194				index += regno;195			break;196		case PHY_WRITE_PREVIOUS:197			fw_write(tp, regno, predata);198			break;199		case PHY_SKIPN:200			index += regno;201			break;202		case PHY_DELAY_MS:203			msleep(data);204			break;205		}206	}207}208 209void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)210{211	release_firmware(rtl_fw->fw);212}213 214int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)215{216	int rc;217 218	rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);219	if (rc < 0)220		goto out;221 222	if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {223		release_firmware(rtl_fw->fw);224		rc = -EINVAL;225		goto out;226	}227 228	return 0;229out:230	dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",231		rtl_fw->fw_name, rc);232	return rc;233}234