LCOV - code coverage report
Current view: top level - drivers/net/ethernet/realtek - r8169_firmware.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 122 0.0 %
Date: 2022-04-01 14:35:51 Functions: 0 5 0.0 %
Branches: 0 64 0.0 %

           Branch data     Line data    Source code
       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                 :            : 
      16                 :            : enum 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                 :            : 
      32                 :            : struct 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                 :            : 
      42                 :          0 : static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
      43                 :            : {
      44                 :          0 :         const struct firmware *fw = rtl_fw->fw;
      45                 :          0 :         struct fw_info *fw_info = (struct fw_info *)fw->data;
      46                 :          0 :         struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
      47                 :            : 
      48         [ #  # ]:          0 :         if (fw->size < FW_OPCODE_SIZE)
      49                 :            :                 return false;
      50                 :            : 
      51         [ #  # ]:          0 :         if (!fw_info->magic) {
      52                 :          0 :                 size_t i, size, start;
      53                 :          0 :                 u8 checksum = 0;
      54                 :            : 
      55         [ #  # ]:          0 :                 if (fw->size < sizeof(*fw_info))
      56                 :            :                         return false;
      57                 :            : 
      58         [ #  # ]:          0 :                 for (i = 0; i < fw->size; i++)
      59                 :          0 :                         checksum += fw->data[i];
      60         [ #  # ]:          0 :                 if (checksum != 0)
      61                 :            :                         return false;
      62                 :            : 
      63                 :          0 :                 start = le32_to_cpu(fw_info->fw_start);
      64         [ #  # ]:          0 :                 if (start > fw->size)
      65                 :            :                         return false;
      66                 :            : 
      67                 :          0 :                 size = le32_to_cpu(fw_info->fw_len);
      68         [ #  # ]:          0 :                 if (size > (fw->size - start) / FW_OPCODE_SIZE)
      69                 :            :                         return false;
      70                 :            : 
      71                 :          0 :                 strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
      72                 :            : 
      73                 :          0 :                 pa->code = (__le32 *)(fw->data + start);
      74                 :          0 :                 pa->size = size;
      75                 :            :         } else {
      76         [ #  # ]:          0 :                 if (fw->size % FW_OPCODE_SIZE)
      77                 :            :                         return false;
      78                 :            : 
      79                 :          0 :                 strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
      80                 :            : 
      81                 :          0 :                 pa->code = (__le32 *)fw->data;
      82                 :          0 :                 pa->size = fw->size / FW_OPCODE_SIZE;
      83                 :            :         }
      84                 :            : 
      85                 :            :         return true;
      86                 :            : }
      87                 :            : 
      88                 :          0 : static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
      89                 :            : {
      90                 :          0 :         struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
      91                 :          0 :         size_t index;
      92                 :            : 
      93         [ #  # ]:          0 :         for (index = 0; index < pa->size; index++) {
      94                 :          0 :                 u32 action = le32_to_cpu(pa->code[index]);
      95                 :          0 :                 u32 val = action & 0x0000ffff;
      96                 :          0 :                 u32 regno = (action & 0x0fff0000) >> 16;
      97                 :            : 
      98   [ #  #  #  #  :          0 :                 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                 :          0 :                 case PHY_MDIO_CHG:
     109         [ #  # ]:          0 :                         if (val > 1)
     110                 :          0 :                                 goto out;
     111                 :            :                         break;
     112                 :            : 
     113                 :          0 :                 case PHY_BJMPN:
     114         [ #  # ]:          0 :                         if (regno > index)
     115                 :          0 :                                 goto out;
     116                 :            :                         break;
     117                 :          0 :                 case PHY_READCOUNT_EQ_SKIP:
     118         [ #  # ]:          0 :                         if (index + 2 >= pa->size)
     119                 :          0 :                                 goto out;
     120                 :            :                         break;
     121                 :          0 :                 case PHY_COMP_EQ_SKIPN:
     122                 :            :                 case PHY_COMP_NEQ_SKIPN:
     123                 :            :                 case PHY_SKIPN:
     124         [ #  # ]:          0 :                         if (index + 1 + regno >= pa->size)
     125                 :          0 :                                 goto out;
     126                 :            :                         break;
     127                 :            : 
     128                 :          0 :                 default:
     129                 :          0 :                         dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
     130                 :          0 :                         return false;
     131                 :            :                 }
     132                 :            :         }
     133                 :            : 
     134                 :            :         return true;
     135                 :          0 : out:
     136                 :          0 :         dev_err(rtl_fw->dev, "Out of range of firmware\n");
     137                 :          0 :         return false;
     138                 :            : }
     139                 :            : 
     140                 :          0 : void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
     141                 :            : {
     142                 :          0 :         struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
     143                 :          0 :         rtl_fw_write_t fw_write = rtl_fw->phy_write;
     144                 :          0 :         rtl_fw_read_t fw_read = rtl_fw->phy_read;
     145                 :          0 :         int predata = 0, count = 0;
     146                 :          0 :         size_t index;
     147                 :            : 
     148         [ #  # ]:          0 :         for (index = 0; index < pa->size; index++) {
     149                 :          0 :                 u32 action = le32_to_cpu(pa->code[index]);
     150                 :          0 :                 u32 data = action & 0x0000ffff;
     151                 :          0 :                 u32 regno = (action & 0x0fff0000) >> 16;
     152                 :          0 :                 enum rtl_fw_opcode opcode = action >> 28;
     153                 :            : 
     154         [ #  # ]:          0 :                 if (!action)
     155                 :            :                         break;
     156                 :            : 
     157   [ #  #  #  #  :          0 :                 switch (opcode) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     158                 :          0 :                 case PHY_READ:
     159                 :          0 :                         predata = fw_read(tp, regno);
     160                 :          0 :                         count++;
     161                 :          0 :                         break;
     162                 :          0 :                 case PHY_DATA_OR:
     163                 :          0 :                         predata |= data;
     164                 :          0 :                         break;
     165                 :          0 :                 case PHY_DATA_AND:
     166                 :          0 :                         predata &= data;
     167                 :          0 :                         break;
     168                 :          0 :                 case PHY_BJMPN:
     169                 :          0 :                         index -= (regno + 1);
     170                 :          0 :                         break;
     171                 :          0 :                 case PHY_MDIO_CHG:
     172         [ #  # ]:          0 :                         if (data) {
     173                 :          0 :                                 fw_write = rtl_fw->mac_mcu_write;
     174                 :          0 :                                 fw_read = rtl_fw->mac_mcu_read;
     175                 :            :                         } else {
     176                 :          0 :                                 fw_write = rtl_fw->phy_write;
     177                 :          0 :                                 fw_read = rtl_fw->phy_read;
     178                 :            :                         }
     179                 :            : 
     180                 :            :                         break;
     181                 :          0 :                 case PHY_CLEAR_READCOUNT:
     182                 :          0 :                         count = 0;
     183                 :          0 :                         break;
     184                 :          0 :                 case PHY_WRITE:
     185                 :          0 :                         fw_write(tp, regno, data);
     186                 :          0 :                         break;
     187                 :          0 :                 case PHY_READCOUNT_EQ_SKIP:
     188         [ #  # ]:          0 :                         if (count == data)
     189                 :          0 :                                 index++;
     190                 :            :                         break;
     191                 :          0 :                 case PHY_COMP_EQ_SKIPN:
     192         [ #  # ]:          0 :                         if (predata == data)
     193                 :          0 :                                 index += regno;
     194                 :            :                         break;
     195                 :          0 :                 case PHY_COMP_NEQ_SKIPN:
     196         [ #  # ]:          0 :                         if (predata != data)
     197                 :          0 :                                 index += regno;
     198                 :            :                         break;
     199                 :          0 :                 case PHY_WRITE_PREVIOUS:
     200                 :          0 :                         fw_write(tp, regno, predata);
     201                 :          0 :                         break;
     202                 :          0 :                 case PHY_SKIPN:
     203                 :          0 :                         index += regno;
     204                 :          0 :                         break;
     205                 :          0 :                 case PHY_DELAY_MS:
     206                 :          0 :                         msleep(data);
     207                 :          0 :                         break;
     208                 :            :                 }
     209                 :          0 :         }
     210                 :          0 : }
     211                 :            : 
     212                 :          0 : void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
     213                 :            : {
     214                 :          0 :         release_firmware(rtl_fw->fw);
     215                 :          0 : }
     216                 :            : 
     217                 :          0 : int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
     218                 :            : {
     219                 :          0 :         int rc;
     220                 :            : 
     221                 :          0 :         rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
     222         [ #  # ]:          0 :         if (rc < 0)
     223                 :          0 :                 goto out;
     224                 :            : 
     225   [ #  #  #  # ]:          0 :         if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
     226                 :          0 :                 release_firmware(rtl_fw->fw);
     227                 :          0 :                 rc = -EINVAL;
     228                 :          0 :                 goto out;
     229                 :            :         }
     230                 :            : 
     231                 :            :         return 0;
     232                 :          0 : out:
     233                 :          0 :         dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
     234                 :            :                 rtl_fw->fw_name, rc);
     235                 :          0 :         return rc;
     236                 :            : }

Generated by: LCOV version 1.14