1266474Sjimharris/*- 2266474Sjimharris * Copyright (C) 2014 Intel Corporation 3266474Sjimharris * All rights reserved. 4266474Sjimharris * 5266474Sjimharris * Redistribution and use in source and binary forms, with or without 6266474Sjimharris * modification, are permitted provided that the following conditions 7266474Sjimharris * are met: 8266474Sjimharris * 1. Redistributions of source code must retain the above copyright 9266474Sjimharris * notice, this list of conditions and the following disclaimer. 10266474Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11266474Sjimharris * notice, this list of conditions and the following disclaimer in the 12266474Sjimharris * documentation and/or other materials provided with the distribution. 13266474Sjimharris * 3. Neither the name of Intel Corporation nor the names of its 14266474Sjimharris * contributors may be used to endorse or promote products derived from 15266474Sjimharris * this software without specific prior written permission. 16266474Sjimharris * 17266474Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18266474Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19266474Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20266474Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21266474Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22266474Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23266474Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24266474Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25266474Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26266474Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27266474Sjimharris * SUCH DAMAGE. 28266474Sjimharris */ 29266474Sjimharris 30266474Sjimharris#include <sys/cdefs.h> 31266474Sjimharris__FBSDID("$FreeBSD: stable/11/sys/dev/ismt/ismt.c 359360 2020-03-27 15:20:19Z jhibbits $"); 32266474Sjimharris 33266474Sjimharris#include <sys/param.h> 34266474Sjimharris#include <sys/systm.h> 35266474Sjimharris#include <sys/bus.h> 36266474Sjimharris#include <sys/errno.h> 37266474Sjimharris#include <sys/kernel.h> 38266474Sjimharris#include <sys/lock.h> 39266474Sjimharris#include <sys/module.h> 40266474Sjimharris#include <sys/priority.h> 41266474Sjimharris#include <sys/proc.h> 42266474Sjimharris#include <sys/syslog.h> 43266474Sjimharris 44266474Sjimharris#include <machine/bus.h> 45266474Sjimharris#include <sys/rman.h> 46266474Sjimharris#include <machine/resource.h> 47266474Sjimharris 48266474Sjimharris#include <dev/pci/pcireg.h> 49266474Sjimharris#include <dev/pci/pcivar.h> 50266474Sjimharris#include <dev/smbus/smbconf.h> 51266474Sjimharris 52266474Sjimharris#include "smbus_if.h" 53266474Sjimharris 54266474Sjimharris#define ISMT_DESC_ENTRIES 32 55266474Sjimharris 56266474Sjimharris/* Hardware Descriptor Constants - Control Field */ 57266474Sjimharris#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ 58266474Sjimharris#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ 59266474Sjimharris#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ 60266474Sjimharris#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ 61266474Sjimharris#define ISMT_DESC_I2C 0x20 /* I2C Enable */ 62266474Sjimharris#define ISMT_DESC_INT 0x40 /* Interrupt */ 63266474Sjimharris#define ISMT_DESC_SOE 0x80 /* Stop On Error */ 64266474Sjimharris 65266474Sjimharris/* Hardware Descriptor Constants - Status Field */ 66266474Sjimharris#define ISMT_DESC_SCS 0x01 /* Success */ 67266474Sjimharris#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ 68266474Sjimharris#define ISMT_DESC_NAK 0x08 /* NAK Received */ 69266474Sjimharris#define ISMT_DESC_CRC 0x10 /* CRC Error */ 70266474Sjimharris#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ 71266474Sjimharris#define ISMT_DESC_COL 0x40 /* Collisions */ 72266474Sjimharris#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ 73266474Sjimharris 74266474Sjimharris/* Macros */ 75359360Sjhibbits#define ISMT_DESC_ADDR_RW(addr, is_read) ((addr) | (is_read)) 76266474Sjimharris 77266474Sjimharris/* iSMT General Register address offsets (SMBBAR + <addr>) */ 78266474Sjimharris#define ISMT_GR_GCTRL 0x000 /* General Control */ 79266474Sjimharris#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ 80266474Sjimharris#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ 81266474Sjimharris#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ 82266474Sjimharris#define ISMT_GR_ERRSTS 0x018 /* Error Status */ 83266474Sjimharris#define ISMT_GR_ERRINFO 0x01c /* Error Information */ 84266474Sjimharris 85266474Sjimharris/* iSMT Master Registers */ 86266474Sjimharris#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ 87266474Sjimharris#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ 88266474Sjimharris#define ISMT_MSTR_MSTS 0x10c /* Master Status */ 89266474Sjimharris#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ 90266474Sjimharris#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ 91266474Sjimharris 92266474Sjimharris/* iSMT Miscellaneous Registers */ 93266474Sjimharris#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ 94266474Sjimharris 95266474Sjimharris/* General Control Register (GCTRL) bit definitions */ 96266474Sjimharris#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ 97266474Sjimharris#define ISMT_GCTRL_KILL 0x08 /* Kill */ 98266474Sjimharris#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ 99266474Sjimharris 100266474Sjimharris/* Master Control Register (MCTRL) bit definitions */ 101266474Sjimharris#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ 102266474Sjimharris#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ 103266474Sjimharris#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ 104266474Sjimharris 105266474Sjimharris/* Master Status Register (MSTS) bit definitions */ 106266474Sjimharris#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ 107266474Sjimharris#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ 108266474Sjimharris#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ 109266474Sjimharris#define ISMT_MSTS_IP 0x01 /* In Progress */ 110266474Sjimharris 111266474Sjimharris/* Master Descriptor Size (MDS) bit definitions */ 112266474Sjimharris#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ 113266474Sjimharris 114266474Sjimharris/* SMBus PHY Global Timing Register (SPGT) bit definitions */ 115266474Sjimharris#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ 116266474Sjimharris#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ 117266474Sjimharris#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ 118266474Sjimharris#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ 119266474Sjimharris#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ 120266474Sjimharris 121266474Sjimharris/* MSI Control Register (MSICTL) bit definitions */ 122266474Sjimharris#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ 123266474Sjimharris 124266474Sjimharris#define ISMT_MAX_BLOCK_SIZE 32 /* per SMBus spec */ 125266474Sjimharris 126266474Sjimharris//#define ISMT_DEBUG device_printf 127266474Sjimharris#ifndef ISMT_DEBUG 128266474Sjimharris#define ISMT_DEBUG(...) 129266474Sjimharris#endif 130266474Sjimharris 131266474Sjimharris/* iSMT Hardware Descriptor */ 132266474Sjimharrisstruct ismt_desc { 133266474Sjimharris uint8_t tgtaddr_rw; /* target address & r/w bit */ 134266474Sjimharris uint8_t wr_len_cmd; /* write length in bytes or a command */ 135266474Sjimharris uint8_t rd_len; /* read length */ 136266474Sjimharris uint8_t control; /* control bits */ 137266474Sjimharris uint8_t status; /* status bits */ 138266474Sjimharris uint8_t retry; /* collision retry and retry count */ 139266474Sjimharris uint8_t rxbytes; /* received bytes */ 140266474Sjimharris uint8_t txbytes; /* transmitted bytes */ 141266474Sjimharris uint32_t dptr_low; /* lower 32 bit of the data pointer */ 142266474Sjimharris uint32_t dptr_high; /* upper 32 bit of the data pointer */ 143266474Sjimharris} __packed; 144266474Sjimharris 145266474Sjimharris#define DESC_SIZE (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc)) 146266474Sjimharris 147266474Sjimharris#define DMA_BUFFER_SIZE 64 148266474Sjimharris 149266474Sjimharrisstruct ismt_softc { 150266474Sjimharris device_t pcidev; 151266474Sjimharris device_t smbdev; 152266474Sjimharris 153266474Sjimharris struct thread *bus_reserved; 154266474Sjimharris 155266474Sjimharris int intr_rid; 156266474Sjimharris struct resource *intr_res; 157266474Sjimharris void *intr_handle; 158266474Sjimharris 159266474Sjimharris bus_space_tag_t mmio_tag; 160266474Sjimharris bus_space_handle_t mmio_handle; 161266474Sjimharris int mmio_rid; 162266474Sjimharris struct resource *mmio_res; 163266474Sjimharris 164266474Sjimharris uint8_t head; 165266474Sjimharris 166266474Sjimharris struct ismt_desc *desc; 167266474Sjimharris bus_dma_tag_t desc_dma_tag; 168266474Sjimharris bus_dmamap_t desc_dma_map; 169266474Sjimharris uint64_t desc_bus_addr; 170266474Sjimharris 171266474Sjimharris uint8_t *dma_buffer; 172266474Sjimharris bus_dma_tag_t dma_buffer_dma_tag; 173266474Sjimharris bus_dmamap_t dma_buffer_dma_map; 174266474Sjimharris uint64_t dma_buffer_bus_addr; 175266474Sjimharris 176266474Sjimharris uint8_t using_msi; 177266474Sjimharris}; 178266474Sjimharris 179266474Sjimharrisstatic void 180266474Sjimharrisismt_intr(void *arg) 181266474Sjimharris{ 182266474Sjimharris struct ismt_softc *sc = arg; 183266474Sjimharris uint32_t val; 184266474Sjimharris 185266474Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS); 186266474Sjimharris ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val); 187266474Sjimharris 188266474Sjimharris val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS); 189266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val); 190266474Sjimharris 191266474Sjimharris wakeup(sc); 192266474Sjimharris} 193266474Sjimharris 194266474Sjimharrisstatic int 195266474Sjimharrisismt_callback(device_t dev, int index, void *data) 196266474Sjimharris{ 197266474Sjimharris struct ismt_softc *sc; 198266474Sjimharris int acquired, err; 199266474Sjimharris 200266474Sjimharris sc = device_get_softc(dev); 201266474Sjimharris 202266474Sjimharris switch (index) { 203266474Sjimharris case SMB_REQUEST_BUS: 204266474Sjimharris acquired = atomic_cmpset_ptr( 205266474Sjimharris (uintptr_t *)&sc->bus_reserved, 206266474Sjimharris (uintptr_t)NULL, (uintptr_t)curthread); 207266474Sjimharris ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired); 208266474Sjimharris if (acquired) 209266474Sjimharris err = 0; 210266474Sjimharris else 211266474Sjimharris err = EWOULDBLOCK; 212266474Sjimharris break; 213266474Sjimharris case SMB_RELEASE_BUS: 214266474Sjimharris KASSERT(sc->bus_reserved == curthread, 215266474Sjimharris ("SMB_RELEASE_BUS called by wrong thread\n")); 216266474Sjimharris ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n"); 217266474Sjimharris atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved, 218266474Sjimharris (uintptr_t)NULL); 219266474Sjimharris err = 0; 220266474Sjimharris break; 221266474Sjimharris default: 222266474Sjimharris err = SMB_EABORT; 223266474Sjimharris break; 224266474Sjimharris } 225266474Sjimharris 226266474Sjimharris return (err); 227266474Sjimharris} 228266474Sjimharris 229266474Sjimharrisstatic struct ismt_desc * 230266474Sjimharrisismt_alloc_desc(struct ismt_softc *sc) 231266474Sjimharris{ 232266474Sjimharris struct ismt_desc *desc; 233266474Sjimharris 234266474Sjimharris KASSERT(sc->bus_reserved == curthread, 235266474Sjimharris ("curthread %p did not request bus (%p has reserved)\n", 236266474Sjimharris curthread, sc->bus_reserved)); 237266474Sjimharris 238266474Sjimharris desc = &sc->desc[sc->head++]; 239266474Sjimharris if (sc->head == ISMT_DESC_ENTRIES) 240266474Sjimharris sc->head = 0; 241266474Sjimharris 242266474Sjimharris memset(desc, 0, sizeof(*desc)); 243266474Sjimharris 244266474Sjimharris return (desc); 245266474Sjimharris} 246266474Sjimharris 247266474Sjimharrisstatic int 248266474Sjimharrisismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave, 249266474Sjimharris uint8_t is_read) 250266474Sjimharris{ 251266474Sjimharris uint32_t err, fmhp, val; 252266474Sjimharris 253266474Sjimharris desc->control |= ISMT_DESC_FAIR; 254266474Sjimharris if (sc->using_msi) 255266474Sjimharris desc->control |= ISMT_DESC_INT; 256266474Sjimharris 257266474Sjimharris desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read); 258266474Sjimharris desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL); 259266474Sjimharris desc->dptr_high = (sc->dma_buffer_bus_addr >> 32); 260266474Sjimharris 261266474Sjimharris wmb(); 262266474Sjimharris 263266474Sjimharris fmhp = sc->head << 16; 264266474Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL); 265266474Sjimharris val &= ~ISMT_MCTRL_FMHP; 266266474Sjimharris val |= fmhp; 267266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val); 268266474Sjimharris 269266474Sjimharris /* set the start bit */ 270266474Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL); 271266474Sjimharris val |= ISMT_MCTRL_SS; 272266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val); 273266474Sjimharris 274266474Sjimharris err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz); 275266474Sjimharris 276266474Sjimharris if (err != 0) { 277266474Sjimharris ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__); 278266474Sjimharris return (SMB_ETIMEOUT); 279266474Sjimharris } 280266474Sjimharris 281266474Sjimharris ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status); 282266474Sjimharris 283266474Sjimharris if (desc->status & ISMT_DESC_SCS) 284266474Sjimharris return (SMB_ENOERR); 285266474Sjimharris 286266474Sjimharris if (desc->status & ISMT_DESC_NAK) 287266474Sjimharris return (SMB_ENOACK); 288266474Sjimharris 289266474Sjimharris if (desc->status & ISMT_DESC_CRC) 290266474Sjimharris return (SMB_EBUSERR); 291266474Sjimharris 292266474Sjimharris if (desc->status & ISMT_DESC_COL) 293266474Sjimharris return (SMB_ECOLLI); 294266474Sjimharris 295266474Sjimharris if (desc->status & ISMT_DESC_LPR) 296266474Sjimharris return (SMB_EINVAL); 297266474Sjimharris 298266474Sjimharris if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) 299266474Sjimharris return (SMB_ETIMEOUT); 300266474Sjimharris 301266474Sjimharris return (SMB_EBUSERR); 302266474Sjimharris} 303266474Sjimharris 304266474Sjimharris 305266474Sjimharrisstatic int 306266474Sjimharrisismt_quick(device_t dev, u_char slave, int how) 307266474Sjimharris{ 308266474Sjimharris struct ismt_desc *desc; 309266474Sjimharris struct ismt_softc *sc; 310266474Sjimharris int is_read; 311266474Sjimharris 312266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 313266474Sjimharris 314266474Sjimharris if (how != SMB_QREAD && how != SMB_QWRITE) { 315266474Sjimharris return (SMB_ENOTSUPP); 316266474Sjimharris } 317266474Sjimharris 318266474Sjimharris sc = device_get_softc(dev); 319266474Sjimharris desc = ismt_alloc_desc(sc); 320266474Sjimharris is_read = (how == SMB_QREAD ? 1 : 0); 321266474Sjimharris return (ismt_submit(sc, desc, slave, is_read)); 322266474Sjimharris} 323266474Sjimharris 324266474Sjimharrisstatic int 325266474Sjimharrisismt_sendb(device_t dev, u_char slave, char byte) 326266474Sjimharris{ 327266474Sjimharris struct ismt_desc *desc; 328266474Sjimharris struct ismt_softc *sc; 329266474Sjimharris 330266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 331266474Sjimharris 332266474Sjimharris sc = device_get_softc(dev); 333266474Sjimharris desc = ismt_alloc_desc(sc); 334266474Sjimharris desc->control = ISMT_DESC_CWRL; 335266474Sjimharris desc->wr_len_cmd = byte; 336266474Sjimharris 337266474Sjimharris return (ismt_submit(sc, desc, slave, 0)); 338266474Sjimharris} 339266474Sjimharris 340266474Sjimharrisstatic int 341266474Sjimharrisismt_recvb(device_t dev, u_char slave, char *byte) 342266474Sjimharris{ 343266474Sjimharris struct ismt_desc *desc; 344266474Sjimharris struct ismt_softc *sc; 345266474Sjimharris int err; 346266474Sjimharris 347266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 348266474Sjimharris 349266474Sjimharris sc = device_get_softc(dev); 350266474Sjimharris desc = ismt_alloc_desc(sc); 351266474Sjimharris desc->rd_len = 1; 352266474Sjimharris 353266474Sjimharris err = ismt_submit(sc, desc, slave, 1); 354266474Sjimharris 355266474Sjimharris if (err != SMB_ENOERR) 356266474Sjimharris return (err); 357266474Sjimharris 358266474Sjimharris *byte = sc->dma_buffer[0]; 359266474Sjimharris 360266474Sjimharris return (err); 361266474Sjimharris} 362266474Sjimharris 363266474Sjimharrisstatic int 364266474Sjimharrisismt_writeb(device_t dev, u_char slave, char cmd, char byte) 365266474Sjimharris{ 366266474Sjimharris struct ismt_desc *desc; 367266474Sjimharris struct ismt_softc *sc; 368266474Sjimharris 369266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 370266474Sjimharris 371266474Sjimharris sc = device_get_softc(dev); 372266474Sjimharris desc = ismt_alloc_desc(sc); 373266474Sjimharris desc->wr_len_cmd = 2; 374266474Sjimharris sc->dma_buffer[0] = cmd; 375266474Sjimharris sc->dma_buffer[1] = byte; 376266474Sjimharris 377266474Sjimharris return (ismt_submit(sc, desc, slave, 0)); 378266474Sjimharris} 379266474Sjimharris 380266474Sjimharrisstatic int 381266474Sjimharrisismt_writew(device_t dev, u_char slave, char cmd, short word) 382266474Sjimharris{ 383266474Sjimharris struct ismt_desc *desc; 384266474Sjimharris struct ismt_softc *sc; 385266474Sjimharris 386266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 387266474Sjimharris 388266474Sjimharris sc = device_get_softc(dev); 389266474Sjimharris desc = ismt_alloc_desc(sc); 390266474Sjimharris desc->wr_len_cmd = 3; 391266474Sjimharris sc->dma_buffer[0] = cmd; 392266474Sjimharris sc->dma_buffer[1] = word & 0xFF; 393266474Sjimharris sc->dma_buffer[2] = word >> 8; 394266474Sjimharris 395266474Sjimharris return (ismt_submit(sc, desc, slave, 0)); 396266474Sjimharris} 397266474Sjimharris 398266474Sjimharrisstatic int 399266474Sjimharrisismt_readb(device_t dev, u_char slave, char cmd, char *byte) 400266474Sjimharris{ 401266474Sjimharris struct ismt_desc *desc; 402266474Sjimharris struct ismt_softc *sc; 403266474Sjimharris int err; 404266474Sjimharris 405266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 406266474Sjimharris 407266474Sjimharris sc = device_get_softc(dev); 408266474Sjimharris desc = ismt_alloc_desc(sc); 409266474Sjimharris desc->control = ISMT_DESC_CWRL; 410266474Sjimharris desc->wr_len_cmd = cmd; 411266474Sjimharris desc->rd_len = 1; 412266474Sjimharris 413266474Sjimharris err = ismt_submit(sc, desc, slave, 1); 414266474Sjimharris 415266474Sjimharris if (err != SMB_ENOERR) 416266474Sjimharris return (err); 417266474Sjimharris 418266474Sjimharris *byte = sc->dma_buffer[0]; 419266474Sjimharris 420266474Sjimharris return (err); 421266474Sjimharris} 422266474Sjimharris 423266474Sjimharrisstatic int 424266474Sjimharrisismt_readw(device_t dev, u_char slave, char cmd, short *word) 425266474Sjimharris{ 426266474Sjimharris struct ismt_desc *desc; 427266474Sjimharris struct ismt_softc *sc; 428266474Sjimharris int err; 429266474Sjimharris 430266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 431266474Sjimharris 432266474Sjimharris sc = device_get_softc(dev); 433266474Sjimharris desc = ismt_alloc_desc(sc); 434266474Sjimharris desc->control = ISMT_DESC_CWRL; 435266474Sjimharris desc->wr_len_cmd = cmd; 436266474Sjimharris desc->rd_len = 2; 437266474Sjimharris 438266474Sjimharris err = ismt_submit(sc, desc, slave, 1); 439266474Sjimharris 440266474Sjimharris if (err != SMB_ENOERR) 441266474Sjimharris return (err); 442266474Sjimharris 443266474Sjimharris *word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8); 444266474Sjimharris 445266474Sjimharris return (err); 446266474Sjimharris} 447266474Sjimharris 448266474Sjimharrisstatic int 449266474Sjimharrisismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 450266474Sjimharris{ 451266474Sjimharris struct ismt_desc *desc; 452266474Sjimharris struct ismt_softc *sc; 453266474Sjimharris int err; 454266474Sjimharris 455266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 456266474Sjimharris 457266474Sjimharris sc = device_get_softc(dev); 458266474Sjimharris desc = ismt_alloc_desc(sc); 459266474Sjimharris desc->wr_len_cmd = 3; 460266474Sjimharris desc->rd_len = 2; 461266474Sjimharris sc->dma_buffer[0] = cmd; 462266474Sjimharris sc->dma_buffer[1] = sdata & 0xff; 463266474Sjimharris sc->dma_buffer[2] = sdata >> 8; 464266474Sjimharris 465266474Sjimharris err = ismt_submit(sc, desc, slave, 0); 466266474Sjimharris 467266474Sjimharris if (err != SMB_ENOERR) 468266474Sjimharris return (err); 469266474Sjimharris 470266474Sjimharris *rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8); 471266474Sjimharris 472266474Sjimharris return (err); 473266474Sjimharris} 474266474Sjimharris 475266474Sjimharrisstatic int 476266474Sjimharrisismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 477266474Sjimharris{ 478266474Sjimharris struct ismt_desc *desc; 479266474Sjimharris struct ismt_softc *sc; 480266474Sjimharris 481266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 482266474Sjimharris 483266474Sjimharris if (count == 0 || count > ISMT_MAX_BLOCK_SIZE) 484266474Sjimharris return (SMB_EINVAL); 485266474Sjimharris 486266474Sjimharris sc = device_get_softc(dev); 487266474Sjimharris desc = ismt_alloc_desc(sc); 488266474Sjimharris desc->control = ISMT_DESC_I2C; 489266474Sjimharris desc->wr_len_cmd = count + 1; 490266474Sjimharris sc->dma_buffer[0] = cmd; 491266474Sjimharris memcpy(&sc->dma_buffer[1], buf, count); 492266474Sjimharris 493266474Sjimharris return (ismt_submit(sc, desc, slave, 0)); 494266474Sjimharris} 495266474Sjimharris 496266474Sjimharrisstatic int 497266474Sjimharrisismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 498266474Sjimharris{ 499266474Sjimharris struct ismt_desc *desc; 500266474Sjimharris struct ismt_softc *sc; 501266474Sjimharris int err; 502266474Sjimharris 503266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 504266474Sjimharris 505266474Sjimharris if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE) 506266474Sjimharris return (SMB_EINVAL); 507266474Sjimharris 508266474Sjimharris sc = device_get_softc(dev); 509266474Sjimharris desc = ismt_alloc_desc(sc); 510266474Sjimharris desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL; 511266474Sjimharris desc->wr_len_cmd = cmd; 512266474Sjimharris desc->rd_len = *count; 513266474Sjimharris 514266474Sjimharris err = ismt_submit(sc, desc, slave, 0); 515266474Sjimharris 516266474Sjimharris if (err != SMB_ENOERR) 517266474Sjimharris return (err); 518266474Sjimharris 519266474Sjimharris memcpy(buf, sc->dma_buffer, desc->rxbytes); 520266474Sjimharris *count = desc->rxbytes; 521266474Sjimharris 522266474Sjimharris return (err); 523266474Sjimharris} 524266474Sjimharris 525266474Sjimharrisstatic int 526266474Sjimharrisismt_detach(device_t dev) 527266474Sjimharris{ 528266474Sjimharris struct ismt_softc *sc; 529266474Sjimharris int error; 530266474Sjimharris 531266474Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 532266474Sjimharris sc = device_get_softc(dev); 533266474Sjimharris 534266474Sjimharris error = bus_generic_detach(dev); 535266474Sjimharris if (error) 536266474Sjimharris return (error); 537266474Sjimharris 538266474Sjimharris device_delete_child(dev, sc->smbdev); 539266474Sjimharris 540266474Sjimharris if (sc->intr_handle != NULL) { 541266474Sjimharris bus_teardown_intr(dev, sc->intr_res, sc->intr_handle); 542266474Sjimharris sc->intr_handle = NULL; 543266474Sjimharris } 544266474Sjimharris if (sc->intr_res != NULL) { 545266474Sjimharris bus_release_resource(dev, 546266474Sjimharris SYS_RES_IRQ, sc->intr_rid, sc->intr_res); 547266474Sjimharris sc->intr_res = NULL; 548266474Sjimharris } 549266474Sjimharris if (sc->using_msi == 1) 550266474Sjimharris pci_release_msi(dev); 551266474Sjimharris 552266474Sjimharris if (sc->mmio_res != NULL) { 553266474Sjimharris bus_release_resource(dev, 554266474Sjimharris SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res); 555266474Sjimharris sc->mmio_res = NULL; 556266474Sjimharris } 557266474Sjimharris 558266474Sjimharris bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map); 559266474Sjimharris bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map); 560266474Sjimharris 561266474Sjimharris bus_dmamem_free(sc->desc_dma_tag, sc->desc, 562266474Sjimharris sc->desc_dma_map); 563266474Sjimharris bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer, 564266474Sjimharris sc->dma_buffer_dma_map); 565266474Sjimharris 566266474Sjimharris bus_dma_tag_destroy(sc->desc_dma_tag); 567266474Sjimharris bus_dma_tag_destroy(sc->dma_buffer_dma_tag); 568266474Sjimharris 569266474Sjimharris pci_disable_busmaster(dev); 570266474Sjimharris 571266474Sjimharris return 0; 572266474Sjimharris} 573266474Sjimharris 574266474Sjimharrisstatic void 575266474Sjimharrisismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error) 576266474Sjimharris{ 577266474Sjimharris uint64_t *bus_addr = (uint64_t *)arg; 578266474Sjimharris 579266474Sjimharris KASSERT(error == 0, ("%s: error=%d\n", __func__, error)); 580266474Sjimharris KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg)); 581266474Sjimharris 582266474Sjimharris *bus_addr = seg[0].ds_addr; 583266474Sjimharris} 584266474Sjimharris 585266474Sjimharrisstatic int 586266474Sjimharrisismt_attach(device_t dev) 587266474Sjimharris{ 588266474Sjimharris struct ismt_softc *sc = device_get_softc(dev); 589266474Sjimharris int err, num_vectors, val; 590266474Sjimharris 591266474Sjimharris sc->pcidev = dev; 592266474Sjimharris pci_enable_busmaster(dev); 593266474Sjimharris 594266474Sjimharris if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) { 595266474Sjimharris device_printf(dev, "no smbus child found\n"); 596266474Sjimharris err = ENXIO; 597266474Sjimharris goto fail; 598266474Sjimharris } 599266474Sjimharris 600266474Sjimharris sc->mmio_rid = PCIR_BAR(0); 601266474Sjimharris sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 602266474Sjimharris &sc->mmio_rid, RF_ACTIVE); 603266474Sjimharris if (sc->mmio_res == NULL) { 604266474Sjimharris device_printf(dev, "cannot allocate mmio region\n"); 605266474Sjimharris err = ENOMEM; 606266474Sjimharris goto fail; 607266474Sjimharris } 608266474Sjimharris 609266474Sjimharris sc->mmio_tag = rman_get_bustag(sc->mmio_res); 610266474Sjimharris sc->mmio_handle = rman_get_bushandle(sc->mmio_res); 611266474Sjimharris 612266474Sjimharris /* Attach "smbus" child */ 613266474Sjimharris if ((err = bus_generic_attach(dev)) != 0) { 614266474Sjimharris device_printf(dev, "failed to attach child: %d\n", err); 615266474Sjimharris err = ENXIO; 616266474Sjimharris goto fail; 617266474Sjimharris } 618266474Sjimharris 619266474Sjimharris bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE, 620266474Sjimharris BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 621266474Sjimharris DESC_SIZE, 1, DESC_SIZE, 622266474Sjimharris 0, NULL, NULL, &sc->desc_dma_tag); 623266474Sjimharris 624266474Sjimharris bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE, 625266474Sjimharris BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 626266474Sjimharris DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE, 627266474Sjimharris 0, NULL, NULL, &sc->dma_buffer_dma_tag); 628266474Sjimharris 629266474Sjimharris bus_dmamap_create(sc->desc_dma_tag, 0, 630266474Sjimharris &sc->desc_dma_map); 631266474Sjimharris bus_dmamap_create(sc->dma_buffer_dma_tag, 0, 632266474Sjimharris &sc->dma_buffer_dma_map); 633266474Sjimharris 634266474Sjimharris bus_dmamem_alloc(sc->desc_dma_tag, 635266474Sjimharris (void **)&sc->desc, BUS_DMA_WAITOK, 636266474Sjimharris &sc->desc_dma_map); 637266474Sjimharris bus_dmamem_alloc(sc->dma_buffer_dma_tag, 638266474Sjimharris (void **)&sc->dma_buffer, BUS_DMA_WAITOK, 639266474Sjimharris &sc->dma_buffer_dma_map); 640266474Sjimharris 641266474Sjimharris bus_dmamap_load(sc->desc_dma_tag, 642266474Sjimharris sc->desc_dma_map, sc->desc, DESC_SIZE, 643266474Sjimharris ismt_single_map, &sc->desc_bus_addr, 0); 644266474Sjimharris bus_dmamap_load(sc->dma_buffer_dma_tag, 645266474Sjimharris sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE, 646266474Sjimharris ismt_single_map, &sc->dma_buffer_bus_addr, 0); 647266474Sjimharris 648266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA, 649266474Sjimharris (sc->desc_bus_addr & 0xFFFFFFFFLL)); 650266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4, 651266474Sjimharris (sc->desc_bus_addr >> 32)); 652266474Sjimharris 653266474Sjimharris /* initialize the Master Control Register (MCTRL) */ 654266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE); 655266474Sjimharris 656266474Sjimharris /* initialize the Master Status Register (MSTS) */ 657266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0); 658266474Sjimharris 659266474Sjimharris /* initialize the Master Descriptor Size (MDS) */ 660266474Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS); 661266474Sjimharris val &= ~ISMT_MDS_MASK; 662266474Sjimharris val |= (ISMT_DESC_ENTRIES - 1); 663266474Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val); 664266474Sjimharris 665266474Sjimharris sc->using_msi = 1; 666266474Sjimharris 667266474Sjimharris if (pci_msi_count(dev) == 0) { 668266474Sjimharris sc->using_msi = 0; 669266474Sjimharris goto intx; 670266474Sjimharris } 671266474Sjimharris 672266474Sjimharris num_vectors = 1; 673266474Sjimharris if (pci_alloc_msi(dev, &num_vectors) != 0) { 674266474Sjimharris sc->using_msi = 0; 675266474Sjimharris goto intx; 676266474Sjimharris } 677266474Sjimharris 678266474Sjimharris sc->intr_rid = 1; 679266474Sjimharris sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 680266474Sjimharris &sc->intr_rid, RF_ACTIVE); 681266474Sjimharris 682266474Sjimharris if (sc->intr_res == NULL) { 683266474Sjimharris sc->using_msi = 0; 684266474Sjimharris pci_release_msi(dev); 685266474Sjimharris } 686266474Sjimharris 687266474Sjimharrisintx: 688266474Sjimharris if (sc->using_msi == 0) { 689266474Sjimharris sc->intr_rid = 0; 690266474Sjimharris sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 691266474Sjimharris &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE); 692266474Sjimharris if (sc->intr_res == NULL) { 693266474Sjimharris device_printf(dev, "cannot allocate irq\n"); 694266474Sjimharris err = ENXIO; 695266474Sjimharris goto fail; 696266474Sjimharris } 697266474Sjimharris } 698266474Sjimharris 699266474Sjimharris ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi); 700266474Sjimharris 701266474Sjimharris err = bus_setup_intr(dev, sc->intr_res, 702266474Sjimharris INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc, 703266474Sjimharris &sc->intr_handle); 704266474Sjimharris if (err != 0) { 705266474Sjimharris device_printf(dev, "cannot setup interrupt\n"); 706266474Sjimharris err = ENXIO; 707266474Sjimharris goto fail; 708266474Sjimharris } 709266474Sjimharris 710266474Sjimharris return (0); 711266474Sjimharris 712266474Sjimharrisfail: 713266474Sjimharris ismt_detach(dev); 714266474Sjimharris return (err); 715266474Sjimharris} 716266474Sjimharris 717266474Sjimharris#define ID_INTEL_S1200_SMT0 0x0c598086 718266474Sjimharris#define ID_INTEL_S1200_SMT1 0x0c5a8086 719266474Sjimharris#define ID_INTEL_C2000_SMT 0x1f158086 720358710Sjhibbits#define ID_INTEL_C3000_SMT 0x19ac8086 721266474Sjimharris 722266474Sjimharrisstatic int 723266474Sjimharrisismt_probe(device_t dev) 724266474Sjimharris{ 725266474Sjimharris const char *desc; 726266474Sjimharris 727266474Sjimharris switch (pci_get_devid(dev)) { 728266474Sjimharris case ID_INTEL_S1200_SMT0: 729266474Sjimharris desc = "Atom Processor S1200 SMBus 2.0 Controller 0"; 730266474Sjimharris break; 731266474Sjimharris case ID_INTEL_S1200_SMT1: 732266474Sjimharris desc = "Atom Processor S1200 SMBus 2.0 Controller 1"; 733266474Sjimharris break; 734266474Sjimharris case ID_INTEL_C2000_SMT: 735266474Sjimharris desc = "Atom Processor C2000 SMBus 2.0"; 736266474Sjimharris break; 737358710Sjhibbits case ID_INTEL_C3000_SMT: 738358710Sjhibbits desc = "Atom Processor C3000 SMBus 2.0"; 739358710Sjhibbits break; 740266474Sjimharris default: 741266474Sjimharris return (ENXIO); 742266474Sjimharris } 743266474Sjimharris 744266474Sjimharris device_set_desc(dev, desc); 745266474Sjimharris return (BUS_PROBE_DEFAULT); 746266474Sjimharris} 747266474Sjimharris 748266474Sjimharris/* Device methods */ 749266474Sjimharrisstatic device_method_t ismt_pci_methods[] = { 750266474Sjimharris DEVMETHOD(device_probe, ismt_probe), 751266474Sjimharris DEVMETHOD(device_attach, ismt_attach), 752266474Sjimharris DEVMETHOD(device_detach, ismt_detach), 753266474Sjimharris 754266474Sjimharris DEVMETHOD(smbus_callback, ismt_callback), 755266474Sjimharris DEVMETHOD(smbus_quick, ismt_quick), 756266474Sjimharris DEVMETHOD(smbus_sendb, ismt_sendb), 757266474Sjimharris DEVMETHOD(smbus_recvb, ismt_recvb), 758266474Sjimharris DEVMETHOD(smbus_writeb, ismt_writeb), 759266474Sjimharris DEVMETHOD(smbus_writew, ismt_writew), 760266474Sjimharris DEVMETHOD(smbus_readb, ismt_readb), 761266474Sjimharris DEVMETHOD(smbus_readw, ismt_readw), 762266474Sjimharris DEVMETHOD(smbus_pcall, ismt_pcall), 763266474Sjimharris DEVMETHOD(smbus_bwrite, ismt_bwrite), 764266474Sjimharris DEVMETHOD(smbus_bread, ismt_bread), 765266474Sjimharris 766266474Sjimharris DEVMETHOD_END 767266474Sjimharris}; 768266474Sjimharris 769266474Sjimharrisstatic driver_t ismt_pci_driver = { 770266474Sjimharris "ismt", 771266474Sjimharris ismt_pci_methods, 772266474Sjimharris sizeof(struct ismt_softc) 773266474Sjimharris}; 774266474Sjimharris 775266474Sjimharrisstatic devclass_t ismt_pci_devclass; 776266474Sjimharris 777266474SjimharrisDRIVER_MODULE(ismt, pci, ismt_pci_driver, ismt_pci_devclass, 0, 0); 778266474SjimharrisDRIVER_MODULE(smbus, ismt, smbus_driver, smbus_devclass, 0, 0); 779266474Sjimharris 780266474SjimharrisMODULE_DEPEND(ismt, pci, 1, 1, 1); 781266474SjimharrisMODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 782266474SjimharrisMODULE_VERSION(ismt, 1); 783