1108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/*
2e7eacd36865ae0707f5efae8e4dda421ffcd1b66Ralph Campbell * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
3108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
4108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
5108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * This software is available to you under a choice of one of two
6108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * licenses.  You may choose to be licensed under the terms of the GNU
7108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * General Public License (GPL) Version 2, available from the file
8108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * COPYING in the main directory of this source tree, or the
9108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * OpenIB.org BSD license below:
10108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
11108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *     Redistribution and use in source and binary forms, with or
12108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *     without modification, are permitted provided that the following
13108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *     conditions are met:
14108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
15108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *      - Redistributions of source code must retain the above
16108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *        copyright notice, this list of conditions and the following
17108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *        disclaimer.
18108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
19108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *      - Redistributions in binary form must reproduce the above
20108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *        copyright notice, this list of conditions and the following
21108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *        disclaimer in the documentation and/or other materials
22108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *        provided with the distribution.
23108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
24108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * SOFTWARE.
32108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
33108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
34108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/delay.h>
35108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/pci.h>
36108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/vmalloc.h>
37108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
38108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include "ipath_kernel.h"
39108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
40108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/*
41108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * InfiniPath I2C driver for a serial eeprom.  This is not a generic
42108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * I2C interface.  For a start, the device we're using (Atmel AT24C11)
43108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * doesn't work like a regular I2C device.  It looks like one
44108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * electrically, but not logically.  Normal I2C devices have a single
45108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 7-bit or 10-bit I2C address that they respond to.  Valid 7-bit
46108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * addresses range from 0x03 to 0x77.  Addresses 0x00 to 0x02 and 0x78
47108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * to 0x7F are special reserved addresses (e.g. 0x00 is the "general
48108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * call" address.)  The Atmel device, on the other hand, responds to ALL
49108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 7-bit addresses.  It's designed to be the only device on a given I2C
50108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * bus.  A 7-bit address corresponds to the memory address within the
51108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Atmel device itself.
52108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
53108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Also, the timing requirements mean more than simple software
54108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * bitbanging, with readbacks from chip to ensure timing (simple udelay
55108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * is not enough).
56108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
57108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * This all means that accessing the device is specialized enough
58108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * that using the standard kernel I2C bitbanging interface would be
59108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * impossible.  For example, the core I2C eeprom driver expects to find
60108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * a device at one or more of a limited set of addresses only.  It doesn't
61108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * allow writing to an eeprom.  It also doesn't provide any means of
62108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * accessing eeprom contents from within the kernel, only via sysfs.
63108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
64108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
65d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/* Added functionality for IBA7220-based cards */
66d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_EEPROM_DEV_V1 0xA0
67d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_EEPROM_DEV_V2 0xA2
68d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_TEMP_DEV 0x98
69d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_BAD_DEV (IPATH_EEPROM_DEV_V2+2)
70d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_NO_DEV (0xFF)
71d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
72d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/*
73d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * The number of I2C chains is proliferating. Table below brings
74d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * some order to the madness. The basic principle is that the
75d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * table is scanned from the top, and a "probe" is made to the
76d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * device probe_dev. If that succeeds, the chain is considered
77d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * to be of that type, and dd->i2c_chain_type is set to the index+1
78d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * of the entry.
79d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * The +1 is so static initialization can mean "unknown, do probe."
80d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
81d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic struct i2c_chain_desc {
82d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	u8 probe_dev;	/* If seen at probe, chain is this type */
83d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	u8 eeprom_dev;	/* Dev addr (if any) for EEPROM */
84d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	u8 temp_dev;	/* Dev Addr (if any) for Temp-sense */
85d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} i2c_chains[] = {
86d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	{ IPATH_BAD_DEV, IPATH_NO_DEV, IPATH_NO_DEV }, /* pre-iba7220 bds */
87d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	{ IPATH_EEPROM_DEV_V1, IPATH_EEPROM_DEV_V1, IPATH_TEMP_DEV}, /* V1 */
88d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	{ IPATH_EEPROM_DEV_V2, IPATH_EEPROM_DEV_V2, IPATH_TEMP_DEV}, /* V2 */
89d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	{ IPATH_NO_DEV }
90d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh};
91d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
92108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanenum i2c_type {
93108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_line_scl = 0,
94108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_line_sda
95108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan};
96108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
97108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanenum i2c_state {
98108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_line_low = 0,
99108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_line_high
100108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan};
101108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
102108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#define READ_CMD 1
103108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#define WRITE_CMD 0
104108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
105108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
106108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_gpio_set - set a GPIO line
107108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
108108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @line: the line to set
109108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @new_line_state: the state to set
110108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
111108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if the line was set to the new state successfully, non-zero
112108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * on error.
113108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
114108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_gpio_set(struct ipath_devdata *dd,
115108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			enum i2c_type line,
116108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			enum i2c_state new_line_state)
117108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
11817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	u64 out_mask, dir_mask, *gpioval;
11917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	unsigned long flags = 0;
120108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
121108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	gpioval = &dd->ipath_gpio_out;
122108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
12317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	if (line == i2c_line_scl) {
12417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		dir_mask = dd->ipath_gpio_scl;
12517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		out_mask = (1UL << dd->ipath_gpio_scl_num);
12617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	} else {
12717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		dir_mask = dd->ipath_gpio_sda;
12817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		out_mask = (1UL << dd->ipath_gpio_sda_num);
12917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	}
13017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh
13117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
13217b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	if (new_line_state == i2c_line_high) {
133108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/* tri-state the output rather than force high */
13417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		dd->ipath_extctrl &= ~dir_mask;
13517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	} else {
136108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/* config line to be an output */
13717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		dd->ipath_extctrl |= dir_mask;
13817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	}
13917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
140108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
14117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	/* set output as well (no real verify) */
142108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (new_line_state == i2c_line_high)
14317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		*gpioval |= out_mask;
144108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	else
14517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh		*gpioval &= ~out_mask;
146108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
147108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
14817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
149108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
150108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return 0;
151108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
152108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
153108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
154108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_gpio_get - get a GPIO line state
155108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
156108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @line: the line to get
157108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @curr_statep: where to put the line state
158108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
159108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if the line was set to the new state successfully, non-zero
160108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * on error.  curr_state is not set on error.
161108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
162108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_gpio_get(struct ipath_devdata *dd,
163108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			enum i2c_type line,
164108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			enum i2c_state *curr_statep)
165108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
16617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	u64 read_val, mask;
167108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int ret;
16817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	unsigned long flags = 0;
169108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
170108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* check args */
171108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (curr_statep == NULL) {
172108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ret = 1;
173108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto bail;
174108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
175108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
176108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* config line to be an input */
177108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (line == i2c_line_scl)
178f62fe77ad26b9c89c2028d96709f0f28793fe6cdBryan O'Sullivan		mask = dd->ipath_gpio_scl;
179108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	else
180f62fe77ad26b9c89c2028d96709f0f28793fe6cdBryan O'Sullivan		mask = dd->ipath_gpio_sda;
18117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh
18217b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
18317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	dd->ipath_extctrl &= ~mask;
18417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
18517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	/*
18617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	 * Below is very unlikely to reflect true input state if Output
18717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	 * Enable actually changed.
18817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	 */
189108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
19017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
191108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
192108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (read_val & mask)
193108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		*curr_statep = i2c_line_high;
194108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	else
195108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		*curr_statep = i2c_line_low;
196108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
197108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ret = 0;
198108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
199108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:
200108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return ret;
201108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
202108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
203108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
204108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_wait_for_writes - wait for a write
205108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
206108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
207108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * We use this instead of udelay directly, so we can make sure
208108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * that previous register writes have been flushed all the way
209108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * to the chip.  Since we are delaying anyway, the cost doesn't
210108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * hurt, and makes the bit twiddling more regular
211108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
212108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void i2c_wait_for_writes(struct ipath_devdata *dd)
213108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
214108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	(void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
2151a4e74a08788db913486cb9a3dc30984c55e9897Bryan O'Sullivan	rmb();
216108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
217108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
218108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void scl_out(struct ipath_devdata *dd, u8 bit)
219108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
22017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	udelay(1);
221108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low);
222108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
223108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_wait_for_writes(dd);
224108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
225108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
226108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void sda_out(struct ipath_devdata *dd, u8 bit)
227108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
228108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_gpio_set(dd, i2c_line_sda, bit ? i2c_line_high : i2c_line_low);
229108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
230108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	i2c_wait_for_writes(dd);
231108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
232108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
233108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic u8 sda_in(struct ipath_devdata *dd, int wait)
234108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
235108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	enum i2c_state bit;
236108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
237108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (i2c_gpio_get(dd, i2c_line_sda, &bit))
238108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_dbg("get bit failed!\n");
239108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
240108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (wait)
241108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		i2c_wait_for_writes(dd);
242108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
243108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return bit == i2c_line_high ? 1U : 0;
244108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
245108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
246108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
247108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_ackrcv - see if ack following write is true
248108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
249108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
250108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_ackrcv(struct ipath_devdata *dd)
251108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
252108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u8 ack_received;
253108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
254108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* AT ENTRY SCL = LOW */
255108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* change direction, ignore data */
256108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ack_received = sda_in(dd, 1);
257108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_high);
258108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ack_received = sda_in(dd, 1) == 0;
259108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_low);
260108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return ack_received;
261108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
262108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
263108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
264d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * rd_byte - read a byte, leaving ACK, STOP, etc up to caller
265d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device
266d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh *
267d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Returns byte shifted out of device
268d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
269d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int rd_byte(struct ipath_devdata *dd)
270d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
271d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int bit_cntr, data;
272d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
273d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	data = 0;
274d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
275d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) {
276d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		data <<= 1;
277d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		scl_out(dd, i2c_line_high);
278d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		data |= sda_in(dd, 0);
279d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		scl_out(dd, i2c_line_low);
280d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
281d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return data;
282d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
283d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
284d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/**
285108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * wr_byte - write a byte, one bit at a time
286108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
287108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @data: the byte to write
288108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
289108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if we got the following ack, otherwise 1
290108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
291108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int wr_byte(struct ipath_devdata *dd, u8 data)
292108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
293108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int bit_cntr;
294108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u8 bit;
295108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
296108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) {
297108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bit = (data >> bit_cntr) & 1;
298108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		sda_out(dd, bit);
299108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		scl_out(dd, i2c_line_high);
300108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		scl_out(dd, i2c_line_low);
301108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
302108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return (!i2c_ackrcv(dd)) ? 1 : 0;
303108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
304108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
305108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void send_ack(struct ipath_devdata *dd)
306108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
307108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_low);
308108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_high);
309108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_low);
310108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_high);
311108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
312108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
313108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
314108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_startcmd - transmit the start condition, followed by address/cmd
315108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
316108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @offset_dir: direction byte
317108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
318108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *      (both clock/data high, clock high, data low while clock is high)
319108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
320108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_startcmd(struct ipath_devdata *dd, u8 offset_dir)
321108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
322108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int res;
323108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
324108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* issue start sequence */
325108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_high);
326108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_high);
327108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_low);
328108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_low);
329108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
330108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* issue length and direction byte */
331108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	res = wr_byte(dd, offset_dir);
332108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
333108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (res)
334108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_cdbg(VERBOSE, "No ack to complete start\n");
335108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
336108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return res;
337108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
338108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
339108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
340108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * stop_cmd - transmit the stop condition
341108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
342108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
343108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * (both clock/data low, clock high, data high while clock is high)
344108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
345108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void stop_cmd(struct ipath_devdata *dd)
346108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
347108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_low);
348108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_low);
349108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_high);
350108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_high);
351108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	udelay(2);
352108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
353108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
354108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
355108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * eeprom_reset - reset I2C communication
356108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
357108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
358108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
359108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int eeprom_reset(struct ipath_devdata *dd)
360108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
361108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int clock_cycles_left = 9;
362108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u64 *gpioval = &dd->ipath_gpio_out;
363108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int ret;
36417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	unsigned long flags;
365108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
36617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
36717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	/* Make sure shadows are consistent */
36817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	dd->ipath_extctrl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
369108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	*gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out);
37017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh	spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
37117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh
372108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg "
373108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		   "is %llx\n", (unsigned long long) *gpioval);
374108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
375108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/*
376108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 * This is to get the i2c into a known state, by first going low,
377108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 * then tristate sda (and then tristate scl as first thing
378108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 * in loop)
379108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 */
380108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	scl_out(dd, i2c_line_low);
381108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	sda_out(dd, i2c_line_high);
382108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
383d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/* Clock up to 9 cycles looking for SDA hi, then issue START and STOP */
384108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	while (clock_cycles_left--) {
385108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		scl_out(dd, i2c_line_high);
386108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
387d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* SDA seen high, issue START by dropping it while SCL high */
388108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		if (sda_in(dd, 0)) {
389108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			sda_out(dd, i2c_line_low);
390108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			scl_out(dd, i2c_line_low);
391d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			/* ATMEL spec says must be followed by STOP. */
392d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			scl_out(dd, i2c_line_high);
393d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			sda_out(dd, i2c_line_high);
394108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			ret = 0;
395108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			goto bail;
396108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		}
397108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
398108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		scl_out(dd, i2c_line_low);
399108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
400108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
401108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ret = 1;
402108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
403108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:
404108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return ret;
405108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
406108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
407d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/*
408d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Probe for I2C device at specified address. Returns 0 for "success"
409d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * to match rest of this file.
410d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Leave bus in "reasonable" state for further commands.
411108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
412d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int i2c_probe(struct ipath_devdata *dd, int devaddr)
413d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
414d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int ret = 0;
415d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
416d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = eeprom_reset(dd);
417d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret) {
418d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dev_err(dd, "Failed reset probing device 0x%02X\n",
419d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			      devaddr);
420d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		return ret;
421d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
422d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/*
423d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * Reset no longer leaves bus in start condition, so normal
424d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * i2c_startcmd() will do.
425d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 */
426d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = i2c_startcmd(dd, devaddr | READ_CMD);
427d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret)
428d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_cdbg(VERBOSE, "Failed startcmd for device 0x%02X\n",
429d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			   devaddr);
430d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	else {
431d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/*
432d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 * Device did respond. Complete a single-byte read, because some
433d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 * devices apparently cannot handle STOP immediately after they
434d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 * ACK the start-cmd.
435d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 */
436d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		int data;
437d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		data = rd_byte(dd);
438d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
439d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_cdbg(VERBOSE, "Response from device 0x%02X\n", devaddr);
440d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
441d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return ret;
442d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
443d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
444d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/*
445d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Returns the "i2c type". This is a pointer to a struct that describes
446d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * the I2C chain on this board. To minimize impact on struct ipath_devdata,
447d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * the (small integer) index into the table is actually memoized, rather
448d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * then the pointer.
449d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Memoization is because the type is determined on the first call per chip.
450d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * An alternative would be to move type determination to early
451d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * init code.
452d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
453d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic struct i2c_chain_desc *ipath_i2c_type(struct ipath_devdata *dd)
454d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
455d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int idx;
456d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
457d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/* Get memoized index, from previous successful probes */
458d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	idx = dd->ipath_i2c_chain_type - 1;
459d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (idx >= 0 && idx < (ARRAY_SIZE(i2c_chains) - 1))
460d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto done;
461d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
462d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	idx = 0;
463d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	while (i2c_chains[idx].probe_dev != IPATH_NO_DEV) {
464d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* if probe succeeds, this is type */
465d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		if (!i2c_probe(dd, i2c_chains[idx].probe_dev))
466d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			break;
467d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		++idx;
468d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
469d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
470d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/*
471d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * Old EEPROM (first entry) may require a reset after probe,
472d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * rather than being able to "start" after "stop"
473d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 */
474d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (idx == 0)
475d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		eeprom_reset(dd);
476d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
477d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (i2c_chains[idx].probe_dev == IPATH_NO_DEV)
478d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		idx = -1;
479d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	else
480d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		dd->ipath_i2c_chain_type = idx + 1;
481d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughdone:
482d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return (idx >= 0) ? i2c_chains + idx : NULL;
483d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
484108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
485aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughstatic int ipath_eeprom_internal_read(struct ipath_devdata *dd,
486aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh					u8 eeprom_offset, void *buffer, int len)
487108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
488108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int ret;
489d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	struct i2c_chain_desc *icd;
490d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	u8 *bp = buffer;
491108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
492d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = 1;
493d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	icd = ipath_i2c_type(dd);
494d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!icd)
495d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
496108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
497d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (icd->eeprom_dev == IPATH_NO_DEV) {
498d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* legacy not-really-I2C */
499d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_cdbg(VERBOSE, "Start command only address\n");
500d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		eeprom_offset = (eeprom_offset << 1) | READ_CMD;
501d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = i2c_startcmd(dd, eeprom_offset);
502d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	} else {
503d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* Actual I2C */
504d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_cdbg(VERBOSE, "Start command uses devaddr\n");
505d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) {
506d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			ipath_dbg("Failed EEPROM startcmd\n");
507d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			stop_cmd(dd);
508d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			ret = 1;
509d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			goto bail;
510d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		}
511d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = wr_byte(dd, eeprom_offset);
512d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
513d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		if (ret) {
514d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			ipath_dev_err(dd, "Failed to write EEPROM address\n");
515d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			ret = 1;
516d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			goto bail;
517d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		}
518d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = i2c_startcmd(dd, icd->eeprom_dev | READ_CMD);
519d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
520d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret) {
521d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dbg("Failed startcmd for dev %02X\n", icd->eeprom_dev);
522108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		stop_cmd(dd);
523108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ret = 1;
524108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto bail;
525108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
526108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
527108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/*
528108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 * eeprom keeps clocking data out as long as we ack, automatically
529108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 * incrementing the address.
530108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	 */
531108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	while (len-- > 0) {
532d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* get and store data */
533d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		*bp++ = rd_byte(dd);
534108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/* send ack if not the last byte */
535108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		if (len)
536108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			send_ack(dd);
537108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
538108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
539108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	stop_cmd(dd);
540108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
541108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ret = 0;
542108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
543108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:
544108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return ret;
545108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
546108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
547da9aec7b627c0369b955f82e855508c6711929acRoland Dreierstatic int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
548da9aec7b627c0369b955f82e855508c6711929acRoland Dreier				       const void *buffer, int len)
549108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
550108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int sub_len;
551108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	const u8 *bp = buffer;
552108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int max_wait_time, i;
553108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int ret;
554d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	struct i2c_chain_desc *icd;
555108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
556d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = 1;
557d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	icd = ipath_i2c_type(dd);
558d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!icd)
559d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
560108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
561108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	while (len > 0) {
562d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		if (icd->eeprom_dev == IPATH_NO_DEV) {
563d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			if (i2c_startcmd(dd,
564d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh					 (eeprom_offset << 1) | WRITE_CMD)) {
565d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				ipath_dbg("Failed to start cmd offset %u\n",
566d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh					eeprom_offset);
567d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				goto failed_write;
568d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			}
569d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		} else {
570d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			/* Real I2C */
571d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) {
572d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				ipath_dbg("Failed EEPROM startcmd\n");
573d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				goto failed_write;
574d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			}
575d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			ret = wr_byte(dd, eeprom_offset);
576d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			if (ret) {
577d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				ipath_dev_err(dd, "Failed to write EEPROM "
578d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh					      "address\n");
579d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh				goto failed_write;
580d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			}
581108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		}
582108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
583108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		sub_len = min(len, 4);
584108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		eeprom_offset += sub_len;
585108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		len -= sub_len;
586108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
587108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		for (i = 0; i < sub_len; i++) {
588108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			if (wr_byte(dd, *bp++)) {
589108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				ipath_dbg("no ack after byte %u/%u (%u "
590108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					  "total remain)\n", i, sub_len,
591108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					  len + sub_len - i);
592108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				goto failed_write;
593108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			}
594108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		}
595108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
596108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		stop_cmd(dd);
597108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
598108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/*
599108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * wait for write complete by waiting for a successful
600108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * read (the chip replies with a zero after the write
601108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * cmd completes, and before it writes to the eeprom.
602108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * The startcmd for the read will fail the ack until
603108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * the writes have completed.   We do this inline to avoid
604108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * the debug prints that are in the real read routine
605108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * if the startcmd fails.
606d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 * We also use the proper device address, so it doesn't matter
607d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		 * whether we have real eeprom_dev. legacy likes any address.
608108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 */
609108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		max_wait_time = 100;
610d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		while (i2c_startcmd(dd, icd->eeprom_dev | READ_CMD)) {
611108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			stop_cmd(dd);
612108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			if (!--max_wait_time) {
613108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				ipath_dbg("Did not get successful read to "
614108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					  "complete write\n");
615108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				goto failed_write;
616108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			}
617108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		}
618d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* now read (and ignore) the resulting byte */
619d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		rd_byte(dd);
620108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		stop_cmd(dd);
621108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
622108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
623108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ret = 0;
624108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	goto bail;
625108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
626108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanfailed_write:
627108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	stop_cmd(dd);
628108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ret = 1;
629108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
630108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:
631108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return ret;
632108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
633108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
634d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/**
635d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_eeprom_read - receives bytes from the eeprom via I2C
636d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device
637d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @eeprom_offset: address to read from
638d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @buffer: where to store result
639d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @len: number of bytes to receive
640aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */
641aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
642aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			void *buff, int len)
643aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{
644aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	int ret;
645aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
6462c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
647aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (!ret) {
648aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
6492c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke		mutex_unlock(&dd->ipath_eep_lock);
650aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
651aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
652aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	return ret;
653aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh}
654aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
655d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/**
656d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_eeprom_write - writes data to the eeprom via I2C
657d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device
658d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @eeprom_offset: where to place data
659d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @buffer: data to write
660d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @len: number of bytes to write
661d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
662aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
663aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			const void *buff, int len)
664aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{
665aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	int ret;
666aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
6672c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
668aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (!ret) {
669aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
6702c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke		mutex_unlock(&dd->ipath_eep_lock);
671aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
672aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
673aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	return ret;
674aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh}
675aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
676108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic u8 flash_csum(struct ipath_flash *ifp, int adjust)
677108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
678108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u8 *ip = (u8 *) ifp;
679108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u8 csum = 0, len;
680108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
681627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	/*
682627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	 * Limit length checksummed to max length of actual data.
683627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	 * Checksum of erased eeprom will still be bad, but we avoid
684627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	 * reading past the end of the buffer we were passed.
685627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	 */
686627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	len = ifp->if_length;
687627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	if (len > sizeof(struct ipath_flash))
688627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh		len = sizeof(struct ipath_flash);
689627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh	while (len--)
690108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		csum += *ip++;
691108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	csum -= ifp->if_csum;
692108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	csum = ~csum;
693108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (adjust)
694108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ifp->if_csum = csum;
695108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
696108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	return csum;
697108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
698108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
699108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/**
700108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * ipath_get_guid - get the GUID from the i2c device
701108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device
702108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *
703f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivan * We have the capability to use the ipath_nguid field, and get
704f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivan * the guid from the first chip's flash, to use for all of them.
705108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */
706f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivanvoid ipath_get_eeprom_info(struct ipath_devdata *dd)
707108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{
708108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	void *buf;
709108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	struct ipath_flash *ifp;
710108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	__be64 guid;
711aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	int len, eep_stat;
712108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	u8 csum, *bguid;
713108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	int t = dd->ipath_unit;
714108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	struct ipath_devdata *dd0 = ipath_lookup(0);
715108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
716108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
717cf9542aa923982428fbf6a6f815c32ae2c3da8c7Roland Dreier		u8 oguid;
718108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		dd->ipath_guid = dd0->ipath_guid;
719108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bguid = (u8 *) & dd->ipath_guid;
720108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
721108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		oguid = bguid[7];
722108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bguid[7] += t;
723108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		if (oguid > bguid[7]) {
724108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			if (bguid[6] == 0xff) {
725108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				if (bguid[5] == 0xff) {
726108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					ipath_dev_err(
727108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan						dd,
728108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan						"Can't set %s GUID from "
729108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan						"base, wraps to OUI!\n",
730108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan						ipath_get_unit_name(t));
731108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					dd->ipath_guid = 0;
732108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan					goto bail;
733108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				}
734108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan				bguid[5]++;
735108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			}
736108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			bguid[6]++;
737108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		}
738108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		dd->ipath_nguid = 1;
739108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
740108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_dbg("nguid %u, so adding %u to device 0 guid, "
741108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			  "for %llx\n",
742108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			  dd0->ipath_nguid, t,
743108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			  (unsigned long long) be64_to_cpu(dd->ipath_guid));
744108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto bail;
745108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
746108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
747d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	/*
748d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	 * read full flash, not just currently used part, since it may have
749d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	 * been written with a newer definition
750d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	 * */
751d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	len = sizeof(struct ipath_flash);
752108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	buf = vmalloc(len);
753108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (!buf) {
754108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_dev_err(dd, "Couldn't allocate memory to read %u "
755108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			      "bytes from eeprom for GUID\n", len);
756108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto bail;
757108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
758108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
7592c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	mutex_lock(&dd->ipath_eep_lock);
760aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
7612c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	mutex_unlock(&dd->ipath_eep_lock);
762aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
763aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (eep_stat) {
764108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
765108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto done;
766108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
767108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ifp = (struct ipath_flash *)buf;
768108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
769108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	csum = flash_csum(ifp, 0);
770108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (csum != ifp->if_csum) {
771108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		dev_info(&dd->pcidev->dev, "Bad I2C flash checksum: "
772108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			 "0x%x, not 0x%x\n", csum, ifp->if_csum);
773108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto done;
774108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
7759c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison	if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) ||
7769c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison	    *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) {
777108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_dev_err(dd, "Invalid GUID %llx from flash; "
778108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			      "ignoring\n",
779108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			      *(unsigned long long *) ifp->if_guid);
780108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/* don't allow GUID if all 0 or all 1's */
781108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		goto done;
782108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	}
783108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
784108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	/* complain, but allow it */
785108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (*(u64 *) ifp->if_guid == 0x100007511000000ULL)
786108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		dev_info(&dd->pcidev->dev, "Warning, GUID %llx is "
787108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			 "default, probably not correct!\n",
788108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			 *(unsigned long long *) ifp->if_guid);
789108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
790108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	bguid = ifp->if_guid;
791108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	if (!bguid[0] && !bguid[1] && !bguid[2]) {
792108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		/* original incorrect GUID format in flash; fix in
793108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * core copy, by shifting up 2 octets; don't need to
794108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * change top octet, since both it and shifted are
795108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		 * 0.. */
796108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bguid[1] = bguid[3];
797108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bguid[2] = bguid[4];
798108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		bguid[3] = bguid[4] = 0;
799108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		guid = *(__be64 *) ifp->if_guid;
800108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		ipath_cdbg(VERBOSE, "Old GUID format in flash, top 3 zero, "
801108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan			   "shifting 2 octets\n");
802108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	} else
803108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		guid = *(__be64 *) ifp->if_guid;
804108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	dd->ipath_guid = guid;
805108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	dd->ipath_nguid = ifp->if_numguid;
8068307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	/*
8078307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	 * Things are slightly complicated by the desire to transparently
8088307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	 * support both the Pathscale 10-digit serial number and the QLogic
8098307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	 * 13-character version.
8108307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	 */
8118307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	if ((ifp->if_fversion > 1) && ifp->if_sprefix[0]
8128307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		&& ((u8 *)ifp->if_sprefix)[0] != 0xFF) {
8138307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		/* This board has a Serial-prefix, which is stored
8148307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		 * elsewhere for backward-compatibility.
8158307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		 */
8168307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		char *snp = dd->ipath_serial;
8178307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
8188307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		snp[sizeof ifp->if_sprefix] = '\0';
8198307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		len = strlen(snp);
8208307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		snp += len;
8218307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		len = (sizeof dd->ipath_serial) - len;
8228307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		if (len > sizeof ifp->if_serial) {
8238307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan			len = sizeof ifp->if_serial;
8248307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		}
8258307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		memcpy(snp, ifp->if_serial, len);
8268307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan	} else
8278307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		memcpy(dd->ipath_serial, ifp->if_serial,
8288307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan		       sizeof ifp->if_serial);
8299783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan	if (!strstr(ifp->if_comment, "Tested successfully"))
8309783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan		ipath_dev_err(dd, "Board SN %s did not pass functional "
8319783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan			"test: %s\n", dd->ipath_serial,
8329783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan			ifp->if_comment);
8338307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan
834108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n",
835108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan		   (unsigned long long) be64_to_cpu(dd->ipath_guid));
836108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
837aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	memcpy(&dd->ipath_eep_st_errs, &ifp->if_errcntp, IPATH_EEP_LOG_CNT);
838aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/*
839aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * Power-on (actually "active") hours are kept as little-endian value
840aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * in EEPROM, but as seconds in a (possibly as small as 24-bit)
841aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * atomic_t while running.
842aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 */
843aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	atomic_set(&dd->ipath_active_time, 0);
844aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	dd->ipath_eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
845aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
846108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivandone:
847108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan	vfree(buf);
848108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan
849108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:;
850108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}
851aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
852aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh/**
853aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * ipath_update_eeprom_log - copy active-time and error counters to eeprom
854aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @dd: the infinipath device
855aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh *
856aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Although the time is kept as seconds in the ipath_devdata struct, it is
857aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * rounded to hours for re-write, as we have only 16 bits in EEPROM.
858aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * First-cut code reads whole (expected) struct ipath_flash, modifies,
859aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * re-writes. Future direction: read/write only what we need, assuming
860aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * that the EEPROM had to have been "good enough" for driver init, and
861aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * if not, we aren't making it worse.
862aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh *
863aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */
864aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
865aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_update_eeprom_log(struct ipath_devdata *dd)
866aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{
867aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	void *buf;
868aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	struct ipath_flash *ifp;
869aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	int len, hi_water;
870aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	uint32_t new_time, new_hrs;
871aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	u8 csum;
872aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	int ret, idx;
873aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	unsigned long flags;
874aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
875aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/* first, check if we actually need to do anything. */
876aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	ret = 0;
877aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
878aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		if (dd->ipath_eep_st_new_errs[idx]) {
879aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			ret = 1;
880aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			break;
881aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		}
882aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
883aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	new_time = atomic_read(&dd->ipath_active_time);
884aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
885aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (ret == 0 && new_time < 3600)
886aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		return 0;
887aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
888aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/*
889aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * The quick-check above determined that there is something worthy
890aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * of logging, so get current contents and do a more detailed idea.
891d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	 * read full flash, not just currently used part, since it may have
892d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	 * been written with a newer definition
893aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 */
894d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson	len = sizeof(struct ipath_flash);
895aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	buf = vmalloc(len);
896aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	ret = 1;
897aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (!buf) {
898aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ipath_dev_err(dd, "Couldn't allocate memory to read %u "
899aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh				"bytes from eeprom for logging\n", len);
900aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		goto bail;
901aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
902aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
903aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/* Grab semaphore and read current EEPROM. If we get an
904aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * error, let go, but if not, keep it until we finish write.
905aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 */
9062c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
907aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (ret) {
908aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
909aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		goto free_bail;
910aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
911aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	ret = ipath_eeprom_internal_read(dd, 0, buf, len);
912aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (ret) {
9132c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke		mutex_unlock(&dd->ipath_eep_lock);
914aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ipath_dev_err(dd, "Unable read EEPROM for logging\n");
915aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		goto free_bail;
916aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
917aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	ifp = (struct ipath_flash *)buf;
918aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
919aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	csum = flash_csum(ifp, 0);
920aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (csum != ifp->if_csum) {
9212c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke		mutex_unlock(&dd->ipath_eep_lock);
922aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
923aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh				csum, ifp->if_csum);
924aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ret = 1;
925aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		goto free_bail;
926aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
927aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	hi_water = 0;
928aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
929aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
930aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		int new_val = dd->ipath_eep_st_new_errs[idx];
931aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		if (new_val) {
932aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			/*
933aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * If we have seen any errors, add to EEPROM values
934aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * We need to saturate at 0xFF (255) and we also
935aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * would need to adjust the checksum if we were
936aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * trying to minimize EEPROM traffic
937aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * Note that we add to actual current count in EEPROM,
938aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * in case it was altered while we were running.
939aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 */
940aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			new_val += ifp->if_errcntp[idx];
941aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			if (new_val > 0xFF)
942aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh				new_val = 0xFF;
943aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			if (ifp->if_errcntp[idx] != new_val) {
944aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh				ifp->if_errcntp[idx] = new_val;
945aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh				hi_water = offsetof(struct ipath_flash,
946aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh						if_errcntp) + idx;
947aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			}
948aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			/*
949aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * update our shadow (used to minimize EEPROM
950aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 * traffic), to match what we are about to write.
951aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			 */
952aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			dd->ipath_eep_st_errs[idx] = new_val;
953aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			dd->ipath_eep_st_new_errs[idx] = 0;
954aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		}
955aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
956aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/*
957aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * now update active-time. We would like to round to the nearest hour
958aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * but unless atomic_t are sure to be proper signed ints we cannot,
959aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * because we need to account for what we "transfer" to EEPROM and
960aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * if we log an hour at 31 minutes, then we would need to set
961aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * active_time to -29 to accurately count the _next_ hour.
962aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 */
963d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (new_time >= 3600) {
964aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		new_hrs = new_time / 3600;
965aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		atomic_sub((new_hrs * 3600), &dd->ipath_active_time);
966aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		new_hrs += dd->ipath_eep_hrs;
967aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		if (new_hrs > 0xFFFF)
968aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			new_hrs = 0xFFFF;
969aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		dd->ipath_eep_hrs = new_hrs;
970aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
971aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			ifp->if_powerhour[0] = new_hrs & 0xFF;
972aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			hi_water = offsetof(struct ipath_flash, if_powerhour);
973aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		}
974aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
975aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			ifp->if_powerhour[1] = new_hrs >> 8;
976aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh			hi_water = offsetof(struct ipath_flash, if_powerhour)
977aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh					+ 1;
978aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		}
979aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
980aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	/*
981aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * There is a tiny possibility that we could somehow fail to write
982aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * the EEPROM after updating our shadows, but problems from holding
983aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 * the spinlock too long are a much bigger issue.
984aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	 */
985aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
986aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (hi_water) {
987aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		/* we made some change to the data, uopdate cksum and write */
988aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		csum = flash_csum(ifp, 1);
989aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
990aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	}
9912c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke	mutex_unlock(&dd->ipath_eep_lock);
992aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (ret)
993aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		ipath_dev_err(dd, "Failed updating EEPROM\n");
994aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
995aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughfree_bail:
996aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	vfree(buf);
997aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughbail:
998aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	return ret;
999aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
1000aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh}
1001aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
1002aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh/**
1003aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * ipath_inc_eeprom_err - increment one of the four error counters
1004aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * that are logged to EEPROM.
1005aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @dd: the infinipath device
1006aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @eidx: 0..3, the counter to increment
1007aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @incr: how much to add
1008aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh *
1009aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Each counter is 8-bits, and saturates at 255 (0xFF). They
1010aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * are copied to the EEPROM (aka flash) whenever ipath_update_eeprom_log()
1011aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * is called, but it can only be called in a context that allows sleep.
1012aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * This function can be called even at interrupt level.
1013aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */
1014aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
1015aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughvoid ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr)
1016aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{
1017aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	uint new_val;
1018aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	unsigned long flags;
1019aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh
1020aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
1021aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	new_val = dd->ipath_eep_st_new_errs[eidx] + incr;
1022aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	if (new_val > 255)
1023aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh		new_val = 255;
1024aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	dd->ipath_eep_st_new_errs[eidx] = new_val;
1025aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
1026aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh	return;
1027aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh}
1028d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1029d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int ipath_tempsense_internal_read(struct ipath_devdata *dd, u8 regnum)
1030d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
1031d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int ret;
1032d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	struct i2c_chain_desc *icd;
1033d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1034d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = -ENOENT;
1035d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1036d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	icd = ipath_i2c_type(dd);
1037d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!icd)
1038d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1039d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1040d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (icd->temp_dev == IPATH_NO_DEV) {
1041d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* tempsense only exists on new, real-I2C boards */
1042d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1043d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1044d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1045d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1046d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) {
1047d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dbg("Failed tempsense startcmd\n");
1048d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
1049d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1050d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1051d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1052d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = wr_byte(dd, regnum);
1053d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	stop_cmd(dd);
1054d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret) {
1055d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dev_err(dd, "Failed tempsense WR command %02X\n",
1056d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			      regnum);
1057d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1058d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1059d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1060d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (i2c_startcmd(dd, icd->temp_dev | READ_CMD)) {
1061d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dbg("Failed tempsense RD startcmd\n");
1062d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
1063d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1064d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1065d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1066d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/*
1067d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * We can only clock out one byte per command, sensibly
1068d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 */
1069d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = rd_byte(dd);
1070d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	stop_cmd(dd);
1071d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1072d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughbail:
1073d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return ret;
1074d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
1075d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1076d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define VALID_TS_RD_REG_MASK 0xBF
1077d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1078d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/**
1079d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_tempsense_read - read register of temp sensor via I2C
1080d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device
1081d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @regnum: register to read from
1082d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh *
1083d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * returns reg contents (0..255) or < 0 for error
1084d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
1085d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughint ipath_tempsense_read(struct ipath_devdata *dd, u8 regnum)
1086d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
1087d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int ret;
1088d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1089d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (regnum > 7)
1090d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		return -EINVAL;
1091d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1092d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/* return a bogus value for (the one) register we do not have */
1093d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!((1 << regnum) & VALID_TS_RD_REG_MASK))
1094d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		return 0;
1095d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1096d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
1097d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!ret) {
1098d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = ipath_tempsense_internal_read(dd, regnum);
1099d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		mutex_unlock(&dd->ipath_eep_lock);
1100d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1101d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1102d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/*
1103d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * There are three possibilities here:
1104d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is actual value (0..255)
1105d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is -ENXIO or -EINVAL from code in this file
1106d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is -EINTR from mutex_lock_interruptible.
1107d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 */
1108d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return ret;
1109d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
1110d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1111d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int ipath_tempsense_internal_write(struct ipath_devdata *dd,
1112d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh					  u8 regnum, u8 data)
1113d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
1114d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int ret = -ENOENT;
1115d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	struct i2c_chain_desc *icd;
1116d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1117d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	icd = ipath_i2c_type(dd);
1118d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!icd)
1119d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1120d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1121d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (icd->temp_dev == IPATH_NO_DEV) {
1122d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		/* tempsense only exists on new, real-I2C boards */
1123d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1124d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1125d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1126d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) {
1127d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dbg("Failed tempsense startcmd\n");
1128d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
1129d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1130d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1131d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1132d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = wr_byte(dd, regnum);
1133d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret) {
1134d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		stop_cmd(dd);
1135d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dev_err(dd, "Failed to write tempsense command %02X\n",
1136d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			      regnum);
1137d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1138d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		goto bail;
1139d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1140d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = wr_byte(dd, data);
1141d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	stop_cmd(dd);
1142d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = i2c_startcmd(dd, icd->temp_dev | READ_CMD);
1143d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (ret) {
1144d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ipath_dev_err(dd, "Failed tempsense data wrt to %02X\n",
1145d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh			      regnum);
1146d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = -ENXIO;
1147d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1148d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1149d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughbail:
1150d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return ret;
1151d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
1152d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1153d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define VALID_TS_WR_REG_MASK ((1 << 9) | (1 << 0xB) | (1 << 0xD))
1154d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1155d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/**
1156d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_tempsense_write - write register of temp sensor via I2C
1157d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device
1158d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @regnum: register to write
1159d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @data: data to write
1160d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh *
1161d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * returns 0 for success or < 0 for error
1162d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */
1163d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughint ipath_tempsense_write(struct ipath_devdata *dd, u8 regnum, u8 data)
1164d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{
1165d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	int ret;
1166d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1167d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (regnum > 15 || !((1 << regnum) & VALID_TS_WR_REG_MASK))
1168d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		return -EINVAL;
1169d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1170d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
1171d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	if (!ret) {
1172d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		ret = ipath_tempsense_internal_write(dd, regnum, data);
1173d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh		mutex_unlock(&dd->ipath_eep_lock);
1174d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	}
1175d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh
1176d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	/*
1177d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * There are three possibilities here:
1178d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is 0 for success
1179d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is -ENXIO or -EINVAL from code in this file
1180d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 * ret is -EINTR from mutex_lock_interruptible.
1181d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	 */
1182d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh	return ret;
1183d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}
1184