xref: /openbsd/sys/dev/pci/amdpm.c (revision 0f9891f1)
1 /*	$OpenBSD: amdpm.c,v 1.40 2024/05/24 06:02:53 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*-
20  * Copyright (c) 2002 The NetBSD Foundation, Inc.
21  * All rights reserved.
22  *
23  * This code is derived from software contributed to The NetBSD Foundation
24  * by Enami Tsugutomo.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  * 2. Redistributions in binary form must reproduce the above copyright
32  *    notice, this list of conditions and the following disclaimer in the
33  *    documentation and/or other materials provided with the distribution.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
36  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
37  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
39  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45  * POSSIBILITY OF SUCH DAMAGE.
46  */
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/rwlock.h>
52 #include <sys/timeout.h>
53 #include <sys/timetc.h>
54 
55 #include <machine/bus.h>
56 
57 #include <dev/pci/pcivar.h>
58 #include <dev/pci/pcireg.h>
59 #include <dev/pci/pcidevs.h>
60 
61 #include <dev/i2c/i2cvar.h>
62 
63 #ifdef AMDPM_DEBUG
64 #define DPRINTF(x...) printf(x)
65 #else
66 #define DPRINTF(x...)
67 #endif
68 
69 #define AMDPM_SMBUS_DELAY	100
70 #define AMDPM_SMBUS_TIMEOUT	1
71 
72 u_int amdpm_get_timecount(struct timecounter *tc);
73 
74 #ifndef AMDPM_FREQUENCY
75 #define AMDPM_FREQUENCY 3579545
76 #endif
77 
78 static struct timecounter amdpm_timecounter = {
79 	.tc_get_timecount = amdpm_get_timecount,
80 	.tc_counter_mask = 0xffffff,
81 	.tc_frequency = AMDPM_FREQUENCY,
82 	.tc_name = "AMDPM",
83 	.tc_quality = 1000,
84 	.tc_priv = NULL,
85 	.tc_user = 0,
86 };
87 
88 #define	AMDPM_CONFREG	0x40
89 
90 /* 0x40: General Configuration 1 Register */
91 #define	AMDPM_RNGEN	0x00000080	/* random number generator enable */
92 #define	AMDPM_STOPTMR	0x00000040	/* stop free-running timer */
93 
94 /* 0x41: General Configuration 2 Register */
95 #define	AMDPM_PMIOEN	0x00008000	/* system management IO space enable */
96 #define	AMDPM_TMRRST	0x00004000	/* reset free-running timer */
97 #define	AMDPM_TMR32	0x00000800	/* extended (32 bit) timer enable */
98 
99 /* 0x42: SCI Interrupt Configuration Register */
100 /* 0x43: Previous Power State Register */
101 
102 #define	AMDPM_PMPTR	0x58		/* PMxx System Management IO space
103 					   Pointer */
104 #define NFPM_PMPTR	0x14		/* nForce System Management IO space
105 					   POinter */
106 #define	AMDPM_PMBASE(x)	((x) & 0xff00)	/* PMxx base address */
107 #define	AMDPM_PMSIZE	256		/* PMxx space size */
108 
109 /* Registers in PMxx space */
110 #define	AMDPM_TMR	0x08		/* 24/32 bit timer register */
111 
112 #define	AMDPM_RNGDATA	0xf0		/* 32 bit random data register */
113 #define	AMDPM_RNGSTAT	0xf4		/* RNG status register */
114 #define	AMDPM_RNGDONE	0x00000001	/* Random number generation complete */
115 
116 #define AMDPM_SMB_REGS  0xe0		/* offset of SMB register space */
117 #define AMDPM_SMB_SIZE  0xf		/* size of SMB register space */
118 #define AMDPM_SMBSTAT	0x0		/* SMBus status */
119 #define AMDPM_SMBSTAT_ABRT	(1 << 0)	/* transfer abort */
120 #define AMDPM_SMBSTAT_COL	(1 << 1)	/* collision */
121 #define AMDPM_SMBSTAT_PRERR	(1 << 2)	/* protocol error */
122 #define AMDPM_SMBSTAT_HBSY	(1 << 3)	/* host controller busy */
123 #define AMDPM_SMBSTAT_CYC	(1 << 4)	/* cycle complete */
124 #define AMDPM_SMBSTAT_TO	(1 << 5)	/* timeout */
125 #define AMDPM_SMBSTAT_SNP	(1 << 8)	/* snoop address match */
126 #define AMDPM_SMBSTAT_SLV	(1 << 9)	/* slave address match */
127 #define AMDPM_SMBSTAT_SMBA	(1 << 10)	/* SMBALERT# asserted */
128 #define AMDPM_SMBSTAT_BSY	(1 << 11)	/* bus busy */
129 #define AMDPM_SMBSTAT_BITS	"\020\001ABRT\002COL\003PRERR\004HBSY\005CYC\006TO\011SNP\012SLV\013SMBA\014BSY"
130 #define AMDPM_SMBCTL	0x2		/* SMBus control */
131 #define AMDPM_SMBCTL_CMD_QUICK	0		/* QUICK command */
132 #define AMDPM_SMBCTL_CMD_BYTE	1		/* BYTE command */
133 #define AMDPM_SMBCTL_CMD_BDATA	2		/* BYTE DATA command */
134 #define AMDPM_SMBCTL_CMD_WDATA	3		/* WORD DATA command */
135 #define AMDPM_SMBCTL_CMD_PCALL	4		/* PROCESS CALL command */
136 #define AMDPM_SMBCTL_CMD_BLOCK	5		/* BLOCK command */
137 #define AMDPM_SMBCTL_START	(1 << 3)	/* start transfer */
138 #define AMDPM_SMBCTL_CYCEN	(1 << 4)	/* intr on cycle complete */
139 #define AMDPM_SMBCTL_ABORT	(1 << 5)	/* abort transfer */
140 #define AMDPM_SMBCTL_SNPEN	(1 << 8)	/* intr on snoop addr match */
141 #define AMDPM_SMBCTL_SLVEN	(1 << 9)	/* intr on slave addr match */
142 #define AMDPM_SMBCTL_SMBAEN	(1 << 10)	/* intr on SMBALERT# */
143 #define AMDPM_SMBADDR	0x4		/* SMBus address */
144 #define AMDPM_SMBADDR_READ	(1 << 0)	/* read direction */
145 #define AMDPM_SMBADDR_ADDR(x)	(((x) & 0x7f) << 1) /* 7-bit address */
146 #define AMDPM_SMBDATA	0x6		/* SMBus data */
147 #define AMDPM_SMBCMD	0x8		/* SMBus command */
148 
149 
150 struct amdpm_softc {
151 	struct device sc_dev;
152 
153 	pci_chipset_tag_t sc_pc;
154 	pcitag_t sc_tag;
155 
156 	bus_space_tag_t sc_iot;
157 	bus_space_handle_t sc_ioh;		/* PMxx space */
158 	bus_space_handle_t sc_i2c_ioh;		/* I2C space */
159 	int sc_poll;
160 
161 	struct timeout sc_rnd_ch;
162 
163 	struct i2c_controller sc_i2c_tag;
164 	struct rwlock sc_i2c_lock;
165 	struct {
166 		i2c_op_t op;
167 		void *buf;
168 		size_t len;
169 		int flags;
170 		volatile int error;
171 	} sc_i2c_xfer;
172 };
173 
174 int	amdpm_match(struct device *, void *, void *);
175 void	amdpm_attach(struct device *, struct device *, void *);
176 int	amdpm_activate(struct device *, int);
177 void	amdpm_rnd_callout(void *);
178 
179 int	amdpm_i2c_acquire_bus(void *, int);
180 void	amdpm_i2c_release_bus(void *, int);
181 int	amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
182 	    void *, size_t, int);
183 
184 int	amdpm_intr(void *);
185 
186 const struct cfattach amdpm_ca = {
187 	sizeof(struct amdpm_softc), amdpm_match, amdpm_attach,
188 	NULL, amdpm_activate
189 };
190 
191 struct cfdriver amdpm_cd = {
192 	NULL, "amdpm", DV_DULL
193 };
194 
195 const struct pci_matchid amdpm_ids[] = {
196 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
197 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
198 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
199 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
200 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
201 };
202 
203 int
amdpm_match(struct device * parent,void * match,void * aux)204 amdpm_match(struct device *parent, void *match, void *aux)
205 {
206 	return (pci_matchbyid(aux, amdpm_ids,
207 	    sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
208 }
209 
210 void
amdpm_attach(struct device * parent,struct device * self,void * aux)211 amdpm_attach(struct device *parent, struct device *self, void *aux)
212 {
213 	struct amdpm_softc *sc = (struct amdpm_softc *) self;
214 	struct pci_attach_args *pa = aux;
215 	struct i2cbus_attach_args iba;
216 	pcireg_t cfg_reg, reg;
217 	int i;
218 
219 	sc->sc_pc = pa->pa_pc;
220 	sc->sc_tag = pa->pa_tag;
221 	sc->sc_iot = pa->pa_iot;
222 	sc->sc_poll = 1; /* XXX */
223 
224 
225 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD)  {
226 		cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
227 		if ((cfg_reg & AMDPM_PMIOEN) == 0) {
228 			printf(": PMxx space isn't enabled\n");
229 			return;
230 		}
231 
232 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
233 		if (AMDPM_PMBASE(reg) == 0 ||
234 		    bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE,
235 		    0, &sc->sc_ioh)) {
236 			printf("\n");
237 			return;
238 		}
239 		if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
240 		    AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
241 			printf(": failed to map I2C subregion\n");
242 			return;
243 		}
244 
245 		if ((cfg_reg & AMDPM_TMRRST) == 0 &&
246 		    (cfg_reg & AMDPM_STOPTMR) == 0 &&
247 		    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
248 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC)) {
249 			printf(": %d-bit timer at %lluHz",
250 			    (cfg_reg & AMDPM_TMR32) ? 32 : 24,
251 			    amdpm_timecounter.tc_frequency);
252 
253 			amdpm_timecounter.tc_priv = sc;
254 			if (cfg_reg & AMDPM_TMR32)
255 				amdpm_timecounter.tc_counter_mask = 0xffffffffu;
256 			tc_init(&amdpm_timecounter);
257 		}
258 		if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
259 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
260 			if ((cfg_reg & AMDPM_RNGEN) ==0) {
261 				pci_conf_write(pa->pa_pc, pa->pa_tag,
262 				    AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
263 				cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
264 				    AMDPM_CONFREG);
265 			}
266 			if (cfg_reg & AMDPM_RNGEN) {
267 			/* Check to see if we can read data from the RNG. */
268 				(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
269 				    AMDPM_RNGDATA);
270 				for (i = 1000; i--; ) {
271 					if (bus_space_read_1(sc->sc_iot,
272 					    sc->sc_ioh, AMDPM_RNGSTAT) &
273 					    AMDPM_RNGDONE)
274 						break;
275 					DELAY(10);
276 				}
277 				if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
278 				    AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
279 					printf(": rng active");
280 					timeout_set(&sc->sc_rnd_ch,
281 					    amdpm_rnd_callout, sc);
282 					amdpm_rnd_callout(sc);
283 				}
284 			}
285 		}
286 	} else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
287 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
288 		if (AMDPM_PMBASE(reg) == 0 ||
289 		    bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
290 		    &sc->sc_i2c_ioh)) {
291 			printf(": failed to map I2C subregion\n");
292 			return;
293 		}
294 	}
295 	printf("\n");
296 
297 	/* Attach I2C bus */
298 	rw_init(&sc->sc_i2c_lock, "iiclk");
299 	sc->sc_i2c_tag.ic_cookie = sc;
300 	sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
301 	sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
302 	sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
303 
304 	bzero(&iba, sizeof(iba));
305 	iba.iba_name = "iic";
306 	iba.iba_tag = &sc->sc_i2c_tag;
307 	config_found(self, &iba, iicbus_print);
308 }
309 
310 int
amdpm_activate(struct device * self,int act)311 amdpm_activate(struct device *self, int act)
312 {
313 	struct amdpm_softc *sc = (struct amdpm_softc *)self;
314 	int rv = 0;
315 
316 	switch (act) {
317 	case DVACT_RESUME:
318 		if (timeout_initialized(&sc->sc_rnd_ch)) {
319 			pcireg_t cfg_reg;
320 
321 			/* Restart the AMD PBC768_PMC/8111_PMC RNG */
322 			cfg_reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
323 			    AMDPM_CONFREG);
324 			pci_conf_write(sc->sc_pc, sc->sc_tag,
325 			    AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
326 
327 		}
328 		rv = config_activate_children(self, act);
329 		break;
330 	default:
331 		rv = config_activate_children(self, act);
332 		break;
333 	}
334 	return (rv);
335 }
336 
337 void
amdpm_rnd_callout(void * v)338 amdpm_rnd_callout(void *v)
339 {
340 	struct amdpm_softc *sc = v;
341 	u_int32_t reg;
342 
343 	if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
344 	    AMDPM_RNGDONE) != 0) {
345 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
346 		enqueue_randomness(reg);
347 	}
348 	timeout_add(&sc->sc_rnd_ch, 1);
349 }
350 
351 u_int
amdpm_get_timecount(struct timecounter * tc)352 amdpm_get_timecount(struct timecounter *tc)
353 {
354 	struct amdpm_softc *sc = tc->tc_priv;
355 	u_int u2;
356 #if 0
357 	u_int u1, u3;
358 #endif
359 
360 	u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
361 #if 0
362 	u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
363 	do {
364 		u1 = u2;
365 		u2 = u3;
366 		u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
367 	} while (u1 > u2 || u2 > u3);
368 #endif
369 	return (u2);
370 }
371 
372 int
amdpm_i2c_acquire_bus(void * cookie,int flags)373 amdpm_i2c_acquire_bus(void *cookie, int flags)
374 {
375 	struct amdpm_softc *sc = cookie;
376 
377 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
378 		return (0);
379 
380 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
381 }
382 
383 void
amdpm_i2c_release_bus(void * cookie,int flags)384 amdpm_i2c_release_bus(void *cookie, int flags)
385 {
386 	struct amdpm_softc *sc = cookie;
387 
388 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
389 		return;
390 
391 	rw_exit(&sc->sc_i2c_lock);
392 }
393 
394 int
amdpm_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)395 amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
396     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
397 {
398 	struct amdpm_softc *sc = cookie;
399 	u_int8_t *b;
400 	u_int16_t st, ctl, data;
401 	int retries;
402 
403 	DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
404 	    "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
405 	    len, flags);
406 
407 	/* Wait for bus to be idle */
408 	for (retries = 100; retries > 0; retries--) {
409 		st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
410 		if (!(st & AMDPM_SMBSTAT_BSY))
411 			break;
412 		DELAY(AMDPM_SMBUS_DELAY);
413 	}
414 	DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
415 	    AMDPM_SMBSTAT_BITS);
416 	if (st & AMDPM_SMBSTAT_BSY)
417 		return (1);
418 
419 	if (cold || sc->sc_poll)
420 		flags |= I2C_F_POLL;
421 
422 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
423 		return (1);
424 
425 	/* Setup transfer */
426 	sc->sc_i2c_xfer.op = op;
427 	sc->sc_i2c_xfer.buf = buf;
428 	sc->sc_i2c_xfer.len = len;
429 	sc->sc_i2c_xfer.flags = flags;
430 	sc->sc_i2c_xfer.error = 0;
431 
432 	/* Set slave address and transfer direction */
433 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
434 	    AMDPM_SMBADDR_ADDR(addr) |
435 	    (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
436 
437 	b = (void *)cmdbuf;
438 	if (cmdlen > 0)
439 		/* Set command byte */
440 		bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
441 
442 	if (I2C_OP_WRITE_P(op)) {
443 		/* Write data */
444 		data = 0;
445 		b = buf;
446 		if (len > 0)
447 			data = b[0];
448 		if (len > 1)
449 			data |= ((u_int16_t)b[1] << 8);
450 		if (len > 0)
451 			bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
452 			    AMDPM_SMBDATA, data);
453 	}
454 
455 	/* Set SMBus command */
456 	if (len == 0)
457 		ctl = AMDPM_SMBCTL_CMD_BYTE;
458 	else if (len == 1)
459 		ctl = AMDPM_SMBCTL_CMD_BDATA;
460 	else if (len == 2)
461 		ctl = AMDPM_SMBCTL_CMD_WDATA;
462 	else
463 		panic("%s: unexpected len %zd", __func__, len);
464 
465 	if ((flags & I2C_F_POLL) == 0)
466 		ctl |= AMDPM_SMBCTL_CYCEN;
467 
468 	/* Start transaction */
469 	ctl |= AMDPM_SMBCTL_START;
470 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
471 
472 	if (flags & I2C_F_POLL) {
473 		/* Poll for completion */
474 		DELAY(AMDPM_SMBUS_DELAY);
475 		for (retries = 1000; retries > 0; retries--) {
476 			st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
477 			    AMDPM_SMBSTAT);
478 			if ((st & AMDPM_SMBSTAT_HBSY) == 0)
479 				break;
480 			DELAY(AMDPM_SMBUS_DELAY);
481 		}
482 		if (st & AMDPM_SMBSTAT_HBSY)
483 			goto timeout;
484 		amdpm_intr(sc);
485 	} else {
486 		/* Wait for interrupt */
487 		if (tsleep_nsec(sc, PRIBIO, "amdpm",
488 		    SEC_TO_NSEC(AMDPM_SMBUS_TIMEOUT)))
489 			goto timeout;
490 	}
491 
492 	if (sc->sc_i2c_xfer.error)
493 		return (1);
494 
495 	return (0);
496 
497 timeout:
498 	/*
499 	 * Transfer timeout. Kill the transaction and clear status bits.
500 	 */
501 	printf("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
502 	    "flags 0x%02x: timeout, status 0x%b\n",
503 	    sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
504 	    st, AMDPM_SMBSTAT_BITS);
505 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
506 	    AMDPM_SMBCTL_ABORT);
507 	DELAY(AMDPM_SMBUS_DELAY);
508 	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
509 	if ((st & AMDPM_SMBSTAT_ABRT) == 0)
510 		printf("%s: abort failed, status 0x%b\n",
511 		    sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
512 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
513 	return (1);
514 }
515 
516 int
amdpm_intr(void * arg)517 amdpm_intr(void *arg)
518 {
519 	struct amdpm_softc *sc = arg;
520 	u_int16_t st, data;
521 	u_int8_t *b;
522 	size_t len;
523 
524 	/* Read status */
525 	st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
526 	if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
527 	    AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
528 	    AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
529 	    AMDPM_SMBSTAT_SMBA)) == 0)
530 		/* Interrupt was not for us */
531 		return (0);
532 
533 	DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
534 	    AMDPM_SMBSTAT_BITS);
535 
536 	/* Clear status bits */
537 	bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
538 
539 	/* Check for errors */
540 	if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
541 	    AMDPM_SMBSTAT_TO)) {
542 		sc->sc_i2c_xfer.error = 1;
543 		goto done;
544 	}
545 
546 	if (st & AMDPM_SMBSTAT_CYC) {
547 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
548 			goto done;
549 
550 		/* Read data */
551 		b = sc->sc_i2c_xfer.buf;
552 		len = sc->sc_i2c_xfer.len;
553 		if (len > 0) {
554 			data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
555 			    AMDPM_SMBDATA);
556 			b[0] = data & 0xff;
557 		}
558 		if (len > 1)
559 			b[1] = (data >> 8) & 0xff;
560 	}
561 
562 done:
563 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
564 		wakeup(sc);
565 	return (1);
566 }
567