xref: /illumos-gate/usr/src/uts/common/io/i2c/ctrl/ismt/ismt.c (revision c1733db148ded3d78431de26089fc479e0ee37e4)
1*c1733db1SRobert Mustacchi /*
2*c1733db1SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*c1733db1SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*c1733db1SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*c1733db1SRobert Mustacchi  * 1.0 of the CDDL.
6*c1733db1SRobert Mustacchi  *
7*c1733db1SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*c1733db1SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*c1733db1SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*c1733db1SRobert Mustacchi  */
11*c1733db1SRobert Mustacchi 
12*c1733db1SRobert Mustacchi /*
13*c1733db1SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*c1733db1SRobert Mustacchi  */
15*c1733db1SRobert Mustacchi 
16*c1733db1SRobert Mustacchi /*
17*c1733db1SRobert Mustacchi  * Intel SMBus Message Transport controller driver.
18*c1733db1SRobert Mustacchi  *
19*c1733db1SRobert Mustacchi  * This is a DMA based SMBus controller that is found in some of the various
20*c1733db1SRobert Mustacchi  * Atom and Xeon-D based platforms. The hardware divides registers into three
21*c1733db1SRobert Mustacchi  * rough groups. There are the general registers, controller specific registers,
22*c1733db1SRobert Mustacchi  * and target specific registers. We don't implement the target.
23*c1733db1SRobert Mustacchi  *
24*c1733db1SRobert Mustacchi  * The device can support a ring of DMA transfers. We only will have one
25*c1733db1SRobert Mustacchi  * outstanding at a time, so we go with a simple length of 4 entries and have a
26*c1733db1SRobert Mustacchi  * single data DMA buffer that is used by all commands.
27*c1733db1SRobert Mustacchi  *
28*c1733db1SRobert Mustacchi  * Unlike the PCH-based SMBus controller, this controller supports both SMBus
29*c1733db1SRobert Mustacchi  * 2.0 commands and can perform arbitrary commands over I2C.
30*c1733db1SRobert Mustacchi  */
31*c1733db1SRobert Mustacchi 
32*c1733db1SRobert Mustacchi #include <sys/modctl.h>
33*c1733db1SRobert Mustacchi #include <sys/conf.h>
34*c1733db1SRobert Mustacchi #include <sys/devops.h>
35*c1733db1SRobert Mustacchi #include <sys/ddi.h>
36*c1733db1SRobert Mustacchi #include <sys/sunddi.h>
37*c1733db1SRobert Mustacchi #include <sys/pci.h>
38*c1733db1SRobert Mustacchi #include <sys/sysmacros.h>
39*c1733db1SRobert Mustacchi 
40*c1733db1SRobert Mustacchi #include <sys/i2c/controller.h>
41*c1733db1SRobert Mustacchi #include "ismt.h"
42*c1733db1SRobert Mustacchi 
43*c1733db1SRobert Mustacchi /*
44*c1733db1SRobert Mustacchi  * The controller has a single BAR, SMTBAR, which is found in the BAR 0/1. This
45*c1733db1SRobert Mustacchi  * translates to reg[1] as reg[0] contains the config space information about
46*c1733db1SRobert Mustacchi  * the device.
47*c1733db1SRobert Mustacchi  */
48*c1733db1SRobert Mustacchi #define	ISMT_REGNO	1
49*c1733db1SRobert Mustacchi 
50*c1733db1SRobert Mustacchi /*
51*c1733db1SRobert Mustacchi  * Because we never use the offset and address for syncing, we want to cast the
52*c1733db1SRobert Mustacchi  * DMA sync call to void, but lets be paranoid on debug.
53*c1733db1SRobert Mustacchi  */
54*c1733db1SRobert Mustacchi #ifdef	DEBUG
55*c1733db1SRobert Mustacchi #define	ISMT_DMA_SYNC(buf, flag)	ASSERT0(ddi_dma_sync((buf).id_hdl, \
56*c1733db1SRobert Mustacchi 					    0, 0, flag))
57*c1733db1SRobert Mustacchi #else
58*c1733db1SRobert Mustacchi #define	ISMT_DMA_SYNC(buf, flag)	(void) ddi_dma_sync((buf).id_hdl, \
59*c1733db1SRobert Mustacchi 					    0, 0, flag)
60*c1733db1SRobert Mustacchi #endif	/* DEBUG */
61*c1733db1SRobert Mustacchi 
62*c1733db1SRobert Mustacchi 
63*c1733db1SRobert Mustacchi /*
64*c1733db1SRobert Mustacchi  * Allocation sizes for our ring and DMA data buffer. We size the ring at 4
65*c1733db1SRobert Mustacchi  * entries (though it seems like we could probably get away with just one). The
66*c1733db1SRobert Mustacchi  * data buffer we size at 128 bytes, which covers both the maximum read and
67*c1733db1SRobert Mustacchi  * maximum write in one go (though we shouldn't exceed it either one). The last
68*c1733db1SRobert Mustacchi  * one of these, the interrupt cause log size is the hardest. It defitely is
69*c1733db1SRobert Mustacchi  * written before every interrupt, but whether we need one of these per entry in
70*c1733db1SRobert Mustacchi  * the log or it just clobbers the last location is unclear. It doesn't actually
71*c1733db1SRobert Mustacchi  * ask for a size so we just double the number of ring entries.
72*c1733db1SRobert Mustacchi  */
73*c1733db1SRobert Mustacchi #define	ISMT_RING_NENTS		4
74*c1733db1SRobert Mustacchi #define	ISMT_RING_DMA_SIZE	(ISMT_RING_NENTS  * sizeof (ismt_desc_t))
75*c1733db1SRobert Mustacchi #define	ISMT_DATA_BUF_SIZE	128U
76*c1733db1SRobert Mustacchi #define	ISMT_ICL_DMA_SIZE	(ISMT_RING_NENTS * sizeof (uint32_t) * 2)
77*c1733db1SRobert Mustacchi 
78*c1733db1SRobert Mustacchi typedef enum {
79*c1733db1SRobert Mustacchi 	ISMT_INIT_PCI		= 1 << 0,
80*c1733db1SRobert Mustacchi 	ISMT_INIT_REGS		= 1 << 1,
81*c1733db1SRobert Mustacchi 	ISMT_INIT_INTR_ALLOC	= 1 << 2,
82*c1733db1SRobert Mustacchi 	ISMT_INIT_INTR_HDL	= 1 << 3,
83*c1733db1SRobert Mustacchi 	ISMT_INIT_SYNC		= 1 << 4,
84*c1733db1SRobert Mustacchi 	ISMT_INIT_INTR_EN	= 1 << 5,
85*c1733db1SRobert Mustacchi 	ISMT_INIT_I2C		= 1 << 6
86*c1733db1SRobert Mustacchi } ismt_init_t;
87*c1733db1SRobert Mustacchi 
88*c1733db1SRobert Mustacchi typedef struct {
89*c1733db1SRobert Mustacchi 	ddi_dma_handle_t id_hdl;
90*c1733db1SRobert Mustacchi 	caddr_t id_va;
91*c1733db1SRobert Mustacchi 	ddi_acc_handle_t id_acc;
92*c1733db1SRobert Mustacchi 	size_t id_alloc_len;
93*c1733db1SRobert Mustacchi 	size_t id_size;
94*c1733db1SRobert Mustacchi } ismt_dma_t;
95*c1733db1SRobert Mustacchi 
96*c1733db1SRobert Mustacchi typedef struct {
97*c1733db1SRobert Mustacchi 	dev_info_t *ismt_dip;
98*c1733db1SRobert Mustacchi 	ddi_acc_handle_t ismt_cfg;
99*c1733db1SRobert Mustacchi 	ismt_init_t ismt_init;
100*c1733db1SRobert Mustacchi 	/*
101*c1733db1SRobert Mustacchi 	 * Register related data
102*c1733db1SRobert Mustacchi 	 */
103*c1733db1SRobert Mustacchi 	caddr_t ismt_base;
104*c1733db1SRobert Mustacchi 	off_t ismt_regsize;
105*c1733db1SRobert Mustacchi 	ddi_acc_handle_t ismt_regs;
106*c1733db1SRobert Mustacchi 	/*
107*c1733db1SRobert Mustacchi 	 * DMA Information
108*c1733db1SRobert Mustacchi 	 */
109*c1733db1SRobert Mustacchi 	ismt_dma_t ismt_ring_dma;
110*c1733db1SRobert Mustacchi 	ismt_dma_t ismt_data_dma;
111*c1733db1SRobert Mustacchi 	ismt_dma_t ismt_icl_dma;
112*c1733db1SRobert Mustacchi 	/*
113*c1733db1SRobert Mustacchi 	 * Interrupt data
114*c1733db1SRobert Mustacchi 	 */
115*c1733db1SRobert Mustacchi 	int ismt_nintrs;
116*c1733db1SRobert Mustacchi 	int ismt_itype;
117*c1733db1SRobert Mustacchi 	ddi_intr_handle_t ismt_intr_hdl;
118*c1733db1SRobert Mustacchi 	uint_t ismt_intr_pri;
119*c1733db1SRobert Mustacchi 	/*
120*c1733db1SRobert Mustacchi 	 * Request and framework synchronization.
121*c1733db1SRobert Mustacchi 	 */
122*c1733db1SRobert Mustacchi 	i2c_speed_t ismt_speed;
123*c1733db1SRobert Mustacchi 	kmutex_t ismt_mutex;
124*c1733db1SRobert Mustacchi 	kcondvar_t ismt_cv;
125*c1733db1SRobert Mustacchi 	i2c_ctrl_hdl_t *ismt_hdl;
126*c1733db1SRobert Mustacchi 	uint32_t ismt_head;
127*c1733db1SRobert Mustacchi 	uint32_t ismt_tail;
128*c1733db1SRobert Mustacchi 	ismt_desc_t *ismt_ring;
129*c1733db1SRobert Mustacchi 	smbus_req_t *ismt_req;
130*c1733db1SRobert Mustacchi 	i2c_req_t *ismt_i2creq;
131*c1733db1SRobert Mustacchi 	i2c_error_t *ismt_err;
132*c1733db1SRobert Mustacchi 	bool ismt_req_done;
133*c1733db1SRobert Mustacchi } ismt_t;
134*c1733db1SRobert Mustacchi 
135*c1733db1SRobert Mustacchi /*
136*c1733db1SRobert Mustacchi  * Consolidated DMA attributes for the descriptor ring and the data buffer. We
137*c1733db1SRobert Mustacchi  * use the stricter requirements from each because we don't actually allocate
138*c1733db1SRobert Mustacchi  * that much DMA memory here to make this simpler.
139*c1733db1SRobert Mustacchi  */
140*c1733db1SRobert Mustacchi static const ddi_dma_attr_t ismt_dma_attr = {
141*c1733db1SRobert Mustacchi 	.dma_attr_version = DMA_ATTR_V0,
142*c1733db1SRobert Mustacchi 	/*
143*c1733db1SRobert Mustacchi 	 * Our DMA attributes can appear anywhere in 64-bit space.
144*c1733db1SRobert Mustacchi 	 */
145*c1733db1SRobert Mustacchi 	.dma_attr_addr_lo = 0,
146*c1733db1SRobert Mustacchi 	.dma_attr_addr_hi = UINT64_MAX,
147*c1733db1SRobert Mustacchi 	/*
148*c1733db1SRobert Mustacchi 	 * Up to 255 bytes are allowed to be specified for transmit / recieve,
149*c1733db1SRobert Mustacchi 	 * where as the descriptor ring allows for up to 256 16 byte
150*c1733db1SRobert Mustacchi 	 * descriptors. We use the latter for here, with the knowledge that
151*c1733db1SRobert Mustacchi 	 * we're never allocating more than an amount that can fit due to the
152*c1733db1SRobert Mustacchi 	 * maxxfer value below.
153*c1733db1SRobert Mustacchi 	 */
154*c1733db1SRobert Mustacchi 	.dma_attr_count_max = 256 * sizeof (ismt_desc_t),
155*c1733db1SRobert Mustacchi 	/*
156*c1733db1SRobert Mustacchi 	 * The descriptor ring requires 64 byte alignment, where as the data
157*c1733db1SRobert Mustacchi 	 * buffer requires byte alignment. Use 64 byte alignment.
158*c1733db1SRobert Mustacchi 	 */
159*c1733db1SRobert Mustacchi 	.dma_attr_align = 0x40,
160*c1733db1SRobert Mustacchi 	/*
161*c1733db1SRobert Mustacchi 	 * Cargo culted burst sizes as PCIe probably doens't have quite the same
162*c1733db1SRobert Mustacchi 	 * concerns.
163*c1733db1SRobert Mustacchi 	 */
164*c1733db1SRobert Mustacchi 	.dma_attr_burstsizes = 0xfff,
165*c1733db1SRobert Mustacchi 	/*
166*c1733db1SRobert Mustacchi 	 * We set the minimum and maximum to the sizes here. The size limits are
167*c1733db1SRobert Mustacchi 	 * really set by PCIe breaking up transactions, not anything in the
168*c1733db1SRobert Mustacchi 	 * kernel. Therefore we set the maximum to the same as
169*c1733db1SRobert Mustacchi 	 * dma_attr_count_max, partially so we can avoid complaints about DMA
170*c1733db1SRobert Mustacchi 	 * less than a page by x86 rootnex.
171*c1733db1SRobert Mustacchi 	 */
172*c1733db1SRobert Mustacchi 	.dma_attr_minxfer = 1,
173*c1733db1SRobert Mustacchi 	.dma_attr_maxxfer = 256 * sizeof (ismt_desc_t),
174*c1733db1SRobert Mustacchi 	/*
175*c1733db1SRobert Mustacchi 	 * Their are no segment restrictions and only one cookie can be used.
176*c1733db1SRobert Mustacchi 	 * For the granularity we basically set this to 1 because everything we
177*c1733db1SRobert Mustacchi 	 * allocate will be a multiple of this and we only have one cookie so it
178*c1733db1SRobert Mustacchi 	 * won't really be split..
179*c1733db1SRobert Mustacchi 	 */
180*c1733db1SRobert Mustacchi 	.dma_attr_seg = UINT64_MAX,
181*c1733db1SRobert Mustacchi 	.dma_attr_sgllen = 1,
182*c1733db1SRobert Mustacchi 	.dma_attr_granular = 1,
183*c1733db1SRobert Mustacchi 	.dma_attr_flags = 0
184*c1733db1SRobert Mustacchi };
185*c1733db1SRobert Mustacchi 
186*c1733db1SRobert Mustacchi static uint32_t
ismt_read32(ismt_t * ismt,uint32_t reg)187*c1733db1SRobert Mustacchi ismt_read32(ismt_t *ismt, uint32_t reg)
188*c1733db1SRobert Mustacchi {
189*c1733db1SRobert Mustacchi 	ASSERT3U(reg, <, ismt->ismt_regsize);
190*c1733db1SRobert Mustacchi 	return (ddi_get32(ismt->ismt_regs, (uint32_t *)(ismt->ismt_base +
191*c1733db1SRobert Mustacchi 	    reg)));
192*c1733db1SRobert Mustacchi }
193*c1733db1SRobert Mustacchi 
194*c1733db1SRobert Mustacchi static void
ismt_write32(ismt_t * ismt,uint32_t reg,uint32_t val)195*c1733db1SRobert Mustacchi ismt_write32(ismt_t *ismt, uint32_t reg, uint32_t val)
196*c1733db1SRobert Mustacchi {
197*c1733db1SRobert Mustacchi 	ASSERT3U(reg, <, ismt->ismt_regsize);
198*c1733db1SRobert Mustacchi 	ddi_put32(ismt->ismt_regs, (uint32_t *)(ismt->ismt_base + reg), val);
199*c1733db1SRobert Mustacchi }
200*c1733db1SRobert Mustacchi 
201*c1733db1SRobert Mustacchi static void
ismt_write64(ismt_t * ismt,uint32_t reg,uint64_t val)202*c1733db1SRobert Mustacchi ismt_write64(ismt_t *ismt, uint32_t reg, uint64_t val)
203*c1733db1SRobert Mustacchi {
204*c1733db1SRobert Mustacchi 	ASSERT3U(reg, <, ismt->ismt_regsize);
205*c1733db1SRobert Mustacchi 	ddi_put64(ismt->ismt_regs, (uint64_t *)(ismt->ismt_base + reg), val);
206*c1733db1SRobert Mustacchi }
207*c1733db1SRobert Mustacchi 
208*c1733db1SRobert Mustacchi static i2c_errno_t
ismt_prop_info(void * arg,i2c_prop_t prop,i2c_prop_info_t * info)209*c1733db1SRobert Mustacchi ismt_prop_info(void *arg, i2c_prop_t prop, i2c_prop_info_t *info)
210*c1733db1SRobert Mustacchi {
211*c1733db1SRobert Mustacchi 	switch (prop) {
212*c1733db1SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
213*c1733db1SRobert Mustacchi 		i2c_prop_info_set_pos_bit32(info, I2C_SPEED_STD |
214*c1733db1SRobert Mustacchi 		    I2C_SPEED_FAST | I2C_SPEED_FPLUS);
215*c1733db1SRobert Mustacchi 		break;
216*c1733db1SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
217*c1733db1SRobert Mustacchi 	case I2C_PROP_MAX_READ:
218*c1733db1SRobert Mustacchi 	case I2C_PROP_MAX_WRITE:
219*c1733db1SRobert Mustacchi 	case SMBUS_PROP_MAX_BLOCK:
220*c1733db1SRobert Mustacchi 		break;
221*c1733db1SRobert Mustacchi 	default:
222*c1733db1SRobert Mustacchi 		return (I2C_PROP_E_UNSUP);
223*c1733db1SRobert Mustacchi 	}
224*c1733db1SRobert Mustacchi 
225*c1733db1SRobert Mustacchi 	i2c_prop_info_set_perm(info, I2C_PROP_PERM_RO);
226*c1733db1SRobert Mustacchi 
227*c1733db1SRobert Mustacchi 	return (I2C_CORE_E_OK);
228*c1733db1SRobert Mustacchi }
229*c1733db1SRobert Mustacchi 
230*c1733db1SRobert Mustacchi /*
231*c1733db1SRobert Mustacchi  * Currently all the information that we return is static. If this changes, we
232*c1733db1SRobert Mustacchi  * should ensure we hold ismt_mutex during this.
233*c1733db1SRobert Mustacchi  */
234*c1733db1SRobert Mustacchi static i2c_errno_t
ismt_prop_get(void * arg,i2c_prop_t prop,void * buf,size_t buflen)235*c1733db1SRobert Mustacchi ismt_prop_get(void *arg, i2c_prop_t prop, void *buf, size_t buflen)
236*c1733db1SRobert Mustacchi {
237*c1733db1SRobert Mustacchi 	ismt_t *ismt = arg;
238*c1733db1SRobert Mustacchi 	uint32_t val;
239*c1733db1SRobert Mustacchi 
240*c1733db1SRobert Mustacchi 	switch (prop) {
241*c1733db1SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
242*c1733db1SRobert Mustacchi 		val = ismt->ismt_speed;
243*c1733db1SRobert Mustacchi 		break;
244*c1733db1SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
245*c1733db1SRobert Mustacchi 		val = SMBUS_PROP_OP_QUICK_COMMAND | SMBUS_PROP_OP_SEND_BYTE |
246*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_RECV_BYTE | SMBUS_PROP_OP_WRITE_BYTE |
247*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_READ_BYTE | SMBUS_PROP_OP_WRITE_WORD |
248*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_READ_WORD | SMBUS_PROP_OP_PROCESS_CALL |
249*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_WRITE_BLOCK | SMBUS_PROP_OP_READ_BLOCK |
250*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_BLOCK_PROCESS_CALL |
251*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_I2C_WRITE_BLOCK |
252*c1733db1SRobert Mustacchi 		    SMBUS_PROP_OP_I2C_READ_BLOCK;
253*c1733db1SRobert Mustacchi 		break;
254*c1733db1SRobert Mustacchi 	case I2C_PROP_MAX_READ:
255*c1733db1SRobert Mustacchi 	case I2C_PROP_MAX_WRITE:
256*c1733db1SRobert Mustacchi 		val = ISMT_MAX_I2C;
257*c1733db1SRobert Mustacchi 		break;
258*c1733db1SRobert Mustacchi 	case SMBUS_PROP_MAX_BLOCK:
259*c1733db1SRobert Mustacchi 		val = ISMT_MAX_SMBUS;
260*c1733db1SRobert Mustacchi 		break;
261*c1733db1SRobert Mustacchi 	default:
262*c1733db1SRobert Mustacchi 		return (I2C_PROP_E_UNSUP);
263*c1733db1SRobert Mustacchi 	}
264*c1733db1SRobert Mustacchi 
265*c1733db1SRobert Mustacchi 	VERIFY3U(buflen, >=, sizeof (val));
266*c1733db1SRobert Mustacchi 	bcopy(&val, buf, sizeof (val));
267*c1733db1SRobert Mustacchi 	return (I2C_CORE_E_OK);
268*c1733db1SRobert Mustacchi }
269*c1733db1SRobert Mustacchi 
270*c1733db1SRobert Mustacchi static void
ismt_io_error(ismt_t * ismt,uint32_t sts)271*c1733db1SRobert Mustacchi ismt_io_error(ismt_t *ismt, uint32_t sts)
272*c1733db1SRobert Mustacchi {
273*c1733db1SRobert Mustacchi 	i2c_ctrl_error_t err;
274*c1733db1SRobert Mustacchi 	VERIFY3P(ismt->ismt_err, !=, NULL);
275*c1733db1SRobert Mustacchi 
276*c1733db1SRobert Mustacchi 	if (ISMT_DESC_STS_GET_NACK(sts) != 0) {
277*c1733db1SRobert Mustacchi 		if (ISMT_DESC_STS_GET_WRLEN(sts) == 0) {
278*c1733db1SRobert Mustacchi 			err = I2C_CTRL_E_ADDR_NACK;
279*c1733db1SRobert Mustacchi 		} else {
280*c1733db1SRobert Mustacchi 			err = I2C_CTRL_E_DATA_NACK;
281*c1733db1SRobert Mustacchi 		}
282*c1733db1SRobert Mustacchi 	} else if (ISMT_DESC_STS_GET_CRC(sts) != 0) {
283*c1733db1SRobert Mustacchi 		/*
284*c1733db1SRobert Mustacchi 		 * As we don't enable PEC right now, we don't expect to see
285*c1733db1SRobert Mustacchi 		 * this. When we do, then this should be changed.
286*c1733db1SRobert Mustacchi 		 */
287*c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_DRIVER;
288*c1733db1SRobert Mustacchi 	} else if (ISMT_DESC_STS_GET_CLTO(sts) != 0) {
289*c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_SMBUS_CLOCK_LOW;
290*c1733db1SRobert Mustacchi 	} else if (ISMT_DESC_STS_GET_COL(sts) != 0) {
291*c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_ARB_LOST;
292*c1733db1SRobert Mustacchi 	} else if (ISMT_DESC_STS_GET_LPR(sts) != 0) {
293*c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_DRIVER;
294*c1733db1SRobert Mustacchi 	} else {
295*c1733db1SRobert Mustacchi 		err = I2C_CTRL_E_INTERNAL;
296*c1733db1SRobert Mustacchi 	}
297*c1733db1SRobert Mustacchi 
298*c1733db1SRobert Mustacchi 	i2c_ctrl_io_error(ismt->ismt_err, I2C_CORE_E_CONTROLLER, err);
299*c1733db1SRobert Mustacchi }
300*c1733db1SRobert Mustacchi 
301*c1733db1SRobert Mustacchi /*
302*c1733db1SRobert Mustacchi  * Process the current completion.
303*c1733db1SRobert Mustacchi  */
304*c1733db1SRobert Mustacchi static void
ismt_io(ismt_t * ismt)305*c1733db1SRobert Mustacchi ismt_io(ismt_t *ismt)
306*c1733db1SRobert Mustacchi {
307*c1733db1SRobert Mustacchi 	ismt_desc_t *desc;
308*c1733db1SRobert Mustacchi 	uint32_t sts;
309*c1733db1SRobert Mustacchi 
310*c1733db1SRobert Mustacchi 	VERIFY(MUTEX_HELD(&ismt->ismt_mutex));
311*c1733db1SRobert Mustacchi 	ISMT_DMA_SYNC(ismt->ismt_ring_dma, DDI_DMA_SYNC_FORKERNEL);
312*c1733db1SRobert Mustacchi 	ISMT_DMA_SYNC(ismt->ismt_data_dma, DDI_DMA_SYNC_FORKERNEL);
313*c1733db1SRobert Mustacchi 	desc = &ismt->ismt_ring[ismt->ismt_tail];
314*c1733db1SRobert Mustacchi 	ismt->ismt_tail = (ismt->ismt_tail + 1) % ISMT_RING_NENTS;
315*c1733db1SRobert Mustacchi 	const uint8_t *buf = (uint8_t *)ismt->ismt_data_dma.id_va;
316*c1733db1SRobert Mustacchi 
317*c1733db1SRobert Mustacchi 	sts = LE_32(desc->id_status);
318*c1733db1SRobert Mustacchi 	if (ISMT_DESC_STS_GET_SCS(sts) == 0) {
319*c1733db1SRobert Mustacchi 		ismt_io_error(ismt, sts);
320*c1733db1SRobert Mustacchi 		return;
321*c1733db1SRobert Mustacchi 	}
322*c1733db1SRobert Mustacchi 
323*c1733db1SRobert Mustacchi 	if (ismt->ismt_i2creq != NULL) {
324*c1733db1SRobert Mustacchi 		VERIFY3P(ismt->ismt_req, ==, NULL);
325*c1733db1SRobert Mustacchi 		if (ismt->ismt_i2creq->ir_rlen > 0) {
326*c1733db1SRobert Mustacchi 			VERIFY3U(ismt->ismt_i2creq->ir_rlen, ==,
327*c1733db1SRobert Mustacchi 			    ISMT_DESC_STS_GET_RDLEN(sts));
328*c1733db1SRobert Mustacchi 			bcopy(buf, ismt->ismt_i2creq->ir_rdata,
329*c1733db1SRobert Mustacchi 			    ISMT_DESC_STS_GET_RDLEN(sts));
330*c1733db1SRobert Mustacchi 		}
331*c1733db1SRobert Mustacchi 		i2c_ctrl_io_success(ismt->ismt_err);
332*c1733db1SRobert Mustacchi 		return;
333*c1733db1SRobert Mustacchi 	}
334*c1733db1SRobert Mustacchi 
335*c1733db1SRobert Mustacchi 	switch (ismt->ismt_req->smbr_op) {
336*c1733db1SRobert Mustacchi 	case SMBUS_OP_QUICK_COMMAND:
337*c1733db1SRobert Mustacchi 	case SMBUS_OP_SEND_BYTE:
338*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BYTE:
339*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_WORD:
340*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
341*c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
342*c1733db1SRobert Mustacchi 		/*
343*c1733db1SRobert Mustacchi 		 * Nothing to do for writes.
344*c1733db1SRobert Mustacchi 		 */
345*c1733db1SRobert Mustacchi 		break;
346*c1733db1SRobert Mustacchi 	case SMBUS_OP_RECV_BYTE:
347*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BYTE:
348*c1733db1SRobert Mustacchi 		ismt->ismt_req->smbr_rdata[0] = buf[0];
349*c1733db1SRobert Mustacchi 		break;
350*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_WORD:
351*c1733db1SRobert Mustacchi 	case SMBUS_OP_PROCESS_CALL:
352*c1733db1SRobert Mustacchi 		ismt->ismt_req->smbr_rdata[0] = buf[0];
353*c1733db1SRobert Mustacchi 		ismt->ismt_req->smbr_rdata[1] = buf[1];
354*c1733db1SRobert Mustacchi 		break;
355*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
356*c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
357*c1733db1SRobert Mustacchi 		if (ISMT_DESC_STS_GET_RDLEN(sts) != buf[0] + 1) {
358*c1733db1SRobert Mustacchi 			i2c_ctrl_io_error(ismt->ismt_err, I2C_CORE_E_CONTROLLER,
359*c1733db1SRobert Mustacchi 			    I2C_CTRL_E_DRIVER);
360*c1733db1SRobert Mustacchi 			return;
361*c1733db1SRobert Mustacchi 		}
362*c1733db1SRobert Mustacchi 		ismt->ismt_req->smbr_rlen = buf[0];
363*c1733db1SRobert Mustacchi 		bcopy(&buf[1], ismt->ismt_req->smbr_rdata, buf[0]);
364*c1733db1SRobert Mustacchi 		break;
365*c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
366*c1733db1SRobert Mustacchi 		bcopy(buf, ismt->ismt_req->smbr_rdata,
367*c1733db1SRobert Mustacchi 		    ISMT_DESC_STS_GET_RDLEN(sts));
368*c1733db1SRobert Mustacchi 		break;
369*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U32:
370*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U64:
371*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U32:
372*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U64:
373*c1733db1SRobert Mustacchi 	case SMBUS_OP_HOST_NOTIFY:
374*c1733db1SRobert Mustacchi 	default:
375*c1733db1SRobert Mustacchi 		panic("programmer error: unsupported request type 0x%x should "
376*c1733db1SRobert Mustacchi 		    "not have been completed", ismt->ismt_req->smbr_op);
377*c1733db1SRobert Mustacchi 	}
378*c1733db1SRobert Mustacchi 
379*c1733db1SRobert Mustacchi 	i2c_ctrl_io_success(ismt->ismt_err);
380*c1733db1SRobert Mustacchi }
381*c1733db1SRobert Mustacchi 
382*c1733db1SRobert Mustacchi /*
383*c1733db1SRobert Mustacchi  * When we're using MSI interrupts then the hardware will automatically clear
384*c1733db1SRobert Mustacchi  * the controller's interrupt status register based on our configuration.
385*c1733db1SRobert Mustacchi  * However if we're using INTx, then we will need to take care of reading the
386*c1733db1SRobert Mustacchi  * various status registers and checking what has happened.
387*c1733db1SRobert Mustacchi  *
388*c1733db1SRobert Mustacchi  * One nice thing is that we'll otherwise always get an interrupt when the whole
389*c1733db1SRobert Mustacchi  * operation is done.
390*c1733db1SRobert Mustacchi  */
391*c1733db1SRobert Mustacchi static uint_t
ismt_intr(caddr_t arg1,caddr_t arg2)392*c1733db1SRobert Mustacchi ismt_intr(caddr_t arg1, caddr_t arg2)
393*c1733db1SRobert Mustacchi {
394*c1733db1SRobert Mustacchi 	ismt_t *ismt = (ismt_t *)arg1;
395*c1733db1SRobert Mustacchi 	uint32_t msts;
396*c1733db1SRobert Mustacchi 	bool mis, meis;
397*c1733db1SRobert Mustacchi 
398*c1733db1SRobert Mustacchi 	mutex_enter(&ismt->ismt_mutex);
399*c1733db1SRobert Mustacchi 	if (ismt->ismt_itype == DDI_INTR_TYPE_FIXED) {
400*c1733db1SRobert Mustacchi 		msts = ismt_read32(ismt, ISMT_R_MSTS);
401*c1733db1SRobert Mustacchi 		mis = ISMT_R_MSTS_GET_MIS(msts);
402*c1733db1SRobert Mustacchi 		meis = ISMT_R_MSTS_GET_MEIS(msts);
403*c1733db1SRobert Mustacchi 
404*c1733db1SRobert Mustacchi 		if (!mis && !meis) {
405*c1733db1SRobert Mustacchi 			mutex_exit(&ismt->ismt_mutex);
406*c1733db1SRobert Mustacchi 			return (DDI_INTR_UNCLAIMED);
407*c1733db1SRobert Mustacchi 		}
408*c1733db1SRobert Mustacchi 		ismt_write32(ismt, ISMT_R_MSTS, msts);
409*c1733db1SRobert Mustacchi 	}
410*c1733db1SRobert Mustacchi 
411*c1733db1SRobert Mustacchi 	ismt_io(ismt);
412*c1733db1SRobert Mustacchi 	ismt->ismt_req_done = true;
413*c1733db1SRobert Mustacchi 	cv_signal(&ismt->ismt_cv);
414*c1733db1SRobert Mustacchi 	mutex_exit(&ismt->ismt_mutex);
415*c1733db1SRobert Mustacchi 	return (DDI_INTR_CLAIMED);
416*c1733db1SRobert Mustacchi }
417*c1733db1SRobert Mustacchi 
418*c1733db1SRobert Mustacchi static void
ismt_wait(ismt_t * ismt)419*c1733db1SRobert Mustacchi ismt_wait(ismt_t *ismt)
420*c1733db1SRobert Mustacchi {
421*c1733db1SRobert Mustacchi 	VERIFY(MUTEX_HELD(&ismt->ismt_mutex));
422*c1733db1SRobert Mustacchi 	VERIFY(ismt->ismt_req == NULL || ismt->ismt_i2creq == NULL);
423*c1733db1SRobert Mustacchi 	VERIFY3P(ismt->ismt_req, !=, ismt->ismt_i2creq);
424*c1733db1SRobert Mustacchi 
425*c1733db1SRobert Mustacchi 	uint32_t to = i2c_ctrl_timeout_delay_us(ismt->ismt_hdl, I2C_CTRL_TO_IO);
426*c1733db1SRobert Mustacchi 	clock_t abs = ddi_get_lbolt() + drv_usectohz(to);
427*c1733db1SRobert Mustacchi 	while (!ismt->ismt_req_done) {
428*c1733db1SRobert Mustacchi 		clock_t ret = cv_timedwait(&ismt->ismt_cv, &ismt->ismt_mutex,
429*c1733db1SRobert Mustacchi 		    abs);
430*c1733db1SRobert Mustacchi 		if (ret == -1) {
431*c1733db1SRobert Mustacchi 			break;
432*c1733db1SRobert Mustacchi 		}
433*c1733db1SRobert Mustacchi 	}
434*c1733db1SRobert Mustacchi 
435*c1733db1SRobert Mustacchi 	/*
436*c1733db1SRobert Mustacchi 	 * The command timed out. We need to set the KILL bit, complete the
437*c1733db1SRobert Mustacchi 	 * transaction, and go from there.
438*c1733db1SRobert Mustacchi 	 */
439*c1733db1SRobert Mustacchi 	if (!ismt->ismt_req_done) {
440*c1733db1SRobert Mustacchi 		uint32_t val = ISMT_R_GCTRL_SET_KILL(0, 1);
441*c1733db1SRobert Mustacchi 		ismt_write32(ismt, ISMT_R_GCTRL, val);
442*c1733db1SRobert Mustacchi 		i2c_ctrl_io_error(ismt->ismt_err, I2C_CORE_E_CONTROLLER,
443*c1733db1SRobert Mustacchi 		    I2C_CTRL_E_REQ_TO);
444*c1733db1SRobert Mustacchi 		ismt->ismt_req_done = true;
445*c1733db1SRobert Mustacchi 	}
446*c1733db1SRobert Mustacchi }
447*c1733db1SRobert Mustacchi 
448*c1733db1SRobert Mustacchi static void
ismt_io_reset(ismt_t * ismt)449*c1733db1SRobert Mustacchi ismt_io_reset(ismt_t *ismt)
450*c1733db1SRobert Mustacchi {
451*c1733db1SRobert Mustacchi 	VERIFY(MUTEX_HELD(&ismt->ismt_mutex));
452*c1733db1SRobert Mustacchi 	bzero(ismt->ismt_data_dma.id_va, ISMT_DATA_BUF_SIZE);
453*c1733db1SRobert Mustacchi 	bzero(ismt->ismt_icl_dma.id_va, ISMT_ICL_DMA_SIZE);
454*c1733db1SRobert Mustacchi 	ismt->ismt_req = NULL;
455*c1733db1SRobert Mustacchi 	ismt->ismt_i2creq = NULL;
456*c1733db1SRobert Mustacchi 	ismt->ismt_err = NULL;
457*c1733db1SRobert Mustacchi 	ismt->ismt_req_done = false;
458*c1733db1SRobert Mustacchi }
459*c1733db1SRobert Mustacchi 
460*c1733db1SRobert Mustacchi /*
461*c1733db1SRobert Mustacchi  * Set the things that are common across all I/O requests: the address, the
462*c1733db1SRobert Mustacchi  * request for the fair bit, and ask for an interrupt. Hardware will ownly honor
463*c1733db1SRobert Mustacchi  * the bit if we're using MSIs and otherwise will always inject the interrupt,
464*c1733db1SRobert Mustacchi  * so we set this regardless.
465*c1733db1SRobert Mustacchi  */
466*c1733db1SRobert Mustacchi static void
ismt_io_cmd_init(const i2c_addr_t * addr,uint32_t * cmdp)467*c1733db1SRobert Mustacchi ismt_io_cmd_init(const i2c_addr_t *addr, uint32_t *cmdp)
468*c1733db1SRobert Mustacchi {
469*c1733db1SRobert Mustacchi 	uint32_t cmd;
470*c1733db1SRobert Mustacchi 
471*c1733db1SRobert Mustacchi 	ASSERT3U(addr->ia_type, ==, I2C_ADDR_7BIT);
472*c1733db1SRobert Mustacchi 	cmd = ISMT_DESC_CMD_SET_ADDR(0, addr->ia_addr);
473*c1733db1SRobert Mustacchi 	cmd = ISMT_DESC_CMD_SET_INT(cmd, 1);
474*c1733db1SRobert Mustacchi 	cmd = ISMT_DESC_CMD_SET_FAIR(cmd, 1);
475*c1733db1SRobert Mustacchi 	*cmdp = cmd;
476*c1733db1SRobert Mustacchi }
477*c1733db1SRobert Mustacchi 
478*c1733db1SRobert Mustacchi static void
ismt_io_cmd_submit(ismt_t * ismt,uint32_t cmd,bool data)479*c1733db1SRobert Mustacchi ismt_io_cmd_submit(ismt_t *ismt, uint32_t cmd, bool data)
480*c1733db1SRobert Mustacchi {
481*c1733db1SRobert Mustacchi 	ismt_desc_t *desc;
482*c1733db1SRobert Mustacchi 
483*c1733db1SRobert Mustacchi 	VERIFY(MUTEX_HELD(&ismt->ismt_mutex));
484*c1733db1SRobert Mustacchi 	desc = &ismt->ismt_ring[ismt->ismt_head];
485*c1733db1SRobert Mustacchi 	bzero(desc, sizeof (desc));
486*c1733db1SRobert Mustacchi 
487*c1733db1SRobert Mustacchi 	desc->id_cmd_addr = LE_32(cmd);
488*c1733db1SRobert Mustacchi 	if (data) {
489*c1733db1SRobert Mustacchi 		const ddi_dma_cookie_t *c;
490*c1733db1SRobert Mustacchi 
491*c1733db1SRobert Mustacchi 		c = ddi_dma_cookie_one(ismt->ismt_data_dma.id_hdl);
492*c1733db1SRobert Mustacchi 		desc->id_low = LE_32(bitx64(c->dmac_laddress, 31, 0));
493*c1733db1SRobert Mustacchi 		desc->id_high = LE_32(bitx64(c->dmac_laddress, 63, 32));
494*c1733db1SRobert Mustacchi 		ISMT_DMA_SYNC(ismt->ismt_data_dma, DDI_DMA_SYNC_FORDEV);
495*c1733db1SRobert Mustacchi 	}
496*c1733db1SRobert Mustacchi 	ISMT_DMA_SYNC(ismt->ismt_ring_dma, DDI_DMA_SYNC_FORDEV);
497*c1733db1SRobert Mustacchi 
498*c1733db1SRobert Mustacchi 	/*
499*c1733db1SRobert Mustacchi 	 * Proceed to tell hardware to process this command. The datasheet
500*c1733db1SRobert Mustacchi 	 * suggests we need to update the descriptor pointer and then come back
501*c1733db1SRobert Mustacchi 	 * and ask the hardware to start as we can't set SS until at least one
502*c1733db1SRobert Mustacchi 	 * descriptor has been programmed.
503*c1733db1SRobert Mustacchi 	 */
504*c1733db1SRobert Mustacchi 	ismt->ismt_head = (ismt->ismt_head + 1) % ISMT_RING_NENTS;
505*c1733db1SRobert Mustacchi 	uint32_t mctrl = ismt_read32(ismt, ISMT_R_MCTRL);
506*c1733db1SRobert Mustacchi 	mctrl = ISMT_R_MCTRL_SET_FMHP(mctrl, ismt->ismt_head);
507*c1733db1SRobert Mustacchi 	ismt_write32(ismt, ISMT_R_MCTRL, mctrl);
508*c1733db1SRobert Mustacchi 	mctrl = ISMT_R_MCTRL_SET_SS(mctrl, 1);
509*c1733db1SRobert Mustacchi 	ismt_write32(ismt, ISMT_R_MCTRL, mctrl);
510*c1733db1SRobert Mustacchi 
511*c1733db1SRobert Mustacchi 	/*
512*c1733db1SRobert Mustacchi 	 * The command is running. We now need to wait for an interrupt or poll
513*c1733db1SRobert Mustacchi 	 * for completion. Unlike other drivers, we always have the interrupt
514*c1733db1SRobert Mustacchi 	 * enabled, which means we can't really poll.
515*c1733db1SRobert Mustacchi 	 */
516*c1733db1SRobert Mustacchi 	ismt_wait(ismt);
517*c1733db1SRobert Mustacchi }
518*c1733db1SRobert Mustacchi 
519*c1733db1SRobert Mustacchi static void
ismt_io_smbus(void * arg,uint32_t port,smbus_req_t * req)520*c1733db1SRobert Mustacchi ismt_io_smbus(void *arg, uint32_t port, smbus_req_t *req)
521*c1733db1SRobert Mustacchi {
522*c1733db1SRobert Mustacchi 	ismt_t *ismt = arg;
523*c1733db1SRobert Mustacchi 	uint8_t *buf;
524*c1733db1SRobert Mustacchi 	uint32_t cmd;
525*c1733db1SRobert Mustacchi 	bool data = false;
526*c1733db1SRobert Mustacchi 
527*c1733db1SRobert Mustacchi 	mutex_enter(&ismt->ismt_mutex);
528*c1733db1SRobert Mustacchi 	ismt_io_reset(ismt);
529*c1733db1SRobert Mustacchi 	ismt->ismt_req = req;
530*c1733db1SRobert Mustacchi 	ismt->ismt_err = &req->smbr_error;
531*c1733db1SRobert Mustacchi 
532*c1733db1SRobert Mustacchi 	buf = (uint8_t *)ismt->ismt_data_dma.id_va;
533*c1733db1SRobert Mustacchi 
534*c1733db1SRobert Mustacchi 	/*
535*c1733db1SRobert Mustacchi 	 * Set up the descriptor. In particualr we need to determine whether to
536*c1733db1SRobert Mustacchi 	 * set:
537*c1733db1SRobert Mustacchi 	 *
538*c1733db1SRobert Mustacchi 	 *  - The read address bit (default is write)
539*c1733db1SRobert Mustacchi 	 *  - The block request bit
540*c1733db1SRobert Mustacchi 	 *  - The C/WRL bit which determines whether the write field is the
541*c1733db1SRobert Mustacchi 	 *    command.
542*c1733db1SRobert Mustacchi 	 *  - The read and write length, if non-zero.
543*c1733db1SRobert Mustacchi 	 *  - Whether we are going to use the data pointer and if we need to do
544*c1733db1SRobert Mustacchi 	 *    anyhting to get it ready
545*c1733db1SRobert Mustacchi 	 *
546*c1733db1SRobert Mustacchi 	 * The read address bit and whether we use data are bools that we apply
547*c1733db1SRobert Mustacchi 	 * at the end.
548*c1733db1SRobert Mustacchi 	 */
549*c1733db1SRobert Mustacchi 	ismt_io_cmd_init(&req->smbr_addr, &cmd);
550*c1733db1SRobert Mustacchi 	switch (req->smbr_op) {
551*c1733db1SRobert Mustacchi 	case SMBUS_OP_QUICK_COMMAND:
552*c1733db1SRobert Mustacchi 		if ((req->smbr_flags & I2C_IO_REQ_F_QUICK_WRITE) != 0) {
553*c1733db1SRobert Mustacchi 			cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
554*c1733db1SRobert Mustacchi 		} else {
555*c1733db1SRobert Mustacchi 			cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
556*c1733db1SRobert Mustacchi 		}
557*c1733db1SRobert Mustacchi 		break;
558*c1733db1SRobert Mustacchi 	case SMBUS_OP_SEND_BYTE:
559*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
560*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
561*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_wdata[0]);
562*c1733db1SRobert Mustacchi 		break;
563*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BYTE:
564*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
565*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, 2);
566*c1733db1SRobert Mustacchi 		data = true;
567*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
568*c1733db1SRobert Mustacchi 		buf[1] = req->smbr_wdata[0];
569*c1733db1SRobert Mustacchi 		break;
570*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_WORD:
571*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
572*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, 3);
573*c1733db1SRobert Mustacchi 		data = true;
574*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
575*c1733db1SRobert Mustacchi 		buf[1] = req->smbr_wdata[0];
576*c1733db1SRobert Mustacchi 		buf[2] = req->smbr_wdata[1];
577*c1733db1SRobert Mustacchi 		break;
578*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_BLOCK:
579*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
580*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_BLK(cmd, 1);
581*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_wlen, <=, ISMT_MAX_SMBUS);
582*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_wlen + 1);
583*c1733db1SRobert Mustacchi 		data = true;
584*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
585*c1733db1SRobert Mustacchi 		bcopy(req->smbr_wdata, &buf[1], req->smbr_wlen);
586*c1733db1SRobert Mustacchi 		break;
587*c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_WRITE_BLOCK:
588*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
589*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_I2C(cmd, 1);
590*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_wlen, >, 0);
591*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_wlen, <=, ISMT_MAX_I2C);
592*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_wlen + 1);
593*c1733db1SRobert Mustacchi 		data = true;
594*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
595*c1733db1SRobert Mustacchi 		bcopy(req->smbr_wdata, &buf[1], req->smbr_wlen);
596*c1733db1SRobert Mustacchi 		break;
597*c1733db1SRobert Mustacchi 	case SMBUS_OP_RECV_BYTE:
598*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
599*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, 1);
600*c1733db1SRobert Mustacchi 		data = true;
601*c1733db1SRobert Mustacchi 		break;
602*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BYTE:
603*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
604*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
605*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_cmd);
606*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, 1);
607*c1733db1SRobert Mustacchi 		data = true;
608*c1733db1SRobert Mustacchi 		break;
609*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_WORD:
610*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
611*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
612*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_cmd);
613*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, 2);
614*c1733db1SRobert Mustacchi 		data = true;
615*c1733db1SRobert Mustacchi 		break;
616*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_BLOCK:
617*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
618*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_BLK(cmd, 1);
619*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
620*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_cmd);
621*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_rlen, >, 0);
622*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_rlen, <=, ISMT_MAX_SMBUS);
623*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, req->smbr_rlen + 1);
624*c1733db1SRobert Mustacchi 		data = true;
625*c1733db1SRobert Mustacchi 		break;
626*c1733db1SRobert Mustacchi 	case SMBUS_OP_I2C_READ_BLOCK:
627*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
628*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_I2C(cmd, 1);
629*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
630*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_cmd);
631*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_rlen, >, 0);
632*c1733db1SRobert Mustacchi 		VERIFY3U(req->smbr_rlen, <=, ISMT_MAX_I2C);
633*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, req->smbr_rlen);
634*c1733db1SRobert Mustacchi 		data = true;
635*c1733db1SRobert Mustacchi 		break;
636*c1733db1SRobert Mustacchi 	case SMBUS_OP_PROCESS_CALL:
637*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
638*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, 3);
639*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, 2);
640*c1733db1SRobert Mustacchi 		data = true;
641*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
642*c1733db1SRobert Mustacchi 		buf[1] = req->smbr_wdata[0];
643*c1733db1SRobert Mustacchi 		buf[2] = req->smbr_wdata[1];
644*c1733db1SRobert Mustacchi 		break;
645*c1733db1SRobert Mustacchi 	case SMBUS_OP_BLOCK_PROCESS_CALL:
646*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
647*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->smbr_wlen + 1);
648*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, req->smbr_rlen + 1);
649*c1733db1SRobert Mustacchi 		data = true;
650*c1733db1SRobert Mustacchi 		buf[0] = req->smbr_cmd;
651*c1733db1SRobert Mustacchi 		bcopy(req->smbr_wdata, &buf[1], req->smbr_wlen);
652*c1733db1SRobert Mustacchi 		break;
653*c1733db1SRobert Mustacchi 	/*
654*c1733db1SRobert Mustacchi 	 * As the datasheets don't have a way to directly run the U32/U64
655*c1733db1SRobert Mustacchi 	 * operations, we allow our translation layer to take care of it.
656*c1733db1SRobert Mustacchi 	 */
657*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U32:
658*c1733db1SRobert Mustacchi 	case SMBUS_OP_READ_U64:
659*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U32:
660*c1733db1SRobert Mustacchi 	case SMBUS_OP_WRITE_U64:
661*c1733db1SRobert Mustacchi 	case SMBUS_OP_HOST_NOTIFY:
662*c1733db1SRobert Mustacchi 	default:
663*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!framework passed "
664*c1733db1SRobert Mustacchi 		    "unsupported SMBus command 0x%x", req->smbr_op);
665*c1733db1SRobert Mustacchi 		i2c_ctrl_io_error(&req->smbr_error, I2C_CORE_E_CONTROLLER,
666*c1733db1SRobert Mustacchi 		    I2C_CTRL_E_UNSUP_CMD);
667*c1733db1SRobert Mustacchi 		goto done;
668*c1733db1SRobert Mustacchi 
669*c1733db1SRobert Mustacchi 	}
670*c1733db1SRobert Mustacchi 
671*c1733db1SRobert Mustacchi 	ismt_io_cmd_submit(ismt, cmd, data);
672*c1733db1SRobert Mustacchi done:
673*c1733db1SRobert Mustacchi 	ismt->ismt_req = NULL;
674*c1733db1SRobert Mustacchi 	ismt->ismt_i2creq = NULL;
675*c1733db1SRobert Mustacchi 	ismt->ismt_err = NULL;
676*c1733db1SRobert Mustacchi 	ismt->ismt_req_done = false;
677*c1733db1SRobert Mustacchi 	mutex_exit(&ismt->ismt_mutex);
678*c1733db1SRobert Mustacchi }
679*c1733db1SRobert Mustacchi 
680*c1733db1SRobert Mustacchi static void
ismt_io_i2c(void * arg,uint32_t port,i2c_req_t * req)681*c1733db1SRobert Mustacchi ismt_io_i2c(void *arg, uint32_t port, i2c_req_t *req)
682*c1733db1SRobert Mustacchi {
683*c1733db1SRobert Mustacchi 	ismt_t *ismt = arg;
684*c1733db1SRobert Mustacchi 	uint8_t *buf;
685*c1733db1SRobert Mustacchi 	uint32_t cmd;
686*c1733db1SRobert Mustacchi 	bool data = false;
687*c1733db1SRobert Mustacchi 
688*c1733db1SRobert Mustacchi 	mutex_enter(&ismt->ismt_mutex);
689*c1733db1SRobert Mustacchi 	ismt_io_reset(ismt);
690*c1733db1SRobert Mustacchi 	ismt->ismt_i2creq = req;
691*c1733db1SRobert Mustacchi 	ismt->ismt_err = &req->ir_error;
692*c1733db1SRobert Mustacchi 
693*c1733db1SRobert Mustacchi 	buf = (uint8_t *)ismt->ismt_data_dma.id_va;
694*c1733db1SRobert Mustacchi 
695*c1733db1SRobert Mustacchi 	/*
696*c1733db1SRobert Mustacchi 	 * I2C Commands are required to always set the I2C bit and we must never
697*c1733db1SRobert Mustacchi 	 * set the block bit. The remaining flags and set up depend on whether
698*c1733db1SRobert Mustacchi 	 * we're doing a write, a read, or a write folowed by a read.
699*c1733db1SRobert Mustacchi 	 */
700*c1733db1SRobert Mustacchi 	ismt_io_cmd_init(&req->ir_addr, &cmd);
701*c1733db1SRobert Mustacchi 	cmd = ISMT_DESC_CMD_SET_I2C(cmd, 1);
702*c1733db1SRobert Mustacchi 	cmd = ISMT_DESC_CMD_SET_BLK(cmd, 0);
703*c1733db1SRobert Mustacchi 
704*c1733db1SRobert Mustacchi 	if (req->ir_rlen > 0) {
705*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_READ);
706*c1733db1SRobert Mustacchi 		VERIFY3U(req->ir_rlen, <, ISMT_MAX_I2C);
707*c1733db1SRobert Mustacchi 		data = true;
708*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RDLEN(cmd, req->ir_rlen);
709*c1733db1SRobert Mustacchi 	}
710*c1733db1SRobert Mustacchi 
711*c1733db1SRobert Mustacchi 	if (req->ir_wlen > 0) {
712*c1733db1SRobert Mustacchi 		cmd = ISMT_DESC_CMD_SET_RW(cmd, ISMT_DESC_CMD_RW_WRITE);
713*c1733db1SRobert Mustacchi 
714*c1733db1SRobert Mustacchi 		/*
715*c1733db1SRobert Mustacchi 		 * The datasheet tells us that if we have a 1 byte write, we
716*c1733db1SRobert Mustacchi 		 * need to set C/WRL and it will encode the data byte. Otherwise
717*c1733db1SRobert Mustacchi 		 * we use the normal write length.
718*c1733db1SRobert Mustacchi 		 */
719*c1733db1SRobert Mustacchi 		if (req->ir_wlen == 1) {
720*c1733db1SRobert Mustacchi 			cmd = ISMT_DESC_CMD_SET_CWRL(cmd, 1);
721*c1733db1SRobert Mustacchi 			cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->ir_wdata[0]);
722*c1733db1SRobert Mustacchi 		} else {
723*c1733db1SRobert Mustacchi 			VERIFY3U(req->ir_wlen, >, 0);
724*c1733db1SRobert Mustacchi 			VERIFY3U(req->ir_wlen, <, ISMT_MAX_I2C);
725*c1733db1SRobert Mustacchi 			cmd = ISMT_DESC_CMD_SET_WRLEN(cmd, req->ir_wlen);
726*c1733db1SRobert Mustacchi 			data = true;
727*c1733db1SRobert Mustacchi 			bcopy(req->ir_wdata, buf, req->ir_wlen);
728*c1733db1SRobert Mustacchi 		}
729*c1733db1SRobert Mustacchi 	}
730*c1733db1SRobert Mustacchi 
731*c1733db1SRobert Mustacchi 	ismt_io_cmd_submit(ismt, cmd, data);
732*c1733db1SRobert Mustacchi 
733*c1733db1SRobert Mustacchi 	ismt->ismt_req = NULL;
734*c1733db1SRobert Mustacchi 	ismt->ismt_i2creq = NULL;
735*c1733db1SRobert Mustacchi 	ismt->ismt_req_done = false;
736*c1733db1SRobert Mustacchi 	mutex_exit(&ismt->ismt_mutex);
737*c1733db1SRobert Mustacchi }
738*c1733db1SRobert Mustacchi 
739*c1733db1SRobert Mustacchi static const i2c_ctrl_ops_t ismt_ctrl_ops = {
740*c1733db1SRobert Mustacchi 	.i2c_port_name_f = i2c_ctrl_port_name_portno,
741*c1733db1SRobert Mustacchi 	.i2c_io_i2c_f = ismt_io_i2c,
742*c1733db1SRobert Mustacchi 	.i2c_io_smbus_f = ismt_io_smbus,
743*c1733db1SRobert Mustacchi 	.i2c_prop_info_f = ismt_prop_info,
744*c1733db1SRobert Mustacchi 	.i2c_prop_get_f = ismt_prop_get
745*c1733db1SRobert Mustacchi };
746*c1733db1SRobert Mustacchi 
747*c1733db1SRobert Mustacchi static bool
ismt_setup_regs(ismt_t * ismt)748*c1733db1SRobert Mustacchi ismt_setup_regs(ismt_t *ismt)
749*c1733db1SRobert Mustacchi {
750*c1733db1SRobert Mustacchi 	int ret;
751*c1733db1SRobert Mustacchi 	ddi_device_acc_attr_t attr;
752*c1733db1SRobert Mustacchi 
753*c1733db1SRobert Mustacchi 	bzero(&attr, sizeof (attr));
754*c1733db1SRobert Mustacchi 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
755*c1733db1SRobert Mustacchi 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
756*c1733db1SRobert Mustacchi 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
757*c1733db1SRobert Mustacchi 	attr.devacc_attr_access = DDI_DEFAULT_ACC;
758*c1733db1SRobert Mustacchi 
759*c1733db1SRobert Mustacchi 	if (ddi_dev_regsize(ismt->ismt_dip, ISMT_REGNO, &ismt->ismt_regsize) !=
760*c1733db1SRobert Mustacchi 	    DDI_SUCCESS) {
761*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to get regs[%u] size",
762*c1733db1SRobert Mustacchi 		    ISMT_REGNO);
763*c1733db1SRobert Mustacchi 		return (false);
764*c1733db1SRobert Mustacchi 	}
765*c1733db1SRobert Mustacchi 
766*c1733db1SRobert Mustacchi 	ret = ddi_regs_map_setup(ismt->ismt_dip, ISMT_REGNO, &ismt->ismt_base,
767*c1733db1SRobert Mustacchi 	    0, ismt->ismt_regsize, &attr, &ismt->ismt_regs);
768*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
769*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to map regs[%u]: %u",
770*c1733db1SRobert Mustacchi 		    ISMT_REGNO, ret);
771*c1733db1SRobert Mustacchi 		return (false);
772*c1733db1SRobert Mustacchi 	}
773*c1733db1SRobert Mustacchi 
774*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_REGS;
775*c1733db1SRobert Mustacchi 	return (true);
776*c1733db1SRobert Mustacchi }
777*c1733db1SRobert Mustacchi 
778*c1733db1SRobert Mustacchi static void
ismt_dma_free(ismt_dma_t * dma)779*c1733db1SRobert Mustacchi ismt_dma_free(ismt_dma_t *dma)
780*c1733db1SRobert Mustacchi {
781*c1733db1SRobert Mustacchi 	/* Proxy for DMA handle bound */
782*c1733db1SRobert Mustacchi 	if (dma->id_size != 0) {
783*c1733db1SRobert Mustacchi 		(void) ddi_dma_unbind_handle(dma->id_hdl);
784*c1733db1SRobert Mustacchi 		dma->id_size = 0;
785*c1733db1SRobert Mustacchi 	}
786*c1733db1SRobert Mustacchi 
787*c1733db1SRobert Mustacchi 	if (dma->id_acc != NULL) {
788*c1733db1SRobert Mustacchi 		ddi_dma_mem_free(&dma->id_acc);
789*c1733db1SRobert Mustacchi 		dma->id_acc = NULL;
790*c1733db1SRobert Mustacchi 		dma->id_va = NULL;
791*c1733db1SRobert Mustacchi 		dma->id_alloc_len = 0;
792*c1733db1SRobert Mustacchi 	}
793*c1733db1SRobert Mustacchi 
794*c1733db1SRobert Mustacchi 	if (dma->id_hdl != NULL) {
795*c1733db1SRobert Mustacchi 		ddi_dma_free_handle(&dma->id_hdl);
796*c1733db1SRobert Mustacchi 		dma->id_hdl = NULL;
797*c1733db1SRobert Mustacchi 	}
798*c1733db1SRobert Mustacchi 
799*c1733db1SRobert Mustacchi 	ASSERT0(dma->id_size);
800*c1733db1SRobert Mustacchi 	ASSERT0(dma->id_alloc_len);
801*c1733db1SRobert Mustacchi 	ASSERT3P(dma->id_acc, ==, NULL);
802*c1733db1SRobert Mustacchi 	ASSERT3P(dma->id_hdl, ==, NULL);
803*c1733db1SRobert Mustacchi 	ASSERT3P(dma->id_va, ==, NULL);
804*c1733db1SRobert Mustacchi }
805*c1733db1SRobert Mustacchi 
806*c1733db1SRobert Mustacchi static bool
ismt_dma_alloc(ismt_t * ismt,ismt_dma_t * dma,size_t size)807*c1733db1SRobert Mustacchi ismt_dma_alloc(ismt_t *ismt, ismt_dma_t *dma, size_t size)
808*c1733db1SRobert Mustacchi {
809*c1733db1SRobert Mustacchi 	int ret;
810*c1733db1SRobert Mustacchi 	ddi_device_acc_attr_t acc;
811*c1733db1SRobert Mustacchi 	uint_t flags = DDI_DMA_CONSISTENT;
812*c1733db1SRobert Mustacchi 
813*c1733db1SRobert Mustacchi 	bzero(dma, sizeof (ismt_dma_t));
814*c1733db1SRobert Mustacchi 	ret = ddi_dma_alloc_handle(ismt->ismt_dip, &ismt_dma_attr,
815*c1733db1SRobert Mustacchi 	    DDI_DMA_SLEEP, NULL, &dma->id_hdl);
816*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
817*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!failed to allocate DMA "
818*c1733db1SRobert Mustacchi 		    "handle: %d", ret);
819*c1733db1SRobert Mustacchi 		return (false);
820*c1733db1SRobert Mustacchi 	}
821*c1733db1SRobert Mustacchi 
822*c1733db1SRobert Mustacchi 	bzero(&acc, sizeof (acc));
823*c1733db1SRobert Mustacchi 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V1;
824*c1733db1SRobert Mustacchi 	acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
825*c1733db1SRobert Mustacchi 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
826*c1733db1SRobert Mustacchi 	acc.devacc_attr_access = DDI_DEFAULT_ACC;
827*c1733db1SRobert Mustacchi 	ret = ddi_dma_mem_alloc(dma->id_hdl, size, &acc, flags,
828*c1733db1SRobert Mustacchi 	    DDI_DMA_SLEEP, NULL, &dma->id_va, &dma->id_alloc_len,
829*c1733db1SRobert Mustacchi 	    &dma->id_acc);
830*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
831*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!failed to allocate %lu "
832*c1733db1SRobert Mustacchi 		    "bytes of DMA memory: %d", size, ret);
833*c1733db1SRobert Mustacchi 		ismt_dma_free(dma);
834*c1733db1SRobert Mustacchi 		return (false);
835*c1733db1SRobert Mustacchi 	}
836*c1733db1SRobert Mustacchi 
837*c1733db1SRobert Mustacchi 	bzero(dma->id_va, dma->id_alloc_len);
838*c1733db1SRobert Mustacchi 	ret = ddi_dma_addr_bind_handle(dma->id_hdl, NULL, dma->id_va,
839*c1733db1SRobert Mustacchi 	    dma->id_alloc_len, DDI_DMA_RDWR | flags, DDI_DMA_DONTWAIT, NULL,
840*c1733db1SRobert Mustacchi 	    NULL, NULL);
841*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
842*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!failed to bind %lu bytes of "
843*c1733db1SRobert Mustacchi 		    "DMA memory: %d", dma->id_alloc_len, ret);
844*c1733db1SRobert Mustacchi 		ismt_dma_free(dma);
845*c1733db1SRobert Mustacchi 		return (false);
846*c1733db1SRobert Mustacchi 	}
847*c1733db1SRobert Mustacchi 
848*c1733db1SRobert Mustacchi 	dma->id_size = size;
849*c1733db1SRobert Mustacchi 	return (true);
850*c1733db1SRobert Mustacchi }
851*c1733db1SRobert Mustacchi 
852*c1733db1SRobert Mustacchi static bool
ismt_alloc_intr(ismt_t * ismt)853*c1733db1SRobert Mustacchi ismt_alloc_intr(ismt_t *ismt)
854*c1733db1SRobert Mustacchi {
855*c1733db1SRobert Mustacchi 	int ret, types;
856*c1733db1SRobert Mustacchi 
857*c1733db1SRobert Mustacchi 	ret = ddi_intr_get_supported_types(ismt->ismt_dip, &types);
858*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
859*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to get supproted "
860*c1733db1SRobert Mustacchi 		    "interrupt types: 0x%d", ret);
861*c1733db1SRobert Mustacchi 		return (false);
862*c1733db1SRobert Mustacchi 	}
863*c1733db1SRobert Mustacchi 
864*c1733db1SRobert Mustacchi 	/*
865*c1733db1SRobert Mustacchi 	 * We only expect hardware to support MSIs and INTx.
866*c1733db1SRobert Mustacchi 	 */
867*c1733db1SRobert Mustacchi 	if ((types & DDI_INTR_TYPE_MSI) != 0) {
868*c1733db1SRobert Mustacchi 		ret = ddi_intr_alloc(ismt->ismt_dip, &ismt->ismt_intr_hdl,
869*c1733db1SRobert Mustacchi 		    DDI_INTR_TYPE_MSI, 0, 1, &ismt->ismt_nintrs,
870*c1733db1SRobert Mustacchi 		    DDI_INTR_ALLOC_STRICT);
871*c1733db1SRobert Mustacchi 		if (ret == DDI_SUCCESS) {
872*c1733db1SRobert Mustacchi 			ismt->ismt_itype = DDI_INTR_TYPE_MSI;
873*c1733db1SRobert Mustacchi 			return (true);
874*c1733db1SRobert Mustacchi 		}
875*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!failed to allocate MSI "
876*c1733db1SRobert Mustacchi 		    "interrupt");
877*c1733db1SRobert Mustacchi 	}
878*c1733db1SRobert Mustacchi 
879*c1733db1SRobert Mustacchi 	if ((types & DDI_INTR_TYPE_FIXED) != 0) {
880*c1733db1SRobert Mustacchi 		ret = ddi_intr_alloc(ismt->ismt_dip, &ismt->ismt_intr_hdl,
881*c1733db1SRobert Mustacchi 		    DDI_INTR_TYPE_MSI, 0, 1, &ismt->ismt_nintrs,
882*c1733db1SRobert Mustacchi 		    DDI_INTR_ALLOC_STRICT);
883*c1733db1SRobert Mustacchi 		if (ret == DDI_SUCCESS) {
884*c1733db1SRobert Mustacchi 			ismt->ismt_itype = DDI_INTR_TYPE_FIXED;
885*c1733db1SRobert Mustacchi 			return (true);
886*c1733db1SRobert Mustacchi 		}
887*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "!failed to allocate INTx "
888*c1733db1SRobert Mustacchi 		    "interrupt");
889*c1733db1SRobert Mustacchi 	}
890*c1733db1SRobert Mustacchi 
891*c1733db1SRobert Mustacchi 	dev_err(ismt->ismt_dip, CE_WARN, "failed to allocate any interrupts "
892*c1733db1SRobert Mustacchi 	    "from type 0x%x", types);
893*c1733db1SRobert Mustacchi 	return (false);
894*c1733db1SRobert Mustacchi }
895*c1733db1SRobert Mustacchi 
896*c1733db1SRobert Mustacchi static bool
ismt_setup_intr(ismt_t * ismt)897*c1733db1SRobert Mustacchi ismt_setup_intr(ismt_t *ismt)
898*c1733db1SRobert Mustacchi {
899*c1733db1SRobert Mustacchi 	int ret = ddi_intr_add_handler(ismt->ismt_intr_hdl, ismt_intr, ismt,
900*c1733db1SRobert Mustacchi 	    NULL);
901*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
902*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to add interrupt "
903*c1733db1SRobert Mustacchi 		    "handler: 0x%x", ret);
904*c1733db1SRobert Mustacchi 		return (false);
905*c1733db1SRobert Mustacchi 	}
906*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_INTR_HDL;
907*c1733db1SRobert Mustacchi 
908*c1733db1SRobert Mustacchi 	ret = ddi_intr_get_pri(ismt->ismt_intr_hdl, &ismt->ismt_intr_pri);
909*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
910*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to get interrupt "
911*c1733db1SRobert Mustacchi 		    "priority");
912*c1733db1SRobert Mustacchi 		return (false);
913*c1733db1SRobert Mustacchi 	}
914*c1733db1SRobert Mustacchi 
915*c1733db1SRobert Mustacchi 	return (true);
916*c1733db1SRobert Mustacchi }
917*c1733db1SRobert Mustacchi 
918*c1733db1SRobert Mustacchi /*
919*c1733db1SRobert Mustacchi  * Go through and set up hardware for use. We need to explicitly take care of:
920*c1733db1SRobert Mustacchi  *
921*c1733db1SRobert Mustacchi  *  - The Interrupt Cause Log
922*c1733db1SRobert Mustacchi  *  - The Controller DMA ring
923*c1733db1SRobert Mustacchi  *  - Firmware Head and Tail Registers
924*c1733db1SRobert Mustacchi  *  - Enabling generation of interrupts
925*c1733db1SRobert Mustacchi  *
926*c1733db1SRobert Mustacchi  * We use the hardwar defaults for the device retry policy.
927*c1733db1SRobert Mustacchi  */
928*c1733db1SRobert Mustacchi static void
ismt_ctrl_init(ismt_t * ismt)929*c1733db1SRobert Mustacchi ismt_ctrl_init(ismt_t *ismt)
930*c1733db1SRobert Mustacchi {
931*c1733db1SRobert Mustacchi 	uint32_t val;
932*c1733db1SRobert Mustacchi 	const ddi_dma_cookie_t *c;
933*c1733db1SRobert Mustacchi 
934*c1733db1SRobert Mustacchi 	c = ddi_dma_cookie_one(ismt->ismt_icl_dma.id_hdl);
935*c1733db1SRobert Mustacchi 	ismt_write64(ismt, ISMT_R_SMTICL, c->dmac_laddress);
936*c1733db1SRobert Mustacchi 
937*c1733db1SRobert Mustacchi 	c = ddi_dma_cookie_one(ismt->ismt_ring_dma.id_hdl);
938*c1733db1SRobert Mustacchi 	ismt_write64(ismt, ISMT_R_MDBA, c->dmac_laddress);
939*c1733db1SRobert Mustacchi 
940*c1733db1SRobert Mustacchi 	val = ISMT_R_MDS_SET_SIZE(0, ISMT_RING_NENTS - 1);
941*c1733db1SRobert Mustacchi 	ismt_write32(ismt, ISMT_R_MDS, val);
942*c1733db1SRobert Mustacchi 
943*c1733db1SRobert Mustacchi 	val = ISMT_R_MCTRL_SET_FMHP(0, 0);
944*c1733db1SRobert Mustacchi 	val = ISMT_R_MCTRL_SET_MEIE(val, 1);
945*c1733db1SRobert Mustacchi 	ismt_write32(ismt, ISMT_R_MCTRL, val);
946*c1733db1SRobert Mustacchi 
947*c1733db1SRobert Mustacchi 	val = ISMT_R_MSTS_SET_HMTP(0, 0);
948*c1733db1SRobert Mustacchi 	ismt_write32(ismt, ISMT_R_MSTS, val);
949*c1733db1SRobert Mustacchi 
950*c1733db1SRobert Mustacchi 	ismt->ismt_head = ismt->ismt_tail = 0;
951*c1733db1SRobert Mustacchi 	ismt->ismt_ring = (ismt_desc_t *)ismt->ismt_ring_dma.id_va;
952*c1733db1SRobert Mustacchi 
953*c1733db1SRobert Mustacchi 	val = ismt_read32(ismt, ISMT_R_SPGT);
954*c1733db1SRobert Mustacchi 	switch (ISMT_R_SPGT_GET_SPD(val)) {
955*c1733db1SRobert Mustacchi 	case ISMT_R_SPT_SPD_80K:
956*c1733db1SRobert Mustacchi 	case ISMT_R_SPT_SPD_100K:
957*c1733db1SRobert Mustacchi 		ismt->ismt_speed = I2C_SPEED_STD;
958*c1733db1SRobert Mustacchi 		break;
959*c1733db1SRobert Mustacchi 	case ISMT_R_SPT_SPD_400K:
960*c1733db1SRobert Mustacchi 		ismt->ismt_speed = I2C_SPEED_FAST;
961*c1733db1SRobert Mustacchi 		break;
962*c1733db1SRobert Mustacchi 	case ISMT_R_SPT_SPD_1M:
963*c1733db1SRobert Mustacchi 		ismt->ismt_speed = I2C_SPEED_FPLUS;
964*c1733db1SRobert Mustacchi 		break;
965*c1733db1SRobert Mustacchi 	}
966*c1733db1SRobert Mustacchi }
967*c1733db1SRobert Mustacchi 
968*c1733db1SRobert Mustacchi static bool
ismt_enable_intr(ismt_t * ismt)969*c1733db1SRobert Mustacchi ismt_enable_intr(ismt_t *ismt)
970*c1733db1SRobert Mustacchi {
971*c1733db1SRobert Mustacchi 	int ret = ddi_intr_enable(ismt->ismt_intr_hdl);
972*c1733db1SRobert Mustacchi 	if (ret != DDI_SUCCESS) {
973*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to enable interrupt "
974*c1733db1SRobert Mustacchi 		    "handler: %d", ret);
975*c1733db1SRobert Mustacchi 		return (false);
976*c1733db1SRobert Mustacchi 	}
977*c1733db1SRobert Mustacchi 
978*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_INTR_EN;
979*c1733db1SRobert Mustacchi 	return (true);
980*c1733db1SRobert Mustacchi }
981*c1733db1SRobert Mustacchi 
982*c1733db1SRobert Mustacchi static bool
ismt_register(ismt_t * ismt)983*c1733db1SRobert Mustacchi ismt_register(ismt_t *ismt)
984*c1733db1SRobert Mustacchi {
985*c1733db1SRobert Mustacchi 	i2c_ctrl_reg_error_t ret;
986*c1733db1SRobert Mustacchi 	i2c_ctrl_register_t *reg;
987*c1733db1SRobert Mustacchi 
988*c1733db1SRobert Mustacchi 	ret = i2c_ctrl_register_alloc(I2C_CTRL_PROVIDER, &reg);
989*c1733db1SRobert Mustacchi 	if (ret != 0) {
990*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to allocate i2c "
991*c1733db1SRobert Mustacchi 		    "controller registration structure: 0x%x", ret);
992*c1733db1SRobert Mustacchi 		return (false);
993*c1733db1SRobert Mustacchi 	}
994*c1733db1SRobert Mustacchi 
995*c1733db1SRobert Mustacchi 	reg->ic_type = I2C_CTRL_TYPE_SMBUS;
996*c1733db1SRobert Mustacchi 	reg->ic_nports = 1;
997*c1733db1SRobert Mustacchi 	reg->ic_dip = ismt->ismt_dip;
998*c1733db1SRobert Mustacchi 	reg->ic_drv = ismt;
999*c1733db1SRobert Mustacchi 	reg->ic_ops = &ismt_ctrl_ops;
1000*c1733db1SRobert Mustacchi 
1001*c1733db1SRobert Mustacchi 	ret = i2c_ctrl_register(reg, &ismt->ismt_hdl);
1002*c1733db1SRobert Mustacchi 	i2c_ctrl_register_free(reg);
1003*c1733db1SRobert Mustacchi 	if (ret != 0) {
1004*c1733db1SRobert Mustacchi 		dev_err(ismt->ismt_dip, CE_WARN, "failed to register with i2c "
1005*c1733db1SRobert Mustacchi 		    "framework: 0x%x", ret);
1006*c1733db1SRobert Mustacchi 		return (false);
1007*c1733db1SRobert Mustacchi 	}
1008*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_I2C;
1009*c1733db1SRobert Mustacchi 
1010*c1733db1SRobert Mustacchi 	return (true);
1011*c1733db1SRobert Mustacchi }
1012*c1733db1SRobert Mustacchi 
1013*c1733db1SRobert Mustacchi static void
ismt_cleanup(ismt_t * ismt)1014*c1733db1SRobert Mustacchi ismt_cleanup(ismt_t *ismt)
1015*c1733db1SRobert Mustacchi {
1016*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_INTR_EN) != 0) {
1017*c1733db1SRobert Mustacchi 		/*
1018*c1733db1SRobert Mustacchi 		 * If this fails while tearing down, there isn't much we can do.
1019*c1733db1SRobert Mustacchi 		 */
1020*c1733db1SRobert Mustacchi 		int ret = ddi_intr_disable(ismt->ismt_intr_hdl);
1021*c1733db1SRobert Mustacchi 		if (ret != DDI_SUCCESS) {
1022*c1733db1SRobert Mustacchi 			dev_err(ismt->ismt_dip, CE_WARN, "failed to disable "
1023*c1733db1SRobert Mustacchi 			    "interrupt handler: %d", ret);
1024*c1733db1SRobert Mustacchi 		}
1025*c1733db1SRobert Mustacchi 
1026*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_INTR_EN;
1027*c1733db1SRobert Mustacchi 	}
1028*c1733db1SRobert Mustacchi 
1029*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_SYNC) != 0) {
1030*c1733db1SRobert Mustacchi 		cv_destroy(&ismt->ismt_cv);
1031*c1733db1SRobert Mustacchi 		mutex_destroy(&ismt->ismt_mutex);
1032*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_SYNC;
1033*c1733db1SRobert Mustacchi 	}
1034*c1733db1SRobert Mustacchi 
1035*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_INTR_HDL) != 0) {
1036*c1733db1SRobert Mustacchi 		int ret = ddi_intr_remove_handler(ismt->ismt_intr_hdl);
1037*c1733db1SRobert Mustacchi 		if (ret != 0) {
1038*c1733db1SRobert Mustacchi 			dev_err(ismt->ismt_dip, CE_WARN, "failed to remove "
1039*c1733db1SRobert Mustacchi 			    "interrupt handler: 0x%x", ret);
1040*c1733db1SRobert Mustacchi 		}
1041*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_INTR_HDL;
1042*c1733db1SRobert Mustacchi 	}
1043*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_INTR_ALLOC) != 0) {
1044*c1733db1SRobert Mustacchi 		int ret = ddi_intr_free(ismt->ismt_intr_hdl);
1045*c1733db1SRobert Mustacchi 		if (ret != DDI_SUCCESS) {
1046*c1733db1SRobert Mustacchi 			dev_err(ismt->ismt_dip, CE_WARN, "failed to free "
1047*c1733db1SRobert Mustacchi 			    "device interrupt: 0x%x", ret);
1048*c1733db1SRobert Mustacchi 		}
1049*c1733db1SRobert Mustacchi 
1050*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_INTR_ALLOC;
1051*c1733db1SRobert Mustacchi 	}
1052*c1733db1SRobert Mustacchi 
1053*c1733db1SRobert Mustacchi 	ismt_dma_free(&ismt->ismt_icl_dma);
1054*c1733db1SRobert Mustacchi 	ismt_dma_free(&ismt->ismt_data_dma);
1055*c1733db1SRobert Mustacchi 	ismt_dma_free(&ismt->ismt_ring_dma);
1056*c1733db1SRobert Mustacchi 
1057*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_REGS) != 0) {
1058*c1733db1SRobert Mustacchi 		ddi_regs_map_free(&ismt->ismt_regs);
1059*c1733db1SRobert Mustacchi 		ismt->ismt_regs = NULL;
1060*c1733db1SRobert Mustacchi 		ismt->ismt_regsize = 0;
1061*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_REGS;
1062*c1733db1SRobert Mustacchi 	}
1063*c1733db1SRobert Mustacchi 
1064*c1733db1SRobert Mustacchi 	if ((ismt->ismt_init & ISMT_INIT_PCI) != 0) {
1065*c1733db1SRobert Mustacchi 		pci_config_teardown(&ismt->ismt_cfg);
1066*c1733db1SRobert Mustacchi 		ismt->ismt_cfg = NULL;
1067*c1733db1SRobert Mustacchi 		ismt->ismt_init &= ~ISMT_INIT_PCI;
1068*c1733db1SRobert Mustacchi 	}
1069*c1733db1SRobert Mustacchi 
1070*c1733db1SRobert Mustacchi 	ASSERT0(ismt->ismt_init);
1071*c1733db1SRobert Mustacchi 	ddi_set_driver_private(ismt->ismt_dip, NULL);
1072*c1733db1SRobert Mustacchi 	kmem_free(ismt, sizeof (ismt_t));
1073*c1733db1SRobert Mustacchi }
1074*c1733db1SRobert Mustacchi 
1075*c1733db1SRobert Mustacchi int
ismt_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1076*c1733db1SRobert Mustacchi ismt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1077*c1733db1SRobert Mustacchi {
1078*c1733db1SRobert Mustacchi 	ismt_t *ismt;
1079*c1733db1SRobert Mustacchi 
1080*c1733db1SRobert Mustacchi 	switch (cmd) {
1081*c1733db1SRobert Mustacchi 	case DDI_ATTACH:
1082*c1733db1SRobert Mustacchi 		break;
1083*c1733db1SRobert Mustacchi 	case DDI_RESUME:
1084*c1733db1SRobert Mustacchi 	default:
1085*c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1086*c1733db1SRobert Mustacchi 	}
1087*c1733db1SRobert Mustacchi 
1088*c1733db1SRobert Mustacchi 	ismt = kmem_zalloc(sizeof (ismt_t), KM_SLEEP);
1089*c1733db1SRobert Mustacchi 	ismt->ismt_dip = dip;
1090*c1733db1SRobert Mustacchi 	ddi_set_driver_private(dip, ismt);
1091*c1733db1SRobert Mustacchi 
1092*c1733db1SRobert Mustacchi 	if (pci_config_setup(dip, &ismt->ismt_cfg) != DDI_SUCCESS) {
1093*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to set up config space");
1094*c1733db1SRobert Mustacchi 		goto cleanup;
1095*c1733db1SRobert Mustacchi 	}
1096*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_PCI;
1097*c1733db1SRobert Mustacchi 
1098*c1733db1SRobert Mustacchi 	if (!ismt_setup_regs(ismt))
1099*c1733db1SRobert Mustacchi 		goto cleanup;
1100*c1733db1SRobert Mustacchi 
1101*c1733db1SRobert Mustacchi 	if (!ismt_dma_alloc(ismt, &ismt->ismt_ring_dma, ISMT_RING_DMA_SIZE)) {
1102*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to allocate ring DMA memory");
1103*c1733db1SRobert Mustacchi 		goto cleanup;
1104*c1733db1SRobert Mustacchi 	}
1105*c1733db1SRobert Mustacchi 
1106*c1733db1SRobert Mustacchi 	if (!ismt_dma_alloc(ismt, &ismt->ismt_data_dma, ISMT_DATA_BUF_SIZE)) {
1107*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to allocate data buffer DMA "
1108*c1733db1SRobert Mustacchi 		    "memory");
1109*c1733db1SRobert Mustacchi 		goto cleanup;
1110*c1733db1SRobert Mustacchi 	}
1111*c1733db1SRobert Mustacchi 
1112*c1733db1SRobert Mustacchi 	if (!ismt_dma_alloc(ismt, &ismt->ismt_icl_dma, ISMT_ICL_DMA_SIZE)) {
1113*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to allocate interrupt cause DMA "
1114*c1733db1SRobert Mustacchi 		    "memory");
1115*c1733db1SRobert Mustacchi 		goto cleanup;
1116*c1733db1SRobert Mustacchi 	}
1117*c1733db1SRobert Mustacchi 
1118*c1733db1SRobert Mustacchi 	if (!ismt_alloc_intr(ismt))
1119*c1733db1SRobert Mustacchi 		goto cleanup;
1120*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_INTR_ALLOC;
1121*c1733db1SRobert Mustacchi 
1122*c1733db1SRobert Mustacchi 	if (!ismt_setup_intr(ismt))
1123*c1733db1SRobert Mustacchi 		goto cleanup;
1124*c1733db1SRobert Mustacchi 
1125*c1733db1SRobert Mustacchi 	mutex_init(&ismt->ismt_mutex, NULL, MUTEX_DRIVER,
1126*c1733db1SRobert Mustacchi 	    DDI_INTR_PRI(ismt->ismt_intr_pri));
1127*c1733db1SRobert Mustacchi 	cv_init(&ismt->ismt_cv, NULL, CV_DRIVER, NULL);
1128*c1733db1SRobert Mustacchi 	ismt->ismt_init |= ISMT_INIT_SYNC;
1129*c1733db1SRobert Mustacchi 
1130*c1733db1SRobert Mustacchi 	ismt_ctrl_init(ismt);
1131*c1733db1SRobert Mustacchi 
1132*c1733db1SRobert Mustacchi 	if (!ismt_enable_intr(ismt))
1133*c1733db1SRobert Mustacchi 		goto cleanup;
1134*c1733db1SRobert Mustacchi 
1135*c1733db1SRobert Mustacchi 	if (!ismt_register(ismt))
1136*c1733db1SRobert Mustacchi 		goto cleanup;
1137*c1733db1SRobert Mustacchi 
1138*c1733db1SRobert Mustacchi 	return (DDI_SUCCESS);
1139*c1733db1SRobert Mustacchi 
1140*c1733db1SRobert Mustacchi cleanup:
1141*c1733db1SRobert Mustacchi 	ismt_cleanup(ismt);
1142*c1733db1SRobert Mustacchi 	return (DDI_FAILURE);
1143*c1733db1SRobert Mustacchi }
1144*c1733db1SRobert Mustacchi 
1145*c1733db1SRobert Mustacchi int
ismt_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1146*c1733db1SRobert Mustacchi ismt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1147*c1733db1SRobert Mustacchi {
1148*c1733db1SRobert Mustacchi 	ismt_t *ismt;
1149*c1733db1SRobert Mustacchi 
1150*c1733db1SRobert Mustacchi 	switch (cmd) {
1151*c1733db1SRobert Mustacchi 	case DDI_DETACH:
1152*c1733db1SRobert Mustacchi 		break;
1153*c1733db1SRobert Mustacchi 	case DDI_SUSPEND:
1154*c1733db1SRobert Mustacchi 	default:
1155*c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1156*c1733db1SRobert Mustacchi 	}
1157*c1733db1SRobert Mustacchi 
1158*c1733db1SRobert Mustacchi 	ismt = ddi_get_driver_private(dip);
1159*c1733db1SRobert Mustacchi 	if (ismt == NULL) {
1160*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "asked to detach, but missing private "
1161*c1733db1SRobert Mustacchi 		    "data");
1162*c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1163*c1733db1SRobert Mustacchi 	}
1164*c1733db1SRobert Mustacchi 
1165*c1733db1SRobert Mustacchi 	VERIFY3P(ismt->ismt_dip, ==, dip);
1166*c1733db1SRobert Mustacchi 	i2c_ctrl_reg_error_t ret = i2c_ctrl_unregister(ismt->ismt_hdl);
1167*c1733db1SRobert Mustacchi 	if (ret != 0) {
1168*c1733db1SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to unregister from i2c "
1169*c1733db1SRobert Mustacchi 		    "framework 0x%x", ret);
1170*c1733db1SRobert Mustacchi 		return (DDI_FAILURE);
1171*c1733db1SRobert Mustacchi 	}
1172*c1733db1SRobert Mustacchi 	ismt->ismt_init &= ~ISMT_INIT_I2C;
1173*c1733db1SRobert Mustacchi 	ismt_cleanup(ismt);
1174*c1733db1SRobert Mustacchi 
1175*c1733db1SRobert Mustacchi 	return (DDI_SUCCESS);
1176*c1733db1SRobert Mustacchi }
1177*c1733db1SRobert Mustacchi 
1178*c1733db1SRobert Mustacchi static struct dev_ops ismt_dev_ops = {
1179*c1733db1SRobert Mustacchi 	.devo_rev = DEVO_REV,
1180*c1733db1SRobert Mustacchi 	.devo_refcnt = 0,
1181*c1733db1SRobert Mustacchi 	.devo_identify = nulldev,
1182*c1733db1SRobert Mustacchi 	.devo_probe = nulldev,
1183*c1733db1SRobert Mustacchi 	.devo_attach = ismt_attach,
1184*c1733db1SRobert Mustacchi 	.devo_detach = ismt_detach,
1185*c1733db1SRobert Mustacchi 	.devo_reset = nodev,
1186*c1733db1SRobert Mustacchi 	.devo_quiesce = ddi_quiesce_not_supported,
1187*c1733db1SRobert Mustacchi };
1188*c1733db1SRobert Mustacchi 
1189*c1733db1SRobert Mustacchi static struct modldrv ismt_modldrv = {
1190*c1733db1SRobert Mustacchi 	.drv_modops = &mod_driverops,
1191*c1733db1SRobert Mustacchi 	.drv_linkinfo = "Intel SMBus Message Target",
1192*c1733db1SRobert Mustacchi 	.drv_dev_ops = &ismt_dev_ops
1193*c1733db1SRobert Mustacchi };
1194*c1733db1SRobert Mustacchi 
1195*c1733db1SRobert Mustacchi static struct modlinkage ismt_modlinkage = {
1196*c1733db1SRobert Mustacchi 	.ml_rev = MODREV_1,
1197*c1733db1SRobert Mustacchi 	.ml_linkage = { &ismt_modldrv, NULL }
1198*c1733db1SRobert Mustacchi };
1199*c1733db1SRobert Mustacchi 
1200*c1733db1SRobert Mustacchi int
_init(void)1201*c1733db1SRobert Mustacchi _init(void)
1202*c1733db1SRobert Mustacchi {
1203*c1733db1SRobert Mustacchi 	int ret;
1204*c1733db1SRobert Mustacchi 
1205*c1733db1SRobert Mustacchi 	i2c_ctrl_mod_init(&ismt_dev_ops);
1206*c1733db1SRobert Mustacchi 	if ((ret = mod_install(&ismt_modlinkage)) != 0) {
1207*c1733db1SRobert Mustacchi 		i2c_ctrl_mod_fini(&ismt_dev_ops);
1208*c1733db1SRobert Mustacchi 	}
1209*c1733db1SRobert Mustacchi 
1210*c1733db1SRobert Mustacchi 	return (ret);
1211*c1733db1SRobert Mustacchi }
1212*c1733db1SRobert Mustacchi 
1213*c1733db1SRobert Mustacchi int
_info(struct modinfo * modinfop)1214*c1733db1SRobert Mustacchi _info(struct modinfo *modinfop)
1215*c1733db1SRobert Mustacchi {
1216*c1733db1SRobert Mustacchi 	return (mod_info(&ismt_modlinkage, modinfop));
1217*c1733db1SRobert Mustacchi }
1218*c1733db1SRobert Mustacchi 
1219*c1733db1SRobert Mustacchi int
_fini(void)1220*c1733db1SRobert Mustacchi _fini(void)
1221*c1733db1SRobert Mustacchi {
1222*c1733db1SRobert Mustacchi 	int ret;
1223*c1733db1SRobert Mustacchi 
1224*c1733db1SRobert Mustacchi 	if ((ret = mod_remove(&ismt_modlinkage)) == 0) {
1225*c1733db1SRobert Mustacchi 		i2c_ctrl_mod_fini(&ismt_dev_ops);
1226*c1733db1SRobert Mustacchi 	}
1227*c1733db1SRobert Mustacchi 
1228*c1733db1SRobert Mustacchi 	return (ret);
1229*c1733db1SRobert Mustacchi }
1230