Author: jimharris
Date: Mon Jan 11 17:53:24 2016
New Revision: 293675
URL: https://svnweb.freebsd.org/changeset/base/293675

Log:
  MFC r266474:
  
    Add ismt(4) driver.
  
    ismt(4) supports the SMBus Message Transport controller found on Intel
    C2000 series (Avoton) and S1200 series (Briarwood) Atom SoCs.
  
  Relnotes:     Yes

Added:
  stable/10/share/man/man4/ismt.4   (contents, props changed)
  stable/10/sys/dev/ismt/
  stable/10/sys/dev/ismt/ismt.c   (contents, props changed)
  stable/10/sys/modules/i2c/controllers/ismt/
  stable/10/sys/modules/i2c/controllers/ismt/Makefile   (contents, props 
changed)
Modified:
  stable/10/share/man/man4/Makefile
  stable/10/sys/conf/NOTES
  stable/10/sys/conf/files
  stable/10/sys/modules/i2c/controllers/Makefile

Modified: stable/10/share/man/man4/Makefile
==============================================================================
--- stable/10/share/man/man4/Makefile   Mon Jan 11 17:52:42 2016        
(r293674)
+++ stable/10/share/man/man4/Makefile   Mon Jan 11 17:53:24 2016        
(r293675)
@@ -208,6 +208,7 @@ MAN=        aac.4 \
        ipw.4 \
        ipwfw.4 \
        isci.4 \
+       ismt.4 \
        isp.4 \
        ispfw.4 \
        iwi.4 \

Added: stable/10/share/man/man4/ismt.4
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/share/man/man4/ismt.4     Mon Jan 11 17:53:24 2016        
(r293675)
@@ -0,0 +1,59 @@
+.\"
+.\" Copyright (c) 2014 Intel Corporation
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions, and the following disclaimer,
+.\"    without modification.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Intel Corporation nor the names of its
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGES.
+.\"
+.\" ismt driver man page.
+.\"
+.\" Author: Jim Harris <jimhar...@freebsd.org>
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 9, 2014
+.Dt ISMT 4
+.Os
+.Sh NAME
+.Nm ismt
+.Nd Intel SMBus Message Transport (SMBus 2.0) driver
+.Sh SYNOPSIS
+.Cd device pci
+.Cd device smbus
+.Cd device smb
+.Cd device ismt
+.Sh DESCRIPTION
+This driver provides access to the SMBus 2.0 controller device contained
+in the Intel Atom S1200 and C2000 CPUs.
+.Sh SEE ALSO
+.Xr smb 4 ,
+.Xr smbus 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Jim Harris Aq jimhar...@freebsd.org

Modified: stable/10/sys/conf/NOTES
==============================================================================
--- stable/10/sys/conf/NOTES    Mon Jan 11 17:52:42 2016        (r293674)
+++ stable/10/sys/conf/NOTES    Mon Jan 11 17:53:24 2016        (r293675)
@@ -2493,6 +2493,7 @@ device            sdhci
 # amdsmb       AMD 8111 SMBus 2.0 Controller
 # nfpm         NVIDIA nForce Power Management Unit
 # nfsmb                NVIDIA nForce2/3/4 MCP SMBus 2.0 Controller
+# ismt         Intel SMBus 2.0 controller chips (on Atom S1200, C2000)
 #
 device         smbus           # Bus support, required for smb below.
 
@@ -2504,6 +2505,7 @@ device            amdpm
 device         amdsmb
 device         nfpm
 device         nfsmb
+device         ismt
 
 device         smb
 

Modified: stable/10/sys/conf/files
==============================================================================
--- stable/10/sys/conf/files    Mon Jan 11 17:52:42 2016        (r293674)
+++ stable/10/sys/conf/files    Mon Jan 11 17:53:24 2016        (r293675)
@@ -1523,6 +1523,7 @@ dev/iscsi_initiator/isc_cam.c     optional i
 dev/iscsi_initiator/isc_soc.c  optional iscsi_initiator scbus
 dev/iscsi_initiator/isc_sm.c   optional iscsi_initiator scbus
 dev/iscsi_initiator/isc_subr.c optional iscsi_initiator scbus
