1 /* 2 * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 /* 27 * Falcon conviniently uses an EEPROM to store it's VPD configuration, 28 * and it stores the VPD contents in native VPD format. This code does 29 * not cope with the presence of an RW block in VPD at all. 30 */ 31 32 #include "efsys.h" 33 #include "efx.h" 34 #include "falcon_nvram.h" 35 #include "efx_types.h" 36 #include "efx_impl.h" 37 38 #if EFSYS_OPT_FALCON 39 40 #if EFSYS_OPT_VPD 41 42 typedef struct { 43 size_t fvpdd_base; 44 size_t fvpdd_size; 45 boolean_t fvpdd_writable; 46 } falcon_vpd_dimension_t; 47 48 static void 49 falcon_vpd_dimension( 50 __in efx_nic_t *enp, 51 __out falcon_vpd_dimension_t *dimp) 52 { 53 efx_oword_t oword; 54 55 #if EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE 56 if (enp->en_u.falcon.enu_forced_cfg != NULL) { 57 memcpy(&oword, (enp->en_u.falcon.enu_forced_cfg 58 + EE_VPD_CFG0_REG_SF_OFST), sizeof (oword)); 59 } 60 else 61 #endif /* EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE */ 62 { 63 EFX_BAR_READO(enp, FR_AB_EE_VPD_CFG0_REG, &oword); 64 } 65 66 dimp->fvpdd_base = EFX_OWORD_FIELD(oword, FRF_AB_EE_VPD_BASE); 67 dimp->fvpdd_size = EFX_OWORD_FIELD(oword, FRF_AB_EE_VPD_LENGTH); 68 if (dimp->fvpdd_size != 0) 69 /* Non-zero "lengths" are actually maximum dword offsets */ 70 dimp->fvpdd_size += 4; 71 dimp->fvpdd_writable = 72 EFX_OWORD_FIELD(oword, FRF_AB_EE_VPDW_LENGTH) != 0; 73 } 74 75 __checkReturn int 76 falcon_vpd_size( 77 __in efx_nic_t *enp, 78 __out size_t *sizep) 79 { 80 falcon_vpd_dimension_t dim; 81 int rc; 82 83 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 84 85 falcon_vpd_dimension(enp, &dim); 86 if (dim.fvpdd_size == 0 || dim.fvpdd_writable) { 87 rc = ENOTSUP; 88 goto fail1; 89 } 90 91 *sizep = dim.fvpdd_size; 92 93 return (0); 94 95 fail1: 96 EFSYS_PROBE1(fail1, int, rc); 97 98 *sizep = 0; 99 100 return (rc); 101 } 102 103 __checkReturn int 104 falcon_vpd_read( 105 __in efx_nic_t *enp, 106 __out_bcount(size) caddr_t data, 107 __in size_t size) 108 { 109 falcon_vpd_dimension_t dim; 110 int rc; 111 112 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 113 114 falcon_vpd_dimension(enp, &dim); 115 if (size < dim.fvpdd_size || size == 0) { 116 rc = ENOTSUP; 117 goto fail1; 118 } 119 120 if ((rc = falcon_spi_dev_read(enp, FALCON_SPI_EEPROM, 121 dim.fvpdd_base, data, size)) != 0) 122 goto fail2; 123 124 return (0); 125 126 fail2: 127 EFSYS_PROBE(fail2); 128 fail1: 129 EFSYS_PROBE1(fail1, int, rc); 130 131 return (rc); 132 } 133 134 __checkReturn int 135 falcon_vpd_verify( 136 __in efx_nic_t *enp, 137 __in_bcount(size) caddr_t data, 138 __in size_t size) 139 { 140 falcon_vpd_dimension_t dim; 141 boolean_t cksummed; 142 int rc; 143 144 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 145 146 falcon_vpd_dimension(enp, &dim); 147 EFSYS_ASSERT3U(dim.fvpdd_size, <=, size); 148 EFSYS_ASSERT(!dim.fvpdd_writable); 149 150 if ((rc = efx_vpd_hunk_verify(data, size, &cksummed)) != 0) 151 goto fail1; 152 153 if (!cksummed) { 154 rc = EFAULT; 155 goto fail2; 156 } 157 158 return (0); 159 160 fail2: 161 EFSYS_PROBE(fail2); 162 fail1: 163 EFSYS_PROBE1(fail1, int, rc); 164 165 return (rc); 166 } 167 168 __checkReturn int 169 falcon_vpd_get( 170 __in efx_nic_t *enp, 171 __in_bcount(size) caddr_t data, 172 __in size_t size, 173 __inout efx_vpd_value_t *evvp) 174 { 175 falcon_vpd_dimension_t dim; 176 unsigned int offset; 177 uint8_t length; 178 int rc; 179 180 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 181 182 if (evvp->evv_tag != EFX_VPD_ID && evvp->evv_tag != EFX_VPD_RO) { 183 rc = EINVAL; 184 goto fail1; 185 } 186 187 falcon_vpd_dimension(enp, &dim); 188 EFSYS_ASSERT3U(dim.fvpdd_size, <=, size); 189 EFSYS_ASSERT(!dim.fvpdd_writable); 190 191 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 192 evvp->evv_keyword, &offset, &length)) != 0) 193 goto fail2; 194 195 /* Copy out */ 196 evvp->evv_length = length; 197 memcpy(evvp->evv_value, data + offset, length); 198 199 return (0); 200 201 fail2: 202 EFSYS_PROBE(fail2); 203 fail1: 204 EFSYS_PROBE1(fail1, int, rc); 205 206 return (rc); 207 } 208 209 __checkReturn int 210 falcon_vpd_set( 211 __in efx_nic_t *enp, 212 __in_bcount(size) caddr_t data, 213 __in size_t size, 214 __in efx_vpd_value_t *evvp) 215 { 216 falcon_vpd_dimension_t dim; 217 int rc; 218 219 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 220 221 falcon_vpd_dimension(enp, &dim); 222 EFSYS_ASSERT3U(dim.fvpdd_size, <=, size); 223 224 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 225 goto fail1; 226 227 fail1: 228 EFSYS_PROBE1(fail1, int, rc); 229 230 return (rc); 231 } 232 233 __checkReturn int 234 falcon_vpd_next( 235 __in efx_nic_t *enp, 236 __in_bcount(size) caddr_t data, 237 __in size_t size, 238 __out efx_vpd_value_t *evvp, 239 __inout unsigned int *contp) 240 { 241 falcon_vpd_dimension_t dim; 242 unsigned int offset; 243 int rc; 244 245 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 246 247 falcon_vpd_dimension(enp, &dim); 248 EFSYS_ASSERT3U(dim.fvpdd_size, <=, size); 249 EFSYS_ASSERT(!dim.fvpdd_writable); 250 251 /* Find the (tag, keyword) */ 252 if ((rc = efx_vpd_hunk_next(data, size, &evvp->evv_tag, 253 &evvp->evv_keyword, &offset, &evvp->evv_length, contp)) != 0) 254 goto fail1; 255 256 /* Copyout */ 257 memcpy(evvp->evv_value, data + offset, evvp->evv_length); 258 259 return (0); 260 261 fail1: 262 EFSYS_PROBE1(fail1, int, rc); 263 264 return (rc); 265 } 266 267 __checkReturn int 268 falcon_vpd_write( 269 __in efx_nic_t *enp, 270 __in_bcount(size) caddr_t data, 271 __in size_t size) 272 { 273 falcon_vpd_dimension_t dim; 274 int rc; 275 276 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 277 278 falcon_vpd_dimension(enp, &dim); 279 if (dim.fvpdd_size != size) { 280 /* User hasn't provided sufficient data */ 281 rc = EINVAL; 282 goto fail1; 283 } 284 285 if ((rc = falcon_spi_dev_write(enp, FALCON_SPI_EEPROM, 286 dim.fvpdd_base, data, dim.fvpdd_size)) != 0) 287 goto fail2; 288 289 return (0); 290 291 fail2: 292 EFSYS_PROBE(fail2); 293 fail1: 294 EFSYS_PROBE1(fail1, int, rc); 295 296 return (rc); 297 } 298 299 #endif /* EFSYS_OPT_FALCON */ 300 301 #endif /* EFSYS_OPT_VPD */