1 /*
   2 * CDDL HEADER START
   3 *
   4 * The contents of this file are subject to the terms of the
   5 * Common Development and Distribution License, v.1,  (the "License").
   6 * You may not use this file except in compliance with the License.
   7 *
   8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9 * or http://opensource.org/licenses/CDDL-1.0.
  10 * See the License for the specific language governing permissions
  11 * and limitations under the License.
  12 *
  13 * When distributing Covered Code, include this CDDL HEADER in each
  14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15 * If applicable, add the following below this CDDL HEADER, with the
  16 * fields enclosed by brackets "[]" replaced with your own identifying
  17 * information: Portions Copyright [yyyy] [name of copyright owner]
  18 *
  19 * CDDL HEADER END
  20 */
  21 
  22 /*
  23 * Copyright 2014-2017 Cavium, Inc. 
  24 * The contents of this file are subject to the terms of the Common Development 
  25 * and Distribution License, v.1,  (the "License").
  26 
  27 * You may not use this file except in compliance with the License.
  28 
  29 * You can obtain a copy of the License at available 
  30 * at http://opensource.org/licenses/CDDL-1.0
  31 
  32 * See the License for the specific language governing permissions and 
  33 * limitations under the License.
  34 */
  35 
  36 /*
  37  * Copyright 2018 Joyent, Inc.
  38  */
  39 
  40 #include "bcm_osal.h"
  41 #include "ecore.h"
  42 #include "reg_addr.h"
  43 #include "ecore_hw.h"
  44 #include "ecore_hsi_common.h"
  45 #include "ecore_mcp.h"
  46 #include "nvm_cfg.h"
  47 #include "ecore_phy_api.h"
  48 
  49 #define SERDESID 0x900e
  50 
  51 
  52 enum _ecore_status_t ecore_phy_read(struct ecore_hwfn *p_hwfn,
  53                                     struct ecore_ptt *p_ptt, u32 port, u32 lane,
  54                                     u32 addr, u32 cmd, u8 *buf)
  55 {
  56         return ecore_mcp_phy_read(p_hwfn->p_dev, cmd,
  57                         addr | (lane << 16) | (1<<29) | (port << 30), buf, 8);
  58 }
  59 
  60 enum _ecore_status_t ecore_phy_write(struct ecore_hwfn *p_hwfn,
  61                                      struct ecore_ptt *p_ptt, u32 port,
  62                                      u32 lane, u32 addr, u32 data_lo,
  63                                      u32 data_hi, u32 cmd)
  64 {
  65         u8 buf64[8] = {0};
  66 
  67         OSAL_MEMCPY(buf64, &data_lo, 4);
  68         OSAL_MEMCPY(buf64 + 4, &data_hi, 4);
  69 
  70         return ecore_mcp_phy_write(p_hwfn->p_dev, cmd,
  71                         addr | (lane << 16) | (1<<29) | (port << 30),
  72                                  buf64, 8);
  73 }
  74 
  75 /* phy core write */
  76 int ecore_phy_core_write(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
  77                           u32 port, u32 addr, u32 data_lo, u32 data_hi,
  78                           char *p_phy_result_buf)
  79 {
  80         enum _ecore_status_t rc = ECORE_INVAL;
  81 
  82         if (port > 3) {
  83                 OSAL_SPRINTF(p_phy_result_buf,
  84                              "ERROR! Port must be in range of 0..3\n");
  85                 return rc;
  86         }
  87 
  88         /* write to address */
  89         rc = ecore_phy_write(p_hwfn, p_ptt, port, 0 /* lane */, addr, data_lo,
  90                              data_hi, ECORE_PHY_CORE_WRITE);
  91         if (rc == ECORE_SUCCESS)
  92                 OSAL_SPRINTF(p_phy_result_buf, "0\n");
  93         else
  94                 OSAL_SPRINTF(p_phy_result_buf,
  95                              "Failed placing phy_core command\n");
  96 
  97         return rc;
  98 }
  99 
 100 /* phy core read */
 101 int ecore_phy_core_read(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 102                          u32 port, u32 addr, char *p_phy_result_buf)
 103 {
 104         enum _ecore_status_t rc = ECORE_INVAL;
 105         u8 buf64[8] = {0};
 106         u8 data_hi[4];
 107         u8 data_lo[4];
 108 
 109         if (port > 3) {
 110                 OSAL_SPRINTF(p_phy_result_buf,
 111                              "ERROR! Port must be in range of 0..3\n");
 112                 return rc;
 113         }
 114 
 115         /* read from address */
 116         rc = ecore_phy_read(p_hwfn, p_ptt, port, 0 /* lane */ , addr,
 117                             ECORE_PHY_CORE_READ, buf64);
 118         if (rc == ECORE_SUCCESS) {
 119                 OSAL_MEMCPY(data_lo, buf64, 4);
 120                 OSAL_MEMCPY(data_hi, (buf64 + 4), 4);
 121                 OSAL_SPRINTF(p_phy_result_buf, "0x%08x%08x\n",
 122                              *(u32 *)data_hi, *(u32 *)data_lo);
 123         }
 124         else
 125                 OSAL_SPRINTF(p_phy_result_buf, "Failed placing phy_core command\n");
 126 
 127         return rc;
 128 }
 129 
 130 /* phy raw write */
 131 int ecore_phy_raw_write(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 132                          u32 port, u32 lane, u32 addr, u32 data_lo,
 133                          u32 data_hi, char *p_phy_result_buf)
 134 {
 135         enum _ecore_status_t rc = ECORE_INVAL;
 136 
 137         /* check if the enterd port is in the range */
 138         if (port > 3) {
 139                 OSAL_SPRINTF(p_phy_result_buf,
 140                              "Port must be in range of 0..3\n");
 141                 return rc;
 142         }
 143 
 144         /* check if the enterd lane is in the range */
 145         if (lane > 6) {
 146                 OSAL_SPRINTF(p_phy_result_buf,
 147                              "Lane must be in range of 0..6\n");
 148                 return rc;
 149         }
 150 
 151         /* write to address*/
 152         rc = ecore_phy_write(p_hwfn,p_ptt, port, lane, addr, data_lo,
 153                              data_hi, ECORE_PHY_RAW_WRITE);
 154         if (rc == ECORE_SUCCESS)
 155                 OSAL_SPRINTF(p_phy_result_buf, "0\n");
 156         else
 157                 OSAL_SPRINTF(p_phy_result_buf,
 158                              "Failed placing phy_core command\n");
 159 
 160         return rc;
 161 }
 162 
 163 /* phy raw read */
 164 int ecore_phy_raw_read(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 165                         u32 port, u32 lane, u32 addr, char *p_phy_result_buf)
 166 {
 167         enum _ecore_status_t rc = ECORE_INVAL;
 168         u8 buf64[8] = {0};
 169         u8 data_hi[4];
 170         u8 data_lo[4];
 171 
 172         /* check if the enterd port is in the range */
 173         if (port > 3) {
 174                 OSAL_SPRINTF(p_phy_result_buf,
 175                              "Port must be in range of 0..3\n");
 176                 return rc;
 177         }
 178 
 179         /* check if the enterd lane is in the range */
 180         if (lane > 6) {
 181                 OSAL_SPRINTF(p_phy_result_buf,
 182                              "Lane must be in range of 0..6\n");
 183                 return rc;
 184         }
 185 
 186         /* read from address */
 187         rc = ecore_phy_read(p_hwfn,p_ptt, port, lane, addr, ECORE_PHY_RAW_READ,
 188                             buf64);
 189         if (rc == ECORE_SUCCESS) {
 190                 OSAL_MEMCPY(data_lo, buf64, 4);
 191                 OSAL_MEMCPY(data_hi, (buf64 + 4), 4);
 192                 OSAL_SPRINTF(p_phy_result_buf, "0x%08x%08x\n",
 193                              *(u32 *)data_hi, *(u32 *)data_lo);
 194         } else {
 195                 OSAL_SPRINTF(p_phy_result_buf,
 196                              "Failed placing phy_core command\n");
 197         }
 198 
 199         return rc;
 200 }
 201 
 202 static u32 ecore_phy_get_nvm_cfg1_addr(struct ecore_hwfn *p_hwfn,
 203                                        struct ecore_ptt *p_ptt)
 204 {
 205         u32 nvm_cfg_addr, nvm_cfg1_offset;
 206 
 207         nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0);
 208         nvm_cfg1_offset = ecore_rd(p_hwfn, p_ptt, nvm_cfg_addr +
 209                                    offsetof(struct nvm_cfg,
 210                                             sections_offset[NVM_CFG_SECTION_NVM_CFG1]));
 211         return MCP_REG_SCRATCH + nvm_cfg1_offset;
 212 }
 213 
 214 /* get phy info */
 215 int ecore_phy_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 216                     char *p_phy_result_buf)
 217 {
 218         u32 nvm_cfg1_addr = ecore_phy_get_nvm_cfg1_addr(p_hwfn, p_ptt);
 219         u32 port_mode, port, max_ports, core_cfg, length = 0;
 220         enum _ecore_status_t rc = ECORE_INVAL;
 221         u8 buf64[8] = {0};
 222         u8 data_hi[4];
 223         u8 data_lo[4];
 224 
 225         u8 is_bb = ((ecore_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_NUM) & 0x8070)
 226                     != 0x8070);
 227 
 228         if (is_bb)
 229                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 230                                        "Device: BB ");
 231         else
 232                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 233                                        "Device: AH ");
 234 
 235         core_cfg = ecore_rd(p_hwfn, p_ptt, nvm_cfg1_addr +
 236                             offsetof(struct nvm_cfg1, glob.core_cfg));
 237         port_mode = (core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >>
 238                 NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET;
 239         switch (port_mode) {
 240         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G:
 241                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "1x100G\n");
 242                 max_ports = 1;
 243                 break;
 244         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G:
 245                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "1x40G\n");
 246                 max_ports = 1;
 247                 break;
 248         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G:
 249                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "1x25G\n");
 250                 max_ports = 1;
 251                 break;
 252         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G:
 253                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "2x40G\n");
 254                 max_ports = 2;
 255                 break;
 256         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G:
 257                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "2x50G\n");
 258                 max_ports = 2;
 259                 break;
 260         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G:
 261                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "2x25G\n");
 262                 max_ports = 2;
 263                 break;
 264         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X10G:
 265                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "2x10G\n");
 266                 max_ports = 2;
 267                 break;
 268         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F:
 269                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "4x10G\n");
 270                 max_ports = 4;
 271                 break;
 272         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E:
 273                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "4x10G\n");
 274                 max_ports = 4;
 275                 break;
 276         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G:
 277                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "4x20G\n");
 278                 max_ports = 4;
 279                 break;
 280         case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G:
 281                 length += OSAL_SPRINTF(&p_phy_result_buf[length], "4x25G\n");
 282                 max_ports = 4;
 283                 break;
 284         default:
 285                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 286                                       "Wrong port mode\n");
 287                 return rc;
 288         }
 289 
 290         if (is_bb) {
 291                 for (port = 0; port < max_ports; port++) {
 292                         rc = ecore_phy_read(p_hwfn, p_ptt, port, 0, SERDESID,
 293                                             DRV_MSG_CODE_PHY_RAW_READ, buf64);
 294                         if (rc == ECORE_SUCCESS) {
 295                                 length += OSAL_SPRINTF(
 296                                         &p_phy_result_buf[length],
 297                                         "Port %d is in ", port);
 298                                 OSAL_MEMCPY(data_lo, buf64, 4);
 299                                 OSAL_MEMCPY(data_hi, (buf64 + 4), 4);
 300                                 if ((data_lo[0] & 0x3f) == 0x14)
 301                                         length += OSAL_SPRINTF(
 302                                                 &p_phy_result_buf[length],
 303                                                 "Falcon\n");
 304                                 else
 305                                         length += OSAL_SPRINTF(
 306                                                 &p_phy_result_buf[length],
 307                                                 "Eagle\n");
 308                         }
 309                 }
 310         } else {
 311                 /* @@@TMP until ecore_phy_read() on AH is supported */
 312                 for (port = 0; port < max_ports; port++)
 313                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 314                                                "Port %d is in MPS25\n", port);
 315                 rc = ECORE_SUCCESS;
 316         }
 317 
 318         return rc;
 319 }
 320 
 321 struct tsc_stat {
 322         u32 reg;
 323         char *name;
 324         char *desc;
 325 };
 326 
 327 static struct tsc_stat ah_stat_regs[] = {
 328         {0x000100, "ETHERSTATSOCTETS               ", "total, good and bad"},
 329 /*      {0x000104, "ETHERSTATSOCTETS_H             ", "total, good and bad"},*/
 330         {0x000108, "OCTETSOK                       ", "total, good"},
 331 /*      {0x00010c, "OCTETSOK_H                     ", "total, good"}, */
 332         {0x000110, "AALIGNMENTERRORS               ", "Wrong SFD detected"},
 333 /*      {0x000114, "AALIGNMENTERRORS_H             ", "Wrong SFD detected"}, */
 334         {0x000118, "APAUSEMACCTRLFRAMES            ", "Good Pause frames received"},
 335 /*      {0x00011c, "APAUSEMACCTRLFRAMES_H          ", "Good Pause frames received"}, */
 336         {0x000120, "FRAMESOK                       ", "Good frames received"},
 337 /*      {0x000124, "FRAMESOK_H                     ", "Good frames received"}, */
 338         {0x000128, "CRCERRORS                      ", "wrong CRC and good length received"},
 339 /*      {0x00012c, "CRCERRORS_H                    ", "wrong CRC and good length received"}, */
 340         {0x000130, "VLANOK                         ", "Good Frames with VLAN tag received"},
 341 /*      {0x000134, "VLANOK_H                       ", "Good Frames with VLAN tag received"}, */
 342         {0x000138, "IFINERRORS                     ", "Errored frames received"},
 343 /*      {0x00013c, "IFINERRORS_H                   ", "Errored frames received"}, */
 344         {0x000140, "IFINUCASTPKTS                  ", "Good Unicast received"},
 345 /*      {0x000144, "IFINUCASTPKTS_H                ", "Good Unicast received"}, */
 346         {0x000148, "IFINMCASTPKTS                  ", "Good Multicast received"},
 347 /*      {0x00014c, "IFINMCASTPKTS_H                ", "Good Multicast received"}, */
 348         {0x000150, "IFINBCASTPKTS                  ", "Good Broadcast received"},
 349 /*      {0x000154, "IFINBCASTPKTS_H                ", "Good Broadcast received"}, */
 350         {0x000158, "ETHERSTATSDROPEVENTS           ", "Dropped frames"},
 351 /*      {0x00015c, "ETHERSTATSDROPEVENTS_H         ", "Dropped frames"}, */
 352         {0x000160, "ETHERSTATSPKTS                 ", "Frames received, good and bad"},
 353 /*      {0x000164, "ETHERSTATSPKTS_H               ", "Frames received, good and bad"}, */
 354         {0x000168, "ETHERSTATSUNDERSIZEPKTS        ", "Frames received less 64 with good crc"},
 355 /*      {0x00016c, "ETHERSTATSUNDERSIZEPKTS_H      ", "Frames received less 64 with good crc"}, */
 356         {0x000170, "ETHERSTATSPKTS64               ", "Frames of 64 octets received"},
 357 /*      {0x000174, "ETHERSTATSPKTS64_H             ", "Frames of 64 octets received"}, */
 358         {0x000178, "ETHERSTATSPKTS65TO127          ", "Frames of 65 to 127 octets received"},
 359 /*       {0x00017c, "ETHERSTATSPKTS65TO127_H        ", "Frames of 65 to 127 octets received"}, */
 360         {0x000180, "ETHERSTATSPKTS128TO255         ", "Frames of 128 to 255 octets received"},
 361 /*      {0x000184, "ETHERSTATSPKTS128TO255_H       ", "Frames of 128 to 255 octets received"}, */
 362         {0x000188, "ETHERSTATSPKTS256TO511         ", "Frames of 256 to 511 octets received"},
 363 /*      {0x00018c, "ETHERSTATSPKTS256TO511_H       ", "Frames of 256 to 511 octets received"},*/
 364         {0x000190, "ETHERSTATSPKTS512TO1023        ", "Frames of 512 to 1023 octets received"},
 365 /*      {0x000194, "ETHERSTATSPKTS512TO1023_H      ", "Frames of 512 to 1023 octets received"},*/
 366         {0x000198, "ETHERSTATSPKTS1024TO1518       ", "Frames of 1024 to 1518 octets received"},
 367 /*      {0x00019c, "ETHERSTATSPKTS1024TO1518_H     ", "Frames of 1024 to 1518 octets received"},*/
 368         {0x0001a0, "ETHERSTATSPKTS1519TOMAX        ", "Frames of 1519 to FRM_LENGTH octets received"},
 369 /*      {0x0001a4, "ETHERSTATSPKTS1519TOMAX_H      ", "Frames of 1519 to FRM_LENGTH octets received"},*/
 370         {0x0001a8, "ETHERSTATSPKTSOVERSIZE         ", "Frames greater FRM_LENGTH and good CRC received"},
 371 /*      {0x0001ac, "ETHERSTATSPKTSOVERSIZE_H       ", "Frames greater FRM_LENGTH and good CRC received"},*/
 372         {0x0001b0, "ETHERSTATSJABBERS              ", "Frames greater FRM_LENGTH and bad CRC received"},
 373 /*      {0x0001b4, "ETHERSTATSJABBERS_H            ", "Frames greater FRM_LENGTH and bad CRC received"},*/
 374         {0x0001b8, "ETHERSTATSFRAGMENTS            ", "Frames less 64 and bad CRC received"},
 375 /*      {0x0001bc, "ETHERSTATSFRAGMENTS_H          ", "Frames less 64 and bad CRC received"},*/
 376         {0x0001c0, "AMACCONTROLFRAMES              ", "Good frames received of type 0x8808 but not Pause"},
 377 /*      {0x0001c4, "AMACCONTROLFRAMES_H            ", "Good frames received of type 0x8808 but not Pause"},*/
 378         {0x0001c8, "AFRAMETOOLONG                  ", "Good and bad frames exceeding FRM_LENGTH received"},
 379 /*      {0x0001cc, "AFRAMETOOLONG_H                ", "Good and bad frames exceeding FRM_LENGTH received"},*/
 380         {0x0001d0, "AINRANGELENGTHERROR            ", "Good frames with invalid length field (not supported)"},
 381 /*      {0x0001d4, "AINRANGELENGTHERROR_H          ", "Good frames with invalid length field (not supported)"},*/
 382         {0x000200, "TXETHERSTATSOCTETS             ", "total, good and bad"},
 383 /*      {0x000204, "TXETHERSTATSOCTETS_H           ", "total, good and bad"},*/
 384         {0x000208, "TXOCTETSOK                     ", "total, good"},
 385 /*      {0x00020c, "TXOCTETSOK_H                   ", "total, good"},*/
 386         {0x000218, "TXAPAUSEMACCTRLFRAMES          ", "Good Pause frames transmitted"},
 387 /*      {0x00021c, "TXAPAUSEMACCTRLFRAMES_H        ", "Good Pause frames transmitted"},*/
 388         {0x000220, "TXFRAMESOK                     ", "Good frames transmitted"},
 389 /*      {0x000224, "TXFRAMESOK_H                   ", "Good frames transmitted"},*/
 390         {0x000228, "TXCRCERRORS                    ", "wrong CRC transmitted"},
 391 /*      {0x00022c, "TXCRCERRORS_H                  ", "wrong CRC transmitted"},*/
 392         {0x000230, "TXVLANOK                       ", "Good Frames with VLAN tag transmitted"},
 393 /*      {0x000234, "TXVLANOK_H                     ", "Good Frames with VLAN tag transmitted"},*/
 394         {0x000238, "IFOUTERRORS                    ", "Errored frames transmitted"},
 395 /*      {0x00023c, "IFOUTERRORS_H                  ", "Errored frames transmitted"},*/
 396         {0x000240, "IFOUTUCASTPKTS                 ", "Good Unicast transmitted"},
 397 /*      {0x000244, "IFOUTUCASTPKTS_H               ", "Good Unicast transmitted"},*/
 398         {0x000248, "IFOUTMCASTPKTS                 ", "Good Multicast transmitted"},
 399 /*      {0x00024c, "IFOUTMCASTPKTS_H               ", "Good Multicast transmitted"},*/
 400         {0x000250, "IFOUTBCASTPKTS                 ", "Good Broadcast transmitted"},
 401 /*      {0x000254, "IFOUTBCASTPKTS_H               ", "Good Broadcast transmitted"},*/
 402         {0x000258, "TXETHERSTATSDROPEVENTS         ", "Dropped frames (unused, reserved)"},
 403 /*      {0x00025c, "TXETHERSTATSDROPEVENTS_H       ", "Dropped frames (unused, reserved)"},*/
 404         {0x000260, "TXETHERSTATSPKTS               ", "Frames transmitted, good and bad"},
 405 /*      {0x000264, "TXETHERSTATSPKTS_H             ", "Frames transmitted, good and bad"},*/
 406         {0x000268, "TXETHERSTATSUNDERSIZEPKTS      ", "Frames transmitted less 64"},
 407 /*      {0x00026c, "TXETHERSTATSUNDERSIZEPKTS_H    ", "Frames transmitted less 64"},*/
 408         {0x000270, "TXETHERSTATSPKTS64             ", "Frames of 64 octets transmitted"},
 409 /*      {0x000274, "TXETHERSTATSPKTS64_H           ", "Frames of 64 octets transmitted"},*/
 410         {0x000278, "TXETHERSTATSPKTS65TO127        ", "Frames of 65 to 127 octets transmitted"},
 411 /*      {0x00027c, "TXETHERSTATSPKTS65TO127_H      ", "Frames of 65 to 127 octets transmitted"},*/
 412         {0x000280, "TXETHERSTATSPKTS128TO255       ", "Frames of 128 to 255 octets transmitted"},
 413 /*      {0x000284, "TXETHERSTATSPKTS128TO255_H     ", "Frames of 128 to 255 octets transmitted"},*/
 414         {0x000288, "TXETHERSTATSPKTS256TO511       ", "Frames of 256 to 511 octets transmitted"},
 415 /*      {0x00028c, "TXETHERSTATSPKTS256TO511_H     ", "Frames of 256 to 511 octets transmitted"},*/
 416         {0x000290, "TXETHERSTATSPKTS512TO1023      ", "Frames of 512 to 1023 octets transmitted"},
 417 /*      {0x000294, "TXETHERSTATSPKTS512TO1023_H    ", "Frames of 512 to 1023 octets transmitted"},*/
 418         {0x000298, "TXETHERSTATSPKTS1024TO1518     ", "Frames of 1024 to 1518 octets transmitted"},
 419 /*      {0x00029c, "TXETHERSTATSPKTS1024TO1518_H   ", "Frames of 1024 to 1518 octets transmitted"},*/
 420         {0x0002a0, "TXETHERSTATSPKTS1519TOTX_MTU   ", "Frames of 1519 to FRM_LENGTH.TX_MTU octets transmitted"},
 421 /*      {0x0002a4, "TXETHERSTATSPKTS1519TOTX_MTU_H ", "Frames of 1519 to FRM_LENGTH.TX_MTU octets transmitted"},*/
 422         {0x0002c0, "TXAMACCONTROLFRAMES            ", "Good frames transmitted of type 0x8808 but not Pause"},
 423 /*      {0x0002c4, "TXAMACCONTROLFRAMES_H          ", "Good frames transmitted of type 0x8808 but not Pause"},*/
 424         {0x000380, "ACBFCPAUSEFRAMESRECEIVED_0     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 425 /*      {0x000384, "ACBFCPAUSEFRAMESRECEIVED_0_H   ", "Upper 32bit of 64bit counter."},*/
 426         {0x000388, "ACBFCPAUSEFRAMESRECEIVED_1     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 427 /*      {0x00038c, "ACBFCPAUSEFRAMESRECEIVED_1_H   ", "Upper 32bit of 64bit counter."},*/
 428         {0x000390, "ACBFCPAUSEFRAMESRECEIVED_2     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 429 /*      {0x000394, "ACBFCPAUSEFRAMESRECEIVED_2_H   ", "Upper 32bit of 64bit counter."},*/
 430         {0x000398, "ACBFCPAUSEFRAMESRECEIVED_3     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 431 /*      {0x00039c, "ACBFCPAUSEFRAMESRECEIVED_3_H   ", "Upper 32bit of 64bit counter."},*/
 432         {0x0003a0, "ACBFCPAUSEFRAMESRECEIVED_4     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 433 /*      {0x0003a4, "ACBFCPAUSEFRAMESRECEIVED_4_H   ", "Upper 32bit of 64bit counter."},*/
 434         {0x0003a8, "ACBFCPAUSEFRAMESRECEIVED_5     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 435 /*      {0x0003ac, "ACBFCPAUSEFRAMESRECEIVED_5_H   ", "Upper 32bit of 64bit counter."},*/
 436         {0x0003b0, "ACBFCPAUSEFRAMESRECEIVED_6     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 437 /*      {0x0003b4, "ACBFCPAUSEFRAMESRECEIVED_6_H   ", "Upper 32bit of 64bit counter."},*/
 438         {0x0003b8, "ACBFCPAUSEFRAMESRECEIVED_7     ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames received for each class."},
 439 /*      {0x0003bc, "ACBFCPAUSEFRAMESRECEIVED_7_H   ", "Upper 32bit of 64bit counter."},*/
 440         {0x0003c0, "ACBFCPAUSEFRAMESTRANSMITTED_0  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 441 /*      {0x0003c4, "ACBFCPAUSEFRAMESTRANSMITTED_0_H", "Upper 32bit of 64bit counter."},*/
 442         {0x0003c8, "ACBFCPAUSEFRAMESTRANSMITTED_1  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 443 /*      {0x0003cc, "ACBFCPAUSEFRAMESTRANSMITTED_1_H", "Upper 32bit of 64bit counter."},*/
 444         {0x0003d0, "ACBFCPAUSEFRAMESTRANSMITTED_2  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 445 /*      {0x0003d4, "ACBFCPAUSEFRAMESTRANSMITTED_2_H", "Upper 32bit of 64bit counter."},*/
 446         {0x0003d8, "ACBFCPAUSEFRAMESTRANSMITTED_3  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 447 /*      {0x0003dc, "ACBFCPAUSEFRAMESTRANSMITTED_3_H", "Upper 32bit of 64bit counter."},*/
 448         {0x0003e0, "ACBFCPAUSEFRAMESTRANSMITTED_4  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 449 /*      {0x0003e4, "ACBFCPAUSEFRAMESTRANSMITTED_4_H", "Upper 32bit of 64bit counter."},*/
 450         {0x0003e8, "ACBFCPAUSEFRAMESTRANSMITTED_5  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 451 /*      {0x0003ec, "ACBFCPAUSEFRAMESTRANSMITTED_5_H", "Upper 32bit of 64bit counter."},*/
 452         {0x0003f0, "ACBFCPAUSEFRAMESTRANSMITTED_6  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 453 /*      {0x0003f4, "ACBFCPAUSEFRAMESTRANSMITTED_6_H", "Upper 32bit of 64bit counter."},*/
 454         {0x0003f8, "ACBFCPAUSEFRAMESTRANSMITTED_7  ", "Set of 8 objects recording the number of CBFC (Class Based Flow Control) pause frames transmitted for each class."},
 455 /*      {0x0003fc, "ACBFCPAUSEFRAMESTRANSMITTED_7_H", "Upper 32bit of 64bit counter."}*/
 456 };
 457 static struct tsc_stat bb_stat_regs[] = {
 458     {0x00000000, "GRX64","RX 64-byte frame counter" },
 459     {0x00000001, "GRX127","RX 65 to 127 byte frame counter" },
 460     {0x00000002, "GRX255","RX 128 to 255 byte frame counter" },
 461     {0x00000003, "GRX511","RX 256 to 511 byte frame counter" },
 462     {0x00000004, "GRX1023","RX 512 to 1023 byte frame counter" },
 463     {0x00000005, "GRX1518","RX 1024 to 1518 byte frame counter" },
 464     {0x00000006, "GRX1522","RX 1519 to 1522 byte VLAN-tagged frame counter" },
 465     {0x00000007, "GRX2047","RX 1519 to 2047 byte frame counter" },
 466     {0x00000008, "GRX4095","RX 2048 to 4095 byte frame counter" },
 467     {0x00000009, "GRX9216","RX 4096 to 9216 byte frame counter" },
 468     {0x0000000a, "GRX16383","RX 9217 to 16383 byte frame counter" },
 469     {0x0000000b, "GRXPKT","RX frame counter (all packets)" },
 470     {0x0000000c, "GRXUCA","RX UC frame counter" },
 471     {0x0000000d, "GRXMCA","RX MC frame counter" },
 472     {0x0000000e, "GRXBCA","RX BC frame counter" },
 473     {0x0000000f, "GRXFCS","RX FCS error frame counter" },
 474     {0x00000010, "GRXCF","RX control frame counter" },
 475     {0x00000011, "GRXPF","RX pause frame counter" },
 476     {0x00000012, "GRXPP","RX PFC frame counter" },
 477     {0x00000013, "GRXUO","RX unsupported opcode frame counter" },
 478     {0x00000014, "GRXUDA","RX unsupported DA for pause/PFC frame counter" },
 479     {0x00000015, "GRXWSA","RX incorrect SA counter" },
 480     {0x00000016, "GRXALN","RX alignment error counter" },
 481     {0x00000017, "GRXFLR","RX out-of-range length frame counter" },
 482     {0x00000018, "GRXFRERR","RX code error frame counter" },
 483     {0x00000019, "GRXFCR","RX false carrier counter" },
 484     {0x0000001a, "GRXOVR","RX oversized frame counter" },
 485     {0x0000001b, "GRXJBR","RX jabber frame counter" },
 486     {0x0000001c, "GRXMTUE","RX MTU check error frame counter" },
 487     {0x0000001d, "GRXMCRC",
 488             "RX packet with 4-Byte CRC matching MACSEC_PROG_TX_CRC." },
 489     {0x0000001e, "GRXPRM","RX promiscuous packet counter" },
 490     {0x0000001f, "GRXVLN","RX single and double VLAN tagged frame counter" },
 491     {0x00000020, "GRXDVLN","RX double VLANG tagged frame counter" },
 492     {0x00000021, "GRXTRFU","RX truncated frame (due to RX FIFO full) counter" },
 493     {0x00000022, "GRXPOK","RX good frame (good CRC, not oversized, no ERROR)" },
 494     {0x00000023, "GRXPFCOFF0",
 495             "RX PFC frame transition XON to XOFF for Priority0" },
 496     {0x00000024, "GRXPFCOFF1",
 497             "RX PFC frame transition XON to XOFF for Priority1" },
 498     {0x00000025, "GRXPFCOFF2",
 499             "RX PFC frame transition XON to XOFF for Priority2" },
 500     {0x00000026, "GRXPFCOFF3",
 501             "RX PFC frame transition XON to XOFF for Priority3" },
 502     {0x00000027, "GRXPFCOFF4",
 503             "RX PFC frame transition XON to XOFF for Priority4" },
 504     {0x00000028, "GRXPFCOFF5",
 505             "RX PFC frame transition XON to XOFF for Priority5" },
 506     {0x00000029, "GRXPFCOFF6",
 507             "RX PFC frame transition XON to XOFF for Priority6" },
 508     {0x0000002a, "GRXPFCOFF7",
 509             "RX PFC frame transition XON to XOFF for Priority7" },
 510     {0x0000002b, "GRXPFCP0","RX PFC frame with enable bit set for Priority0" },
 511     {0x0000002c, "GRXPFCP1","RX PFC frame with enable bit set for Priority1" },
 512     {0x0000002d, "GRXPFCP2","RX PFC frame with enable bit set for Priority2" },
 513     {0x0000002e, "GRXPFCP3","RX PFC frame with enable bit set for Priority3" },
 514     {0x0000002f, "GRXPFCP4","RX PFC frame with enable bit set for Priority4" },
 515     {0x00000030, "GRXPFCP5","RX PFC frame with enable bit set for Priority5" },
 516     {0x00000031, "GRXPFCP6","RX PFC frame with enable bit set for Priority6" },
 517     {0x00000032, "GRXPFCP7","RX PFC frame with enable bit set for Priority7" },
 518     {0x00000033, "GRXSCHCRC","RX frame with SCH CRC error. For LH mode only" },
 519     {0x00000034, "GRXUND","RX undersized frame counter" },
 520     {0x00000035, "GRXFRG","RX fragment counter" },
 521     {0x00000036, "RXEEELPI", "RX EEE LPI counter"},
 522     {0x00000037, "RXEEELPIDU", "RX EEE LPI duration counter"},
 523     {0x00000038, "RXLLFCPHY", "RX LLFC PHY COUNTER"},
 524     {0x00000039, "RXLLFCLOG", "RX LLFC LOG COUNTER"},
 525     {0x0000003a, "RXLLFCCRC", "RX LLFC CRC COUNTER"},
 526     {0x0000003b, "RXHCFC", "RX HCFC COUNTER"},
 527     {0x0000003c, "RXHCFCCRC", "RX HCFC CRC COUNTER"},
 528     {0x0000003d, "GRXBYT", "RX byte counter"},
 529     {0x0000003e, "GRXRBYT", "RX runt byte counter"},
 530     {0x0000003f, "GRXRPKT", "RX packet counter"},
 531     {0x00000040, "GTX64", "TX 64-byte frame counter"},
 532     {0x00000041, "GTX127", "TX 65 to 127 byte frame counter"},
 533     {0x00000042, "GTX255", "TX 128 to 255 byte frame counter"},
 534     {0x00000043, "GTX511", "TX 256 to 511 byte frame counter"},
 535     {0x00000044, "GTX1023", "TX 512 to 1023 byte frame counter"},
 536     {0x00000045, "GTX1518", "TX 1024 to 1518 byte frame counter"},
 537     {0x00000046, "GTX1522", "TX 1519 to 1522 byte VLAN-tagged frame counter"},
 538     {0x00000047, "GTX2047", "TX 1519 to 2047 byte frame counter"},
 539     {0x00000048, "GTX4095", "TX 2048 to 4095 byte frame counte"},
 540     {0x00000049, "GTX9216", "TX 4096 to 9216 byte frame counter"},
 541     {0x0000004a, "GTX16383", "TX 9217 to 16383 byte frame counter"},
 542     {0x0000004b, "GTXPOK", "TX good frame counter"},
 543     {0x0000004c, "GTXPKT", "TX frame counter (all packets"},
 544     {0x0000004d, "GTXUCA", "TX UC frame counter"},
 545     {0x0000004e, "GTXMCA", "TX MC frame counter"},
 546     {0x0000004f, "GTXBCA", "TX BC frame counter"},
 547     {0x00000050, "GTXPF", "TX pause frame counter"},
 548     {0x00000051, "GTXPP", "TX PFC frame counter"},
 549     {0x00000052, "GTXJBR", "TX jabber counter"},
 550     {0x00000053, "GTXFCS", "TX FCS error counter"},
 551     {0x00000054, "GTXCF", "TX control frame counter"},
 552     {0x00000055, "GTXOVR", "TX oversize packet counter"},
 553     {0x00000056, "GTXDFR", "TX Single Deferral Frame Counter"},
 554     {0x00000057, "GTXEDF", "TX Multiple Deferral Frame Counter"},
 555     {0x00000058, "GTXSCL", "TX Single Collision Frame Counter"},
 556     {0x00000059, "GTXMCL", "TX Multiple Collision Frame Counter"},
 557     {0x0000005a, "GTXLCL", "TX Late Collision Frame Counter"},
 558     {0x0000005b, "GTXXCL", "TX Excessive Collision Frame Counter"},
 559     {0x0000005c, "GTXFRG", "TX fragment counter"},
 560     {0x0000005d, "GTXERR", "TX error (set by system) frame counter"},
 561     {0x0000005e, "GTXVLN", "TX VLAN Tag Frame Counter"},
 562     {0x0000005f, "GTXDVLN", "TX Double VLAN Tag Frame Counter"},
 563     {0x00000060, "GTXRPKT", "TX RUNT Frame Counter"},
 564     {0x00000061, "GTXUFL", "TX FIFO Underrun Counter"},
 565     {0x00000062, "GTXPFCP0", "TX PFC frame with enable bit set for Priority0"},
 566     {0x00000063, "GTXPFCP1", "TX PFC frame with enable bit set for Priority1"},
 567     {0x00000064, "GTXPFCP2", "TX PFC frame with enable bit set for Priority2"},
 568     {0x00000065, "GTXPFCP3", "TX PFC frame with enable bit set for Priority3"},
 569     {0x00000066, "GTXPFCP4", "TX PFC frame with enable bit set for Priority4"},
 570     {0x00000067, "GTXPFCP5", "TX PFC frame with enable bit set for Priority5"},
 571     {0x00000068, "GTXPFCP6", "TX PFC frame with enable bit set for Priority6"},
 572     {0x00000069, "GTXPFCP7", "TX PFC frame with enable bit set for Priority7"},
 573     {0x0000006a, "TXEEELPI", "TX EEE LPI Event Counter"},
 574     {0x0000006b, "TXEEELPIDU", "TX EEE LPI Duration Counter"},
 575     {0x0000006c, "TXLLFCLOG", "Transmit Logical Type LLFC message counter"},
 576     {0x0000006d, "TXHCFC", "Transmit Logical Type LLFC message counter"},
 577     {0x0000006e, "GTXNCL", "Transmit Total Collision Counter"},
 578     {0x0000006f, "GTXBYT", "TX byte counter"}
 579 };
 580 
 581 /* get mac status */
 582 static int ecore_bb_phy_mac_stat(struct ecore_hwfn *p_hwfn,
 583                                  struct ecore_ptt *p_ptt,
 584                                  u32 port, char *p_phy_result_buf)
 585 {
 586         u8 buf64[8] = {0}, data_hi[4], data_lo[4];
 587         bool b_false_alarm = false;
 588         u32 length, reg_id, addr;
 589         enum _ecore_status_t rc = ECORE_INVAL;
 590 
 591         length = OSAL_SPRINTF(p_phy_result_buf,
 592                                "MAC stats for port %d (only non-zero)\n", port);
 593 
 594         for (reg_id = 0; reg_id < OSAL_ARRAY_SIZE(bb_stat_regs); reg_id++) {
 595                 addr = bb_stat_regs[reg_id].reg;
 596                 rc = ecore_phy_read(p_hwfn, p_ptt, port, 0 /*lane*/, addr,
 597                                     ECORE_PHY_CORE_READ, buf64);
 598 
 599                 OSAL_MEMCPY(data_lo, buf64, 4);
 600                 OSAL_MEMCPY(data_hi, (buf64 + 4), 4);
 601 
 602                 if (rc == ECORE_SUCCESS) {
 603                         if (*(u32 *)data_lo != 0) {  /* Only non-zero */
 604                                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 605                                                        "%-10s: 0x%08x (%s)\n",
 606                                                        bb_stat_regs[reg_id].name,
 607                                                        *(u32 *)data_lo,
 608                                                        bb_stat_regs[reg_id].desc); 
 609                                 if ((bb_stat_regs[reg_id].reg == 0x0000000f) ||
 610                                     (bb_stat_regs[reg_id].reg == 0x00000018) ||
 611                                     (bb_stat_regs[reg_id].reg == 0x00000035))
 612                                         b_false_alarm = true;
 613                         }
 614                 } else {
 615                         OSAL_SPRINTF(p_phy_result_buf, "Failed reading stat 0x%x\n\n",
 616                                      addr); 
 617                 }
 618         }
 619 
 620         if (b_false_alarm)
 621                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 622                                        "Note: GRXFCS/GRXFRERR/GRXFRG may "
 623                                        "increment when the port shuts down\n");
 624 
 625         return rc;
 626 }
 627 
 628 /* get mac status */
 629 static int ecore_ah_e5_phy_mac_stat(struct ecore_hwfn *p_hwfn,
 630                                     struct ecore_ptt *p_ptt, u32 port,
 631                                     char *p_phy_result_buf)
 632 {
 633         u32 length, reg_id, addr, data_hi __unused, data_lo;
 634 
 635         length = OSAL_SPRINTF(p_phy_result_buf,
 636                                "MAC stats for port %d (only non-zero)\n", port);
 637 
 638         for (reg_id = 0; reg_id < OSAL_ARRAY_SIZE(ah_stat_regs); reg_id++) {
 639                 addr = ah_stat_regs[reg_id].reg;
 640                 data_lo = ecore_rd(p_hwfn, p_ptt,
 641                                    NWM_REG_MAC0_K2_E5 +
 642                                    NWM_REG_MAC0_SIZE * 4 * port +
 643                                    addr);
 644                 data_hi = ecore_rd(p_hwfn, p_ptt,
 645                                    NWM_REG_MAC0_K2_E5 +
 646                                    NWM_REG_MAC0_SIZE * 4 * port +
 647                                    addr + 4);
 648 
 649                 if (data_lo) {  /* Only non-zero */
 650                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 651                                                "%-10s: 0x%08x (%s)\n",
 652                                                ah_stat_regs[reg_id].name,
 653                                                data_lo,
 654                                                ah_stat_regs[reg_id].desc);
 655                 }
 656         }
 657 
 658         return ECORE_SUCCESS;
 659 }
 660 
 661 int ecore_phy_mac_stat(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 662                         u32 port, char *p_phy_result_buf)
 663 {
 664         int num_ports = ecore_device_num_ports(p_hwfn->p_dev);
 665 
 666         if (port >= (u32)num_ports) {
 667                 OSAL_SPRINTF(p_phy_result_buf,
 668                              "Port must be in range of 0..%d\n", num_ports);
 669                 return ECORE_INVAL;
 670         }
 671 
 672         if (ECORE_IS_BB(p_hwfn->p_dev))
 673                 return ecore_bb_phy_mac_stat(p_hwfn, p_ptt, port,
 674                                              p_phy_result_buf);
 675         else
 676                 return ecore_ah_e5_phy_mac_stat(p_hwfn, p_ptt, port,
 677                                                 p_phy_result_buf);
 678 }
 679 
 680 #define SFP_RX_LOS_OFFSET 110
 681 #define SFP_TX_DISABLE_OFFSET 110
 682 #define SFP_TX_FAULT_OFFSET 110
 683 
 684 #define QSFP_RX_LOS_OFFSET 3
 685 #define QSFP_TX_DISABLE_OFFSET 86
 686 #define QSFP_TX_FAULT_OFFSET 4
 687 
 688 /* Set SFP error string */
 689 static int ecore_sfp_set_error(enum _ecore_status_t rc, u32 offset,
 690                                char *p_phy_result_buf, char *p_err_str)
 691 {
 692         if (rc != ECORE_SUCCESS) {
 693                 if (rc == ECORE_NODEV)
 694                         OSAL_SPRINTF((char *)&p_phy_result_buf[offset],
 695                                      "Transceiver is unplugged.\n");
 696                 else
 697                         OSAL_SPRINTF((char *)&p_phy_result_buf[offset], "%s",
 698                                      p_err_str);
 699 
 700                 return ECORE_UNKNOWN_ERROR;
 701         }
 702 
 703         return rc;
 704 }
 705 
 706 /* Validate SFP port */
 707 static int ecore_validate_sfp_port(struct ecore_hwfn *p_hwfn,
 708                                    struct ecore_ptt *p_ptt,
 709                                    u32 port, char *p_phy_result_buf)
 710 {
 711         /* Verify <port> field is between 0 and number of ports */
 712         u32 num_ports = ecore_device_num_ports(p_hwfn->p_dev);
 713 
 714         if (port >= num_ports) {
 715                 if (num_ports == 1)
 716                         OSAL_SPRINTF(p_phy_result_buf,
 717                                      "Bad port number, must be 0.\n");
 718                 else
 719                         OSAL_SPRINTF(p_phy_result_buf,
 720                                      "Bad port number, must be between 0 and %d.\n",
 721                                      num_ports-1);
 722 
 723                 return ECORE_INVAL;
 724         }
 725 
 726         return ECORE_SUCCESS;
 727 }
 728 
 729 /* Validate SFP parameters */
 730 static int ecore_validate_sfp_parameters(struct ecore_hwfn *p_hwfn,
 731                                          struct ecore_ptt *p_ptt,
 732                                          u32 port, u32 addr, u32 offset,
 733                                          u32 size, char *p_phy_result_buf)
 734 {
 735         enum _ecore_status_t rc;
 736 
 737         /* Verify <port> field is between 0 and number of ports */
 738         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
 739         if (rc != ECORE_SUCCESS)
 740                 return rc;
 741 
 742         /* Verify <I2C> field is 0xA0 or 0xA2 */
 743         if ((addr != 0xA0) && (addr != 0xA2)) {
 744                 OSAL_SPRINTF(p_phy_result_buf,
 745                              "Bad I2C address, must be 0xA0 or 0xA2.\n");
 746                 return ECORE_INVAL;
 747         }
 748 
 749         /* Verify <size> field is 1 - MAX_I2C_TRANSCEIVER_PAGE_SIZE */
 750         if ((size == 0) || (size > MAX_I2C_TRANSCEIVER_PAGE_SIZE)) {
 751                 OSAL_SPRINTF(p_phy_result_buf,
 752                              "Bad size, must be between 1 and %d.\n",
 753                              MAX_I2C_TRANSCEIVER_PAGE_SIZE);
 754                 return ECORE_INVAL;
 755         }
 756 
 757         /* Verify <offset> + <size> <= MAX_I2C_TRANSCEIVER_PAGE_SIZE */
 758         if (offset + size > MAX_I2C_TRANSCEIVER_PAGE_SIZE) {
 759                 OSAL_SPRINTF(p_phy_result_buf,
 760                              "Bad offset and size, must not exceed %d.\n",
 761                              MAX_I2C_TRANSCEIVER_PAGE_SIZE);
 762                 return ECORE_INVAL;
 763         }
 764 
 765         return rc;
 766 }
 767 
 768 /* Write to SFP */
 769 int ecore_phy_sfp_write(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 770                         u32 port, u32 addr, u32 offset, u32 size,
 771                         u32 val, char *p_phy_result_buf)
 772 {
 773         enum _ecore_status_t rc;
 774 
 775         rc = ecore_validate_sfp_parameters(p_hwfn, p_ptt, port, addr,
 776                                            offset, size, p_phy_result_buf);
 777         if (rc == ECORE_SUCCESS)
 778         {
 779                 rc = ecore_mcp_phy_sfp_write(p_hwfn, p_ptt, port, addr,
 780                                              offset, size, (u8 *)&val);
 781 
 782                 if (rc != ECORE_SUCCESS)
 783                         return ecore_sfp_set_error(rc, 0, p_phy_result_buf,
 784                                                    "Error writing to transceiver.\n");
 785 
 786                 OSAL_SPRINTF(p_phy_result_buf,
 787                              "Written successfully to transceiver.\n");
 788         }
 789 
 790         return rc;
 791 }
 792 
 793 /* Read from SFP */
 794 int ecore_phy_sfp_read(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 795                        u32 port, u32 addr, u32 offset,
 796                        u32 size, char *p_phy_result_buf)
 797 {
 798         enum _ecore_status_t rc;
 799         u32 i;
 800 
 801         rc = ecore_validate_sfp_parameters(p_hwfn, p_ptt, port, addr,
 802                                            offset, size, p_phy_result_buf);
 803         if (rc == ECORE_SUCCESS)
 804         {
 805                 int length = 0;
 806                 u8 buf[MAX_I2C_TRANSCEIVER_PAGE_SIZE];
 807 
 808                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, addr,
 809                                             offset, size, buf);
 810                 if (rc != ECORE_SUCCESS)
 811                         return ecore_sfp_set_error(rc, 0, p_phy_result_buf,
 812                                                    "Error reading from transceiver.\n");
 813                 for (i = 0; i < size; i++)
 814                         length += OSAL_SPRINTF(
 815                                 (char *)&p_phy_result_buf[length],
 816                                 "%02x ", buf[i]);
 817         }
 818 
 819         return rc;
 820 }
 821 
 822 static enum _ecore_status_t ecore_decode_sfp_info(struct ecore_hwfn *p_hwfn,
 823                                                   struct ecore_ptt *p_ptt,
 824                                                   u32 port, u32 length,
 825                                                   char *p_phy_result_buf)
 826 {
 827         /* SFP EEPROM contents are described in SFF-8024 and SFF-8472 */
 828         /***********************************************/
 829         /* SFP DATA and locations                      */
 830         /* get specification complianace bytes 3-10    */
 831         /* get signal rate byte 12                     */
 832         /* get extended compliance code byte 36        */
 833         /* get vendor length bytes 14-19               */
 834         /* get vendor name bytes bytes 20-35           */
 835         /* get vendor OUI bytes 37-39                  */
 836         /* get vendor PN  bytes 40-55                  */
 837         /* get vendor REV bytes 56-59                  */
 838         /* validated                                   */
 839         /***********************************************/
 840         enum _ecore_status_t rc;
 841         u8 buf[32];
 842 
 843         /* Read byte 12 - signal rate, and if nothing matches */
 844         /* check byte 8 for 10G copper                        */
 845         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
 846                                     12, 1, buf);
 847         if (rc != ECORE_SUCCESS)
 848                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
 849                                            "Error reading specification compliance field.\n");
 850 
 851         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 852                                "BYTE 12 signal rate: %d\n", buf[0]);
 853 
 854         if (buf[0] >= 250) {
 855                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 856                                        "25G signal rate: %d\n", buf[0]);
 857                 /* 25G - This should be copper - could double check */
 858                 /* Read byte 3 - optics, and if nothing matches     */
 859                 /* check byte 8 for 10G copper                      */
 860                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
 861                                             I2C_TRANSCEIVER_ADDR, 3, 1, buf);
 862                 if (rc != ECORE_SUCCESS)
 863                         return ecore_sfp_set_error(rc, length,
 864                                                    p_phy_result_buf,
 865                                                    "Error reading optics field.\n");
 866 
 867                 switch (buf[0]) {
 868                 case 1:
 869                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 870                                                "25G Passive copper detected\n");
 871                         break;
 872                 case 2:
 873                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 874                                                "25G Active copper detected\n");
 875                         break;
 876                 default:
 877                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 878                                                "UNKNOWN 25G cable detected: %x\n",
 879                                                buf[0]);
 880                         break;
 881                 }
 882 
 883         } else if (buf[3] >= 100) {
 884                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 885                                        "10G signal rate: %d\n", buf[0]);
 886                 /* 10G - Read byte 3 for optics and byte 8 for copper, and */
 887                 /* byte 2 for AOC                                          */
 888                 /* Read byte 3 - optics, and if nothing matches check byte */
 889                 /* 8 for 10G copper                                        */
 890                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
 891                                         I2C_TRANSCEIVER_ADDR, 3, 1, buf);
 892                 if (rc != ECORE_SUCCESS)
 893                         return ecore_sfp_set_error(rc, length,
 894                                                    p_phy_result_buf,
 895                                                    "Error reading optics field.\n");
 896 
 897                 switch (buf[0]) {
 898                 case 0x10:
 899                         /* 10G SR */
 900                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 901                                                "10G SR detected\n");
 902                         break;
 903                 case 0x20:
 904                         /* 10G LR */
 905                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 906                                                "10G LR detected\n");
 907                         break;
 908                 case 0x40:
 909                         /* 10G LRM */
 910                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 911                                                "10G LRM detected\n");
 912                         break;
 913                 case 0x80:
 914                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 915                                                "10G ER detected\n");
 916                         break;
 917                 default:
 918                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 919                                                "SFP/SFP+/SFP-28 transceiver type 0x%x not known...  Check for 10G copper.\n",
 920                                                buf[0]);
 921                         /* Read 3, check 8 too */
 922                         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
 923                                                     I2C_TRANSCEIVER_ADDR,
 924                                                     8, 1, buf);
 925                         if (rc != ECORE_SUCCESS)
 926                                 return ecore_sfp_set_error(rc, length,
 927                                                            p_phy_result_buf,
 928                                                            "Error reading 10G copper field.\n");
 929 
 930                         switch (buf[0]) {
 931                         case 0x04:
 932                         case 0x84:
 933                                 length += OSAL_SPRINTF(
 934                                         &p_phy_result_buf[length],
 935                                         "10G Passive copper detected\n");
 936                                 break;
 937                         case 0x08:
 938                         case 0x88:
 939                                 length += OSAL_SPRINTF(
 940                                         &p_phy_result_buf[length],
 941                                         "10G Active copper detected\n");
 942                                 break;
 943                         default:
 944                                 length += OSAL_SPRINTF(
 945                                         &p_phy_result_buf[length],
 946                                         "Unexpected SFP/SFP+/SFP-28 transceiver type 0x%x\n",
 947                                         buf[3]);
 948                                 break;
 949                         } /* switch byte 8 */
 950 
 951                 } /* switch byte 3 */
 952 
 953         } else if (buf[0] >= 10) {
 954                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
 955                                        "1G signal rate: %d\n", buf[3]);
 956                 /* 1G -  Read byte 6 for optics and byte 8 for copper */
 957                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
 958                                             I2C_TRANSCEIVER_ADDR, 6, 1, buf);
 959                 if (rc != ECORE_SUCCESS)
 960                         return ecore_sfp_set_error(rc, length,
 961                                                    p_phy_result_buf,
 962                                                    "Error reading optics field.\n");
 963 
 964                 switch (buf[0]) {
 965                 case 1:
 966                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 967                                                "1G SX detected\n");
 968                         break;
 969                 case 2:
 970                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 971                                                "1G LX detected\n");
 972                         break;
 973                 default:
 974                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 975                                                "Assume 1G Passive copper detected\n");
 976                         break;
 977                 }
 978         }
 979 
 980         /* get vendor length bytes 14-19 */
 981         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
 982                                     14, 6, buf);
 983         if (rc != ECORE_SUCCESS)
 984                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
 985                                            "Error reading vendor length bytes.\n");
 986 
 987         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 988                                "Length (SMF, km) 0x%x\n", buf[0]);
 989         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 990                                "Length (SMF) 0x%x\n", buf[1]);
 991         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 992                                "Length (50 um) 0x%x\n", buf[2]);
 993         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 994                                "Length (62.5 um) 0x%x\n", buf[3]);
 995         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 996                                "Length (OM4 or copper cable) 0x%x\n", buf[4]);
 997         length += OSAL_SPRINTF(&p_phy_result_buf[length],
 998                                "Length (OM3) 0x%x\n", buf[5]);
 999 