+dev/ismt/ismt.c                        optional ismt
 dev/isp/isp.c                  optional isp
 dev/isp/isp_freebsd.c          optional isp
 dev/isp/isp_library.c          optional isp

Added: stable/10/sys/dev/ismt/ismt.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/sys/dev/ismt/ismt.c       Mon Jan 11 17:53:24 2016        
(r293675)
@@ -0,0 +1,778 @@
+/*-
+ * Copyright (C) 2014 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/priority.h>
+#include <sys/proc.h>
+#include <sys/syslog.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/smbus/smbconf.h>
+
+#include "smbus_if.h"
+
+#define ISMT_DESC_ENTRIES      32
+
+/* Hardware Descriptor Constants - Control Field */
+#define ISMT_DESC_CWRL 0x01    /* Command/Write Length */
+#define ISMT_DESC_BLK  0X04    /* Perform Block Transaction */
+#define ISMT_DESC_FAIR 0x08    /* Set fairness flag upon successful arbit. */
+#define ISMT_DESC_PEC  0x10    /* Packet Error Code */
+#define ISMT_DESC_I2C  0x20    /* I2C Enable */
+#define ISMT_DESC_INT  0x40    /* Interrupt */
+#define ISMT_DESC_SOE  0x80    /* Stop On Error */
+
+/* Hardware Descriptor Constants - Status Field */
+#define ISMT_DESC_SCS  0x01    /* Success */
+#define ISMT_DESC_DLTO 0x04    /* Data Low Time Out */
+#define ISMT_DESC_NAK  0x08    /* NAK Received */
+#define ISMT_DESC_CRC  0x10    /* CRC Error */
+#define ISMT_DESC_CLTO 0x20    /* Clock Low Time Out */
+#define ISMT_DESC_COL  0x40    /* Collisions */
+#define ISMT_DESC_LPR  0x80    /* Large Packet Received */
+
+/* Macros */
+#define ISMT_DESC_ADDR_RW(addr, is_read) ((addr) | (is_read))
+
+/* iSMT General Register address offsets (SMBBAR + <addr>) */
+#define ISMT_GR_GCTRL          0x000   /* General Control */
+#define ISMT_GR_SMTICL         0x008   /* SMT Interrupt Cause Location */
+#define ISMT_GR_ERRINTMSK      0x010   /* Error Interrupt Mask */
+#define ISMT_GR_ERRAERMSK      0x014   /* Error AER Mask */
+#define ISMT_GR_ERRSTS         0x018   /* Error Status */
+#define ISMT_GR_ERRINFO                0x01c   /* Error Information */
+
+/* iSMT Master Registers */
+#define ISMT_MSTR_MDBA         0x100   /* Master Descriptor Base Address */
+#define ISMT_MSTR_MCTRL                0x108   /* Master Control */
+#define ISMT_MSTR_MSTS         0x10c   /* Master Status */
+#define ISMT_MSTR_MDS          0x110   /* Master Descriptor Size */
+#define ISMT_MSTR_RPOLICY      0x114   /* Retry Policy */
+
+/* iSMT Miscellaneous Registers */
+#define ISMT_SPGT      0x300   /* SMBus PHY Global Timing */
+
+/* General Control Register (GCTRL) bit definitions */
+#define ISMT_GCTRL_TRST        0x04    /* Target Reset */
+#define ISMT_GCTRL_KILL        0x08    /* Kill */
+#define ISMT_GCTRL_SRST        0x40    /* Soft Reset */
+
+/* Master Control Register (MCTRL) bit definitions */
+#define ISMT_MCTRL_SS  0x01            /* Start/Stop */
+#define ISMT_MCTRL_MEIE        0x10            /* Master Error Interrupt 
Enable */
+#define ISMT_MCTRL_FMHP        0x00ff0000      /* Firmware Master Head Ptr 
(FMHP) */
+
+/* Master Status Register (MSTS) bit definitions */
+#define ISMT_MSTS_HMTP 0xff0000        /* HW Master Tail Pointer (HMTP) */
+#define ISMT_MSTS_MIS  0x20            /* Master Interrupt Status (MIS) */
+#define ISMT_MSTS_MEIS 0x10            /* Master Error Int Status (MEIS) */
+#define ISMT_MSTS_IP   0x01            /* In Progress */
+
+/* Master Descriptor Size (MDS) bit definitions */
+#define ISMT_MDS_MASK  0xff    /* Master Descriptor Size mask (MDS) */
+
+/* SMBus PHY Global Timing Register (SPGT) bit definitions */
+#define ISMT_SPGT_SPD_MASK     0xc0000000      /* SMBus Speed mask */
+#define ISMT_SPGT_SPD_80K      0x00            /* 80 kHz */
+#define ISMT_SPGT_SPD_100K     (0x1 << 30)     /* 100 kHz */
+#define ISMT_SPGT_SPD_400K     (0x2 << 30)     /* 400 kHz */
+#define ISMT_SPGT_SPD_1M       (0x3 << 30)     /* 1 MHz */
+
+/* MSI Control Register (MSICTL) bit definitions */
+#define ISMT_MSICTL_MSIE       0x01    /* MSI Enable */
+
+#define ISMT_MAX_BLOCK_SIZE    32 /* per SMBus spec */
+
+//#define ISMT_DEBUG   device_printf
+#ifndef ISMT_DEBUG
+#define ISMT_DEBUG(...)
+#endif
+
+/* iSMT Hardware Descriptor */
+struct ismt_desc {
+       uint8_t tgtaddr_rw;     /* target address & r/w bit */
+       uint8_t wr_len_cmd;     /* write length in bytes or a command */
+       uint8_t rd_len;         /* read length */
+       uint8_t control;        /* control bits */
+       uint8_t status;         /* status bits */
+       uint8_t retry;          /* collision retry and retry count */
+       uint8_t rxbytes;        /* received bytes */
+       uint8_t txbytes;        /* transmitted bytes */
+       uint32_t dptr_low;      /* lower 32 bit of the data pointer */
+       uint32_t dptr_high;     /* upper 32 bit of the data pointer */
+} __packed;
+
+#define DESC_SIZE      (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc))
+
+#define DMA_BUFFER_SIZE        64
+
+struct ismt_softc {
+       device_t                pcidev;
+       device_t                smbdev;
+
+       struct thread           *bus_reserved;
+
+       int                     intr_rid;
+       struct resource         *intr_res;
+       void                    *intr_handle;
+
+       bus_space_tag_t         mmio_tag;
+       bus_space_handle_t      mmio_handle;
+       int                     mmio_rid;
+       struct resource         *mmio_res;
+
+       uint8_t                 head;
+
+       struct ismt_desc        *desc;
+       bus_dma_tag_t           desc_dma_tag;
+       bus_dmamap_t            desc_dma_map;
+       uint64_t                desc_bus_addr;
+
+       uint8_t                 *dma_buffer;
+       bus_dma_tag_t           dma_buffer_dma_tag;
+       bus_dmamap_t            dma_buffer_dma_map;
+       uint64_t                dma_buffer_bus_addr;
+
+       uint8_t                 using_msi;
+};
+
+static void
+ismt_intr(void *arg)
+{
+       struct ismt_softc *sc = arg;
+       uint32_t val;
+
+       val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS);
+       ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val);
+
+       val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS);
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val);
+
+       wakeup(sc);
+}
+
+static int 
+ismt_callback(device_t dev, int index, void *data)
+{
+       struct ismt_softc       *sc;
+       int                     acquired, err;
+
+       sc = device_get_softc(dev);
+
+       switch (index) {
+       case SMB_REQUEST_BUS:
+               acquired = atomic_cmpset_ptr(
+                   (uintptr_t *)&sc->bus_reserved,
+                   (uintptr_t)NULL, (uintptr_t)curthread);
+               ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired);
+               if (acquired)
+                       err = 0;
+               else
+                       err = EWOULDBLOCK;
+               break;
+       case SMB_RELEASE_BUS:
+               KASSERT(sc->bus_reserved == curthread,
+                   ("SMB_RELEASE_BUS called by wrong thread\n"));
+               ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n");
+               atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved,
+                   (uintptr_t)NULL);
+               err = 0;
+               break;
+       default:
+               err = SMB_EABORT;
+               break;
+       }
+
+       return (err);
+}
+
+static struct ismt_desc *
+ismt_alloc_desc(struct ismt_softc *sc)
+{
+       struct ismt_desc *desc;
+
+       KASSERT(sc->bus_reserved == curthread,
+           ("curthread %p did not request bus (%p has reserved)\n",
+           curthread, sc->bus_reserved));
+
+       desc = &sc->desc[sc->head++];
+       if (sc->head == ISMT_DESC_ENTRIES)
+               sc->head = 0;
+
+       memset(desc, 0, sizeof(*desc));
+
+       return (desc);
+}
+
+static int
+ismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave,
+    uint8_t is_read)
+{
+       uint32_t err, fmhp, val;
+
+       desc->control |= ISMT_DESC_FAIR;
+       if (sc->using_msi)
+               desc->control |= ISMT_DESC_INT;
+
+       desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read);
+       desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL);
+       desc->dptr_high = (sc->dma_buffer_bus_addr >> 32);
+
+       wmb();
+
+       fmhp = sc->head << 16;
+       val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
+       val &= ~ISMT_MCTRL_FMHP;
+       val |= fmhp;
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
+
+       /* set the start bit */
+       val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
+       val |= ISMT_MCTRL_SS;
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
+
+       err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz);
+
+       if (err != 0) {
+               ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__);
+               return (SMB_ETIMEOUT);
+       }
+
+       ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status);
+
+       if (desc->status & ISMT_DESC_SCS)
+               return (SMB_ENOERR);
+
+       if (desc->status & ISMT_DESC_NAK)
+               return (SMB_ENOACK);
+
+       if (desc->status & ISMT_DESC_CRC)
+               return (SMB_EBUSERR);
+
+       if (desc->status & ISMT_DESC_COL)
+               return (SMB_ECOLLI);
+
+       if (desc->status & ISMT_DESC_LPR)
+               return (SMB_EINVAL);
+
+       if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO))
+               return (SMB_ETIMEOUT);
+
+       return (SMB_EBUSERR);
+}
+
+
+static int
+ismt_quick(device_t dev, u_char slave, int how)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     is_read;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       if (how != SMB_QREAD && how != SMB_QWRITE) {
+               return (SMB_ENOTSUPP);
+       }
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       is_read = (how == SMB_QREAD ? 1 : 0);
+       return (ismt_submit(sc, desc, slave, is_read));
+}
+
+static int
+ismt_sendb(device_t dev, u_char slave, char byte)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->control = ISMT_DESC_CWRL;
+       desc->wr_len_cmd = byte;
+
+       return (ismt_submit(sc, desc, slave, 0));
+}
+
+static int
+ismt_recvb(device_t dev, u_char slave, char *byte)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     err;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->rd_len = 1;
+
+       err = ismt_submit(sc, desc, slave, 1);
+
+       if (err != SMB_ENOERR)
+               return (err);
+
+       *byte = sc->dma_buffer[0];
+
+       return (err);
+}
+
+static int
+ismt_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->wr_len_cmd = 2;
+       sc->dma_buffer[0] = cmd;
+       sc->dma_buffer[1] = byte;
+
+       return (ismt_submit(sc, desc, slave, 0));
+}
+
+static int
+ismt_writew(device_t dev, u_char slave, char cmd, short word)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->wr_len_cmd = 3;
+       sc->dma_buffer[0] = cmd;
+       sc->dma_buffer[1] = word & 0xFF;
+       sc->dma_buffer[2] = word >> 8;
+
+       return (ismt_submit(sc, desc, slave, 0));
+}
+
+static int
+ismt_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     err;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->control = ISMT_DESC_CWRL;
+       desc->wr_len_cmd = cmd;
+       desc->rd_len = 1;
+
+       err = ismt_submit(sc, desc, slave, 1);
+
+       if (err != SMB_ENOERR)
+               return (err);
+
+       *byte = sc->dma_buffer[0];
+
+       return (err);
+}
+
+static int
+ismt_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     err;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->control = ISMT_DESC_CWRL;
+       desc->wr_len_cmd = cmd;
+       desc->rd_len = 2;
+
+       err = ismt_submit(sc, desc, slave, 1);
+
+       if (err != SMB_ENOERR)
+               return (err);
+
+       *word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
+
+       return (err);
+}
+
+static int
+ismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     err;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->wr_len_cmd = 3;
+       desc->rd_len = 2;
+       sc->dma_buffer[0] = cmd;
+       sc->dma_buffer[1] = sdata & 0xff;
+       sc->dma_buffer[2] = sdata >> 8;
+
+       err = ismt_submit(sc, desc, slave, 0);
+
+       if (err != SMB_ENOERR)
+               return (err);
+
+       *rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
+
+       return (err);
+}
+
+static int
+ismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       if (count == 0 || count > ISMT_MAX_BLOCK_SIZE)
+               return (SMB_EINVAL);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->control = ISMT_DESC_I2C;
+       desc->wr_len_cmd = count + 1;
+       sc->dma_buffer[0] = cmd;
+       memcpy(&sc->dma_buffer[1], buf, count);
+
+       return (ismt_submit(sc, desc, slave, 0));
+}
+
+static int
+ismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
+{
+       struct ismt_desc        *desc;
+       struct ismt_softc       *sc;
+       int                     err;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+
+       if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE)
+               return (SMB_EINVAL);
+
+       sc = device_get_softc(dev);
+       desc = ismt_alloc_desc(sc);
+       desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL;
+       desc->wr_len_cmd = cmd;
+       desc->rd_len = *count;
+
+       err = ismt_submit(sc, desc, slave, 0);
+
+       if (err != SMB_ENOERR)
+               return (err);
+
+       memcpy(buf, sc->dma_buffer, desc->rxbytes);
+       *count = desc->rxbytes;
+
+       return (err);
+}
+
+static int
+ismt_detach(device_t dev)
+{
+       struct ismt_softc       *sc;
+       int                     error;
+
+       ISMT_DEBUG(dev, "%s\n", __func__);
+       sc = device_get_softc(dev);
+
+       error = bus_generic_detach(dev);
+       if (error)
+               return (error);
+
+       device_delete_child(dev, sc->smbdev);
+
+       if (sc->intr_handle != NULL) {
+               bus_teardown_intr(dev, sc->intr_res, sc->intr_handle);
+               sc->intr_handle = NULL;
+       }
+       if (sc->intr_res != NULL) {
+               bus_release_resource(dev,
+                   SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
+               sc->intr_res = NULL;
+       }
+       if (sc->using_msi == 1)
+               pci_release_msi(dev);
+
+       if (sc->mmio_res != NULL) {
+               bus_release_resource(dev,
+                   SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res);
+               sc->mmio_res = NULL;
+       }
+
+       bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map);
+       bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map);
+
+       bus_dmamem_free(sc->desc_dma_tag, sc->desc,
+           sc->desc_dma_map);
+       bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer,
+           sc->dma_buffer_dma_map);
+
+       bus_dma_tag_destroy(sc->desc_dma_tag);
+       bus_dma_tag_destroy(sc->dma_buffer_dma_tag);
+
+       pci_disable_busmaster(dev);
+
+       return 0;
+}
+
+static void
+ismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
+{
+       uint64_t *bus_addr = (uint64_t *)arg;
+
+       KASSERT(error == 0, ("%s: error=%d\n", __func__, error));
+       KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg));
+
+       *bus_addr = seg[0].ds_addr;
+}
+
+static int
+ismt_attach(device_t dev)
+{
+       struct ismt_softc *sc = device_get_softc(dev);
+       int err, num_vectors, val;
+
+       sc->pcidev = dev;
+       pci_enable_busmaster(dev);
+
+       if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) {
+               device_printf(dev, "no smbus child found\n");
+               err = ENXIO;
+               goto fail;
+       }
+
+       sc->mmio_rid = PCIR_BAR(0);
+       sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+           &sc->mmio_rid, RF_ACTIVE);
+       if (sc->mmio_res == NULL) {
+               device_printf(dev, "cannot allocate mmio region\n");
+               err = ENOMEM;
+               goto fail;
+       }
+
+       sc->mmio_tag = rman_get_bustag(sc->mmio_res);
+       sc->mmio_handle = rman_get_bushandle(sc->mmio_res);
+
+       /* Attach "smbus" child */
+       if ((err = bus_generic_attach(dev)) != 0) {
+               device_printf(dev, "failed to attach child: %d\n", err);
+               err = ENXIO;
+               goto fail;
+       }
+
+       bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
+           BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+           DESC_SIZE, 1, DESC_SIZE,
+           0, NULL, NULL, &sc->desc_dma_tag);
+
+       bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
+           BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+           DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE,
+           0, NULL, NULL, &sc->dma_buffer_dma_tag);
+
+       bus_dmamap_create(sc->desc_dma_tag, 0,
+           &sc->desc_dma_map);
+       bus_dmamap_create(sc->dma_buffer_dma_tag, 0,
+           &sc->dma_buffer_dma_map);
+
+       bus_dmamem_alloc(sc->desc_dma_tag,
+           (void **)&sc->desc, BUS_DMA_WAITOK,
+           &sc->desc_dma_map);
+       bus_dmamem_alloc(sc->dma_buffer_dma_tag,
+           (void **)&sc->dma_buffer, BUS_DMA_WAITOK,
+           &sc->dma_buffer_dma_map);
+
+       bus_dmamap_load(sc->desc_dma_tag,
+           sc->desc_dma_map, sc->desc, DESC_SIZE,
+           ismt_single_map, &sc->desc_bus_addr, 0);
+       bus_dmamap_load(sc->dma_buffer_dma_tag,
+           sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE,
+           ismt_single_map, &sc->dma_buffer_bus_addr, 0);
+
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA,
+           (sc->desc_bus_addr & 0xFFFFFFFFLL));
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4,
+           (sc->desc_bus_addr >> 32));
+
+       /* initialize the Master Control Register (MCTRL) */
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE);
+
+       /* initialize the Master Status Register (MSTS) */
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0);
+
+       /* initialize the Master Descriptor Size (MDS) */
+       val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS);
+       val &= ~ISMT_MDS_MASK;
+       val |= (ISMT_DESC_ENTRIES - 1);
+       bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val);
+
+       sc->using_msi = 1;
+
+       if (pci_msi_count(dev) == 0) {
+               sc->using_msi = 0;
+               goto intx;
+       }
+
+       num_vectors = 1;
+       if (pci_alloc_msi(dev, &num_vectors) != 0) {
+               sc->using_msi = 0;
+               goto intx;
+       }
+
+       sc->intr_rid = 1;
+       sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+           &sc->intr_rid, RF_ACTIVE);
+
+       if (sc->intr_res == NULL) {
+               sc->using_msi = 0;
+               pci_release_msi(dev);
+       }
+
+intx:
+       if (sc->using_msi == 0) {
+               sc->intr_rid = 0;
+               sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+                   &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE);
+               if (sc->intr_res == NULL) {
+                       device_printf(dev, "cannot allocate irq\n");
+                       err = ENXIO;
+                       goto fail;
+               }
+       }
+
+       ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi);
+
+       err = bus_setup_intr(dev, sc->intr_res,
+           INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc,
+           &sc->intr_handle);
+       if (err != 0) {
+               device_printf(dev, "cannot setup interrupt\n");
+               err = ENXIO;
+               goto fail;
+       }
+
+       return (0);
+
+fail:
+       ismt_detach(dev);
+       return (err);
+}
+
+#define ID_INTEL_S1200_SMT0            0x0c598086
+#define ID_INTEL_S1200_SMT1            0x0c5a8086
+#define ID_INTEL_C2000_SMT             0x1f158086
+
+static int
+ismt_probe(device_t dev)
+{
+       const char *desc;
+
+       switch (pci_get_devid(dev)) {
+       case ID_INTEL_S1200_SMT0:
+               desc = "Atom Processor S1200 SMBus 2.0 Controller 0";
+               break;
+       case ID_INTEL_S1200_SMT1:
+               desc = "Atom Processor S1200 SMBus 2.0 Controller 1";
+               break;
+       case ID_INTEL_C2000_SMT:
+               desc = "Atom Processor C2000 SMBus 2.0";
+               break;
+       default:
+               return (ENXIO);
+       }
+
+       device_set_desc(dev, desc);
+       return (BUS_PROBE_DEFAULT);
+}
+
+/* Device methods */
+static device_method_t ismt_pci_methods[] = {
+        DEVMETHOD(device_probe,                ismt_probe),
+        DEVMETHOD(device_attach,       ismt_attach),
+        DEVMETHOD(device_detach,       ismt_detach),
+
+        DEVMETHOD(smbus_callback,      ismt_callback),
+        DEVMETHOD(smbus_quick,         ismt_quick),
+        DEVMETHOD(smbus_sendb,         ismt_sendb),
+        DEVMETHOD(smbus_recvb,         ismt_recvb),
+        DEVMETHOD(smbus_writeb,                ismt_writeb),
+        DEVMETHOD(smbus_writew,                ismt_writew),
+        DEVMETHOD(smbus_readb,         ismt_readb),
+        DEVMETHOD(smbus_readw,         ismt_readw),
+        DEVMETHOD(smbus_pcall,         ismt_pcall),
+        DEVMETHOD(smbus_bwrite,                ismt_bwrite),
+        DEVMETHOD(smbus_bread,         ismt_bread),
+
+       DEVMETHOD_END
+};
+
+static driver_t ismt_pci_driver = {
+       "ismt",
+       ismt_pci_methods,
+       sizeof(struct ismt_softc)
+};
+
+static devclass_t ismt_pci_devclass;
+
+DRIVER_MODULE(ismt, pci, ismt_pci_driver, ismt_pci_devclass, 0, 0);
+DRIVER_MODULE(smbus, ismt, smbus_driver, smbus_devclass, 0, 0);
+
+MODULE_DEPEND(ismt, pci, 1, 1, 1);
+MODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(ismt, 1);

