brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · bf660c0 Raw
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