xref: /freebsd/sys/dev/ismt/ismt.c (revision b196276c20b577b364372f1aa1a646b9ce34bf5c)
10572ccaaSJim Harris /*-
20572ccaaSJim Harris  * Copyright (C) 2014 Intel Corporation
30572ccaaSJim Harris  * All rights reserved.
40572ccaaSJim Harris  *
50572ccaaSJim Harris  * Redistribution and use in source and binary forms, with or without
60572ccaaSJim Harris  * modification, are permitted provided that the following conditions
70572ccaaSJim Harris  * are met:
80572ccaaSJim Harris  * 1. Redistributions of source code must retain the above copyright
90572ccaaSJim Harris  *    notice, this list of conditions and the following disclaimer.
100572ccaaSJim Harris  * 2. Redistributions in binary form must reproduce the above copyright
110572ccaaSJim Harris  *    notice, this list of conditions and the following disclaimer in the
120572ccaaSJim Harris  *    documentation and/or other materials provided with the distribution.
130572ccaaSJim Harris  * 3. Neither the name of Intel Corporation nor the names of its
140572ccaaSJim Harris  *    contributors may be used to endorse or promote products derived from
150572ccaaSJim Harris  *    this software without specific prior written permission.
160572ccaaSJim Harris  *
170572ccaaSJim Harris  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180572ccaaSJim Harris  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190572ccaaSJim Harris  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200572ccaaSJim Harris  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
210572ccaaSJim Harris  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220572ccaaSJim Harris  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230572ccaaSJim Harris  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240572ccaaSJim Harris  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250572ccaaSJim Harris  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260572ccaaSJim Harris  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270572ccaaSJim Harris  * SUCH DAMAGE.
280572ccaaSJim Harris  */
290572ccaaSJim Harris 
300572ccaaSJim Harris #include <sys/param.h>
310572ccaaSJim Harris #include <sys/systm.h>
320572ccaaSJim Harris #include <sys/bus.h>
330572ccaaSJim Harris #include <sys/errno.h>
340572ccaaSJim Harris #include <sys/kernel.h>
350572ccaaSJim Harris #include <sys/lock.h>
360572ccaaSJim Harris #include <sys/module.h>
370572ccaaSJim Harris #include <sys/priority.h>
380572ccaaSJim Harris #include <sys/proc.h>
390572ccaaSJim Harris #include <sys/syslog.h>
400572ccaaSJim Harris 
410572ccaaSJim Harris #include <machine/bus.h>
420572ccaaSJim Harris #include <sys/rman.h>
430572ccaaSJim Harris #include <machine/resource.h>
440572ccaaSJim Harris 
450572ccaaSJim Harris #include <dev/pci/pcireg.h>
460572ccaaSJim Harris #include <dev/pci/pcivar.h>
470572ccaaSJim Harris #include <dev/smbus/smbconf.h>
480572ccaaSJim Harris 
490572ccaaSJim Harris #include "smbus_if.h"
500572ccaaSJim Harris 
510572ccaaSJim Harris #define ISMT_DESC_ENTRIES	32
520572ccaaSJim Harris 
530572ccaaSJim Harris /* Hardware Descriptor Constants - Control Field */
540572ccaaSJim Harris #define ISMT_DESC_CWRL	0x01	/* Command/Write Length */
550572ccaaSJim Harris #define ISMT_DESC_BLK	0X04	/* Perform Block Transaction */
560572ccaaSJim Harris #define ISMT_DESC_FAIR	0x08	/* Set fairness flag upon successful arbit. */
570572ccaaSJim Harris #define ISMT_DESC_PEC	0x10	/* Packet Error Code */
580572ccaaSJim Harris #define ISMT_DESC_I2C	0x20	/* I2C Enable */
590572ccaaSJim Harris #define ISMT_DESC_INT	0x40	/* Interrupt */
600572ccaaSJim Harris #define ISMT_DESC_SOE	0x80	/* Stop On Error */
610572ccaaSJim Harris 
620572ccaaSJim Harris /* Hardware Descriptor Constants - Status Field */
630572ccaaSJim Harris #define ISMT_DESC_SCS	0x01	/* Success */
640572ccaaSJim Harris #define ISMT_DESC_DLTO	0x04	/* Data Low Time Out */
650572ccaaSJim Harris #define ISMT_DESC_NAK	0x08	/* NAK Received */
660572ccaaSJim Harris #define ISMT_DESC_CRC	0x10	/* CRC Error */
670572ccaaSJim Harris #define ISMT_DESC_CLTO	0x20	/* Clock Low Time Out */
680572ccaaSJim Harris #define ISMT_DESC_COL	0x40	/* Collisions */
690572ccaaSJim Harris #define ISMT_DESC_LPR	0x80	/* Large Packet Received */
700572ccaaSJim Harris 
710572ccaaSJim Harris /* Macros */
72d681bc9eSJustin Hibbits #define ISMT_DESC_ADDR_RW(addr, is_read) ((addr) | (is_read))
730572ccaaSJim Harris 
740572ccaaSJim Harris /* iSMT General Register address offsets (SMBBAR + <addr>) */
750572ccaaSJim Harris #define ISMT_GR_GCTRL		0x000	/* General Control */
760572ccaaSJim Harris #define ISMT_GR_SMTICL		0x008	/* SMT Interrupt Cause Location */
770572ccaaSJim Harris #define ISMT_GR_ERRINTMSK	0x010	/* Error Interrupt Mask */
780572ccaaSJim Harris #define ISMT_GR_ERRAERMSK	0x014	/* Error AER Mask */
790572ccaaSJim Harris #define ISMT_GR_ERRSTS		0x018	/* Error Status */
800572ccaaSJim Harris #define ISMT_GR_ERRINFO		0x01c	/* Error Information */
810572ccaaSJim Harris 
820572ccaaSJim Harris /* iSMT Master Registers */
830572ccaaSJim Harris #define ISMT_MSTR_MDBA		0x100	/* Master Descriptor Base Address */
840572ccaaSJim Harris #define ISMT_MSTR_MCTRL		0x108	/* Master Control */
850572ccaaSJim Harris #define ISMT_MSTR_MSTS		0x10c	/* Master Status */
860572ccaaSJim Harris #define ISMT_MSTR_MDS		0x110	/* Master Descriptor Size */
870572ccaaSJim Harris #define ISMT_MSTR_RPOLICY	0x114	/* Retry Policy */
880572ccaaSJim Harris 
890572ccaaSJim Harris /* iSMT Miscellaneous Registers */
900572ccaaSJim Harris #define ISMT_SPGT	0x300	/* SMBus PHY Global Timing */
910572ccaaSJim Harris 
920572ccaaSJim Harris /* General Control Register (GCTRL) bit definitions */
930572ccaaSJim Harris #define ISMT_GCTRL_TRST	0x04	/* Target Reset */
940572ccaaSJim Harris #define ISMT_GCTRL_KILL	0x08	/* Kill */
950572ccaaSJim Harris #define ISMT_GCTRL_SRST	0x40	/* Soft Reset */
960572ccaaSJim Harris 
970572ccaaSJim Harris /* Master Control Register (MCTRL) bit definitions */
980572ccaaSJim Harris #define ISMT_MCTRL_SS	0x01		/* Start/Stop */
990572ccaaSJim Harris #define ISMT_MCTRL_MEIE	0x10		/* Master Error Interrupt Enable */
1000572ccaaSJim Harris #define ISMT_MCTRL_FMHP	0x00ff0000	/* Firmware Master Head Ptr (FMHP) */
1010572ccaaSJim Harris 
1020572ccaaSJim Harris /* Master Status Register (MSTS) bit definitions */
1030572ccaaSJim Harris #define ISMT_MSTS_HMTP	0xff0000	/* HW Master Tail Pointer (HMTP) */
1040572ccaaSJim Harris #define ISMT_MSTS_MIS	0x20		/* Master Interrupt Status (MIS) */
1050572ccaaSJim Harris #define ISMT_MSTS_MEIS	0x10		/* Master Error Int Status (MEIS) */
1060572ccaaSJim Harris #define ISMT_MSTS_IP	0x01		/* In Progress */
1070572ccaaSJim Harris 
1080572ccaaSJim Harris /* Master Descriptor Size (MDS) bit definitions */
1090572ccaaSJim Harris #define ISMT_MDS_MASK	0xff	/* Master Descriptor Size mask (MDS) */
1100572ccaaSJim Harris 
1110572ccaaSJim Harris /* SMBus PHY Global Timing Register (SPGT) bit definitions */
1120572ccaaSJim Harris #define ISMT_SPGT_SPD_MASK	0xc0000000	/* SMBus Speed mask */
1130572ccaaSJim Harris #define ISMT_SPGT_SPD_80K	0x00		/* 80 kHz */
1140572ccaaSJim Harris #define ISMT_SPGT_SPD_100K	(0x1 << 30)	/* 100 kHz */
1150572ccaaSJim Harris #define ISMT_SPGT_SPD_400K	(0x2 << 30)	/* 400 kHz */
1160572ccaaSJim Harris #define ISMT_SPGT_SPD_1M	(0x3 << 30)	/* 1 MHz */
1170572ccaaSJim Harris 
1180572ccaaSJim Harris /* MSI Control Register (MSICTL) bit definitions */
1190572ccaaSJim Harris #define ISMT_MSICTL_MSIE	0x01	/* MSI Enable */
1200572ccaaSJim Harris 
1210572ccaaSJim Harris #define ISMT_MAX_BLOCK_SIZE	32 /* per SMBus spec */
1220572ccaaSJim Harris 
1230572ccaaSJim Harris //#define ISMT_DEBUG	device_printf
1240572ccaaSJim Harris #ifndef ISMT_DEBUG
1250572ccaaSJim Harris #define ISMT_DEBUG(...)
1260572ccaaSJim Harris #endif
1270572ccaaSJim Harris 
1280572ccaaSJim Harris /* iSMT Hardware Descriptor */
1290572ccaaSJim Harris struct ismt_desc {
1300572ccaaSJim Harris 	uint8_t tgtaddr_rw;	/* target address & r/w bit */
1310572ccaaSJim Harris 	uint8_t wr_len_cmd;	/* write length in bytes or a command */
1320572ccaaSJim Harris 	uint8_t rd_len;		/* read length */
1330572ccaaSJim Harris 	uint8_t control;	/* control bits */
1340572ccaaSJim Harris 	uint8_t status;		/* status bits */
1350572ccaaSJim Harris 	uint8_t retry;		/* collision retry and retry count */
1360572ccaaSJim Harris 	uint8_t rxbytes;	/* received bytes */
1370572ccaaSJim Harris 	uint8_t txbytes;	/* transmitted bytes */
1380572ccaaSJim Harris 	uint32_t dptr_low;	/* lower 32 bit of the data pointer */
1390572ccaaSJim Harris 	uint32_t dptr_high;	/* upper 32 bit of the data pointer */
1400572ccaaSJim Harris } __packed;
1410572ccaaSJim Harris 
1420572ccaaSJim Harris #define DESC_SIZE	(ISMT_DESC_ENTRIES * sizeof(struct ismt_desc))
1430572ccaaSJim Harris 
1440572ccaaSJim Harris #define DMA_BUFFER_SIZE	64
1450572ccaaSJim Harris 
1460572ccaaSJim Harris struct ismt_softc {
1470572ccaaSJim Harris 	device_t		pcidev;
1480572ccaaSJim Harris 	device_t		smbdev;
1490572ccaaSJim Harris 
1500572ccaaSJim Harris 	struct thread		*bus_reserved;
1510572ccaaSJim Harris 
1520572ccaaSJim Harris 	int			intr_rid;
1530572ccaaSJim Harris 	struct resource		*intr_res;
1540572ccaaSJim Harris 	void			*intr_handle;
1550572ccaaSJim Harris 
1560572ccaaSJim Harris 	bus_space_tag_t		mmio_tag;
1570572ccaaSJim Harris 	bus_space_handle_t	mmio_handle;
1580572ccaaSJim Harris 	int			mmio_rid;
1590572ccaaSJim Harris 	struct resource		*mmio_res;
1600572ccaaSJim Harris 
1610572ccaaSJim Harris 	uint8_t			head;
1620572ccaaSJim Harris 
1630572ccaaSJim Harris 	struct ismt_desc	*desc;
1640572ccaaSJim Harris 	bus_dma_tag_t		desc_dma_tag;
1650572ccaaSJim Harris 	bus_dmamap_t		desc_dma_map;
1660572ccaaSJim Harris 	uint64_t		desc_bus_addr;
1670572ccaaSJim Harris 
1680572ccaaSJim Harris 	uint8_t			*dma_buffer;
1690572ccaaSJim Harris 	bus_dma_tag_t		dma_buffer_dma_tag;
1700572ccaaSJim Harris 	bus_dmamap_t		dma_buffer_dma_map;
1710572ccaaSJim Harris 	uint64_t		dma_buffer_bus_addr;
1720572ccaaSJim Harris 
1730572ccaaSJim Harris 	uint8_t			using_msi;
1740572ccaaSJim Harris };
1750572ccaaSJim Harris 
1760572ccaaSJim Harris static void
ismt_intr(void * arg)1770572ccaaSJim Harris ismt_intr(void *arg)
1780572ccaaSJim Harris {
1790572ccaaSJim Harris 	struct ismt_softc *sc = arg;
1800572ccaaSJim Harris 	uint32_t val;
1810572ccaaSJim Harris 
1820572ccaaSJim Harris 	val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS);
1830572ccaaSJim Harris 	ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val);
1840572ccaaSJim Harris 
1850572ccaaSJim Harris 	val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS);
1860572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val);
1870572ccaaSJim Harris 
1880572ccaaSJim Harris 	wakeup(sc);
1890572ccaaSJim Harris }
1900572ccaaSJim Harris 
1910572ccaaSJim Harris static int
ismt_callback(device_t dev,int index,void * data)1920572ccaaSJim Harris ismt_callback(device_t dev, int index, void *data)
1930572ccaaSJim Harris {
1940572ccaaSJim Harris 	struct ismt_softc	*sc;
1950572ccaaSJim Harris 	int			acquired, err;
1960572ccaaSJim Harris 
1970572ccaaSJim Harris 	sc = device_get_softc(dev);
1980572ccaaSJim Harris 
1990572ccaaSJim Harris 	switch (index) {
2000572ccaaSJim Harris 	case SMB_REQUEST_BUS:
2010572ccaaSJim Harris 		acquired = atomic_cmpset_ptr(
2020572ccaaSJim Harris 		    (uintptr_t *)&sc->bus_reserved,
2030572ccaaSJim Harris 		    (uintptr_t)NULL, (uintptr_t)curthread);
2040572ccaaSJim Harris 		ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired);
2050572ccaaSJim Harris 		if (acquired)
2060572ccaaSJim Harris 			err = 0;
2070572ccaaSJim Harris 		else
2080572ccaaSJim Harris 			err = EWOULDBLOCK;
2090572ccaaSJim Harris 		break;
2100572ccaaSJim Harris 	case SMB_RELEASE_BUS:
2110572ccaaSJim Harris 		KASSERT(sc->bus_reserved == curthread,
2120572ccaaSJim Harris 		    ("SMB_RELEASE_BUS called by wrong thread\n"));
2130572ccaaSJim Harris 		ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n");
2140572ccaaSJim Harris 		atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved,
2150572ccaaSJim Harris 		    (uintptr_t)NULL);
2160572ccaaSJim Harris 		err = 0;
2170572ccaaSJim Harris 		break;
2180572ccaaSJim Harris 	default:
2190572ccaaSJim Harris 		err = SMB_EABORT;
2200572ccaaSJim Harris 		break;
2210572ccaaSJim Harris 	}
2220572ccaaSJim Harris 
2230572ccaaSJim Harris 	return (err);
2240572ccaaSJim Harris }
2250572ccaaSJim Harris 
2260572ccaaSJim Harris static struct ismt_desc *
ismt_alloc_desc(struct ismt_softc * sc)2270572ccaaSJim Harris ismt_alloc_desc(struct ismt_softc *sc)
2280572ccaaSJim Harris {
2290572ccaaSJim Harris 	struct ismt_desc *desc;
2300572ccaaSJim Harris 
2310572ccaaSJim Harris 	KASSERT(sc->bus_reserved == curthread,
2320572ccaaSJim Harris 	    ("curthread %p did not request bus (%p has reserved)\n",
2330572ccaaSJim Harris 	    curthread, sc->bus_reserved));
2340572ccaaSJim Harris 
2350572ccaaSJim Harris 	desc = &sc->desc[sc->head++];
2360572ccaaSJim Harris 	if (sc->head == ISMT_DESC_ENTRIES)
2370572ccaaSJim Harris 		sc->head = 0;
2380572ccaaSJim Harris 
2390572ccaaSJim Harris 	memset(desc, 0, sizeof(*desc));
2400572ccaaSJim Harris 
2410572ccaaSJim Harris 	return (desc);
2420572ccaaSJim Harris }
2430572ccaaSJim Harris 
2440572ccaaSJim Harris static int
ismt_submit(struct ismt_softc * sc,struct ismt_desc * desc,uint8_t slave,uint8_t is_read)2450572ccaaSJim Harris ismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave,
2460572ccaaSJim Harris     uint8_t is_read)
2470572ccaaSJim Harris {
2480572ccaaSJim Harris 	uint32_t err, fmhp, val;
2490572ccaaSJim Harris 
2500572ccaaSJim Harris 	desc->control |= ISMT_DESC_FAIR;
2510572ccaaSJim Harris 	if (sc->using_msi)
2520572ccaaSJim Harris 		desc->control |= ISMT_DESC_INT;
2530572ccaaSJim Harris 
2540572ccaaSJim Harris 	desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read);
2550572ccaaSJim Harris 	desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL);
2560572ccaaSJim Harris 	desc->dptr_high = (sc->dma_buffer_bus_addr >> 32);
2570572ccaaSJim Harris 
2580572ccaaSJim Harris 	wmb();
2590572ccaaSJim Harris 
2600572ccaaSJim Harris 	fmhp = sc->head << 16;
2610572ccaaSJim Harris 	val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
2620572ccaaSJim Harris 	val &= ~ISMT_MCTRL_FMHP;
2630572ccaaSJim Harris 	val |= fmhp;
2640572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
2650572ccaaSJim Harris 
2660572ccaaSJim Harris 	/* set the start bit */
2670572ccaaSJim Harris 	val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
2680572ccaaSJim Harris 	val |= ISMT_MCTRL_SS;
2690572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
2700572ccaaSJim Harris 
2710572ccaaSJim Harris 	err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz);
2720572ccaaSJim Harris 
2730572ccaaSJim Harris 	if (err != 0) {
2740572ccaaSJim Harris 		ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__);
2750572ccaaSJim Harris 		return (SMB_ETIMEOUT);
2760572ccaaSJim Harris 	}
2770572ccaaSJim Harris 
2780572ccaaSJim Harris 	ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status);
2790572ccaaSJim Harris 
2800572ccaaSJim Harris 	if (desc->status & ISMT_DESC_SCS)
2810572ccaaSJim Harris 		return (SMB_ENOERR);
2820572ccaaSJim Harris 
2830572ccaaSJim Harris 	if (desc->status & ISMT_DESC_NAK)
2840572ccaaSJim Harris 		return (SMB_ENOACK);
2850572ccaaSJim Harris 
2860572ccaaSJim Harris 	if (desc->status & ISMT_DESC_CRC)
2870572ccaaSJim Harris 		return (SMB_EBUSERR);
2880572ccaaSJim Harris 
2890572ccaaSJim Harris 	if (desc->status & ISMT_DESC_COL)
2900572ccaaSJim Harris 		return (SMB_ECOLLI);
2910572ccaaSJim Harris 
2920572ccaaSJim Harris 	if (desc->status & ISMT_DESC_LPR)
2930572ccaaSJim Harris 		return (SMB_EINVAL);
2940572ccaaSJim Harris 
2950572ccaaSJim Harris 	if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO))
2960572ccaaSJim Harris 		return (SMB_ETIMEOUT);
2970572ccaaSJim Harris 
2980572ccaaSJim Harris 	return (SMB_EBUSERR);
2990572ccaaSJim Harris }
3000572ccaaSJim Harris 
3010572ccaaSJim Harris 
3020572ccaaSJim Harris static int
ismt_quick(device_t dev,u_char slave,int how)3030572ccaaSJim Harris ismt_quick(device_t dev, u_char slave, int how)
3040572ccaaSJim Harris {
3050572ccaaSJim Harris 	struct ismt_desc	*desc;
3060572ccaaSJim Harris 	struct ismt_softc	*sc;
3070572ccaaSJim Harris 	int			is_read;
3080572ccaaSJim Harris 
3090572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
3100572ccaaSJim Harris 
3110572ccaaSJim Harris 	if (how != SMB_QREAD && how != SMB_QWRITE) {
3120572ccaaSJim Harris 		return (SMB_ENOTSUPP);
3130572ccaaSJim Harris 	}
3140572ccaaSJim Harris 
3150572ccaaSJim Harris 	sc = device_get_softc(dev);
3160572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
3170572ccaaSJim Harris 	is_read = (how == SMB_QREAD ? 1 : 0);
3180572ccaaSJim Harris 	return (ismt_submit(sc, desc, slave, is_read));
3190572ccaaSJim Harris }
3200572ccaaSJim Harris 
3210572ccaaSJim Harris static int
ismt_sendb(device_t dev,u_char slave,char byte)3220572ccaaSJim Harris ismt_sendb(device_t dev, u_char slave, char byte)
3230572ccaaSJim Harris {
3240572ccaaSJim Harris 	struct ismt_desc	*desc;
3250572ccaaSJim Harris 	struct ismt_softc	*sc;
3260572ccaaSJim Harris 
3270572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
3280572ccaaSJim Harris 
3290572ccaaSJim Harris 	sc = device_get_softc(dev);
3300572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
3310572ccaaSJim Harris 	desc->control = ISMT_DESC_CWRL;
3320572ccaaSJim Harris 	desc->wr_len_cmd = byte;
3330572ccaaSJim Harris 
3340572ccaaSJim Harris 	return (ismt_submit(sc, desc, slave, 0));
3350572ccaaSJim Harris }
3360572ccaaSJim Harris 
3370572ccaaSJim Harris static int
ismt_recvb(device_t dev,u_char slave,char * byte)3380572ccaaSJim Harris ismt_recvb(device_t dev, u_char slave, char *byte)
3390572ccaaSJim Harris {
3400572ccaaSJim Harris 	struct ismt_desc	*desc;
3410572ccaaSJim Harris 	struct ismt_softc	*sc;
3420572ccaaSJim Harris 	int			err;
3430572ccaaSJim Harris 
3440572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
3450572ccaaSJim Harris 
3460572ccaaSJim Harris 	sc = device_get_softc(dev);
3470572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
3480572ccaaSJim Harris 	desc->rd_len = 1;
3490572ccaaSJim Harris 
3500572ccaaSJim Harris 	err = ismt_submit(sc, desc, slave, 1);
3510572ccaaSJim Harris 
3520572ccaaSJim Harris 	if (err != SMB_ENOERR)
3530572ccaaSJim Harris 		return (err);
3540572ccaaSJim Harris 
3550572ccaaSJim Harris 	*byte = sc->dma_buffer[0];
3560572ccaaSJim Harris 
3570572ccaaSJim Harris 	return (err);
3580572ccaaSJim Harris }
3590572ccaaSJim Harris 
3600572ccaaSJim Harris static int
ismt_writeb(device_t dev,u_char slave,char cmd,char byte)3610572ccaaSJim Harris ismt_writeb(device_t dev, u_char slave, char cmd, char byte)
3620572ccaaSJim Harris {
3630572ccaaSJim Harris 	struct ismt_desc	*desc;
3640572ccaaSJim Harris 	struct ismt_softc	*sc;
3650572ccaaSJim Harris 
3660572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
3670572ccaaSJim Harris 
3680572ccaaSJim Harris 	sc = device_get_softc(dev);
3690572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
3700572ccaaSJim Harris 	desc->wr_len_cmd = 2;
3710572ccaaSJim Harris 	sc->dma_buffer[0] = cmd;
3720572ccaaSJim Harris 	sc->dma_buffer[1] = byte;
3730572ccaaSJim Harris 
3740572ccaaSJim Harris 	return (ismt_submit(sc, desc, slave, 0));
3750572ccaaSJim Harris }
3760572ccaaSJim Harris 
3770572ccaaSJim Harris static int
ismt_writew(device_t dev,u_char slave,char cmd,short word)3780572ccaaSJim Harris ismt_writew(device_t dev, u_char slave, char cmd, short word)
3790572ccaaSJim Harris {
3800572ccaaSJim Harris 	struct ismt_desc	*desc;
3810572ccaaSJim Harris 	struct ismt_softc	*sc;
3820572ccaaSJim Harris 
3830572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
3840572ccaaSJim Harris 
3850572ccaaSJim Harris 	sc = device_get_softc(dev);
3860572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
3870572ccaaSJim Harris 	desc->wr_len_cmd = 3;
3880572ccaaSJim Harris 	sc->dma_buffer[0] = cmd;
3890572ccaaSJim Harris 	sc->dma_buffer[1] = word & 0xFF;
3900572ccaaSJim Harris 	sc->dma_buffer[2] = word >> 8;
3910572ccaaSJim Harris 
3920572ccaaSJim Harris 	return (ismt_submit(sc, desc, slave, 0));
3930572ccaaSJim Harris }
3940572ccaaSJim Harris 
3950572ccaaSJim Harris static int
ismt_readb(device_t dev,u_char slave,char cmd,char * byte)3960572ccaaSJim Harris ismt_readb(device_t dev, u_char slave, char cmd, char *byte)
3970572ccaaSJim Harris {
3980572ccaaSJim Harris 	struct ismt_desc	*desc;
3990572ccaaSJim Harris 	struct ismt_softc	*sc;
4000572ccaaSJim Harris 	int			err;
4010572ccaaSJim Harris 
4020572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
4030572ccaaSJim Harris 
4040572ccaaSJim Harris 	sc = device_get_softc(dev);
4050572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
4060572ccaaSJim Harris 	desc->control = ISMT_DESC_CWRL;
4070572ccaaSJim Harris 	desc->wr_len_cmd = cmd;
4080572ccaaSJim Harris 	desc->rd_len = 1;
4090572ccaaSJim Harris 
4100572ccaaSJim Harris 	err = ismt_submit(sc, desc, slave, 1);
4110572ccaaSJim Harris 
4120572ccaaSJim Harris 	if (err != SMB_ENOERR)
4130572ccaaSJim Harris 		return (err);
4140572ccaaSJim Harris 
4150572ccaaSJim Harris 	*byte = sc->dma_buffer[0];
4160572ccaaSJim Harris 
4170572ccaaSJim Harris 	return (err);
4180572ccaaSJim Harris }
4190572ccaaSJim Harris 
4200572ccaaSJim Harris static int
ismt_readw(device_t dev,u_char slave,char cmd,short * word)4210572ccaaSJim Harris ismt_readw(device_t dev, u_char slave, char cmd, short *word)
4220572ccaaSJim Harris {
4230572ccaaSJim Harris 	struct ismt_desc	*desc;
4240572ccaaSJim Harris 	struct ismt_softc	*sc;
4250572ccaaSJim Harris 	int			err;
4260572ccaaSJim Harris 
4270572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
4280572ccaaSJim Harris 
4290572ccaaSJim Harris 	sc = device_get_softc(dev);
4300572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
4310572ccaaSJim Harris 	desc->control = ISMT_DESC_CWRL;
4320572ccaaSJim Harris 	desc->wr_len_cmd = cmd;
4330572ccaaSJim Harris 	desc->rd_len = 2;
4340572ccaaSJim Harris 
4350572ccaaSJim Harris 	err = ismt_submit(sc, desc, slave, 1);
4360572ccaaSJim Harris 
4370572ccaaSJim Harris 	if (err != SMB_ENOERR)
4380572ccaaSJim Harris 		return (err);
4390572ccaaSJim Harris 
4400572ccaaSJim Harris 	*word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
4410572ccaaSJim Harris 
4420572ccaaSJim Harris 	return (err);
4430572ccaaSJim Harris }
4440572ccaaSJim Harris 
4450572ccaaSJim Harris static int
ismt_pcall(device_t dev,u_char slave,char cmd,short sdata,short * rdata)4460572ccaaSJim Harris ismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
4470572ccaaSJim Harris {
4480572ccaaSJim Harris 	struct ismt_desc	*desc;
4490572ccaaSJim Harris 	struct ismt_softc	*sc;
4500572ccaaSJim Harris 	int			err;
4510572ccaaSJim Harris 
4520572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
4530572ccaaSJim Harris 
4540572ccaaSJim Harris 	sc = device_get_softc(dev);
4550572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
4560572ccaaSJim Harris 	desc->wr_len_cmd = 3;
4570572ccaaSJim Harris 	desc->rd_len = 2;
4580572ccaaSJim Harris 	sc->dma_buffer[0] = cmd;
4590572ccaaSJim Harris 	sc->dma_buffer[1] = sdata & 0xff;
4600572ccaaSJim Harris 	sc->dma_buffer[2] = sdata >> 8;
4610572ccaaSJim Harris 
4620572ccaaSJim Harris 	err = ismt_submit(sc, desc, slave, 0);
4630572ccaaSJim Harris 
4640572ccaaSJim Harris 	if (err != SMB_ENOERR)
4650572ccaaSJim Harris 		return (err);
4660572ccaaSJim Harris 
4670572ccaaSJim Harris 	*rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
4680572ccaaSJim Harris 
4690572ccaaSJim Harris 	return (err);
4700572ccaaSJim Harris }
4710572ccaaSJim Harris 
4720572ccaaSJim Harris static int
ismt_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)4730572ccaaSJim Harris ismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
4740572ccaaSJim Harris {
4750572ccaaSJim Harris 	struct ismt_desc	*desc;
4760572ccaaSJim Harris 	struct ismt_softc	*sc;
4770572ccaaSJim Harris 
4780572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
4790572ccaaSJim Harris 
4800572ccaaSJim Harris 	if (count == 0 || count > ISMT_MAX_BLOCK_SIZE)
4810572ccaaSJim Harris 		return (SMB_EINVAL);
4820572ccaaSJim Harris 
4830572ccaaSJim Harris 	sc = device_get_softc(dev);
4840572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
4850572ccaaSJim Harris 	desc->control = ISMT_DESC_I2C;
4860572ccaaSJim Harris 	desc->wr_len_cmd = count + 1;
4870572ccaaSJim Harris 	sc->dma_buffer[0] = cmd;
4880572ccaaSJim Harris 	memcpy(&sc->dma_buffer[1], buf, count);
4890572ccaaSJim Harris 
4900572ccaaSJim Harris 	return (ismt_submit(sc, desc, slave, 0));
4910572ccaaSJim Harris }
4920572ccaaSJim Harris 
4930572ccaaSJim Harris static int
ismt_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)4940572ccaaSJim Harris ismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
4950572ccaaSJim Harris {
4960572ccaaSJim Harris 	struct ismt_desc	*desc;
4970572ccaaSJim Harris 	struct ismt_softc	*sc;
4980572ccaaSJim Harris 	int			err;
4990572ccaaSJim Harris 
5000572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
5010572ccaaSJim Harris 
5020572ccaaSJim Harris 	if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE)
5030572ccaaSJim Harris 		return (SMB_EINVAL);
5040572ccaaSJim Harris 
5050572ccaaSJim Harris 	sc = device_get_softc(dev);
5060572ccaaSJim Harris 	desc = ismt_alloc_desc(sc);
5070572ccaaSJim Harris 	desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL;
5080572ccaaSJim Harris 	desc->wr_len_cmd = cmd;
5090572ccaaSJim Harris 	desc->rd_len = *count;
5100572ccaaSJim Harris 
5110572ccaaSJim Harris 	err = ismt_submit(sc, desc, slave, 0);
5120572ccaaSJim Harris 
5130572ccaaSJim Harris 	if (err != SMB_ENOERR)
5140572ccaaSJim Harris 		return (err);
5150572ccaaSJim Harris 
5160572ccaaSJim Harris 	memcpy(buf, sc->dma_buffer, desc->rxbytes);
5170572ccaaSJim Harris 	*count = desc->rxbytes;
5180572ccaaSJim Harris 
5190572ccaaSJim Harris 	return (err);
5200572ccaaSJim Harris }
5210572ccaaSJim Harris 
5220572ccaaSJim Harris static int
ismt_detach(device_t dev)5230572ccaaSJim Harris ismt_detach(device_t dev)
5240572ccaaSJim Harris {
5250572ccaaSJim Harris 	struct ismt_softc	*sc;
5260572ccaaSJim Harris 	int			error;
5270572ccaaSJim Harris 
5280572ccaaSJim Harris 	ISMT_DEBUG(dev, "%s\n", __func__);
5290572ccaaSJim Harris 	sc = device_get_softc(dev);
5300572ccaaSJim Harris 
5310572ccaaSJim Harris 	error = bus_generic_detach(dev);
5320572ccaaSJim Harris 	if (error)
5330572ccaaSJim Harris 		return (error);
5340572ccaaSJim Harris 
5350572ccaaSJim Harris 	if (sc->intr_handle != NULL) {
5360572ccaaSJim Harris 		bus_teardown_intr(dev, sc->intr_res, sc->intr_handle);
5370572ccaaSJim Harris 		sc->intr_handle = NULL;
5380572ccaaSJim Harris 	}
5390572ccaaSJim Harris 	if (sc->intr_res != NULL) {
5400572ccaaSJim Harris 		bus_release_resource(dev,
5410572ccaaSJim Harris 		    SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
5420572ccaaSJim Harris 		sc->intr_res = NULL;
5430572ccaaSJim Harris 	}
5440572ccaaSJim Harris 	if (sc->using_msi == 1)
5450572ccaaSJim Harris 		pci_release_msi(dev);
5460572ccaaSJim Harris 
5470572ccaaSJim Harris 	if (sc->mmio_res != NULL) {
5480572ccaaSJim Harris 		bus_release_resource(dev,
5490572ccaaSJim Harris 		    SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res);
5500572ccaaSJim Harris 		sc->mmio_res = NULL;
5510572ccaaSJim Harris 	}
5520572ccaaSJim Harris 
5530572ccaaSJim Harris 	bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map);
5540572ccaaSJim Harris 	bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map);
5550572ccaaSJim Harris 
5560572ccaaSJim Harris 	bus_dmamem_free(sc->desc_dma_tag, sc->desc,
5570572ccaaSJim Harris 	    sc->desc_dma_map);
5580572ccaaSJim Harris 	bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer,
5590572ccaaSJim Harris 	    sc->dma_buffer_dma_map);
5600572ccaaSJim Harris 
5610572ccaaSJim Harris 	bus_dma_tag_destroy(sc->desc_dma_tag);
5620572ccaaSJim Harris 	bus_dma_tag_destroy(sc->dma_buffer_dma_tag);
5630572ccaaSJim Harris 
5640572ccaaSJim Harris 	pci_disable_busmaster(dev);
5650572ccaaSJim Harris 
5660572ccaaSJim Harris 	return 0;
5670572ccaaSJim Harris }
5680572ccaaSJim Harris 
5690572ccaaSJim Harris static void
ismt_single_map(void * arg,bus_dma_segment_t * seg,int nseg,int error)5700572ccaaSJim Harris ismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
5710572ccaaSJim Harris {
5720572ccaaSJim Harris 	uint64_t *bus_addr = (uint64_t *)arg;
5730572ccaaSJim Harris 
5740572ccaaSJim Harris 	KASSERT(error == 0, ("%s: error=%d\n", __func__, error));
5750572ccaaSJim Harris 	KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg));
5760572ccaaSJim Harris 
5770572ccaaSJim Harris 	*bus_addr = seg[0].ds_addr;
5780572ccaaSJim Harris }
5790572ccaaSJim Harris 
5800572ccaaSJim Harris static int
ismt_attach(device_t dev)5810572ccaaSJim Harris ismt_attach(device_t dev)
5820572ccaaSJim Harris {
5830572ccaaSJim Harris 	struct ismt_softc *sc = device_get_softc(dev);
5840572ccaaSJim Harris 	int err, num_vectors, val;
5850572ccaaSJim Harris 
5860572ccaaSJim Harris 	sc->pcidev = dev;
5870572ccaaSJim Harris 	pci_enable_busmaster(dev);
5880572ccaaSJim Harris 
5890572ccaaSJim Harris 	if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) {
5900572ccaaSJim Harris 		device_printf(dev, "no smbus child found\n");
5910572ccaaSJim Harris 		err = ENXIO;
5920572ccaaSJim Harris 		goto fail;
5930572ccaaSJim Harris 	}
5940572ccaaSJim Harris 
5950572ccaaSJim Harris 	sc->mmio_rid = PCIR_BAR(0);
5960572ccaaSJim Harris 	sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
5970572ccaaSJim Harris 	    &sc->mmio_rid, RF_ACTIVE);
5980572ccaaSJim Harris 	if (sc->mmio_res == NULL) {
5990572ccaaSJim Harris 		device_printf(dev, "cannot allocate mmio region\n");
6000572ccaaSJim Harris 		err = ENOMEM;
6010572ccaaSJim Harris 		goto fail;
6020572ccaaSJim Harris 	}
6030572ccaaSJim Harris 
6040572ccaaSJim Harris 	sc->mmio_tag = rman_get_bustag(sc->mmio_res);
6050572ccaaSJim Harris 	sc->mmio_handle = rman_get_bushandle(sc->mmio_res);
6060572ccaaSJim Harris 
6070572ccaaSJim Harris 	/* Attach "smbus" child */
608*18250ec6SJohn Baldwin 	bus_attach_children(dev);
6090572ccaaSJim Harris 
6100572ccaaSJim Harris 	bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
6110572ccaaSJim Harris 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
6120572ccaaSJim Harris 	    DESC_SIZE, 1, DESC_SIZE,
6130572ccaaSJim Harris 	    0, NULL, NULL, &sc->desc_dma_tag);
6140572ccaaSJim Harris 
6150572ccaaSJim Harris 	bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
6160572ccaaSJim Harris 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
6170572ccaaSJim Harris 	    DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE,
6180572ccaaSJim Harris 	    0, NULL, NULL, &sc->dma_buffer_dma_tag);
6190572ccaaSJim Harris 
6200572ccaaSJim Harris 	bus_dmamap_create(sc->desc_dma_tag, 0,
6210572ccaaSJim Harris 	    &sc->desc_dma_map);
6220572ccaaSJim Harris 	bus_dmamap_create(sc->dma_buffer_dma_tag, 0,
6230572ccaaSJim Harris 	    &sc->dma_buffer_dma_map);
6240572ccaaSJim Harris 
6250572ccaaSJim Harris 	bus_dmamem_alloc(sc->desc_dma_tag,
6260572ccaaSJim Harris 	    (void **)&sc->desc, BUS_DMA_WAITOK,
6270572ccaaSJim Harris 	    &sc->desc_dma_map);
6280572ccaaSJim Harris 	bus_dmamem_alloc(sc->dma_buffer_dma_tag,
6290572ccaaSJim Harris 	    (void **)&sc->dma_buffer, BUS_DMA_WAITOK,
6300572ccaaSJim Harris 	    &sc->dma_buffer_dma_map);
6310572ccaaSJim Harris 
6320572ccaaSJim Harris 	bus_dmamap_load(sc->desc_dma_tag,
6330572ccaaSJim Harris 	    sc->desc_dma_map, sc->desc, DESC_SIZE,
6340572ccaaSJim Harris 	    ismt_single_map, &sc->desc_bus_addr, 0);
6350572ccaaSJim Harris 	bus_dmamap_load(sc->dma_buffer_dma_tag,
6360572ccaaSJim Harris 	    sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE,
6370572ccaaSJim Harris 	    ismt_single_map, &sc->dma_buffer_bus_addr, 0);
6380572ccaaSJim Harris 
6390572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA,
6400572ccaaSJim Harris 	    (sc->desc_bus_addr & 0xFFFFFFFFLL));
6410572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4,
6420572ccaaSJim Harris 	    (sc->desc_bus_addr >> 32));
6430572ccaaSJim Harris 
6440572ccaaSJim Harris 	/* initialize the Master Control Register (MCTRL) */
6450572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE);
6460572ccaaSJim Harris 
6470572ccaaSJim Harris 	/* initialize the Master Status Register (MSTS) */
6480572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0);
6490572ccaaSJim Harris 
6500572ccaaSJim Harris 	/* initialize the Master Descriptor Size (MDS) */
6510572ccaaSJim Harris 	val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS);
6520572ccaaSJim Harris 	val &= ~ISMT_MDS_MASK;
6530572ccaaSJim Harris 	val |= (ISMT_DESC_ENTRIES - 1);
6540572ccaaSJim Harris 	bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val);
6550572ccaaSJim Harris 
6560572ccaaSJim Harris 	sc->using_msi = 1;
6570572ccaaSJim Harris 
6580572ccaaSJim Harris 	if (pci_msi_count(dev) == 0) {
6590572ccaaSJim Harris 		sc->using_msi = 0;
6600572ccaaSJim Harris 		goto intx;
6610572ccaaSJim Harris 	}
6620572ccaaSJim Harris 
6630572ccaaSJim Harris 	num_vectors = 1;
6640572ccaaSJim Harris 	if (pci_alloc_msi(dev, &num_vectors) != 0) {
6650572ccaaSJim Harris 		sc->using_msi = 0;
6660572ccaaSJim Harris 		goto intx;
6670572ccaaSJim Harris 	}
6680572ccaaSJim Harris 
6690572ccaaSJim Harris 	sc->intr_rid = 1;
6700572ccaaSJim Harris 	sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
6710572ccaaSJim Harris 	    &sc->intr_rid, RF_ACTIVE);
6720572ccaaSJim Harris 
6730572ccaaSJim Harris 	if (sc->intr_res == NULL) {
6740572ccaaSJim Harris 		sc->using_msi = 0;
6750572ccaaSJim Harris 		pci_release_msi(dev);
6760572ccaaSJim Harris 	}
6770572ccaaSJim Harris 
6780572ccaaSJim Harris intx:
6790572ccaaSJim Harris 	if (sc->using_msi == 0) {
6800572ccaaSJim Harris 		sc->intr_rid = 0;
6810572ccaaSJim Harris 		sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
6820572ccaaSJim Harris 		    &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE);
6830572ccaaSJim Harris 		if (sc->intr_res == NULL) {
6840572ccaaSJim Harris 			device_printf(dev, "cannot allocate irq\n");
6850572ccaaSJim Harris 			err = ENXIO;
6860572ccaaSJim Harris 			goto fail;
6870572ccaaSJim Harris 		}
6880572ccaaSJim Harris 	}
6890572ccaaSJim Harris 
6900572ccaaSJim Harris 	ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi);
6910572ccaaSJim Harris 
6920572ccaaSJim Harris 	err = bus_setup_intr(dev, sc->intr_res,
6930572ccaaSJim Harris 	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc,
6940572ccaaSJim Harris 	    &sc->intr_handle);
6950572ccaaSJim Harris 	if (err != 0) {
6960572ccaaSJim Harris 		device_printf(dev, "cannot setup interrupt\n");
6970572ccaaSJim Harris 		err = ENXIO;
6980572ccaaSJim Harris 		goto fail;
6990572ccaaSJim Harris 	}
7000572ccaaSJim Harris 
7010572ccaaSJim Harris 	return (0);
7020572ccaaSJim Harris 
7030572ccaaSJim Harris fail:
7040572ccaaSJim Harris 	ismt_detach(dev);
7050572ccaaSJim Harris 	return (err);
7060572ccaaSJim Harris }
7070572ccaaSJim Harris 
7080572ccaaSJim Harris #define ID_INTEL_S1200_SMT0		0x0c598086
7090572ccaaSJim Harris #define ID_INTEL_S1200_SMT1		0x0c5a8086
7100572ccaaSJim Harris #define ID_INTEL_C2000_SMT		0x1f158086
7115df2e54cSJustin Hibbits #define ID_INTEL_C3000_SMT		0x19ac8086
7120572ccaaSJim Harris 
7130572ccaaSJim Harris static int
ismt_probe(device_t dev)7140572ccaaSJim Harris ismt_probe(device_t dev)
7150572ccaaSJim Harris {
7160572ccaaSJim Harris 	const char *desc;
7170572ccaaSJim Harris 
7180572ccaaSJim Harris 	switch (pci_get_devid(dev)) {
7190572ccaaSJim Harris 	case ID_INTEL_S1200_SMT0:
7200572ccaaSJim Harris 		desc = "Atom Processor S1200 SMBus 2.0 Controller 0";
7210572ccaaSJim Harris 		break;
7220572ccaaSJim Harris 	case ID_INTEL_S1200_SMT1:
7230572ccaaSJim Harris 		desc = "Atom Processor S1200 SMBus 2.0 Controller 1";
7240572ccaaSJim Harris 		break;
7250572ccaaSJim Harris 	case ID_INTEL_C2000_SMT:
7260572ccaaSJim Harris 		desc = "Atom Processor C2000 SMBus 2.0";
7270572ccaaSJim Harris 		break;
7285df2e54cSJustin Hibbits 	case ID_INTEL_C3000_SMT:
7295df2e54cSJustin Hibbits 		desc = "Atom Processor C3000 SMBus 2.0";
7305df2e54cSJustin Hibbits 		break;
7310572ccaaSJim Harris 	default:
7320572ccaaSJim Harris 		return (ENXIO);
7330572ccaaSJim Harris 	}
7340572ccaaSJim Harris 
7350572ccaaSJim Harris 	device_set_desc(dev, desc);
7360572ccaaSJim Harris 	return (BUS_PROBE_DEFAULT);
7370572ccaaSJim Harris }
7380572ccaaSJim Harris 
7390572ccaaSJim Harris /* Device methods */
7400572ccaaSJim Harris static device_method_t ismt_pci_methods[] = {
7410572ccaaSJim Harris         DEVMETHOD(device_probe,		ismt_probe),
7420572ccaaSJim Harris         DEVMETHOD(device_attach,	ismt_attach),
7430572ccaaSJim Harris         DEVMETHOD(device_detach,	ismt_detach),
7440572ccaaSJim Harris 
7450572ccaaSJim Harris         DEVMETHOD(smbus_callback,	ismt_callback),
7460572ccaaSJim Harris         DEVMETHOD(smbus_quick,		ismt_quick),
7470572ccaaSJim Harris         DEVMETHOD(smbus_sendb,		ismt_sendb),
7480572ccaaSJim Harris         DEVMETHOD(smbus_recvb,		ismt_recvb),
7490572ccaaSJim Harris         DEVMETHOD(smbus_writeb,		ismt_writeb),
7500572ccaaSJim Harris         DEVMETHOD(smbus_writew,		ismt_writew),
7510572ccaaSJim Harris         DEVMETHOD(smbus_readb,		ismt_readb),
7520572ccaaSJim Harris         DEVMETHOD(smbus_readw,		ismt_readw),
7530572ccaaSJim Harris         DEVMETHOD(smbus_pcall,		ismt_pcall),
7540572ccaaSJim Harris         DEVMETHOD(smbus_bwrite,		ismt_bwrite),
7550572ccaaSJim Harris         DEVMETHOD(smbus_bread,		ismt_bread),
7560572ccaaSJim Harris 
7570572ccaaSJim Harris 	DEVMETHOD_END
7580572ccaaSJim Harris };
7590572ccaaSJim Harris 
7600572ccaaSJim Harris static driver_t ismt_pci_driver = {
7610572ccaaSJim Harris 	"ismt",
7620572ccaaSJim Harris 	ismt_pci_methods,
7630572ccaaSJim Harris 	sizeof(struct ismt_softc)
7640572ccaaSJim Harris };
7650572ccaaSJim Harris 
766dfee3204SJohn Baldwin DRIVER_MODULE(ismt, pci, ismt_pci_driver, 0, 0);
767c6d39765SJohn Baldwin DRIVER_MODULE(smbus, ismt, smbus_driver, 0, 0);
7680572ccaaSJim Harris 
7690572ccaaSJim Harris MODULE_DEPEND(ismt, pci, 1, 1, 1);
7700572ccaaSJim Harris MODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
7710572ccaaSJim Harris MODULE_VERSION(ismt, 1);
772