xref: /illumos-gate/usr/src/uts/common/io/i2c/ctrl/pchsmbus/pchsmbus.c (revision 9fe9c13c87b112555793ee3ed5d7de3ef769b461)
1c1733db1SRobert Mustacchi /*
2c1733db1SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3c1733db1SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4c1733db1SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5c1733db1SRobert Mustacchi  * 1.0 of the CDDL.
6c1733db1SRobert Mustacchi  *
7c1733db1SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8c1733db1SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9c1733db1SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10c1733db1SRobert Mustacchi  */
11c1733db1SRobert Mustacchi 
12c1733db1SRobert Mustacchi /*
13*9fe9c13cSRobert Mustacchi  * Copyright 2026 Oxide Computer Company
14c1733db1SRobert Mustacchi  */
15c1733db1SRobert Mustacchi 
16c1733db1SRobert Mustacchi /*
17c1733db1SRobert Mustacchi  * Intel PCH (ICH) SMBus Controller
18c1733db1SRobert Mustacchi  *
19c1733db1SRobert Mustacchi  * This driver supports a wide variety of controllers, having been found in
20c1733db1SRobert Mustacchi  * various Intel chipsets since the late 1990s. The hardware has evolved a
21c1733db1SRobert Mustacchi  * little bit, but it is a controller that only supports SMBus 2.0 and a little
22c1733db1SRobert Mustacchi  * bit of I2C emulation to support EEPROMs that fit in a single address byte. It
23c1733db1SRobert Mustacchi  * cannot run arbitrary I2C commands.
24c1733db1SRobert Mustacchi  *
25c1733db1SRobert Mustacchi  * As a result, the hardware interface is structured around issuing specific
26c1733db1SRobert Mustacchi  * SMBus commands and operations. For non-block based commands this is
27c1733db1SRobert Mustacchi  * straightforward. Unfortunately, for block commands it is less simple. In the
28c1733db1SRobert Mustacchi  * hardware's evolution, support for a block buffer was added. Prior to this one
29c1733db1SRobert Mustacchi  * has to read and write a single byte at a time. With this, one can instead use
30c1733db1SRobert Mustacchi  * the 32-byte buffer for transactions. Notably, 32 bytes comes from the SMBus
31c1733db1SRobert Mustacchi  * 2.0 block limit.
32c1733db1SRobert Mustacchi  *
33c1733db1SRobert Mustacchi  * While this 32-byte buffer is a great simplifying thing, it actually doesn't
34c1733db1SRobert Mustacchi  * work with I2C emulation and therefore we have to do per-byte I/Os in the
35c1733db1SRobert Mustacchi  * device. Because I2C block I/Os are much more common than SMBus, this means
36c1733db1SRobert Mustacchi  * that the block buffer flag, like the I2C flag, are enabled on a per-request
37c1733db1SRobert Mustacchi  * basis.
38c1733db1SRobert Mustacchi  *
39c1733db1SRobert Mustacchi  * When operating in the byte mode, we basically track how many bytes there are
40c1733db1SRobert Mustacchi  * to transmit and receive and will issue all transmit bytes before any repeated
41c1733db1SRobert Mustacchi  * start that requires reading.
42c1733db1SRobert Mustacchi  */
43c1733db1SRobert Mustacchi 
44c1733db1SRobert Mustacchi #include <sys/modctl.h>
45c1733db1SRobert Mustacchi #include <sys/conf.h>
46c1733db1SRobert Mustacchi #include <sys/devops.h>
47c1733db1SRobert Mustacchi #include <sys/ddi.h>
48c1733db1SRobert Mustacchi #include <sys/sunddi.h>
49c1733db1SRobert Mustacchi #include <sys/pci.h>
50c1733db1SRobert Mustacchi #include <sys/sysmacros.h>
51c1733db1SRobert Mustacchi 
52c1733db1SRobert Mustacchi #include <sys/i2c/controller.h>
53c1733db1SRobert Mustacchi #include "pchsmbus.h"
54c1733db1SRobert Mustacchi 
55c1733db1SRobert Mustacchi /*
56c1733db1SRobert Mustacchi  * The controller only has a single BAR which contains what we need. This may be
57c1733db1SRobert Mustacchi  * in I/O space or MMIO space, but which it is doesn't make a difference to the
58c1733db1SRobert Mustacchi  * driver itself.
59c1733db1SRobert Mustacchi  */
60c1733db1SRobert Mustacchi #define	PCHSMBUS_REGNO	1
61c1733db1SRobert Mustacchi 
62c1733db1SRobert Mustacchi typedef enum {
63c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_PCI		= 1 << 0,
64c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_REGS		= 1 << 1,
65c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_INTR_ALLOC	= 1 << 2,
66c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_INTR_HDL		= 1 << 3,
67c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_SYNC		= 1 << 4,
68c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_CTRL		= 1 << 5,
69c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_INTR_EN		= 1 << 6,
70c1733db1SRobert Mustacchi 	PCHSMBUS_INIT_I2C		= 1 << 7,
71c1733db1SRobert Mustacchi 	/*
72c1733db1SRobert Mustacchi 	 * The following are used at run time.
73c1733db1SRobert Mustacchi 	 */
74c1733db1SRobert Mustacchi 	PCHSMBUS_RUN_BUF_EN		= 1 << 8,
75c1733db1SRobert Mustacchi 	PCHSMBUS_RUN_I2C_EN		= 1 << 9
76c1733db1SRobert Mustacchi } pchsmbus_init_t;
77c1733db1SRobert Mustacchi 
78c1733db1SRobert Mustacchi typedef struct {
79c1733db1SRobert Mustacchi 	dev_info_t *ps_dip;
80c1733db1SRobert Mustacchi 	ddi_acc_handle_t ps_cfg;
81c1733db1SRobert Mustacchi 	pchsmbus_init_t ps_init;
82c1733db1SRobert Mustacchi 	pch_smbus_feat_t ps_feats;
83c1733db1SRobert Mustacchi 	/*
84c1733db1SRobert Mustacchi 	 * Register related data
85c1733db1SRobert Mustacchi 	 */
86c1733db1SRobert Mustacchi 	caddr_t ps_base;
87c1733db1SRobert Mustacchi 	off_t ps_regsize;
88c1733db1SRobert Mustacchi 	ddi_acc_handle_t ps_regs;
89c1733db1SRobert Mustacchi 	uint32_t ps_init_hcfg;
90c1733db1SRobert Mustacchi 	uint8_t ps_init_hctl;
91c1733db1SRobert Mustacchi 	uint8_t ps_init_scmd;
92c1733db1SRobert Mustacchi 	/*
93c1733db1SRobert Mustacchi 	 * Interrupt data
94c1733db1SRobert Mustacchi 	 */
95c1733db1SRobert Mustacchi 	int ps_nintrs;
96c1733db1SRobert Mustacchi 	ddi_intr_handle_t ps_intr_hdl;
97c1733db1SRobert Mustacchi 	uint_t ps_intr_pri;
98c1733db1SRobert Mustacchi 	/*
99c1733db1SRobert Mustacchi 	 * Request and framework synchronization
100c1733db1SRobert Mustacchi 	 */
101c1733db1SRobert Mustacchi 	kmutex_t ps_mutex;
102c1733db1SRobert Mustacchi 	kcondvar_t ps_cv;
103c1733db1SRobert Mustacchi 	i2c_ctrl_hdl_t *ps_hdl;
104c1733db1SRobert Mustacchi 	smbus_req_t *ps_req;
105c1733db1SRobert Mustacchi 	uint16_t ps_req_off;
106c1733db1SRobert Mustacchi 	uint8_t ps_req_hctl;
107c1733db1SRobert Mustacchi 	bool ps_req_done;
108c1733db1SRobert Mustacchi 	i2c_ctrl_error_t ps_kill_err;
109c1733db1SRobert Mustacchi } pchsmbus_t;
110c1733db1SRobert Mustacchi 
111c1733db1SRobert Mustacchi typedef struct {
112c1733db1SRobert Mustacchi 	uint16_t pcm_did;
113c1733db1SRobert Mustacchi 	pch_smbus_feat_t pcm_feat;
114c1733db1SRobert Mustacchi } pchsmbus_hw_map_t;
115c1733db1SRobert Mustacchi 
116c1733db1SRobert Mustacchi static const pchsmbus_hw_map_t pchsmbus_feats[] = {
117c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH0_82801AA, 0 },
118c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH0_82901AB, 0 },
119c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH2_82801BA, PCH_SMBUS_FEAT_TARG },
120c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH3_82801CA, PCH_SMBUS_FEAT_ALL_ICH3 },
121c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH4_82801DB, PCH_SMBUS_FEAT_ALL_ICH4 },
122c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH5_82801Ex, PCH_SMBUS_FEAT_ALL_ICH5 },
123c1733db1SRobert Mustacchi 	{ PCH_SMBUS_6300ESB, PCH_SMBUS_FEAT_ALL_ICH5 },
124c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH6, PCH_SMBUS_FEAT_ALL_ICH5 },
125c1733db1SRobert Mustacchi 	{ PCH_SMBUS_631xESB, PCH_SMBUS_FEAT_ALL_ICH5 },
126c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH7, PCH_SMBUS_FEAT_ALL_ICH5 },
127c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH8, PCH_SMBUS_FEAT_ALL_ICH8 },
128c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH9, PCH_SMBUS_FEAT_ALL_ICH8 },
129c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH10_CORP, PCH_SMBUS_FEAT_ALL_ICH8 },
130c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICH10_USER, PCH_SMBUS_FEAT_ALL_ICH8 },
131c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH5, PCH_SMBUS_FEAT_ALL_ICH8 },
132c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C600, PCH_SMBUS_FEAT_ALL_ICH8 },
133c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C600_SMB0, PCH_SMBUS_FEAT_ALL_ICH8 },
134c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C600_SMB1, PCH_SMBUS_FEAT_ALL_ICH8 },
135c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C600_SMB2, PCH_SMBUS_FEAT_ALL_ICH8 },
136c1733db1SRobert Mustacchi 	{ PCH_SMBUS_DH89xxCC, PCH_SMBUS_FEAT_ALL_ICH8 },
137c1733db1SRobert Mustacchi 	{ PCH_SMBUS_DH89xxCL, PCH_SMBUS_FEAT_ALL_ICH8 },
138c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH6, PCH_SMBUS_FEAT_ALL_ICH8 },
139c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH7, PCH_SMBUS_FEAT_ALL_ICH8 },
140c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH8, PCH_SMBUS_FEAT_ALL_ICH8 },
141c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH8_LP, PCH_SMBUS_FEAT_ALL_ICH8 },
142c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C610, PCH_SMBUS_FEAT_ALL_ICH8 },
143c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C610_MS0, PCH_SMBUS_FEAT_ALL_ICH8 },
144c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C610_MS1, PCH_SMBUS_FEAT_ALL_ICH8 },
145c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C610_MS2, PCH_SMBUS_FEAT_ALL_ICH8 },
146c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH9, PCH_SMBUS_FEAT_ALL_ICH8 },
147c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PCH9_LP, PCH_SMBUS_FEAT_ALL_ICH8 },
148c1733db1SRobert Mustacchi 	{ PCH_SMBUS_BAYTRAIL, PCH_SMBUS_FEAT_ALL_ICH8 },
149c1733db1SRobert Mustacchi 	{ PCH_SMBUS_100, PCH_SMBUS_FEAT_ALL_ICH8 },
150c1733db1SRobert Mustacchi 	{ PCH_SMBUS_DENVERTON, PCH_SMBUS_FEAT_ALL_ICH8 },
151c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C740, PCH_SMBUS_FEAT_ALL_ICH8 },
152c1733db1SRobert Mustacchi 	{ PCH_SMBUS_APOLLO, PCH_SMBUS_FEAT_ALL_ICH8 },
153c1733db1SRobert Mustacchi 	{ PCH_SMBUS_200, PCH_SMBUS_FEAT_ALL_ICH8 },
154c1733db1SRobert Mustacchi 	{ PCH_SMBUS_GEMINI, PCH_SMBUS_FEAT_ALL_ICH8 },
155c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C620, PCH_SMBUS_FEAT_ALL_ICH8 },
156c1733db1SRobert Mustacchi 	{ PCH_SMBUS_C620_SUPER, PCH_SMBUS_FEAT_ALL_ICH8 },
157c1733db1SRobert Mustacchi 	{ PCH_SMBUS_300, PCH_SMBUS_FEAT_ALL_ICH8 },
158c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ICE_LAKE_D, PCH_SMBUS_FEAT_ALL_ICH8 },
159c1733db1SRobert Mustacchi 	{ PCH_SMBUS_495_PKG, PCH_SMBUS_FEAT_ALL_ICH8 },
160c1733db1SRobert Mustacchi 	{ PCH_SMBUS_400, PCH_SMBUS_FEAT_ALL_ICH8 },
161c1733db1SRobert Mustacchi 	{ PCH_SMBUS_400_PKG, PCH_SMBUS_FEAT_ALL_ICH8 },
162c1733db1SRobert Mustacchi 	{ PCH_SMBUS_ELKHART, PCH_SMBUS_FEAT_ALL_ICH8 },
163c1733db1SRobert Mustacchi 	{ PCH_SMBUS_500, PCH_SMBUS_FEAT_ALL_ICH8 },
164c1733db1SRobert Mustacchi 	{ PCH_SMBUS_500_PKG, PCH_SMBUS_FEAT_ALL_ICH8 },
165c1733db1SRobert Mustacchi 	{ PCH_SMBUS_JASPER, PCH_SMBUS_FEAT_ALL_ICH8 },
166c1733db1SRobert Mustacchi 	{ PCH_SMBUS_600, PCH_SMBUS_FEAT_ALL_ICH8 },
167c1733db1SRobert Mustacchi 	{ PCH_SMBUS_600_PKG, PCH_SMBUS_FEAT_ALL_ICH8 },
168*9fe9c13cSRobert Mustacchi 	{ PCH_SMBUS_ALDER_N, PCH_SMBUS_FEAT_ALL_ICH8 },
169*9fe9c13cSRobert Mustacchi 	{ PCH_SMBUS_700, PCH_SMBUS_FEAT_ALL_ICH8 },
170c1733db1SRobert Mustacchi 	{ PCH_SMBUS_800, PCH_SMBUS_FEAT_ALL_ICH8 },
171c1733db1SRobert Mustacchi 	{ PCH_SMBUS_METEOR_PS, PCH_SMBUS_FEAT_ALL_ICH8 },
172c1733db1SRobert Mustacchi 	{ PCH_SMBUS_PANTHER_H, PCH_SMBUS_FEAT_ALL_ICH8 },
173*9fe9c13cSRobert Mustacchi 	{ PCH_SMBUS_PANTHER_P, PCH_SMBUS_FEAT_ALL_ICH8 },
174*9fe9c13cSRobert Mustacchi 	{ PCH_SMBUS_900, PCH_SMBUS_FEAT_ALL_ICH8 }
175c1733db1SRobert Mustacchi };
176c1733db1SRobert Mustacchi 
177c1733db1SRobert Mustacchi static uint8_t
pchsmbus_read8(pchsmbus_t * pch,uint8_t regno)178c1733db1SRobert Mustacchi pchsmbus_read8(pchsmbus_t *pch, uint8_t regno)
179c1733db1SRobert Mustacchi {
180c1733db1SRobert Mustacchi 	ASSERT3U(regno, <, pch->ps_regsize);
181c1733db1SRobert Mustacchi 
182c1733db1SRobert Mustacchi 	return (ddi_get8(pch->ps_regs, (uint8_t *)(pch->ps_base + regno)));
183c1733db1SRobert Mustacchi }
184c1733db1SRobert Mustacchi 
185c1733db1SRobert Mustacchi static void
pchsmbus_write8(pchsmbus_t * pch,uint8_t regno,uint8_t val)186c1733db1SRobert Mustacchi pchsmbus_write8(pchsmbus_t *pch, uint8_t regno, uint8_t val)
187c1733db1SRobert Mustacchi {
188c1733db1SRobert Mustacchi 	ASSERT3U(regno, <, pch->ps_regsize);
189c1733db1SRobert Mustacchi 
190c1733db1SRobert Mustacchi 	ddi_put8(pch->ps_regs, (uint8_t *)(pch->ps_base + regno), val);
191c1733db1SRobert Mustacchi }
192c1733db1SRobert Mustacchi 
193c1733db1SRobert Mustacchi static i2c_errno_t
pchsmbus_prop_info(void * arg,i2c_prop_t prop,i2c_prop_info_t * info)194c1733db1SRobert Mustacchi pchsmbus_prop_info(void *arg, i2c_prop_t prop, i2c_prop_info_t *info)
195c1733db1SRobert Mustacchi {
196c1733db1SRobert Mustacchi 	switch (prop) {
197c1733db1SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
198c1733db1SRobert Mustacchi 		i2c_prop_info_set_def_u32(info, I2C_SPEED_STD);
199c1733db1SRobert Mustacchi 		i2c_prop_info_set_pos_bit32(info, I2C_SPEED_STD);
200c1733db1SRobert Mustacchi 		break;
201c1733db1SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
202c1733db1SRobert Mustacchi 	case SMBUS_PROP_MAX_BLOCK:
203c1733db1SRobert Mustacchi 		break;
204c1733db1SRobert Mustacchi 	default:
205c1733db1SRobert Mustacchi 		return (I2C_PROP_E_UNSUP);
206c1733db1SRobert Mustacchi 	}
207c1733db1SRobert Mustacchi 
208c1733db1SRobert Mustacchi 	/*
209c1733db1SRobert Mustacchi 	 * We can't set any timing properties or the speed really, so we
210c1733db1SRobert Mustacchi 	 * indicate that all properties are read-only.
211c1733db1SRobert Mustacchi 	 */
212c1733db1SRobert Mustacchi 	i2c_prop_info_set_perm(info, I2C_PROP_PERM_RO);
213c1733db1SRobert Mustacchi 
214c1733db1SRobert Mustacchi 	return (I2C_CORE_E_OK);
215c1733db1SRobert Mustacchi }
216c1733db1SRobert Mustacchi 
217c1733db1SRobert Mustacchi static i2c_errno_t
pchsmbus_prop_get(void * arg,i2c_prop_t prop,void * buf,size_t buflen)218c1733db1SRobert Mustacchi pchsmbus_prop_get(void *arg, i2c_prop_t prop, void *buf, size_t buflen)
219c1733db1SRobert Mustacchi {
220c1733db1SRobert Mustacchi 	uint32_t val;
221c1733db1SRobert Mustacchi 
222c1733db1SRobert Mustacchi 	switch (prop) {
223c1733db1SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
224c1733db1SRobert Mustacchi 		val = I2C_SPEED_STD;
225c1733db1SRobert Mustacchi 		break;
226c1733db1SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
227c1733db1SRobert Mustacchi 		val = SMBUS_PROP_OP_QUICK_COMMAND | SMBUS_PROP_OP_SEND_BYTE |
228c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_RECV_BYTE | SMBUS_PROP_OP_WRITE_BYTE |
229c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_READ_BYTE | SMBUS_PROP_OP_WRITE_WORD |
230c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_READ_WORD | SMBUS_PROP_OP_PROCESS_CALL |
231c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_WRITE_BLOCK | SMBUS_PROP_OP_READ_BLOCK |
232c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_BLOCK_PROCESS_CALL |
233c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_I2C_WRITE_BLOCK |
234c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_I2C_READ_BLOCK;
235c1733db1SRobert Mustacchi 		break;
236c1733db1SRobert Mustacchi 	case SMBUS_PROP_MAX_BLOCK:
237c1733db1SRobert Mustacchi 		val = SMBUS_V2_MAX_BLOCK;
238c1733db1SRobert Mustacchi 		break;
239c1733db1SRobert Mustacchi 	default:
240c1733db1SRobert Mustacchi 		return (I2C_PROP_E_UNSUP);
241c1733db1SRobert Mustacchi 	}
242c1733db1SRobert Mustacchi 
243c1733db1SRobert Mustacchi 	VERIFY3U(buflen, >=, sizeof (val));
244c1733db1SRobert Mustacchi 	bcopy(&val, buf, sizeof (val));
245c1733db1SRobert Mustacchi 	return (I2C_CORE_E_OK);
246c1733db1SRobert Mustacchi }
247c1733db1SRobert Mustacchi 
248c1733db1SRobert Mustacchi static bool
pchsmbus_bus_avail(pchsmbus_t * pch)249c1733db1SRobert Mustacchi pchsmbus_bus_avail(pchsmbus_t *pch)
250c1733db1SRobert Mustacchi {
251c1733db1SRobert Mustacchi 	const uint32_t count = i2c_ctrl_timeout_count(pch->ps_hdl,
252c1733db1SRobert Mustacchi 	    I2C_CTRL_TO_BUS_ACT);
253c1733db1SRobert Mustacchi 	const uint32_t wait = i2c_ctrl_timeout_delay_us(pch->ps_hdl,
254c1733db1SRobert Mustacchi 	    I2C_CTRL_TO_BUS_ACT);
255c1733db1SRobert Mustacchi 
256c1733db1SRobert Mustacchi 	for (uint32_t i = 0; i < count; i++) {
257c1733db1SRobert Mustacchi 		uint8_t hsts = pchsmbus_read8(pch, PCH_R_BAR_HSTS);
258c1733db1SRobert Mustacchi 		if ((hsts & PCH_HSTS_BUSY) == 0) {
259c1733db1SRobert Mustacchi 			return (true);
260c1733db1SRobert Mustacchi 		}
261c1733db1SRobert Mustacchi 
262c1733db1SRobert Mustacchi 		delay(drv_usectohz(wait));
263c1733db1SRobert Mustacchi 	}
264c1733db1SRobert Mustacchi 
265c1733db1SRobert Mustacchi 	dev_err(pch->ps_dip, CE_WARN, "controller timed out waiting for "
266c1733db1SRobert Mustacchi 	    "bus activity to cease");
267c1733db1SRobert Mustacchi 	return (false);
268c1733db1SRobert Mustacchi }
269c1733db1SRobert Mustacchi 
270c1733db1SRobert Mustacchi static void
pchsmbus_set_addr(pchsmbus_t * pch,const smbus_req_t * req,bool write)271c1733db1SRobert Mustacchi pchsmbus_set_addr(pchsmbus_t *pch, const smbus_req_t *req, bool write)
272c1733db1SRobert Mustacchi {
273c1733db1SRobert Mustacchi 	uint8_t addr = 0;
274c1733db1SRobert Mustacchi 	uint8_t wbit = write ? PCH_R_TSA_RW_WRITE : PCH_R_TSA_RW_READ;
275c1733db1SRobert Mustacchi 
276c1733db1SRobert Mustacchi 
277c1733db1SRobert Mustacchi 	ASSERT3U(req->smbr_addr.ia_type, ==, I2C_ADDR_7BIT);
278c1733db1SRobert Mustacchi 	addr = PCH_R_TSA_SET_ADDR(addr, req->smbr_addr.ia_addr);
279c1733db1SRobert Mustacchi 	addr = PCH_R_TSA_SET_RW(addr, wbit);
280c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_TSA, addr);
281c1733db1SRobert Mustacchi }
282c1733db1SRobert Mustacchi 
283c1733db1SRobert Mustacchi static pch_smbus_cmd_t
pchsmbus_req_to_cmd(const smbus_req_t * req)284c1733db1SRobert Mustacchi pchsmbus_req_to_cmd(const smbus_req_t *req)
285c1733db1SRobert Mustacchi {
286c1733db1SRobert Mustacchi 	switch (req->smbr_op) {
287c1733db1SRobert Mustacchi 	case SMBUS_OP_QUICK_COMMAND:
288c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_QUICK);
289c1733db1SRobert Mustacchi 	case SMBUS_OP_SEND_BYTE:
290c1733db1SRobert Mustacchi 	case SMBUS_OP_RECV_BYTE:
291c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_BYTE);
292c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BYTE:
293c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BYTE:
294c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_BYTE_DATA);
295c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_WORD:
296c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_WORD:
297c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_WORD_DATA);
298c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
299c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
300c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
301c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_BLOCK);
302c1733db1SRobert Mustacchi 	case SMBUS_OP_PROCESS_CALL:
303c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_PROC_CALL);
304c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
305c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_BLOCK_PROC);
306c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
307c1733db1SRobert Mustacchi 		return (PCH_SMBUS_CMD_I2C_READ);
308c1733db1SRobert Mustacchi 	default:
309c1733db1SRobert Mustacchi 		panic("asked to translate unexpected request type: 0x%x",
310c1733db1SRobert Mustacchi 		    req->smbr_op);
311c1733db1SRobert Mustacchi 	}
312c1733db1SRobert Mustacchi }
313c1733db1SRobert Mustacchi 
314c1733db1SRobert Mustacchi /*
315c1733db1SRobert Mustacchi  * Initialize a block request. These are the most complicated requests to deal
316c1733db1SRobert Mustacchi  * with because of the different variations. There are two modes of operation: a
317c1733db1SRobert Mustacchi  * 32 byte buffer that we can use to just take care of the operation in one shot
318c1733db1SRobert Mustacchi  * or a single byte at a time operation. Most hardware supports the 32 byte
319c1733db1SRobert Mustacchi  * buffer; however, when performing an I2C read or write, it must operate in
320c1733db1SRobert Mustacchi  * byte at a time mode.
321c1733db1SRobert Mustacchi  *
322c1733db1SRobert Mustacchi  * We also need to update the controller registers. This means specifically:
323c1733db1SRobert Mustacchi  *
324c1733db1SRobert Mustacchi  *  - Enabling I2C mode specifically for I2C block writes. This is not required
325c1733db1SRobert Mustacchi  *    for I2C block reads which have their own dedicated command in the
326c1733db1SRobert Mustacchi  *    controller.
327c1733db1SRobert Mustacchi  *  - Enabling the 32-byte buffer for block reads when it's supported in
328c1733db1SRobert Mustacchi  *    hardware. This cannot be done for I2C operations and must be done for
329c1733db1SRobert Mustacchi  *    block procedure calls. We will not advertise support for block procedure
330c1733db1SRobert Mustacchi  *    calls to the framework if they are not supported in hardware.
331c1733db1SRobert Mustacchi  *
332c1733db1SRobert Mustacchi  * Note, regardless of whether this is the 'i2c' form or not, we are going to
333c1733db1SRobert Mustacchi  * end up issuing the 'command' register. When doing an i2c block read, the
334c1733db1SRobert Mustacchi  * controller will issue a repeated start and do the transition to a read.
335c1733db1SRobert Mustacchi  */
336c1733db1SRobert Mustacchi static void
pchsmbus_io_init_block(pchsmbus_t * pch,const smbus_req_t * req)337c1733db1SRobert Mustacchi pchsmbus_io_init_block(pchsmbus_t *pch, const smbus_req_t *req)
338c1733db1SRobert Mustacchi {
339c1733db1SRobert Mustacchi 	bool write, want_buf = false, want_i2c = false;
340c1733db1SRobert Mustacchi 
341c1733db1SRobert Mustacchi 	switch (req->smbr_op) {
342c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
343c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
344c1733db1SRobert Mustacchi 		want_buf = true;
345c1733db1SRobert Mustacchi 		write = true;
346c1733db1SRobert Mustacchi 		break;
347c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
348c1733db1SRobert Mustacchi 		want_buf = true;
349c1733db1SRobert Mustacchi 		write = false;
350c1733db1SRobert Mustacchi 		break;
351c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
352c1733db1SRobert Mustacchi 		write = true;
353c1733db1SRobert Mustacchi 		want_buf = false;
354c1733db1SRobert Mustacchi 		/*
355c1733db1SRobert Mustacchi 		 * This is the only operation that requires an explicit I2C
356c1733db1SRobert Mustacchi 		 * enable. This causes us to skip sending the byte count. This
357c1733db1SRobert Mustacchi 		 * isn't required for the I2C Read Block operation because it's
358c1733db1SRobert Mustacchi 		 * just part of the controller's semantics.
359c1733db1SRobert Mustacchi 		 */
360c1733db1SRobert Mustacchi 		want_i2c = true;
361c1733db1SRobert Mustacchi 		break;
362c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
363c1733db1SRobert Mustacchi 		/*
364c1733db1SRobert Mustacchi 		 * Yes, this seems on the face an oxymoron. The reason for this
365c1733db1SRobert Mustacchi 		 * is buried in the datasheets (though some are inconsistent).
366c1733db1SRobert Mustacchi 		 * When issuing an I2C block read we first are going to do a
367c1733db1SRobert Mustacchi 		 * write with a byte and then issue a repeated start with a
368c1733db1SRobert Mustacchi 		 * read. The first thing we do will be a write, hence we set
369c1733db1SRobert Mustacchi 		 * this.
370c1733db1SRobert Mustacchi 		 *
371c1733db1SRobert Mustacchi 		 * However, this gets more nuanced. There exists the SPD write
372c1733db1SRobert Mustacchi 		 * disable bit which was added in the PCH7 generation. When this
373c1733db1SRobert Mustacchi 		 * is set, this needs to be false. This is likely why some
374c1733db1SRobert Mustacchi 		 * chipsets after this generation say this should always be
375c1733db1SRobert Mustacchi 		 * treated as a read (i.e. Ice Lake-D); however, this is also
376c1733db1SRobert Mustacchi 		 * contradicted by other devices between PCH7 and Ice Lake such
377c1733db1SRobert Mustacchi 		 * as the 100/200-series chipsets. A right mess, isn't it?
378c1733db1SRobert Mustacchi 		 */
379c1733db1SRobert Mustacchi 		write = PCH_R_HCFG_GET_SPDWD(pch->ps_init_hcfg) == 0;
380c1733db1SRobert Mustacchi 		break;
381c1733db1SRobert Mustacchi 	default:
382c1733db1SRobert Mustacchi 		panic("programmer error: not a block type: 0x%x\n",
383c1733db1SRobert Mustacchi 		    req->smbr_op);
384c1733db1SRobert Mustacchi 	}
385c1733db1SRobert Mustacchi 
386c1733db1SRobert Mustacchi 	if ((pch->ps_feats & PCH_SMBUS_FEAT_32B_BUF) == 0)
387c1733db1SRobert Mustacchi 		want_buf = false;
388c1733db1SRobert Mustacchi 
389c1733db1SRobert Mustacchi 	VERIFY(!(want_i2c && want_buf));
390c1733db1SRobert Mustacchi 	if (want_i2c) {
391c1733db1SRobert Mustacchi 		uint32_t val = pci_config_get32(pch->ps_cfg, PCH_R_PCIE_HCFG);
392c1733db1SRobert Mustacchi 		val = PCH_R_HCFG_SET_I2CEN(val, 1);
393c1733db1SRobert Mustacchi 		pci_config_put32(pch->ps_cfg, PCH_R_PCIE_HCFG, val);
394c1733db1SRobert Mustacchi 		pch->ps_init |= PCHSMBUS_RUN_I2C_EN;
395c1733db1SRobert Mustacchi 	}
396c1733db1SRobert Mustacchi 
397c1733db1SRobert Mustacchi 	if (want_buf) {
398c1733db1SRobert Mustacchi 		uint8_t val = pchsmbus_read8(pch, PCH_R_BAR_AUXC);
399c1733db1SRobert Mustacchi 		val = PCH_R_AUXC_SET_E32B(val, 1);
400c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_AUXC, val);
401c1733db1SRobert Mustacchi 		pch->ps_init |= PCHSMBUS_RUN_BUF_EN;
402c1733db1SRobert Mustacchi 	}
403c1733db1SRobert Mustacchi 
404c1733db1SRobert Mustacchi 	/*
405c1733db1SRobert Mustacchi 	 * All operations get the address and the command register set. Though
406c1733db1SRobert Mustacchi 	 * of course the I2C Block read actually doesn't use the command
407c1733db1SRobert Mustacchi 	 * register and instead uses the data 1 register for it.
408c1733db1SRobert Mustacchi 	 */
409c1733db1SRobert Mustacchi 	pchsmbus_set_addr(pch, req, write);
410c1733db1SRobert Mustacchi 	if (req->smbr_op == SMBUS_OP_I2C_READ_BLOCK) {
411c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HD1, req->smbr_cmd);
412c1733db1SRobert Mustacchi 	} else {
413c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCMD, req->smbr_cmd);
414c1733db1SRobert Mustacchi 	}
415c1733db1SRobert Mustacchi 
416c1733db1SRobert Mustacchi 	/*
417c1733db1SRobert Mustacchi 	 * If this is a read command, there is nothing else to do. For the
418c1733db1SRobert Mustacchi 	 * various write types we must actually write the data in question.
419c1733db1SRobert Mustacchi 	 */
420c1733db1SRobert Mustacchi 	if (req->smbr_op == SMBUS_OP_I2C_READ_BLOCK || SMBUS_OP_READ_BLOCK) {
421c1733db1SRobert Mustacchi 		return;
422c1733db1SRobert Mustacchi 	}
423c1733db1SRobert Mustacchi 
424c1733db1SRobert Mustacchi 	/*
425c1733db1SRobert Mustacchi 	 * For all writes, regardless of length, indicate how many bytes are in
426c1733db1SRobert Mustacchi 	 * the transaction.
427c1733db1SRobert Mustacchi 	 */
428c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_HD0, req->smbr_wlen);
429c1733db1SRobert Mustacchi 	uint16_t wlen = req->smbr_wlen;
430c1733db1SRobert Mustacchi 	if (!want_buf) {
431c1733db1SRobert Mustacchi 		wlen = 1;
432c1733db1SRobert Mustacchi 	}
433c1733db1SRobert Mustacchi 
434c1733db1SRobert Mustacchi 	/*
435c1733db1SRobert Mustacchi 	 * Explicitly reset the index into the buffer. This is a nop if we're
436c1733db1SRobert Mustacchi 	 * not using the buffer.
437c1733db1SRobert Mustacchi 	 */
438c1733db1SRobert Mustacchi 	(void) pchsmbus_read8(pch, PCH_R_BAR_HCTL);
439c1733db1SRobert Mustacchi 	for (uint16_t i = 0; i < wlen; i++, pch->ps_req_off++) {
440c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HBD, req->smbr_wdata[i]);
441c1733db1SRobert Mustacchi 	}
442c1733db1SRobert Mustacchi }
443c1733db1SRobert Mustacchi 
444c1733db1SRobert Mustacchi /*
445c1733db1SRobert Mustacchi  * We have one of three different general classes of errors that we need to
446c1733db1SRobert Mustacchi  * prioritize and synthesize into useful errors upstack. We treat them in the
447c1733db1SRobert Mustacchi  * following order:
448c1733db1SRobert Mustacchi  *
449c1733db1SRobert Mustacchi  * 1) The FAIL error takes priority as this is set due to a request by us to
450c1733db1SRobert Mustacchi  *    abort the error. The driver sets the appropriate error to use in our
451c1733db1SRobert Mustacchi  *    device structure before issuing this.
452c1733db1SRobert Mustacchi  * 2) The Bus Error indicates that something went wrong on the bus itself. The
453c1733db1SRobert Mustacchi  *    datasheet says it's a general transaction collision or a bus arbitration
454c1733db1SRobert Mustacchi  *    loss. We always translate that into I2C_CTRL_E_ARB_LOST.
455c1733db1SRobert Mustacchi  * 3) The device error is a combination of different possibilities. The most
456c1733db1SRobert Mustacchi  *    common case is getting no acknowledgement. However, this can also happen
457c1733db1SRobert Mustacchi  *    because the driver requests an illegal command, a PEC error occurs, or we
458c1733db1SRobert Mustacchi  *    exceed the 25 ms SMBus timeout. This is definitely unfortunate, but we
459c1733db1SRobert Mustacchi  *    basically just stick to the unknown I2C_CTRL_E_NACK.
460c1733db1SRobert Mustacchi  */
461c1733db1SRobert Mustacchi static void
pchsmbus_io_error(pchsmbus_t * pch,pch_smbus_sts_t status)462c1733db1SRobert Mustacchi pchsmbus_io_error(pchsmbus_t *pch, pch_smbus_sts_t status)
463c1733db1SRobert Mustacchi {
464c1733db1SRobert Mustacchi 	i2c_ctrl_error_t err;
465c1733db1SRobert Mustacchi 
466c1733db1SRobert Mustacchi 	if ((status & PCH_HSTS_FAIL) != 0) {
467c1733db1SRobert Mustacchi 		ASSERT3U(pch->ps_kill_err, !=, I2C_CTRL_E_OK);
468c1733db1SRobert Mustacchi 		err = pch->ps_kill_err;
469c1733db1SRobert Mustacchi 	} else if ((status & PCH_HSTS_BUS_ERR)) {
470c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_ARB_LOST;
471c1733db1SRobert Mustacchi 	} else {
472c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_NACK;
473c1733db1SRobert Mustacchi 	}
474c1733db1SRobert Mustacchi 
475c1733db1SRobert Mustacchi 	i2c_ctrl_io_error(&pch->ps_req->smbr_error, I2C_CORE_E_CONTROLLER,
476c1733db1SRobert Mustacchi 	    err);
477c1733db1SRobert Mustacchi 	pch->ps_req_done = true;
478c1733db1SRobert Mustacchi }
479c1733db1SRobert Mustacchi 
480c1733db1SRobert Mustacchi /*
481c1733db1SRobert Mustacchi  * We have received a byte done callback. This means that we're either
482c1733db1SRobert Mustacchi  * performing a read or write. The controller does not support performing both
483c1733db1SRobert Mustacchi  * without the buffer enabled.
484c1733db1SRobert Mustacchi  *
485c1733db1SRobert Mustacchi  * If we are writing, we need to write the next byte into the buffer. If there
486c1733db1SRobert Mustacchi  * is any more.
487c1733db1SRobert Mustacchi  *
488c1733db1SRobert Mustacchi  * If we are reading, we need to read the next byte out of the buffer. It the
489c1733db1SRobert Mustacchi  * subsequent byte (the one after we just read) would be the last one, then we
490c1733db1SRobert Mustacchi  * need to indicate to the controller that this it will be the last byte. When
491c1733db1SRobert Mustacchi  * executing an SMBus block read, the data length is not known in advance.
492c1733db1SRobert Mustacchi  *
493c1733db1SRobert Mustacchi  * In both cases, reading or writing all bytes is not indicating of completing
494c1733db1SRobert Mustacchi  * the command. The controller explicitly sets the INTR status bit for that.
495c1733db1SRobert Mustacchi  */
496c1733db1SRobert Mustacchi static void
pchsmbus_io_byte_done(pchsmbus_t * pch)497c1733db1SRobert Mustacchi pchsmbus_io_byte_done(pchsmbus_t *pch)
498c1733db1SRobert Mustacchi {
499c1733db1SRobert Mustacchi 	ASSERT(MUTEX_HELD(&pch->ps_mutex));
500c1733db1SRobert Mustacchi 	ASSERT3U(pch->ps_init & PCHSMBUS_RUN_BUF_EN, ==, 0);
501c1733db1SRobert Mustacchi 	ASSERT3P(pch->ps_req, !=, NULL);
502c1733db1SRobert Mustacchi 
503c1733db1SRobert Mustacchi 	if (pch->ps_req->smbr_op == SMBUS_OP_WRITE_BLOCK ||
504c1733db1SRobert Mustacchi 	    pch->ps_req->smbr_op == SMBUS_OP_I2C_WRITE_BLOCK) {
505c1733db1SRobert Mustacchi 		if (pch->ps_req_off < pch->ps_req->smbr_wlen) {
506c1733db1SRobert Mustacchi 			pchsmbus_write8(pch, PCH_R_BAR_HBD,
507c1733db1SRobert Mustacchi 			    pch->ps_req->smbr_wdata[pch->ps_req_off]);
508c1733db1SRobert Mustacchi 			pch->ps_req_off++;
509c1733db1SRobert Mustacchi 		}
510c1733db1SRobert Mustacchi 		return;
511c1733db1SRobert Mustacchi 	}
512c1733db1SRobert Mustacchi 
513c1733db1SRobert Mustacchi 	/*
514c1733db1SRobert Mustacchi 	 * I2C block reads already know the size that they care about. However,
515c1733db1SRobert Mustacchi 	 * normal SMBus block reads have it in their first byte, which will be
516c1733db1SRobert Mustacchi 	 * in the HD0 register, not the HDB register like normal data.
517c1733db1SRobert Mustacchi 	 */
518c1733db1SRobert Mustacchi 	if (pch->ps_req->smbr_rlen == 0) {
519c1733db1SRobert Mustacchi 		ASSERT3U(pch->ps_req->smbr_op, ==, SMBUS_OP_READ_BLOCK);
520c1733db1SRobert Mustacchi 
521c1733db1SRobert Mustacchi 		uint8_t len = pchsmbus_read8(pch, PCH_R_BAR_HD0);
522c1733db1SRobert Mustacchi 		if (len == 0 || len > SMBUS_V2_MAX_BLOCK) {
523c1733db1SRobert Mustacchi 			pch->ps_kill_err = I2C_CTRL_E_BAD_SMBUS_RLEN;
524c1733db1SRobert Mustacchi 			uint8_t val = PCH_R_HCTL_SET_KILL(0, 1);
525c1733db1SRobert Mustacchi 			pchsmbus_write8(pch, PCH_R_BAR_HCTL, val);
526c1733db1SRobert Mustacchi 			return;
527c1733db1SRobert Mustacchi 		}
528c1733db1SRobert Mustacchi 		pch->ps_req->smbr_rlen = len;
529c1733db1SRobert Mustacchi 		return;
530c1733db1SRobert Mustacchi 	}
531c1733db1SRobert Mustacchi 
532c1733db1SRobert Mustacchi 	pch->ps_req->smbr_rdata[pch->ps_req_off] = pchsmbus_read8(pch,
533c1733db1SRobert Mustacchi 	    PCH_R_BAR_HBD);
534c1733db1SRobert Mustacchi 	pch->ps_req_off++;
535c1733db1SRobert Mustacchi 	if (pch->ps_req_off + 1 == pch->ps_req->smbr_rlen) {
536c1733db1SRobert Mustacchi 		uint8_t hctl = PCH_R_HCTL_SET_LAST(pch->ps_req_hctl, 1);
537c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCTL, hctl);
538c1733db1SRobert Mustacchi 	}
539c1733db1SRobert Mustacchi }
540c1733db1SRobert Mustacchi 
541c1733db1SRobert Mustacchi /*
542c1733db1SRobert Mustacchi  * We've been told that the request completed successfully. The action that we
543c1733db1SRobert Mustacchi  * must take will vary based upon the type of request. Here is where we read out
544c1733db1SRobert Mustacchi  * result data. For writes, we're simply done. Note, for block requests, we will
545c1733db1SRobert Mustacchi  * have already processed it if we're not operating in block mode.
546c1733db1SRobert Mustacchi  */
547c1733db1SRobert Mustacchi static void
pchsmbus_io_req_done(pchsmbus_t * pch)548c1733db1SRobert Mustacchi pchsmbus_io_req_done(pchsmbus_t *pch)
549c1733db1SRobert Mustacchi {
550c1733db1SRobert Mustacchi 	uint8_t len;
551c1733db1SRobert Mustacchi 
552c1733db1SRobert Mustacchi 	pch->ps_req_done = true;
553c1733db1SRobert Mustacchi 	switch (pch->ps_req->smbr_op) {
554c1733db1SRobert Mustacchi 	case SMBUS_OP_QUICK_COMMAND:
555c1733db1SRobert Mustacchi 	case SMBUS_OP_SEND_BYTE:
556c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BYTE:
557c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_WORD:
558c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
559c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
560c1733db1SRobert Mustacchi 		/*
561c1733db1SRobert Mustacchi 		 * There is nothing to do for all write requests.
562c1733db1SRobert Mustacchi 		 */
563c1733db1SRobert Mustacchi 		break;
564c1733db1SRobert Mustacchi 	case SMBUS_OP_RECV_BYTE:
565c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BYTE:
566c1733db1SRobert Mustacchi 		pch->ps_req->smbr_rdata[0] = pchsmbus_read8(pch, PCH_R_BAR_HD0);
567c1733db1SRobert Mustacchi 		break;
568c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_WORD:
569c1733db1SRobert Mustacchi 	case SMBUS_OP_PROCESS_CALL:
570c1733db1SRobert Mustacchi 		pch->ps_req->smbr_rdata[0] = pchsmbus_read8(pch, PCH_R_BAR_HD0);
571c1733db1SRobert Mustacchi 		pch->ps_req->smbr_rdata[1] = pchsmbus_read8(pch, PCH_R_BAR_HD1);
572c1733db1SRobert Mustacchi 		break;
573c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
574c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
575c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
576c1733db1SRobert Mustacchi 		/*
577c1733db1SRobert Mustacchi 		 * Byte mode already has all of its data.
578c1733db1SRobert Mustacchi 		 */
579c1733db1SRobert Mustacchi 		if ((pch->ps_init & PCHSMBUS_RUN_BUF_EN) == 0) {
580c1733db1SRobert Mustacchi 			break;
581c1733db1SRobert Mustacchi 		}
582c1733db1SRobert Mustacchi 
583c1733db1SRobert Mustacchi 		len = pchsmbus_read8(pch, PCH_R_BAR_HD0);
584c1733db1SRobert Mustacchi 		if (len == 0 || len > SMBUS_V2_MAX_BLOCK) {
585c1733db1SRobert Mustacchi 			i2c_ctrl_io_error(&pch->ps_req->smbr_error,
586c1733db1SRobert Mustacchi 			    I2C_CORE_E_CONTROLLER,
587c1733db1SRobert Mustacchi 			    I2C_CTRL_E_BAD_SMBUS_RLEN);
588c1733db1SRobert Mustacchi 			return;
589c1733db1SRobert Mustacchi 		}
590c1733db1SRobert Mustacchi 
591c1733db1SRobert Mustacchi 		pch->ps_req->smbr_rlen = len;
592c1733db1SRobert Mustacchi 		/* Explicitly reset the buffer index */
593c1733db1SRobert Mustacchi 		(void) pchsmbus_read8(pch, PCH_R_BAR_HCTL);
594c1733db1SRobert Mustacchi 		for (uint16_t i = 0; i < pch->ps_req->smbr_rlen; i++) {
595c1733db1SRobert Mustacchi 			pch->ps_req->smbr_rdata[i] = pchsmbus_read8(pch,
596c1733db1SRobert Mustacchi 			    PCH_R_BAR_HBD);
597c1733db1SRobert Mustacchi 		}
598c1733db1SRobert Mustacchi 		break;
599c1733db1SRobert Mustacchi 	case SMBUS_OP_HOST_NOTIFY:
600c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U32:
601c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U32:
602c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U64:
603c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U64:
604c1733db1SRobert Mustacchi 	default:
605c1733db1SRobert Mustacchi 		panic("programmer error: unsupported request type 0x%x should "
606c1733db1SRobert Mustacchi 		    "not have been completed", pch->ps_req->smbr_op);
607c1733db1SRobert Mustacchi 	}
608c1733db1SRobert Mustacchi 
609c1733db1SRobert Mustacchi 	i2c_ctrl_io_success(&pch->ps_req->smbr_error);
610c1733db1SRobert Mustacchi }
611c1733db1SRobert Mustacchi 
612c1733db1SRobert Mustacchi /*
613c1733db1SRobert Mustacchi  * We have been given a status register read from the driver, whether by polling
614c1733db1SRobert Mustacchi  * or by an interrupt. We must look at the bits present, clear anything that
615c1733db1SRobert Mustacchi  * needs to be, and then take action to advance the state machine. Here's how we
616c1733db1SRobert Mustacchi  * have to react to each bit:
617c1733db1SRobert Mustacchi  *
618c1733db1SRobert Mustacchi  *  - Byte Done: This indicates a byte has been transferred when we're not in
619c1733db1SRobert Mustacchi  *    the 32 byte buffer mode. At this time, we either write the next byte or
620c1733db1SRobert Mustacchi  *    read the next byte out of the buffer.
621c1733db1SRobert Mustacchi  *  - Alert: This shouldn't be generated, so we generally ignore it, but clear
622c1733db1SRobert Mustacchi  *    it just for completeness.
623c1733db1SRobert Mustacchi  *  - Fail, Bus Error, Device Error: The transaction is over. We need to guess
624c1733db1SRobert Mustacchi  *    the best error that we can with the unfortunately limited information that
625c1733db1SRobert Mustacchi  *    we get.
626c1733db1SRobert Mustacchi  *  - Interrupt: This indicates that the entire command was completed and is the
627c1733db1SRobert Mustacchi  *    only thing that we should use to signal successful completion.
628c1733db1SRobert Mustacchi  */
629c1733db1SRobert Mustacchi static bool
pchsmbus_io(pchsmbus_t * pch,pch_smbus_sts_t status)630c1733db1SRobert Mustacchi pchsmbus_io(pchsmbus_t *pch, pch_smbus_sts_t status)
631c1733db1SRobert Mustacchi {
632c1733db1SRobert Mustacchi 	ASSERT(MUTEX_HELD(&pch->ps_mutex));
633c1733db1SRobert Mustacchi 
634c1733db1SRobert Mustacchi 	/*
635c1733db1SRobert Mustacchi 	 * Is there actually activity for us to process or not. If not, then
636c1733db1SRobert Mustacchi 	 * we're done. Mask off bits like In Use and related. Clear them now and
637c1733db1SRobert Mustacchi 	 * proceed to process them all in turn.
638c1733db1SRobert Mustacchi 	 */
639c1733db1SRobert Mustacchi 	status &= PCH_HSTS_CLEAR_PRE;
640c1733db1SRobert Mustacchi 	if (status == 0) {
641c1733db1SRobert Mustacchi 		return (false);
642c1733db1SRobert Mustacchi 	}
643c1733db1SRobert Mustacchi 
644c1733db1SRobert Mustacchi 	if ((status & PCH_HSTS_ERRORS) != 0) {
645c1733db1SRobert Mustacchi 		pchsmbus_io_error(pch, status);
646c1733db1SRobert Mustacchi 		goto done;
647c1733db1SRobert Mustacchi 	}
648c1733db1SRobert Mustacchi 
649c1733db1SRobert Mustacchi 	if ((status & PCH_HSTS_BYTE_DONE) != 0) {
650c1733db1SRobert Mustacchi 		pchsmbus_io_byte_done(pch);
651c1733db1SRobert Mustacchi 	}
652c1733db1SRobert Mustacchi 
653c1733db1SRobert Mustacchi 	if ((status & PCH_HSTS_INTR) != 0) {
654c1733db1SRobert Mustacchi 		pchsmbus_io_req_done(pch);
655c1733db1SRobert Mustacchi 	}
656c1733db1SRobert Mustacchi 
657c1733db1SRobert Mustacchi done:
658c1733db1SRobert Mustacchi 	/*
659c1733db1SRobert Mustacchi 	 * We clear the status codes last as when operating in byte at a time
660c1733db1SRobert Mustacchi 	 * mode, the data must be read and written prior to clearing this status
661c1733db1SRobert Mustacchi 	 * to indicate that we are done.
662c1733db1SRobert Mustacchi 	 */
663c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_HSTS, status);
664c1733db1SRobert Mustacchi 	return (true);
665c1733db1SRobert Mustacchi }
666c1733db1SRobert Mustacchi 
667c1733db1SRobert Mustacchi static uint_t
pchsmbus_intr(caddr_t arg1,caddr_t arg2)668c1733db1SRobert Mustacchi pchsmbus_intr(caddr_t arg1, caddr_t arg2)
669c1733db1SRobert Mustacchi {
670c1733db1SRobert Mustacchi 	pchsmbus_t *pch = (pchsmbus_t *)arg1;
671c1733db1SRobert Mustacchi 	pch_smbus_sts_t sts;
672c1733db1SRobert Mustacchi 
673c1733db1SRobert Mustacchi 	mutex_enter(&pch->ps_mutex);
674c1733db1SRobert Mustacchi 	sts = pchsmbus_read8(pch, PCH_R_BAR_HSTS);
675c1733db1SRobert Mustacchi 	if (!pchsmbus_io(pch, sts)) {
676c1733db1SRobert Mustacchi 		mutex_exit(&pch->ps_mutex);
677c1733db1SRobert Mustacchi 		return (DDI_INTR_UNCLAIMED);
678c1733db1SRobert Mustacchi 	}
679c1733db1SRobert Mustacchi 
680c1733db1SRobert Mustacchi 	if (pch->ps_req_done) {
681c1733db1SRobert Mustacchi 		cv_signal(&pch->ps_cv);
682c1733db1SRobert Mustacchi 	}
683c1733db1SRobert Mustacchi 	mutex_exit(&pch->ps_mutex);
684c1733db1SRobert Mustacchi 	return (DDI_INTR_CLAIMED);
685c1733db1SRobert Mustacchi }
686c1733db1SRobert Mustacchi 
687c1733db1SRobert Mustacchi static void
pchsmbus_wait(pchsmbus_t * pch,bool poll)688c1733db1SRobert Mustacchi pchsmbus_wait(pchsmbus_t *pch, bool poll)
689c1733db1SRobert Mustacchi {
690c1733db1SRobert Mustacchi 	uint32_t to, spin;
691c1733db1SRobert Mustacchi 
692c1733db1SRobert Mustacchi 	VERIFY(MUTEX_HELD(&pch->ps_mutex));
693c1733db1SRobert Mustacchi 	VERIFY3P(pch->ps_req, !=, NULL);
694c1733db1SRobert Mustacchi 
695c1733db1SRobert Mustacchi 	to = i2c_ctrl_timeout_delay_us(pch->ps_hdl, I2C_CTRL_TO_IO);
696c1733db1SRobert Mustacchi 	spin = i2c_ctrl_timeout_delay_us(pch->ps_hdl, I2C_CTRL_TO_POLL_CTRL);
697c1733db1SRobert Mustacchi 
698c1733db1SRobert Mustacchi 	if (!poll) {
699c1733db1SRobert Mustacchi 		clock_t abs = ddi_get_lbolt() + drv_usectohz(to);
700c1733db1SRobert Mustacchi 		while (!pch->ps_req_done) {
701c1733db1SRobert Mustacchi 			clock_t ret = cv_timedwait(&pch->ps_cv, &pch->ps_mutex,
702c1733db1SRobert Mustacchi 			    abs);
703c1733db1SRobert Mustacchi 			if (ret == -1) {
704c1733db1SRobert Mustacchi 				break;
705c1733db1SRobert Mustacchi 			}
706c1733db1SRobert Mustacchi 		}
707c1733db1SRobert Mustacchi 	} else {
708c1733db1SRobert Mustacchi 		hrtime_t abs = gethrtime() + USEC2NSEC(to);
709c1733db1SRobert Mustacchi 
710c1733db1SRobert Mustacchi 		while (!pch->ps_req_done && gethrtime() < abs) {
711c1733db1SRobert Mustacchi 			drv_usecwait(spin);
712c1733db1SRobert Mustacchi 			uint8_t status = pchsmbus_read8(pch, PCH_R_BAR_HSTS);
713c1733db1SRobert Mustacchi 			(void) pchsmbus_io(pch, status);
714c1733db1SRobert Mustacchi 		}
715c1733db1SRobert Mustacchi 	}
716c1733db1SRobert Mustacchi 
717c1733db1SRobert Mustacchi 	/*
718c1733db1SRobert Mustacchi 	 * If this is not done, we're going to set the kill bit. The next user
719c1733db1SRobert Mustacchi 	 * will be the one that waits for the kill to actually complete with the
720c1733db1SRobert Mustacchi 	 * normal call to pchsmbus_bus_avail(). The FAIL status in the HSTS
721c1733db1SRobert Mustacchi 	 * register will get cleared before the next transaction begins and the
722c1733db1SRobert Mustacchi 	 * HCTL KILL bit will be cleared when we issue the next command.
723c1733db1SRobert Mustacchi 	 */
724c1733db1SRobert Mustacchi 	if (!pch->ps_req_done) {
725c1733db1SRobert Mustacchi 		uint8_t val = PCH_R_HCTL_SET_KILL(0, 1);
726c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCTL, val);
727c1733db1SRobert Mustacchi 		i2c_ctrl_io_error(&pch->ps_req->smbr_error,
728c1733db1SRobert Mustacchi 		    I2C_CORE_E_CONTROLLER, I2C_CTRL_E_REQ_TO);
729c1733db1SRobert Mustacchi 		pch->ps_req_done = true;
730c1733db1SRobert Mustacchi 	}
731c1733db1SRobert Mustacchi }
732c1733db1SRobert Mustacchi 
733c1733db1SRobert Mustacchi static void
pchsmbus_io_smbus(void * arg,uint32_t port,smbus_req_t * req)734c1733db1SRobert Mustacchi pchsmbus_io_smbus(void *arg, uint32_t port, smbus_req_t *req)
735c1733db1SRobert Mustacchi {
736c1733db1SRobert Mustacchi 	bool poll;
737c1733db1SRobert Mustacchi 	pchsmbus_t *pch = arg;
738c1733db1SRobert Mustacchi 
739c1733db1SRobert Mustacchi 	ASSERT3U(port, ==, 0);
740c1733db1SRobert Mustacchi 
741c1733db1SRobert Mustacchi 	mutex_enter(&pch->ps_mutex);
742c1733db1SRobert Mustacchi 	if (!pchsmbus_bus_avail(pch)) {
743c1733db1SRobert Mustacchi 		mutex_exit(&pch->ps_mutex);
744c1733db1SRobert Mustacchi 		i2c_ctrl_io_error(&req->smbr_error, I2C_CORE_E_CONTROLLER,
745c1733db1SRobert Mustacchi 		    I2C_CTRL_E_BUS_BUSY);
746c1733db1SRobert Mustacchi 		return;
747c1733db1SRobert Mustacchi 	}
748c1733db1SRobert Mustacchi 
749c1733db1SRobert Mustacchi 	ASSERT3P(pch->ps_req, ==, NULL);
750c1733db1SRobert Mustacchi 	pch->ps_req = req;
751c1733db1SRobert Mustacchi 	pch->ps_req_off = 0;
752c1733db1SRobert Mustacchi 	pch->ps_req_done = false;
753c1733db1SRobert Mustacchi 
754c1733db1SRobert Mustacchi 	/*
755c1733db1SRobert Mustacchi 	 * Determine whether or not we should use interrupts or poll for
756c1733db1SRobert Mustacchi 	 * completion. We may have been asked to poll explicitly. We may also
757c1733db1SRobert Mustacchi 	 * not have interrupt support.
758c1733db1SRobert Mustacchi 	 */
759c1733db1SRobert Mustacchi 	poll = (req->smbr_flags & I2C_IO_REQ_F_POLL) != 0;
760c1733db1SRobert Mustacchi 	if (pch->ps_nintrs == 0)
761c1733db1SRobert Mustacchi 		poll = true;
762c1733db1SRobert Mustacchi 
763c1733db1SRobert Mustacchi 	switch (req->smbr_op) {
764c1733db1SRobert Mustacchi 	case SMBUS_OP_QUICK_COMMAND:
765c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, (req->smbr_flags &
766c1733db1SRobert Mustacchi 		    I2C_IO_REQ_F_QUICK_WRITE) != 0);
767c1733db1SRobert Mustacchi 		break;
768c1733db1SRobert Mustacchi 	case SMBUS_OP_SEND_BYTE:
769c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, true);
770c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCMD, req->smbr_wdata[0]);
771c1733db1SRobert Mustacchi 		break;
772c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BYTE:
773c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, true);
774c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCMD, req->smbr_cmd);
775c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HD0, req->smbr_wdata[0]);
776c1733db1SRobert Mustacchi 		break;
777c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_WORD:
778c1733db1SRobert Mustacchi 	case SMBUS_OP_PROCESS_CALL:
779c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, true);
780c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCMD, req->smbr_cmd);
781c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HD0, req->smbr_wdata[0]);
782c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HD1, req->smbr_wdata[1]);
783c1733db1SRobert Mustacchi 		break;
784c1733db1SRobert Mustacchi 	case SMBUS_OP_RECV_BYTE:
785c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, false);
786c1733db1SRobert Mustacchi 		break;
787c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BYTE:
788c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_WORD:
789c1733db1SRobert Mustacchi 		pchsmbus_set_addr(pch, req, false);
790c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCMD, req->smbr_cmd);
791c1733db1SRobert Mustacchi 		break;
792c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
793c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
794c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
795c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
796c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
797c1733db1SRobert Mustacchi 		pchsmbus_io_init_block(pch, req);
798c1733db1SRobert Mustacchi 		break;
799c1733db1SRobert Mustacchi 	case SMBUS_OP_HOST_NOTIFY:
800c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U32:
801c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U32:
802c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U64:
803c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U64:
804c1733db1SRobert Mustacchi 	default:
805c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "!framework passed unsupported "
806c1733db1SRobert Mustacchi 		    "SMBus command 0x%x", req->smbr_op);
807c1733db1SRobert Mustacchi 		i2c_ctrl_io_error(&req->smbr_error, I2C_CORE_E_CONTROLLER,
808c1733db1SRobert Mustacchi 		    I2C_CTRL_E_UNSUP_CMD);
809c1733db1SRobert Mustacchi 		goto done;
810c1733db1SRobert Mustacchi 	}
811c1733db1SRobert Mustacchi 
812c1733db1SRobert Mustacchi 	/*
813c1733db1SRobert Mustacchi 	 * Prepare to issue the command. We do this in a few different steps:
814c1733db1SRobert Mustacchi 	 *
815c1733db1SRobert Mustacchi 	 * 1) We set up command-specific parameters such as I2C enable. If the
816c1733db1SRobert Mustacchi 	 *    block enable is present, then it will have been already enabled.
817c1733db1SRobert Mustacchi 	 * 2) Clear all interrupts.
818c1733db1SRobert Mustacchi 	 * 3) Actually begin the transaction, indicating whether or not
819c1733db1SRobert Mustacchi 	 *    interrupts should occur.
820c1733db1SRobert Mustacchi 	 * 4) Poll or wait for completion.
821c1733db1SRobert Mustacchi 	 */
822c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_HSTS, PCH_HSTS_CLEAR_PRE);
823c1733db1SRobert Mustacchi 	pch_smbus_cmd_t cmd = pchsmbus_req_to_cmd(req);
824c1733db1SRobert Mustacchi 	uint8_t ctl = PCH_R_HCTL_SET_CMD(0, cmd);
825c1733db1SRobert Mustacchi 	ctl = PCH_R_HCTL_SET_START(ctl, 1);
826c1733db1SRobert Mustacchi 	ctl = PCH_R_HCTL_SET_INT_EN(ctl, !poll);
827c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_HCTL, ctl);
828c1733db1SRobert Mustacchi 	pch->ps_req_hctl = ctl;
829c1733db1SRobert Mustacchi 
830c1733db1SRobert Mustacchi 	pchsmbus_wait(pch, poll);
831c1733db1SRobert Mustacchi 
832c1733db1SRobert Mustacchi done:
833c1733db1SRobert Mustacchi 	/*
834c1733db1SRobert Mustacchi 	 * Now that this operation has completed, whether successful or not,
835c1733db1SRobert Mustacchi 	 * restore the host configuration and block enable to our defaults.
836c1733db1SRobert Mustacchi 	 */
837c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_RUN_I2C_EN) != 0) {
838c1733db1SRobert Mustacchi 		uint32_t val = pci_config_get32(pch->ps_cfg, PCH_R_PCIE_HCFG);
839c1733db1SRobert Mustacchi 		val = PCH_R_HCFG_SET_I2CEN(val, 0);
840c1733db1SRobert Mustacchi 		pci_config_put32(pch->ps_cfg, PCH_R_PCIE_HCFG, val);
841c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_RUN_I2C_EN;
842c1733db1SRobert Mustacchi 	}
843c1733db1SRobert Mustacchi 
844c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_RUN_BUF_EN) != 0) {
845c1733db1SRobert Mustacchi 		uint8_t val = pchsmbus_read8(pch, PCH_R_BAR_AUXC);
846c1733db1SRobert Mustacchi 		val = PCH_R_AUXC_SET_E32B(val, 0);
847c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_AUXC, val);
848c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_RUN_BUF_EN;
849c1733db1SRobert Mustacchi 	}
850c1733db1SRobert Mustacchi 
851c1733db1SRobert Mustacchi 	pch->ps_req = NULL;
852c1733db1SRobert Mustacchi 	pch->ps_req_off = 0;
853c1733db1SRobert Mustacchi 	pch->ps_req_hctl = 0;
854c1733db1SRobert Mustacchi 	pch->ps_req_done = false;
855c1733db1SRobert Mustacchi 	pch->ps_kill_err = I2C_CTRL_E_OK;
856c1733db1SRobert Mustacchi 	mutex_exit(&pch->ps_mutex);
857c1733db1SRobert Mustacchi }
858c1733db1SRobert Mustacchi 
859c1733db1SRobert Mustacchi static const i2c_ctrl_ops_t pchsmbus_ctrl_ops = {
860c1733db1SRobert Mustacchi 	.i2c_port_name_f = i2c_ctrl_port_name_portno,
861c1733db1SRobert Mustacchi 	.i2c_io_smbus_f = pchsmbus_io_smbus,
862c1733db1SRobert Mustacchi 	.i2c_prop_info_f = pchsmbus_prop_info,
863c1733db1SRobert Mustacchi 	.i2c_prop_get_f = pchsmbus_prop_get
864c1733db1SRobert Mustacchi };
865c1733db1SRobert Mustacchi 
866c1733db1SRobert Mustacchi static bool
pchsmbus_supported(pchsmbus_t * pch)867c1733db1SRobert Mustacchi pchsmbus_supported(pchsmbus_t *pch)
868c1733db1SRobert Mustacchi {
869c1733db1SRobert Mustacchi 	uint16_t id = pci_config_get16(pch->ps_cfg, PCI_CONF_VENID);
870c1733db1SRobert Mustacchi 
871c1733db1SRobert Mustacchi 	if (id != PCH_SMBUS_VID_INTEL) {
872c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "found unsupported non-Intel "
873c1733db1SRobert Mustacchi 		    "vendor ID: 0x%x", id);
874c1733db1SRobert Mustacchi 		return (false);
875c1733db1SRobert Mustacchi 	}
876c1733db1SRobert Mustacchi 
877c1733db1SRobert Mustacchi 	id = pci_config_get16(pch->ps_cfg, PCI_CONF_DEVID);
878c1733db1SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(pchsmbus_feats); i++) {
879c1733db1SRobert Mustacchi 		if (id != pchsmbus_feats[i].pcm_did)
880c1733db1SRobert Mustacchi 			continue;
881c1733db1SRobert Mustacchi 
882c1733db1SRobert Mustacchi 		pch->ps_feats = pchsmbus_feats[i].pcm_feat;
883c1733db1SRobert Mustacchi 		return (true);
884c1733db1SRobert Mustacchi 	}
885c1733db1SRobert Mustacchi 
886c1733db1SRobert Mustacchi 	dev_err(pch->ps_dip, CE_WARN, "found unsupported device ID: 0x%x", id);
887c1733db1SRobert Mustacchi 	return (false);
888c1733db1SRobert Mustacchi }
889c1733db1SRobert Mustacchi 
890c1733db1SRobert Mustacchi static bool
pchsmbus_setup_regs(pchsmbus_t * pch)891c1733db1SRobert Mustacchi pchsmbus_setup_regs(pchsmbus_t *pch)
892c1733db1SRobert Mustacchi {
893c1733db1SRobert Mustacchi 	int ret;
894c1733db1SRobert Mustacchi 	ddi_device_acc_attr_t attr;
895c1733db1SRobert Mustacchi 
896c1733db1SRobert Mustacchi 	bzero(&attr, sizeof (attr));
897c1733db1SRobert Mustacchi 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
898c1733db1SRobert Mustacchi 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
899c1733db1SRobert Mustacchi 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
900c1733db1SRobert Mustacchi 	attr.devacc_attr_access = DDI_DEFAULT_ACC;
901c1733db1SRobert Mustacchi 
902c1733db1SRobert Mustacchi 	if (ddi_dev_regsize(pch->ps_dip, PCHSMBUS_REGNO, &pch->ps_regsize) !=
903c1733db1SRobert Mustacchi 	    DDI_SUCCESS) {
904c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to get regs[%u] size",
905c1733db1SRobert Mustacchi 		    PCHSMBUS_REGNO);
906c1733db1SRobert Mustacchi 		return (false);
907c1733db1SRobert Mustacchi 	}
908c1733db1SRobert Mustacchi 
909c1733db1SRobert Mustacchi 	ret = ddi_regs_map_setup(pch->ps_dip, PCHSMBUS_REGNO, &pch->ps_base,
910c1733db1SRobert Mustacchi 	    0, pch->ps_regsize, &attr, &pch->ps_regs);
911c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
912c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to map regs[%u]: %u",
913c1733db1SRobert Mustacchi 		    PCHSMBUS_REGNO, ret);
914c1733db1SRobert Mustacchi 		return (false);
915c1733db1SRobert Mustacchi 	}
916c1733db1SRobert Mustacchi 
917c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_REGS;
918c1733db1SRobert Mustacchi 	return (true);
919c1733db1SRobert Mustacchi }
920c1733db1SRobert Mustacchi 
921c1733db1SRobert Mustacchi /*
922c1733db1SRobert Mustacchi  * Go ahead and set up interrupts. It is possible that we don't get access to
923c1733db1SRobert Mustacchi  * interrupts because firmware has enabled it to be delivered via a #SMI. If
924c1733db1SRobert Mustacchi  * that's the case, we will just always rely on polling. Because that is the
925c1733db1SRobert Mustacchi  * nature of this hardware, we treat the failure to detect interrupts as
926c1733db1SRobert Mustacchi  * non-fatal, but if we find one and cannot actually set it up, we will fail
927c1733db1SRobert Mustacchi  * then.
928c1733db1SRobert Mustacchi  */
929c1733db1SRobert Mustacchi static bool
pchsmbus_setup_intr(pchsmbus_t * pch)930c1733db1SRobert Mustacchi pchsmbus_setup_intr(pchsmbus_t *pch)
931c1733db1SRobert Mustacchi {
932c1733db1SRobert Mustacchi 	int types, ret;
933c1733db1SRobert Mustacchi 
934c1733db1SRobert Mustacchi 	pch->ps_nintrs = 0;
935c1733db1SRobert Mustacchi 	pch->ps_intr_pri = 0;
936c1733db1SRobert Mustacchi 
937c1733db1SRobert Mustacchi 	/*
938c1733db1SRobert Mustacchi 	 * If the SMI enable flag is set, that means that firmware is on the
939c1733db1SRobert Mustacchi 	 * scene and we will just need to poll for completion rather than
940c1733db1SRobert Mustacchi 	 * assuming we get interrupts. That's fine. Why it means that they won't
941c1733db1SRobert Mustacchi 	 * fight us for the controller despite that is a deeper mystery.
942c1733db1SRobert Mustacchi 	 */
943c1733db1SRobert Mustacchi 	if (PCH_R_HCFG_GET_SMI_EN(pch->ps_init_hcfg) != 0) {
944c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "!firmware has taken our "
945c1733db1SRobert Mustacchi 		    "interrupt for itself via #SMI; limiting to polling");
946c1733db1SRobert Mustacchi 		return (true);
947c1733db1SRobert Mustacchi 	}
948c1733db1SRobert Mustacchi 
949c1733db1SRobert Mustacchi 	ret = ddi_intr_get_supported_types(pch->ps_dip, &types);
950c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
951c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to get supported "
952c1733db1SRobert Mustacchi 		    "interrupt types: 0x%x; limiting to polling", ret);
953c1733db1SRobert Mustacchi 		return (true);
954c1733db1SRobert Mustacchi 	}
955c1733db1SRobert Mustacchi 
956c1733db1SRobert Mustacchi 	/*
957c1733db1SRobert Mustacchi 	 * Hardware only supports INTx style fixed interrupts. That hasn't
958c1733db1SRobert Mustacchi 	 * changed in 25 years of hardware. If we don't find a fixed interrupt
959c1733db1SRobert Mustacchi 	 * that's that.
960c1733db1SRobert Mustacchi 	 */
961c1733db1SRobert Mustacchi 	if ((types & DDI_INTR_TYPE_FIXED) == 0) {
962c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "missing support for fixed "
963c1733db1SRobert Mustacchi 		    "interrupts: found 0x%x; limiting to polling", types);
964c1733db1SRobert Mustacchi 		return (true);
965c1733db1SRobert Mustacchi 	}
966c1733db1SRobert Mustacchi 
967c1733db1SRobert Mustacchi 	ret = ddi_intr_alloc(pch->ps_dip, &pch->ps_intr_hdl,
968c1733db1SRobert Mustacchi 	    DDI_INTR_TYPE_FIXED, 0, 1, &pch->ps_nintrs, DDI_INTR_ALLOC_STRICT);
969c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
970c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to allocate "
971c1733db1SRobert Mustacchi 		    "interrupts: 0x%x", ret);
972c1733db1SRobert Mustacchi 		return (false);
973c1733db1SRobert Mustacchi 	}
974c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_INTR_ALLOC;
975c1733db1SRobert Mustacchi 
976c1733db1SRobert Mustacchi 	ret = ddi_intr_add_handler(pch->ps_intr_hdl, pchsmbus_intr, pch, NULL);
977c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
978c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to add interrupt "
979c1733db1SRobert Mustacchi 		    "handler: 0x%x", ret);
980c1733db1SRobert Mustacchi 		return (false);
981c1733db1SRobert Mustacchi 	}
982c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_INTR_HDL;
983c1733db1SRobert Mustacchi 
984c1733db1SRobert Mustacchi 	ret = ddi_intr_get_pri(pch->ps_intr_hdl, &pch->ps_intr_pri);
985c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
986c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to get interrupt "
987c1733db1SRobert Mustacchi 		    "priority");
988c1733db1SRobert Mustacchi 		return (false);
989c1733db1SRobert Mustacchi 	}
990c1733db1SRobert Mustacchi 
991c1733db1SRobert Mustacchi 	return (true);
992c1733db1SRobert Mustacchi }
993c1733db1SRobert Mustacchi 
994c1733db1SRobert Mustacchi /*
995c1733db1SRobert Mustacchi  * Go through and set up the controller for general use. In particular, there
996c1733db1SRobert Mustacchi  * are a few things that we go through and make sure are set in a way that makes
997c1733db1SRobert Mustacchi  * sense for us:
998c1733db1SRobert Mustacchi  *
999c1733db1SRobert Mustacchi  *  - We always disable automatic PEC. The Auxiliary 32 byte buffer control will
1000c1733db1SRobert Mustacchi  *    be enabled when it can be used.
1001c1733db1SRobert Mustacchi  *  - We disable any events that can be generated by the target.
1002c1733db1SRobert Mustacchi  *  - We make sure that SMBus timing is enabled by default.
1003c1733db1SRobert Mustacchi  *  - Ensure that interrupts are disabled and that the PEC feature is not set.
1004c1733db1SRobert Mustacchi  *    Interrupts will be enabled when we actually enable commands.
1005c1733db1SRobert Mustacchi  *  - We actually enable the controller.
1006c1733db1SRobert Mustacchi  */
1007c1733db1SRobert Mustacchi static void
pchsmbus_ctrl_init(pchsmbus_t * pch)1008c1733db1SRobert Mustacchi pchsmbus_ctrl_init(pchsmbus_t *pch)
1009c1733db1SRobert Mustacchi {
1010c1733db1SRobert Mustacchi 	if ((pch->ps_feats & PCH_SMBUS_FEAT_HW_PEC) != 0) {
1011c1733db1SRobert Mustacchi 		uint8_t val = pchsmbus_read8(pch, PCH_R_BAR_AUXC);
1012c1733db1SRobert Mustacchi 		val = PCH_R_AUXC_SET_AAC(val, 0);
1013c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_AUXC, val);
1014c1733db1SRobert Mustacchi 	}
1015c1733db1SRobert Mustacchi 
1016c1733db1SRobert Mustacchi 	if ((pch->ps_feats & PCH_SMBUS_FEAT_TARG_NOTIFY) != 0) {
1017c1733db1SRobert Mustacchi 		pch->ps_init_scmd = pchsmbus_read8(pch, PCH_R_BAR_SCMD);
1018c1733db1SRobert Mustacchi 
1019c1733db1SRobert Mustacchi 		uint8_t val = PCH_R_SCMD_SET_SMB_D(pch->ps_init_scmd, 1);
1020c1733db1SRobert Mustacchi 		val = PCH_R_SCMD_SET_HNI(val, 0);
1021c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_SCMD, 0);
1022c1733db1SRobert Mustacchi 	}
1023c1733db1SRobert Mustacchi 
1024c1733db1SRobert Mustacchi 	/*
1025c1733db1SRobert Mustacchi 	 * Save the initial control register to restore later. However, don't
1026c1733db1SRobert Mustacchi 	 * save the kill bit which stops transactions. At this point, make sure
1027c1733db1SRobert Mustacchi 	 * interrupts and related activity are all disabled.
1028c1733db1SRobert Mustacchi 	 */
1029c1733db1SRobert Mustacchi 	pch->ps_init_hctl = pchsmbus_read8(pch, PCH_R_BAR_HCTL);
1030c1733db1SRobert Mustacchi 	pch->ps_init_hctl = PCH_R_HCTL_SET_KILL(pch->ps_init_hctl, 0);
1031c1733db1SRobert Mustacchi 	pchsmbus_write8(pch, PCH_R_BAR_HCTL, 0);
1032c1733db1SRobert Mustacchi 
1033c1733db1SRobert Mustacchi 	uint32_t val = pch->ps_init_hcfg;
1034c1733db1SRobert Mustacchi 	val = PCH_R_HCFG_SET_EN(val, 1);
1035c1733db1SRobert Mustacchi 	val = PCH_R_HCFG_SET_I2CEN(val, PCH_R_HCFG_I2CEN_SMBUS);
1036c1733db1SRobert Mustacchi 	pci_config_put32(pch->ps_cfg, PCH_R_PCIE_HCFG, val);
1037c1733db1SRobert Mustacchi 
1038c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_CTRL;
1039c1733db1SRobert Mustacchi }
1040c1733db1SRobert Mustacchi 
1041c1733db1SRobert Mustacchi static bool
pchsmbus_enable_intr(pchsmbus_t * pch)1042c1733db1SRobert Mustacchi pchsmbus_enable_intr(pchsmbus_t *pch)
1043c1733db1SRobert Mustacchi {
1044c1733db1SRobert Mustacchi 	int ret = ddi_intr_enable(pch->ps_intr_hdl);
1045c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
1046c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to enable interrupt "
1047c1733db1SRobert Mustacchi 		    "handler: %d", ret);
1048c1733db1SRobert Mustacchi 		return (false);
1049c1733db1SRobert Mustacchi 	}
1050c1733db1SRobert Mustacchi 
1051c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_INTR_EN;
1052c1733db1SRobert Mustacchi 	return (true);
1053c1733db1SRobert Mustacchi }
1054c1733db1SRobert Mustacchi 
1055c1733db1SRobert Mustacchi static bool
pchsmbus_register(pchsmbus_t * pch)1056c1733db1SRobert Mustacchi pchsmbus_register(pchsmbus_t *pch)
1057c1733db1SRobert Mustacchi {
1058c1733db1SRobert Mustacchi 	i2c_ctrl_reg_error_t ret;
1059c1733db1SRobert Mustacchi 	i2c_ctrl_register_t *reg;
1060c1733db1SRobert Mustacchi 
1061c1733db1SRobert Mustacchi 	ret = i2c_ctrl_register_alloc(I2C_CTRL_PROVIDER, &reg);
1062c1733db1SRobert Mustacchi 	if (ret != 0) {
1063c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to allocate i2c "
1064c1733db1SRobert Mustacchi 		    "controller registration structure: 0x%x", ret);
1065c1733db1SRobert Mustacchi 		return (false);
1066c1733db1SRobert Mustacchi 	}
1067c1733db1SRobert Mustacchi 
1068c1733db1SRobert Mustacchi 	reg->ic_type = I2C_CTRL_TYPE_SMBUS;
1069c1733db1SRobert Mustacchi 	reg->ic_nports = 1;
1070c1733db1SRobert Mustacchi 	reg->ic_dip = pch->ps_dip;
1071c1733db1SRobert Mustacchi 	reg->ic_drv = pch;
1072c1733db1SRobert Mustacchi 	reg->ic_ops = &pchsmbus_ctrl_ops;
1073c1733db1SRobert Mustacchi 
1074c1733db1SRobert Mustacchi 	ret = i2c_ctrl_register(reg, &pch->ps_hdl);
1075c1733db1SRobert Mustacchi 	i2c_ctrl_register_free(reg);
1076c1733db1SRobert Mustacchi 	if (ret != 0) {
1077c1733db1SRobert Mustacchi 		dev_err(pch->ps_dip, CE_WARN, "failed to register with i2c "
1078c1733db1SRobert Mustacchi 		    "framework: 0x%x", ret);
1079c1733db1SRobert Mustacchi 		return (false);
1080c1733db1SRobert Mustacchi 	}
1081c1733db1SRobert Mustacchi 
1082c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_I2C;
1083c1733db1SRobert Mustacchi 	return (true);
1084c1733db1SRobert Mustacchi }
1085c1733db1SRobert Mustacchi 
1086c1733db1SRobert Mustacchi static void
pchsmbus_cleanup(pchsmbus_t * pch)1087c1733db1SRobert Mustacchi pchsmbus_cleanup(pchsmbus_t *pch)
1088c1733db1SRobert Mustacchi {
1089c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_INTR_EN) != 0) {
1090c1733db1SRobert Mustacchi 		/*
1091c1733db1SRobert Mustacchi 		 * If this fails while tearing down, there isn't much we can do.
1092c1733db1SRobert Mustacchi 		 */
1093c1733db1SRobert Mustacchi 		int ret = ddi_intr_disable(pch->ps_intr_hdl);
1094c1733db1SRobert Mustacchi 		if (ret != DDI_SUCCESS) {
1095c1733db1SRobert Mustacchi 			dev_err(pch->ps_dip, CE_WARN, "failed to disable "
1096c1733db1SRobert Mustacchi 			    "interrupt handler: %d", ret);
1097c1733db1SRobert Mustacchi 		}
1098c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_INTR_EN;
1099c1733db1SRobert Mustacchi 	}
1100c1733db1SRobert Mustacchi 
1101c1733db1SRobert Mustacchi 	/*
1102c1733db1SRobert Mustacchi 	 * We restore several of the controllers original values as the BIOS may
1103c1733db1SRobert Mustacchi 	 * use this device and can rely on it.
1104c1733db1SRobert Mustacchi 	 */
1105c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_CTRL) != 0) {
1106c1733db1SRobert Mustacchi 		if ((pch->ps_feats & PCH_SMBUS_FEAT_TARG_NOTIFY) != 0) {
1107c1733db1SRobert Mustacchi 			pchsmbus_write8(pch, PCH_R_BAR_SCMD, pch->ps_init_scmd);
1108c1733db1SRobert Mustacchi 		}
1109c1733db1SRobert Mustacchi 
1110c1733db1SRobert Mustacchi 		pchsmbus_write8(pch, PCH_R_BAR_HCTL, pch->ps_init_hctl);
1111c1733db1SRobert Mustacchi 		pci_config_put32(pch->ps_cfg, PCH_R_PCIE_HCFG,
1112c1733db1SRobert Mustacchi 		    pch->ps_init_hcfg);
1113c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_CTRL;
1114c1733db1SRobert Mustacchi 	}
1115c1733db1SRobert Mustacchi 
1116c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_SYNC) != 0) {
1117c1733db1SRobert Mustacchi 		cv_destroy(&pch->ps_cv);
1118c1733db1SRobert Mustacchi 		mutex_destroy(&pch->ps_mutex);
1119c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_SYNC;
1120c1733db1SRobert Mustacchi 	}
1121c1733db1SRobert Mustacchi 
1122c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_INTR_HDL) != 0) {
1123c1733db1SRobert Mustacchi 		int ret = ddi_intr_remove_handler(pch->ps_intr_hdl);
1124c1733db1SRobert Mustacchi 		if (ret != 0) {
1125c1733db1SRobert Mustacchi 			dev_err(pch->ps_dip, CE_WARN, "failed to remove "
1126c1733db1SRobert Mustacchi 			    "interrupt handler: 0x%x", ret);
1127c1733db1SRobert Mustacchi 		}
1128c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_INTR_HDL;
1129c1733db1SRobert Mustacchi 	}
1130c1733db1SRobert Mustacchi 
1131c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_INTR_ALLOC) != 0) {
1132c1733db1SRobert Mustacchi 		int ret = ddi_intr_free(pch->ps_intr_hdl);
1133c1733db1SRobert Mustacchi 		if (ret != DDI_SUCCESS) {
1134c1733db1SRobert Mustacchi 			dev_err(pch->ps_dip, CE_WARN, "failed to free "
1135c1733db1SRobert Mustacchi 			    "device interrupt: 0x%x", ret);
1136c1733db1SRobert Mustacchi 		}
1137c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_INTR_ALLOC;
1138c1733db1SRobert Mustacchi 	}
1139c1733db1SRobert Mustacchi 
1140c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_REGS) != 0) {
1141c1733db1SRobert Mustacchi 		ddi_regs_map_free(&pch->ps_regs);
1142c1733db1SRobert Mustacchi 		pch->ps_base = NULL;
1143c1733db1SRobert Mustacchi 		pch->ps_regsize = 0;
1144c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_REGS;
1145c1733db1SRobert Mustacchi 	}
1146c1733db1SRobert Mustacchi 
1147c1733db1SRobert Mustacchi 	if ((pch->ps_init & PCHSMBUS_INIT_PCI) != 0) {
1148c1733db1SRobert Mustacchi 		pci_config_teardown(&pch->ps_cfg);
1149c1733db1SRobert Mustacchi 		pch->ps_cfg = NULL;
1150c1733db1SRobert Mustacchi 		pch->ps_init &= ~PCHSMBUS_INIT_PCI;
1151c1733db1SRobert Mustacchi 	}
1152c1733db1SRobert Mustacchi 
1153c1733db1SRobert Mustacchi 	ASSERT0(pch->ps_init);
1154c1733db1SRobert Mustacchi 	ddi_set_driver_private(pch->ps_dip, NULL);
1155c1733db1SRobert Mustacchi 	kmem_free(pch, sizeof (pchsmbus_t));
1156c1733db1SRobert Mustacchi }
1157c1733db1SRobert Mustacchi 
1158c1733db1SRobert Mustacchi int
pchsmbus_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1159c1733db1SRobert Mustacchi pchsmbus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1160c1733db1SRobert Mustacchi {
1161c1733db1SRobert Mustacchi 	pchsmbus_t *pch;
1162c1733db1SRobert Mustacchi 
1163c1733db1SRobert Mustacchi 	switch (cmd) {
1164c1733db1SRobert Mustacchi 	case DDI_ATTACH:
1165c1733db1SRobert Mustacchi 		break;
1166c1733db1SRobert Mustacchi 	case DDI_RESUME:
1167c1733db1SRobert Mustacchi 	default:
1168c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1169c1733db1SRobert Mustacchi 	}
1170c1733db1SRobert Mustacchi 
1171c1733db1SRobert Mustacchi 	pch = kmem_zalloc(sizeof (pchsmbus_t), KM_SLEEP);
1172c1733db1SRobert Mustacchi 	pch->ps_dip = dip;
1173c1733db1SRobert Mustacchi 	ddi_set_driver_private(dip, pch);
1174c1733db1SRobert Mustacchi 
1175c1733db1SRobert Mustacchi 	if (pci_config_setup(dip, &pch->ps_cfg) != DDI_SUCCESS) {
1176c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to set up config space");
1177c1733db1SRobert Mustacchi 		goto cleanup;
1178c1733db1SRobert Mustacchi 	}
1179c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_PCI;
1180c1733db1SRobert Mustacchi 
1181c1733db1SRobert Mustacchi 	if (!pchsmbus_supported(pch))
1182c1733db1SRobert Mustacchi 		goto cleanup;
1183c1733db1SRobert Mustacchi 
1184c1733db1SRobert Mustacchi 	if (!pchsmbus_setup_regs(pch))
1185c1733db1SRobert Mustacchi 		goto cleanup;
1186c1733db1SRobert Mustacchi 
1187c1733db1SRobert Mustacchi 	/*
1188c1733db1SRobert Mustacchi 	 * Snapshot the original value of the host configuration register. This
1189c1733db1SRobert Mustacchi 	 * is something that some systems will restore on detach as sometimes
1190c1733db1SRobert Mustacchi 	 * firmware uses this controller. In addition, we need this to determine
1191c1733db1SRobert Mustacchi 	 * if we have interrupts available to us.
1192c1733db1SRobert Mustacchi 	 */
1193c1733db1SRobert Mustacchi 	pch->ps_init_hcfg = pci_config_get32(pch->ps_cfg, PCH_R_PCIE_HCFG);
1194c1733db1SRobert Mustacchi 
1195c1733db1SRobert Mustacchi 	if (!pchsmbus_setup_intr(pch))
1196c1733db1SRobert Mustacchi 		goto cleanup;
1197c1733db1SRobert Mustacchi 
1198c1733db1SRobert Mustacchi 	/*
1199c1733db1SRobert Mustacchi 	 * Now that we (potentially) have our interrupt. Go ahead and get our
1200c1733db1SRobert Mustacchi 	 * intrrupt and CV. If we don't have an interrupt this'll turn into a
1201c1733db1SRobert Mustacchi 	 * NULL.
1202c1733db1SRobert Mustacchi 	 */
1203c1733db1SRobert Mustacchi 	mutex_init(&pch->ps_mutex, NULL, MUTEX_DRIVER,
1204c1733db1SRobert Mustacchi 	    DDI_INTR_PRI(pch->ps_intr_pri));
1205c1733db1SRobert Mustacchi 	cv_init(&pch->ps_cv, NULL, CV_DRIVER, NULL);
1206c1733db1SRobert Mustacchi 	pch->ps_init |= PCHSMBUS_INIT_SYNC;
1207c1733db1SRobert Mustacchi 
1208c1733db1SRobert Mustacchi 	pchsmbus_ctrl_init(pch);
1209c1733db1SRobert Mustacchi 
1210c1733db1SRobert Mustacchi 	if (!pchsmbus_enable_intr(pch))
1211c1733db1SRobert Mustacchi 		goto cleanup;
1212c1733db1SRobert Mustacchi 
1213c1733db1SRobert Mustacchi 	if (!pchsmbus_register(pch))
1214c1733db1SRobert Mustacchi 		goto cleanup;
1215c1733db1SRobert Mustacchi 
1216c1733db1SRobert Mustacchi 	return (DDI_SUCCESS);
1217c1733db1SRobert Mustacchi 
1218c1733db1SRobert Mustacchi cleanup:
1219c1733db1SRobert Mustacchi 	pchsmbus_cleanup(pch);
1220c1733db1SRobert Mustacchi 	return (DDI_FAILURE);
1221c1733db1SRobert Mustacchi }
1222c1733db1SRobert Mustacchi 
1223c1733db1SRobert Mustacchi int
pchsmbus_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1224c1733db1SRobert Mustacchi pchsmbus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1225c1733db1SRobert Mustacchi {
1226c1733db1SRobert Mustacchi 	pchsmbus_t *pch;
1227c1733db1SRobert Mustacchi 
1228c1733db1SRobert Mustacchi 	switch (cmd) {
1229c1733db1SRobert Mustacchi 	case DDI_DETACH:
1230c1733db1SRobert Mustacchi 		break;
1231c1733db1SRobert Mustacchi 	case DDI_SUSPEND:
1232c1733db1SRobert Mustacchi 	default:
1233c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1234c1733db1SRobert Mustacchi 	}
1235c1733db1SRobert Mustacchi 
1236c1733db1SRobert Mustacchi 	pch = ddi_get_driver_private(dip);
1237c1733db1SRobert Mustacchi 	if (pch == NULL) {
1238c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "asked to detach, but missing private "
1239c1733db1SRobert Mustacchi 		    "data");
1240c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1241c1733db1SRobert Mustacchi 	}
1242c1733db1SRobert Mustacchi 
1243c1733db1SRobert Mustacchi 	VERIFY3P(pch->ps_dip, ==, dip);
1244c1733db1SRobert Mustacchi 	i2c_ctrl_reg_error_t ret = i2c_ctrl_unregister(pch->ps_hdl);
1245c1733db1SRobert Mustacchi 	if (ret != 0) {
1246c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to unregister from i2c "
1247c1733db1SRobert Mustacchi 		    "framework 0x%x", ret);
1248c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1249c1733db1SRobert Mustacchi 	}
1250c1733db1SRobert Mustacchi 	pch->ps_init &= ~PCHSMBUS_INIT_I2C;
1251c1733db1SRobert Mustacchi 	pchsmbus_cleanup(pch);
1252c1733db1SRobert Mustacchi 
1253c1733db1SRobert Mustacchi 	return (DDI_SUCCESS);
1254c1733db1SRobert Mustacchi }
1255c1733db1SRobert Mustacchi 
1256c1733db1SRobert Mustacchi static struct dev_ops pchsmbus_dev_ops = {
1257c1733db1SRobert Mustacchi 	.devo_rev = DEVO_REV,
1258c1733db1SRobert Mustacchi 	.devo_refcnt = 0,
1259c1733db1SRobert Mustacchi 	.devo_identify = nulldev,
1260c1733db1SRobert Mustacchi 	.devo_probe = nulldev,
1261c1733db1SRobert Mustacchi 	.devo_attach = pchsmbus_attach,
1262c1733db1SRobert Mustacchi 	.devo_detach = pchsmbus_detach,
1263c1733db1SRobert Mustacchi 	.devo_reset = nodev,
1264c1733db1SRobert Mustacchi 	.devo_quiesce = ddi_quiesce_not_supported,
1265c1733db1SRobert Mustacchi };
1266c1733db1SRobert Mustacchi 
1267c1733db1SRobert Mustacchi static struct modldrv pchsmbus_modldrv = {
1268c1733db1SRobert Mustacchi 	.drv_modops = &mod_driverops,
1269c1733db1SRobert Mustacchi 	.drv_linkinfo = "Intel ICH/PCH SMBus Controller",
1270c1733db1SRobert Mustacchi 	.drv_dev_ops = &pchsmbus_dev_ops
1271c1733db1SRobert Mustacchi };
1272c1733db1SRobert Mustacchi 
1273c1733db1SRobert Mustacchi static struct modlinkage pchsmbus_modlinkage = {
1274c1733db1SRobert Mustacchi 	.ml_rev = MODREV_1,
1275c1733db1SRobert Mustacchi 	.ml_linkage = { &pchsmbus_modldrv, NULL }
1276c1733db1SRobert Mustacchi };
1277c1733db1SRobert Mustacchi 
1278c1733db1SRobert Mustacchi int
_init(void)1279c1733db1SRobert Mustacchi _init(void)
1280c1733db1SRobert Mustacchi {
1281c1733db1SRobert Mustacchi 	int ret;
1282c1733db1SRobert Mustacchi 
1283c1733db1SRobert Mustacchi 	i2c_ctrl_mod_init(&pchsmbus_dev_ops);
1284c1733db1SRobert Mustacchi 	if ((ret = mod_install(&pchsmbus_modlinkage)) != 0) {
1285c1733db1SRobert Mustacchi 		i2c_ctrl_mod_fini(&pchsmbus_dev_ops);
1286c1733db1SRobert Mustacchi 	}
1287c1733db1SRobert Mustacchi 
1288c1733db1SRobert Mustacchi 	return (ret);
1289c1733db1SRobert Mustacchi }
1290c1733db1SRobert Mustacchi 
1291c1733db1SRobert Mustacchi int
_info(struct modinfo * modinfop)1292c1733db1SRobert Mustacchi _info(struct modinfo *modinfop)
1293c1733db1SRobert Mustacchi {
1294c1733db1SRobert Mustacchi 	return (mod_info(&pchsmbus_modlinkage, modinfop));
1295c1733db1SRobert Mustacchi }
1296c1733db1SRobert Mustacchi 
1297c1733db1SRobert Mustacchi int
_fini(void)1298c1733db1SRobert Mustacchi _fini(void)
1299c1733db1SRobert Mustacchi {
1300c1733db1SRobert Mustacchi 	int ret;
1301c1733db1SRobert Mustacchi 
1302c1733db1SRobert Mustacchi 	if ((ret = mod_remove(&pchsmbus_modlinkage)) == 0) {
1303c1733db1SRobert Mustacchi 		i2c_ctrl_mod_fini(&pchsmbus_dev_ops);
1304c1733db1SRobert Mustacchi 	}
1305c1733db1SRobert Mustacchi 
1306c1733db1SRobert Mustacchi 	return (ret);
1307c1733db1SRobert Mustacchi }
1308