1000         /* get vendor name bytes bytes 20-35 */
1001         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1002                                     20, 16, buf);
1003         if (rc != ECORE_SUCCESS)
1004                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1005                                            "Error reading vendor name.\n");
1006 
1007         buf[16] = 0;
1008         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1009                                "Vendor name: %s\n", buf);
1010 
1011         /* get vendor OUI bytes 37-39 */
1012         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1013                                     37, 3, buf);
1014         if (rc != ECORE_SUCCESS)
1015                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1016                                            "Error reading vendor OUI.\n");
1017 
1018         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1019                                "Vendor OUI: %02x%02x%02x\n",
1020                                buf[0], buf[1], buf[2]);
1021 
1022         /* get vendor PN  bytes 40-55 */
1023         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1024                                     40, 16, buf);
1025         if (rc != ECORE_SUCCESS)
1026                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1027                                            "Error reading vendor PN.\n");
1028 
1029         buf[16] = 0;
1030         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1031                                "Vendor PN: %s\n", buf);
1032 
1033         /* get vendor REV bytes 56-59 */
1034         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1035                                     56, 4, buf);
1036         if (rc != ECORE_SUCCESS)
1037                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1038                                            "Error reading vendor rev.\n");
1039 
1040         buf[4] = 0;
1041         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1042                                "Vendor rev: %s\n", buf);
1043 
1044         return rc;
1045 }
1046 
1047 static enum _ecore_status_t ecore_decode_qsfp_info(struct ecore_hwfn *p_hwfn,
1048                                                    struct ecore_ptt *p_ptt,
1049                                                    u32 port, u32 length,
1050                                                    char *p_phy_result_buf)
1051 {
1052         /* QSFP EEPROM contents are described in SFF-8024 and SFF-8636 */
1053         /***********************************************/
1054         /* QSFP DATA and locations                     */
1055         /* get specification complianace bytes 131-138 */
1056         /* get extended rate select bytes 141          */
1057         /* get vendor length bytes 142-146             */
1058         /* get device technology byte 147              */
1059         /* get vendor name bytes bytes 148-163         */
1060         /* get vendor OUI bytes 165-167                */
1061         /* get vendor PN  bytes 168-183                */
1062         /* get vendor REV bytes 184-185                */
1063         /* validated                                   */
1064         /***********************************************/
1065         enum _ecore_status_t rc;
1066         u8 buf[32];
1067 
1068         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1069                                     131, 1, buf);
1070         if (rc != ECORE_SUCCESS)
1071                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1072                                            "Error reading transceiver compliance code.\n");
1073 
1074         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1075                                "Transceiver compliance code 0x%x\n", buf[0]);
1076 
1077         switch (buf[0]) {
1078         case 0x1:
1079                 /* 40G Active (XLPPI) */
1080                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1081                                        "40G Active (XLPPI) detected.\n");
1082                 break;
1083         case 0x2:
1084                 /* 40G LR-4 */
1085                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1086                                        "40G LR-4 detected.\n");
1087                 break;
1088         case 0x4:
1089                 /* 40G SR-4 */
1090                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1091                                        "40G SR-4 detected.\n");
1092                 break;
1093         case 0x8:
1094                 /* 40G CR-4 */
1095                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1096                                        "40G CR-4 detected.\n");
1097                 break;
1098         case 0x10:
1099                 /* 10G SR */
1100                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1101                                        "10G SR detected.\n");
1102                 break;
1103         case 0x20:
1104                 /* 10G LR */
1105                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1106                                        "10G LR detected.\n");
1107                 break;
1108         case 0x40:
1109                 /* 10G LRM */
1110                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1111                                        "10G LRM detected.\n");
1112                 break;
1113         case 0x88: /* Could be 40G/100G CR4 cable, check 192 for 100G CR4 */
1114                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1115                                        "Multi-rate transceiver: 40G CR-4 detected...\n");
1116                 break;
1117         case 0x80:
1118                 /* Use extended technology field */
1119                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1120                                        "Use extended technology field\n");
1121                 /* Byte 93 & 129 is supposed to have power info. During    */
1122                 /* testing all reads 0.  Ignore for now                    */
1123                 /* 0-127 is in the first page  this in high region -       */
1124                 /* see what page it is.                                    */
1125                 /*  buf[3] = 0;                                            */
1126                 /*  ret_val = read_transceiver_data(g_port, i2c_addr, 129, */
1127                 /*  buf, 1);                                               */
1128                 /*  length += OSAL_SPRINTF(&p_phy_result_buf[length],      */
1129                 /*  "Read transceiver power data.  Value read: 0x%hx\n\n", */
1130                 /*  buf[3]);                                               */
1131 
1132                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1133                                             I2C_TRANSCEIVER_ADDR, 192, 1, buf);
1134                 if (rc != ECORE_SUCCESS)
1135                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1136                                                    "Error reading technology compliance field.\n");
1137 
1138                 switch (buf[0]) {
1139                 case 0:
1140                         /* Unspecified */
1141                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1142                                                "Unspecified detected.\n");
1143                         break;
1144                 case 0x1:
1145                         /* 100G AOC (active optical cable) */
1146                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1147                                                "100G AOC (active optical cable) detected\n");
1148                         break;
1149                 case 0x2:
1150                         /* 100G SR-4 */
1151                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1152                                                "100G SR-4 detected\n");
1153                         break;
1154                 case 0x3:
1155                         /* 100G LR-4 */
1156                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1157                                                "100G LR-4 detected\n");
1158                         break;
1159                 case 0x4:
1160                         /* 100G ER-4 */
1161                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1162                                                "100G ER-4 detected\n");
1163                         break;
1164                 case 0x8:
1165                         /* 100G ACC (active copper cable) */
1166                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1167                                                "100G ACC (active copper cable detected\n");
1168                         break;
1169                 case 0xb:
1170                         /* 100G CR-4 */
1171                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1172                                                "100G CR-4 detected\n");
1173                         break;
1174                 case 0x11:
1175                         /* 4x10G SR */
1176                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1177                                                "4x10G SR detected\n");
1178                         break;
1179                 default:
1180                         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1181                                                "Unexpected technology. NEW COMPLIANCE CODE TO SUPPORT 0x%x\n",
1182                                                buf[0]);
1183                         break;
1184                 }
1185                 break;
1186         default:
1187                 /* Unexpected technology compliance field */
1188                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1189                                        "WARNING: Unexpected technology compliance field detected 0x%x\n",
1190                                        buf[0]);
1191                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1192                                        "Assume SR-4 detected\n");
1193                 break;
1194         }
1195 
1196         /* get extended rate select bytes 141 */
1197         /* get vendor length bytes 142-146 */
1198         /* get device technology byte 147 */
1199         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1200                                     141, 7, buf);
1201         if (rc != ECORE_SUCCESS)
1202                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1203                                            "Error reading extended rate select bytes.\n");
1204 
1205         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1206                                "Extended rate select bytes 0x%x\n", buf[0]);
1207         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1208                                "Length (SMF) 0x%x\n", buf[1]);
1209         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1210                                "Length (OM3 50 um) 0x%x\n", buf[2]);
1211         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1212                                "Length (OM2 50 um) 0x%x\n", buf[3]);
1213         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1214                                "Length (OM1 62.5 um) 0x%x\n", buf[4]);
1215         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1216                                "Length (Passive or active) 0x%x\n", buf[5]);
1217         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1218                                "Device technology byte 0x%x\n", buf[6]);
1219 
1220         /* get vendor name bytes bytes 148-163 */
1221         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1222                                     148, 16, buf);
1223         if (rc != ECORE_SUCCESS)
1224                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1225                                            "Error reading vendor name.\n");
1226 
1227         buf[16] = 0;
1228         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1229                                "Vendor name: %s\n", buf);
1230 
1231         /* get vendor OUI bytes 165-167 */
1232         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1233                                     165, 3, buf);
1234         if (rc != ECORE_SUCCESS)
1235                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1236                                            "Error reading vendor OUI.\n");
1237 
1238         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1239                                "Vendor OUI: %02x%02x%02x\n",
1240                                buf[0], buf[1], buf[2]);
1241 
1242         /* get vendor PN  bytes 168-183 */
1243         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1244                                     168, 16, buf);
1245         if (rc != ECORE_SUCCESS)
1246                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1247                                            "Error reading vendor PN.\n");
1248 
1249         buf[16] = 0;
1250         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1251                                "Vendor PN: %s\n", buf);
1252 
1253         /* get vendor REV bytes 184-185 */
1254         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1255                                     184, 2, buf);
1256         if (rc != ECORE_SUCCESS)
1257                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1258                                            "Error reading vendor rev.\n");
1259 
1260         buf[2] = 0;
1261         length += OSAL_SPRINTF(&p_phy_result_buf[length],
1262                                "Vendor rev: %s\n", buf);
1263 
1264         return rc;
1265 }
1266 
1267 /* Decode SFP information */
1268 int ecore_phy_sfp_decode(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1269                          u32 port, char *p_phy_result_buf)
1270 {
1271         enum _ecore_status_t rc;
1272         u32 length = 0;
1273         u8 buf[4];
1274 
1275         /* Verify <port> field is between 0 and number of ports */
1276         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
1277         if (rc != ECORE_SUCCESS)
1278                 return rc;
1279 
1280         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1281                                     0, 1, buf);
1282         if (rc != ECORE_SUCCESS)
1283                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1284                                            "Error reading transceiver identification field.\n");
1285 
1286         switch (buf[0]) {
1287         case 0x3: /* SFP, SFP+, SFP-28 */
1288                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1289                                        "SFP, SFP+ or SFP-28 inserted.\n");
1290                 rc = ecore_decode_sfp_info(p_hwfn, p_ptt, port,
1291                                            length, p_phy_result_buf);
1292                 break;
1293         case 0xc: /* QSFP */
1294                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1295                                        "QSFP inserted.\n");
1296                 rc = ecore_decode_qsfp_info(p_hwfn, p_ptt, port,
1297                                             length, p_phy_result_buf);
1298                 break;
1299         case 0xd: /* QSFP+ */
1300                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1301                                        "QSFP+ inserted.\n");
1302                 rc = ecore_decode_qsfp_info(p_hwfn, p_ptt, port,
1303                                             length, p_phy_result_buf);
1304                 break;
1305         case 0x11: /* QSFP-28 */
1306                 length += OSAL_SPRINTF(&p_phy_result_buf[length],
1307                                        "QSFP-28 inserted.\n");
1308                 rc = ecore_decode_qsfp_info(p_hwfn, p_ptt, port,
1309                                             length, p_phy_result_buf);
1310                 break;
1311         case 0x12: /* CXP2 (CXP-28) */
1312                 OSAL_SPRINTF(p_phy_result_buf,
1313                              "CXP2 (CXP-28) inserted.\n");
1314                 rc = ECORE_UNKNOWN_ERROR;
1315                 break;
1316         default:
1317                 OSAL_SPRINTF(p_phy_result_buf,
1318                              "Unknown transceiver type inserted.\n");
1319                 rc = ECORE_UNKNOWN_ERROR;
1320                 break;
1321         }
1322 
1323         return rc;
1324 }
1325 
1326 /* Get SFP inserted status */
1327 int ecore_phy_sfp_get_inserted(struct ecore_hwfn *p_hwfn,
1328                                struct ecore_ptt *p_ptt,
1329                                u32 port, char *p_phy_result_buf)
1330 {
1331         u32 transceiver_state;
1332         u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
1333                                         PUBLIC_PORT);
1334         u32 mfw_mb_offsize = ecore_rd(p_hwfn, p_ptt, addr);
1335         u32 port_addr = SECTION_ADDR(mfw_mb_offsize, port);
1336 
1337         transceiver_state = ecore_rd(p_hwfn, p_ptt,
1338                                      port_addr +
1339                                      OFFSETOF(struct public_port,
1340                                               transceiver_data));
1341 
1342         transceiver_state = GET_FIELD(transceiver_state, ETH_TRANSCEIVER_STATE);
1343 
1344         OSAL_SPRINTF(p_phy_result_buf, "%d",
1345                      (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT));
1346 
1347         return ECORE_SUCCESS;
1348 }
1349 
1350 /* Get SFP TX disable status */
1351 int ecore_phy_sfp_get_txdisable(struct ecore_hwfn *p_hwfn,
1352                                 struct ecore_ptt *p_ptt,
1353                                 u32 port, char *p_phy_result_buf)
1354 {
1355         enum _ecore_status_t rc;
1356         u32 length = 0;
1357         u8 buf[4];
1358 
1359         /* Verify <port> field is between 0 and number of ports */
1360         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
1361         if (rc != ECORE_SUCCESS)
1362                 return rc;
1363 
1364         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1365                                     0, 1, buf);
1366         if (rc != ECORE_SUCCESS)
1367                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1368                                            "Error reading transceiver identification field.\n");
1369 
1370         switch (buf[0]) {
1371         case 0x3: /* SFP, SFP+, SFP-28 */
1372                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1373                                             I2C_TRANSCEIVER_ADDR, 110, 1, buf);
1374                 if (rc != ECORE_SUCCESS)
1375                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1376                                                    "Error reading transceiver tx disable status field.\n");
1377                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1378                              ((buf[0] & 0xC0) ? 1 : 0));
1379                 break;
1380         case 0xc: /* QSFP */
1381         case 0xd: /* QSFP+ */
1382         case 0x11: /* QSFP-28 */
1383                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1384                                             I2C_TRANSCEIVER_ADDR, 86, 1, buf);
1385                 if (rc != ECORE_SUCCESS)
1386                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1387                                                    "Error reading transceiver tx disable status field.\n");
1388                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1389                              ((buf[0] & ((1 << port))) ? 1 : 0));
1390                 break;
1391         default:
1392                 OSAL_SPRINTF(p_phy_result_buf,
1393                              "Unknown transceiver type inserted.\n");
1394                 rc = ECORE_UNKNOWN_ERROR;
1395                 break;
1396         }
1397 
1398         return rc;
1399 }
1400 
1401 /* Set SFP TX disable */
1402 int ecore_phy_sfp_set_txdisable(struct ecore_hwfn *p_hwfn,
1403                                 struct ecore_ptt *p_ptt,
1404                                 u32 port, u8 txdisable,
1405                                 char *p_phy_result_buf)
1406 {
1407         enum _ecore_status_t rc;
1408         u32 length = 0;
1409         u8 buf[4];
1410 
1411         /* Verify <txdisable> field is between 0 and 1 */
1412         if (txdisable > 1) {
1413                 OSAL_SPRINTF(p_phy_result_buf,
1414                              "Bad tx disable value, must be 0 or 1.\n");
1415                 return ECORE_INVAL;
1416         }
1417 
1418         /* Verify <port> field is between 0 and number of ports */
1419         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port,
1420                                      p_phy_result_buf);
1421         if (rc != ECORE_SUCCESS)
1422                 return rc;
1423 
1424         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1425                                     0, 1, buf);
1426         if (rc != ECORE_SUCCESS)
1427                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1428                                            "Error reading transceiver identification field.\n");
1429 
1430         switch (buf[0]) {
1431         case 0x3: /* SFP, SFP+, SFP-28 */
1432                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1433                                             I2C_TRANSCEIVER_ADDR,
1434                                             SFP_TX_DISABLE_OFFSET, 1, buf);
1435                 if (rc != ECORE_SUCCESS)
1436                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1437                                                    "Error reading transceiver tx disable status field.\n");
1438 
1439                 if (((buf[0] & 0x40) >> 6) != txdisable) {
1440                         buf[0] ^= 0x40;
1441                         rc = ecore_mcp_phy_sfp_write(p_hwfn, p_ptt, port,
1442                                                      I2C_TRANSCEIVER_ADDR,
1443                                                      SFP_TX_DISABLE_OFFSET,
1444                                                      1, buf);
1445                         if (rc != ECORE_SUCCESS)
1446                                 OSAL_SPRINTF(&p_phy_result_buf[length],
1447                                              "Error setting transceiver tx disable status field.\n");
1448                 }
1449 
1450                 if (((buf[0] & 0x80) >> 7) != txdisable) {
1451                         u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr;
1452                         u16 gpio;
1453 
1454                         nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt,
1455                                                 MISC_REG_GEN_PURP_CR0);
1456                         nvm_cfg1_offset = ecore_rd(p_hwfn, p_ptt,
1457                                                    nvm_cfg_addr + 4);
1458                         port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
1459                                         OFFSETOF(struct nvm_cfg1, port[port]);
1460                         gpio = (u16)ecore_rd(p_hwfn, p_ptt,
1461                                              port_cfg_addr +
1462                                              OFFSETOF(struct nvm_cfg1_port,
1463                                                       transceiver_00));
1464                         gpio &= NVM_CFG1_PORT_TRANS_MODULE_ABS_MASK;
1465                         rc = ecore_phy_gpio_write(p_hwfn, p_ptt, gpio,
1466                                                   txdisable,
1467                                                   p_phy_result_buf);
1468                         if (rc != ECORE_SUCCESS)
1469                                 OSAL_SPRINTF(&p_phy_result_buf[length],
1470                                              "Error setting transceiver tx disable status field.\n");
1471                 }
1472                 break;
1473         case 0xc: /* QSFP */
1474         case 0xd: /* QSFP+ */
1475         case 0x11: /* QSFP-28 */
1476                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1477                                             I2C_TRANSCEIVER_ADDR,
1478                                             QSFP_TX_DISABLE_OFFSET, 1, buf);
1479                 if (rc != ECORE_SUCCESS)
1480                         return ecore_sfp_set_error(rc, length,
1481                                                    p_phy_result_buf,
1482                                                    "Error reading transceiver tx disable status field.\n");
1483                 if (((buf[0] & (1 << port)) >> port) != txdisable) {
1484                         buf[0] ^= (1 << port);
1485                         rc = ecore_mcp_phy_sfp_write(p_hwfn, p_ptt, port,
1486                                                      I2C_TRANSCEIVER_ADDR,
1487                                                      QSFP_TX_DISABLE_OFFSET,
1488                                                      1, buf);
1489                         if (rc != ECORE_SUCCESS)
1490                                 OSAL_SPRINTF(&p_phy_result_buf[length],
1491                                              "Error setting transceiver tx disable status field.\n");
1492                 }
1493                 break;
1494         default:
1495                 OSAL_SPRINTF(p_phy_result_buf,
1496                              "Unknown transceiver type inserted.\n");
1497                 rc = ECORE_UNKNOWN_ERROR;
1498                 break;
1499         }
1500 
1501         return rc;
1502 }
1503 
1504 /* Get SFP TX fault status */
1505 int ecore_phy_sfp_get_txreset(struct ecore_hwfn *p_hwfn,
1506                               struct ecore_ptt *p_ptt,
1507                               u32 port, char *p_phy_result_buf)
1508 {
1509         enum _ecore_status_t rc;
1510         u32 length = 0;
1511         u8 buf[4];
1512 
1513         /* Verify <port> field is between 0 and number of ports */
1514         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
1515         if (rc != ECORE_SUCCESS)
1516                 return rc;
1517 
1518         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1519                                     0, 1, buf);
1520         if (rc != ECORE_SUCCESS)
1521                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1522                                            "Error reading transceiver identification field.\n");
1523 
1524         switch (buf[0]) {
1525         case 0x3: /* SFP, SFP+, SFP-28 */
1526                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1527                                             I2C_TRANSCEIVER_ADDR,
1528                                             SFP_TX_FAULT_OFFSET, 1, buf);
1529                 if (rc != ECORE_SUCCESS)
1530                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1531                                                    "Error reading transceiver tx fault status field.\n");
1532                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1533                              ((buf[0] & 0x02) ? 1 : 0));
1534                 break;
1535         case 0xc: /* QSFP */
1536         case 0xd: /* QSFP+ */
1537         case 0x11: /* QSFP-28 */
1538                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1539                                             I2C_TRANSCEIVER_ADDR,
1540                                             QSFP_TX_FAULT_OFFSET, 1, buf);
1541                 if (rc != ECORE_SUCCESS)
1542                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1543                                                    "Error reading transceiver tx fault status field.\n");
1544                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1545                              ((buf[0] & (1 << port)) ? 1 : 0));
1546                 break;
1547         default:
1548                 OSAL_SPRINTF(p_phy_result_buf,
1549                              "Unknown transceiver type inserted.\n");
1550                 rc = ECORE_UNKNOWN_ERROR;
1551                 break;
1552         }
1553 
1554         return rc;
1555 }
1556 
1557 /* Get SFP RX los status */
1558 int ecore_phy_sfp_get_rxlos(struct ecore_hwfn *p_hwfn,
1559                             struct ecore_ptt *p_ptt,
1560                             u32 port, char *p_phy_result_buf)
1561 {
1562         enum _ecore_status_t rc;
1563         u32 length = 0;
1564         u8 buf[4];
1565 
1566         /* Verify <port> field is between 0 and number of ports */
1567         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
1568         if (rc != ECORE_SUCCESS)
1569                 return rc;
1570 
1571         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1572                                     0, 1, buf);
1573         if (rc != ECORE_SUCCESS)
1574                 return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1575                                            "Error reading transceiver identification field.\n");
1576 
1577         switch (buf[0]) {
1578         case 0x3: /* SFP, SFP+, SFP-28 */
1579                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1580                                             I2C_TRANSCEIVER_ADDR,
1581                                             SFP_RX_LOS_OFFSET, 1, buf);
1582                 if (rc != ECORE_SUCCESS)
1583                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1584                                                    "Error reading transceiver rx los status field.\n");
1585                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1586                              ((buf[0] & 0x01) ? 1 : 0));
1587                 break;
1588         case 0xc: /* QSFP */
1589         case 0xd: /* QSFP+ */
1590         case 0x11: /* QSFP-28 */
1591                 rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port,
1592                                             I2C_TRANSCEIVER_ADDR,
1593                                             QSFP_RX_LOS_OFFSET, 1, buf);
1594                 if (rc != ECORE_SUCCESS)
1595                         return ecore_sfp_set_error(rc, length, p_phy_result_buf,
1596                                                    "Error reading transceiver rx los status field.\n");
1597                 OSAL_SPRINTF(p_phy_result_buf, "%d",
1598                              ((buf[0] & (1 << port)) ? 1 : 0));
1599                 break;
1600         default:
1601                 OSAL_SPRINTF(p_phy_result_buf,
1602                              "Unknown transceiver type inserted.\n");
1603                 rc = ECORE_UNKNOWN_ERROR;
1604                 break;
1605         }
1606 
1607         return rc;
1608 }
1609 
1610 /* Get SFP EEPROM memory dump */
1611 int ecore_phy_sfp_get_eeprom(struct ecore_hwfn *p_hwfn,
1612                              struct ecore_ptt *p_ptt,
1613                              u32 port, char *p_phy_result_buf)
1614 {
1615         enum _ecore_status_t rc;
1616         u8 buf[4];
1617 
1618         /* Verify <port> field is between 0 and number of ports */
1619         rc = ecore_validate_sfp_port(p_hwfn, p_ptt, port, p_phy_result_buf);
1620         if (rc != ECORE_SUCCESS)
1621                 return rc;
1622 
1623         rc = ecore_mcp_phy_sfp_read(p_hwfn, p_ptt, port, I2C_TRANSCEIVER_ADDR,
1624                                     0, 1, buf);
1625         if (rc != ECORE_SUCCESS)
1626                 return ecore_sfp_set_error(rc, 0, p_phy_result_buf,
1627                                            "Error reading transceiver identification field.\n");
1628 
1629         switch (buf[0]) {
1630         case 0x3: /* SFP, SFP+, SFP-28 */
1631         case 0xc: /* QSFP */
1632         case 0xd: /* QSFP+ */
1633         case 0x11: /* QSFP-28 */
1634                 rc = ecore_phy_sfp_read(p_hwfn, p_ptt, port,
1635                                         I2C_TRANSCEIVER_ADDR, 0,
1636                                         MAX_I2C_TRANSCEIVER_PAGE_SIZE,
1637                                         p_phy_result_buf);
1638                 break;
1639         default:
1640                 OSAL_SPRINTF(p_phy_result_buf,
1641                              "Unknown transceiver type inserted.\n");
1642                 rc = ECORE_UNKNOWN_ERROR;
1643                 break;
1644         }
1645 
1646         return rc;
1647 }
1648 
1649 /* Write to gpio */
1650 int ecore_phy_gpio_write(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1651                          u16 gpio, u16 gpio_val, char *p_phy_result_buf)
1652 {
1653         enum _ecore_status_t rc;
1654 
1655         rc = ecore_mcp_gpio_write(p_hwfn, p_ptt, gpio, gpio_val);
1656 
1657         if (rc == ECORE_SUCCESS)
1658                 OSAL_SPRINTF(p_phy_result_buf,
1659                              "Written successfully to gpio number %d.\n",
1660                              gpio);
1661         else
1662                 OSAL_SPRINTF(p_phy_result_buf,
1663                              "Can't write to gpio %d\n", gpio);
1664 
1665         return rc;
1666 }
1667 
1668 /* Read from gpio */
1669 int ecore_phy_gpio_read(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1670                         u16 gpio, char *p_phy_result_buf)
1671 {
1672         enum _ecore_status_t rc;
1673         u32 param;
1674 
1675         rc = ecore_mcp_gpio_read(p_hwfn, p_ptt, gpio, &param);
1676 
1677         if (rc == ECORE_SUCCESS)
1678                 OSAL_SPRINTF(p_phy_result_buf, "%x", param);
1679         else
1680                 OSAL_SPRINTF(p_phy_result_buf,
1681                              "Can't read from gpio %d\n", gpio);
1682 
1683         return rc;
1684 }
1685 
1686 /* Get information from gpio */
1687 int ecore_phy_gpio_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1688                         u16 gpio, char *p_phy_result_buf)
1689 {
1690         u32 direction, ctrl, length = 0;
1691         enum _ecore_status_t rc;
1692 
1693         rc = ecore_mcp_gpio_info(p_hwfn, p_ptt, gpio, &direction, &ctrl);
1694 
1695         if (rc != ECORE_SUCCESS) {
1696                 OSAL_SPRINTF(p_phy_result_buf,
1697                              "Can't get information for gpio %d\n", gpio);
1698                 return rc;
1699         }
1700 
1701         length = OSAL_SPRINTF(p_phy_result_buf, "Gpio %d is %s - ",
1702                               gpio,
1703                               ((direction == 0) ? "output" : "input"));
1704         switch (ctrl) {
1705         case 0:
1706                 OSAL_SPRINTF(&p_phy_result_buf[length],
1707                              "control is uninitialized\n");
1708                 break;
1709         case 1:
1710                 OSAL_SPRINTF(&p_phy_result_buf[length],
1711                              "control is path 0\n");
1712                 break;
1713         case 2:
1714                 OSAL_SPRINTF(&p_phy_result_buf[length],
1715                              "control is path 1\n");
1716                 break;
1717         case 3:
1718                 OSAL_SPRINTF(&p_phy_result_buf[length],
1719                              "control is shared\n");
1720                 break;
1721         default:
1722                 OSAL_SPRINTF(&p_phy_result_buf[length],
1723                              "\nError - control is invalid\n");
1724                 break;
1725         }
1726 
1727         return ECORE_SUCCESS;
1728 }
1729 
1730 /* Get information from gpio */
1731 int ecore_phy_extphy_read(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1732                           u16 port, u16 devad, u16 reg, char *p_phy_result_buf)
1733 {
1734         enum _ecore_status_t rc;
1735         u32 resp_cmd;
1736         u32 val;
1737 
1738         rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_EXT_PHY_READ,
1739                            ((port << DRV_MB_PARAM_PORT_SHIFT) |
1740                             (devad << DRV_MB_PARAM_DEVAD_SHIFT) |
1741                             (reg << DRV_MB_PARAM_ADDR_SHIFT)),
1742                            &resp_cmd,
1743                            &val);
1744 
1745         if ((rc != ECORE_SUCCESS) || (resp_cmd != FW_MSG_CODE_PHY_OK)) {
1746                 OSAL_SPRINTF(p_phy_result_buf,
1747                              "Failed reading external PHY\n");
1748                 return rc;
1749         }
1750         OSAL_SPRINTF(p_phy_result_buf, "0x%04x\n", val);
1751         return ECORE_SUCCESS;
1752 }
1753 
1754 /* Get information from gpio */
1755 int ecore_phy_extphy_write(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
1756                            u16 port, u16 devad, u16 reg, u16 val,
1757                            char *p_phy_result_buf)
1758 {
1759         enum _ecore_status_t rc;
1760         u32 resp_cmd;
1761         u32 fw_param;
1762 
1763         rc = ecore_mcp_nvm_wr_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_EXT_PHY_WRITE,
1764                                   ((port << DRV_MB_PARAM_PORT_SHIFT) |
1765                                    (devad << DRV_MB_PARAM_DEVAD_SHIFT) |
1766                                    (reg << DRV_MB_PARAM_ADDR_SHIFT)),
1767                                   &resp_cmd,
1768                                   &fw_param,
1769                                   sizeof(u32),
1770                                   (u32 *)&val);
1771 
1772         if ((rc != ECORE_SUCCESS) || (resp_cmd != FW_MSG_CODE_PHY_OK)) {
1773                 OSAL_SPRINTF(p_phy_result_buf,
1774                              "Failed writing external PHY\n");
1775                 return rc;
1776         }
1777         OSAL_SPRINTF(p_phy_result_buf, "0\n");
1778         return ECORE_SUCCESS;
1779 }