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