272 lines · c
1/*2 * Copyright (c) 2012 Intel Corporation. All rights reserved.3 * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.4 * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.5 *6 * This software is available to you under a choice of one of two7 * licenses. You may choose to be licensed under the terms of the GNU8 * General Public License (GPL) Version 2, available from the file9 * COPYING in the main directory of this source tree, or the10 * OpenIB.org BSD license below:11 *12 * Redistribution and use in source and binary forms, with or13 * without modification, are permitted provided that the following14 * conditions are met:15 *16 * - Redistributions of source code must retain the above17 * copyright notice, this list of conditions and the following18 * disclaimer.19 *20 * - Redistributions in binary form must reproduce the above21 * copyright notice, this list of conditions and the following22 * disclaimer in the documentation and/or other materials23 * provided with the distribution.24 *25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE32 * SOFTWARE.33 */34 35#include <linux/delay.h>36#include <linux/pci.h>37#include <linux/vmalloc.h>38 39#include "qib.h"40 41/*42 * Functions specific to the serial EEPROM on cards handled by ib_qib.43 * The actual serail interface code is in qib_twsi.c. This file is a client44 */45 46/**47 * qib_eeprom_read - receives bytes from the eeprom via I2C48 * @dd: the qlogic_ib device49 * @eeprom_offset: address to read from50 * @buff: where to store result51 * @len: number of bytes to receive52 */53int qib_eeprom_read(struct qib_devdata *dd, u8 eeprom_offset,54 void *buff, int len)55{56 int ret;57 58 ret = mutex_lock_interruptible(&dd->eep_lock);59 if (!ret) {60 ret = qib_twsi_reset(dd);61 if (ret)62 qib_dev_err(dd, "EEPROM Reset for read failed\n");63 else64 ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev,65 eeprom_offset, buff, len);66 mutex_unlock(&dd->eep_lock);67 }68 69 return ret;70}71 72/*73 * Actually update the eeprom, first doing write enable if74 * needed, then restoring write enable state.75 * Must be called with eep_lock held76 */77static int eeprom_write_with_enable(struct qib_devdata *dd, u8 offset,78 const void *buf, int len)79{80 int ret, pwen;81 82 pwen = dd->f_eeprom_wen(dd, 1);83 ret = qib_twsi_reset(dd);84 if (ret)85 qib_dev_err(dd, "EEPROM Reset for write failed\n");86 else87 ret = qib_twsi_blk_wr(dd, dd->twsi_eeprom_dev,88 offset, buf, len);89 dd->f_eeprom_wen(dd, pwen);90 return ret;91}92 93/**94 * qib_eeprom_write - writes data to the eeprom via I2C95 * @dd: the qlogic_ib device96 * @eeprom_offset: where to place data97 * @buff: data to write98 * @len: number of bytes to write99 */100int qib_eeprom_write(struct qib_devdata *dd, u8 eeprom_offset,101 const void *buff, int len)102{103 int ret;104 105 ret = mutex_lock_interruptible(&dd->eep_lock);106 if (!ret) {107 ret = eeprom_write_with_enable(dd, eeprom_offset, buff, len);108 mutex_unlock(&dd->eep_lock);109 }110 111 return ret;112}113 114static u8 flash_csum(struct qib_flash *ifp, int adjust)115{116 u8 *ip = (u8 *) ifp;117 u8 csum = 0, len;118 119 /*120 * Limit length checksummed to max length of actual data.121 * Checksum of erased eeprom will still be bad, but we avoid122 * reading past the end of the buffer we were passed.123 */124 len = ifp->if_length;125 if (len > sizeof(struct qib_flash))126 len = sizeof(struct qib_flash);127 while (len--)128 csum += *ip++;129 csum -= ifp->if_csum;130 csum = ~csum;131 if (adjust)132 ifp->if_csum = csum;133 134 return csum;135}136 137/**138 * qib_get_eeprom_info- get the GUID et al. from the TSWI EEPROM device139 * @dd: the qlogic_ib device140 *141 * We have the capability to use the nguid field, and get142 * the guid from the first chip's flash, to use for all of them.143 */144void qib_get_eeprom_info(struct qib_devdata *dd)145{146 void *buf;147 struct qib_flash *ifp;148 __be64 guid;149 int len, eep_stat;150 u8 csum, *bguid;151 int t = dd->unit;152 struct qib_devdata *dd0 = qib_lookup(0);153 154 if (t && dd0->nguid > 1 && t <= dd0->nguid) {155 u8 oguid;156 157 dd->base_guid = dd0->base_guid;158 bguid = (u8 *) &dd->base_guid;159 160 oguid = bguid[7];161 bguid[7] += t;162 if (oguid > bguid[7]) {163 if (bguid[6] == 0xff) {164 if (bguid[5] == 0xff) {165 qib_dev_err(dd,166 "Can't set GUID from base, wraps to OUI!\n");167 dd->base_guid = 0;168 goto bail;169 }170 bguid[5]++;171 }172 bguid[6]++;173 }174 dd->nguid = 1;175 goto bail;176 }177 178 /*179 * Read full flash, not just currently used part, since it may have180 * been written with a newer definition.181 * */182 len = sizeof(struct qib_flash);183 buf = vmalloc(len);184 if (!buf)185 goto bail;186 187 /*188 * Use "public" eeprom read function, which does locking and189 * figures out device. This will migrate to chip-specific.190 */191 eep_stat = qib_eeprom_read(dd, 0, buf, len);192 193 if (eep_stat) {194 qib_dev_err(dd, "Failed reading GUID from eeprom\n");195 goto done;196 }197 ifp = (struct qib_flash *)buf;198 199 csum = flash_csum(ifp, 0);200 if (csum != ifp->if_csum) {201 qib_devinfo(dd->pcidev,202 "Bad I2C flash checksum: 0x%x, not 0x%x\n",203 csum, ifp->if_csum);204 goto done;205 }206 if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) ||207 *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) {208 qib_dev_err(dd,209 "Invalid GUID %llx from flash; ignoring\n",210 *(unsigned long long *) ifp->if_guid);211 /* don't allow GUID if all 0 or all 1's */212 goto done;213 }214 215 /* complain, but allow it */216 if (*(u64 *) ifp->if_guid == 0x100007511000000ULL)217 qib_devinfo(dd->pcidev,218 "Warning, GUID %llx is default, probably not correct!\n",219 *(unsigned long long *) ifp->if_guid);220 221 bguid = ifp->if_guid;222 if (!bguid[0] && !bguid[1] && !bguid[2]) {223 /*224 * Original incorrect GUID format in flash; fix in225 * core copy, by shifting up 2 octets; don't need to226 * change top octet, since both it and shifted are 0.227 */228 bguid[1] = bguid[3];229 bguid[2] = bguid[4];230 bguid[3] = 0;231 bguid[4] = 0;232 guid = *(__be64 *) ifp->if_guid;233 } else234 guid = *(__be64 *) ifp->if_guid;235 dd->base_guid = guid;236 dd->nguid = ifp->if_numguid;237 /*238 * Things are slightly complicated by the desire to transparently239 * support both the Pathscale 10-digit serial number and the QLogic240 * 13-character version.241 */242 if ((ifp->if_fversion > 1) && ifp->if_sprefix[0] &&243 ((u8 *) ifp->if_sprefix)[0] != 0xFF) {244 char *snp = dd->serial;245 246 /*247 * This board has a Serial-prefix, which is stored248 * elsewhere for backward-compatibility.249 */250 memcpy(snp, ifp->if_sprefix, sizeof(ifp->if_sprefix));251 snp[sizeof(ifp->if_sprefix)] = '\0';252 len = strlen(snp);253 snp += len;254 len = sizeof(dd->serial) - len;255 if (len > sizeof(ifp->if_serial))256 len = sizeof(ifp->if_serial);257 memcpy(snp, ifp->if_serial, len);258 } else {259 memcpy(dd->serial, ifp->if_serial, sizeof(ifp->if_serial));260 }261 if (!strstr(ifp->if_comment, "Tested successfully"))262 qib_dev_err(dd,263 "Board SN %s did not pass functional test: %s\n",264 dd->serial, ifp->if_comment);265 266done:267 vfree(buf);268 269bail:;270}271 272