Index: stable/11/share/man/man4/ismt.4 =================================================================== --- stable/11/share/man/man4/ismt.4 (revision 358709) +++ stable/11/share/man/man4/ismt.4 (revision 358710) @@ -1,60 +1,60 @@ .\" .\" 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 .\" .\" $FreeBSD$ .\" -.Dd January 11, 2016 +.Dd March 4, 2020 .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. +in the Intel Atom S1200, C2000 and C3000 CPUs. .Sh SEE ALSO .Xr ichsmb 4 , .Xr smb 4 , .Xr smbus 4 .Sh HISTORY The .Nm driver first appeared in .Fx 10.3 . .Sh AUTHORS .An Jim Harris Aq Mt jimharris@FreeBSD.org Index: stable/11/sys/dev/ismt/ismt.c =================================================================== --- stable/11/sys/dev/ismt/ismt.c (revision 358709) +++ stable/11/sys/dev/ismt/ismt.c (revision 358710) @@ -1,778 +1,782 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 << 1) | (is_read)) /* iSMT General Register address offsets (SMBBAR + ) */ #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 +#define ID_INTEL_C3000_SMT 0x19ac8086 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; + case ID_INTEL_C3000_SMT: + desc = "Atom Processor C3000 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); Index: stable/11 =================================================================== --- stable/11 (revision 358709) +++ stable/11 (revision 358710) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r358595,358619 Index: stable/12/share/man/man4/ismt.4 =================================================================== --- stable/12/share/man/man4/ismt.4 (revision 358709) +++ stable/12/share/man/man4/ismt.4 (revision 358710) @@ -1,60 +1,60 @@ .\" .\" 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 .\" .\" $FreeBSD$ .\" -.Dd January 11, 2016 +.Dd March 4, 2020 .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. +in the Intel Atom S1200, C2000 and C3000 CPUs. .Sh SEE ALSO .Xr ichsmb 4 , .Xr smb 4 , .Xr smbus 4 .Sh HISTORY The .Nm driver first appeared in .Fx 10.3 . .Sh AUTHORS .An Jim Harris Aq Mt jimharris@FreeBSD.org Index: stable/12/sys/dev/ismt/ismt.c =================================================================== --- stable/12/sys/dev/ismt/ismt.c (revision 358709) +++ stable/12/sys/dev/ismt/ismt.c (revision 358710) @@ -1,778 +1,782 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 << 1) | (is_read)) /* iSMT General Register address offsets (SMBBAR + ) */ #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 +#define ID_INTEL_C3000_SMT 0x19ac8086 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; + case ID_INTEL_C3000_SMT: + desc = "Atom Processor C3000 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); Index: stable/12 =================================================================== --- stable/12 (revision 358709) +++ stable/12 (revision 358710) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r358595,358619