Modified: stable/10/sys/modules/i2c/controllers/Makefile
==============================================================================
--- stable/10/sys/modules/i2c/controllers/Makefile      Mon Jan 11 17:52:42 
2016        (r293674)
+++ stable/10/sys/modules/i2c/controllers/Makefile      Mon Jan 11 17:53:24 
2016        (r293675)
@@ -3,7 +3,7 @@
 .if ${MACHINE} == "pc98"
 SUBDIR = lpbb
 .else
-SUBDIR = alpm amdpm amdsmb ichsmb intpm nfsmb viapm lpbb pcf
+SUBDIR = alpm amdpm amdsmb ichsmb intpm ismt nfsmb viapm lpbb pcf
 .endif
 
 .include <bsd.subdir.mk>

Added: stable/10/sys/modules/i2c/controllers/ismt/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/sys/modules/i2c/controllers/ismt/Makefile Mon Jan 11 17:53:24 
2016        (r293675)
@@ -0,0 +1,8 @@
+#$FreeBSD$
+
+.PATH:         ${.CURDIR}/../../../../dev/ismt
+KMOD           = ismt
+SRCS           = device_if.h bus_if.h iicbb_if.h pci_if.h smbus_if.h \
+                 ismt.c
+
+.include <bsd.kmod.mk>
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to