root/drivers/net/ethernet/mellanox/mlxsw/core_env.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_env_validate_cable_ident
  2. mlxsw_env_query_module_eeprom
  3. mlxsw_env_module_temp_thresholds_get
  4. mlxsw_env_get_module_info
  5. mlxsw_env_get_module_eeprom

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/kernel.h>
   5 #include <linux/err.h>
   6 #include <linux/sfp.h>
   7 
   8 #include "core.h"
   9 #include "core_env.h"
  10 #include "item.h"
  11 #include "reg.h"
  12 
  13 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
  14                                           bool *qsfp)
  15 {
  16         char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
  17         char mcia_pl[MLXSW_REG_MCIA_LEN];
  18         u8 ident;
  19         int err;
  20 
  21         mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
  22                             MLXSW_REG_MCIA_I2C_ADDR_LOW);
  23         err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
  24         if (err)
  25                 return err;
  26         mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
  27         ident = eeprom_tmp[0];
  28         switch (ident) {
  29         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
  30                 *qsfp = false;
  31                 break;
  32         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: /* fall-through */
  33         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
  34         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: /* fall-through */
  35         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
  36                 *qsfp = true;
  37                 break;
  38         default:
  39                 return -EINVAL;
  40         }
  41 
  42         return 0;
  43 }
  44 
  45 static int
  46 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
  47                               u16 offset, u16 size, void *data,
  48                               unsigned int *p_read_size)
  49 {
  50         char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
  51         char mcia_pl[MLXSW_REG_MCIA_LEN];
  52         u16 i2c_addr;
  53         int status;
  54         int err;
  55 
  56         size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
  57 
  58         if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
  59             offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
  60                 /* Cross pages read, read until offset 256 in low page */
  61                 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
  62 
  63         i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
  64         if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
  65                 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
  66                 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
  67         }
  68 
  69         mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr);
  70 
  71         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
  72         if (err)
  73                 return err;
  74 
  75         status = mlxsw_reg_mcia_status_get(mcia_pl);
  76         if (status)
  77                 return -EIO;
  78 
  79         mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
  80         memcpy(data, eeprom_tmp, size);
  81         *p_read_size = size;
  82 
  83         return 0;
  84 }
  85 
  86 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
  87                                          int off, int *temp)
  88 {
  89         char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
  90         union {
  91                 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
  92                 u16 temp;
  93         } temp_thresh;
  94         char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
  95         char mtmp_pl[MLXSW_REG_MTMP_LEN];
  96         unsigned int module_temp;
  97         bool qsfp;
  98         int err;
  99 
 100         mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
 101                             false, false);
 102         err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
 103         if (err)
 104                 return err;
 105         mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL);
 106         if (!module_temp) {
 107                 *temp = 0;
 108                 return 0;
 109         }
 110 
 111         /* Read Free Side Device Temperature Thresholds from page 03h
 112          * (MSB at lower byte address).
 113          * Bytes:
 114          * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
 115          * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
 116          * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
 117          * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
 118          */
 119 
 120         /* Validate module identifier value. */
 121         err = mlxsw_env_validate_cable_ident(core, module, &qsfp);
 122         if (err)
 123                 return err;
 124 
 125         if (qsfp)
 126                 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
 127                                     MLXSW_REG_MCIA_TH_PAGE_NUM,
 128                                     MLXSW_REG_MCIA_TH_PAGE_OFF + off,
 129                                     MLXSW_REG_MCIA_TH_ITEM_SIZE,
 130                                     MLXSW_REG_MCIA_I2C_ADDR_LOW);
 131         else
 132                 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
 133                                     MLXSW_REG_MCIA_PAGE0_LO,
 134                                     off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
 135                                     MLXSW_REG_MCIA_I2C_ADDR_HIGH);
 136 
 137         err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
 138         if (err)
 139                 return err;
 140 
 141         mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
 142         memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
 143         *temp = temp_thresh.temp * 1000;
 144 
 145         return 0;
 146 }
 147 
 148 int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
 149                               struct ethtool_modinfo *modinfo)
 150 {
 151         u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
 152         u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
 153         u8 module_rev_id, module_id, diag_mon;
 154         unsigned int read_size;
 155         int err;
 156 
 157         err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
 158                                             module_info, &read_size);
 159         if (err)
 160                 return err;
 161 
 162         if (read_size < offset)
 163                 return -EIO;
 164 
 165         module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
 166         module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
 167 
 168         switch (module_id) {
 169         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
 170                 modinfo->type       = ETH_MODULE_SFF_8436;
 171                 modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
 172                 break;
 173         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
 174         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
 175                 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
 176                     module_rev_id >=
 177                     MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
 178                         modinfo->type       = ETH_MODULE_SFF_8636;
 179                         modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
 180                 } else {
 181                         modinfo->type       = ETH_MODULE_SFF_8436;
 182                         modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
 183                 }
 184                 break;
 185         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
 186                 /* Verify if transceiver provides diagnostic monitoring page */
 187                 err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
 188                                                     SFP_DIAGMON, 1, &diag_mon,
 189                                                     &read_size);
 190                 if (err)
 191                         return err;
 192 
 193                 if (read_size < 1)
 194                         return -EIO;
 195 
 196                 modinfo->type       = ETH_MODULE_SFF_8472;
 197                 if (diag_mon)
 198                         modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
 199                 else
 200                         modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
 201                 break;
 202         default:
 203                 return -EINVAL;
 204         }
 205 
 206         return 0;
 207 }
 208 EXPORT_SYMBOL(mlxsw_env_get_module_info);
 209 
 210 int mlxsw_env_get_module_eeprom(struct net_device *netdev,
 211                                 struct mlxsw_core *mlxsw_core, int module,
 212                                 struct ethtool_eeprom *ee, u8 *data)
 213 {
 214         int offset = ee->offset;
 215         unsigned int read_size;
 216         int i = 0;
 217         int err;
 218 
 219         if (!ee->len)
 220                 return -EINVAL;
 221 
 222         memset(data, 0, ee->len);
 223 
 224         while (i < ee->len) {
 225                 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
 226                                                     ee->len - i, data + i,
 227                                                     &read_size);
 228                 if (err) {
 229                         netdev_err(netdev, "Eeprom query failed\n");
 230                         return err;
 231                 }
 232 
 233                 i += read_size;
 234                 offset += read_size;
 235         }
 236 
 237         return 0;
 238 }
 239 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);

/* [<][>][^][v][top][bottom][index][help] */