pci_lpc.c revision 257396
155714Skris/*- 255714Skris * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 355714Skris * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 455714Skris * All rights reserved. 555714Skris * 655714Skris * Redistribution and use in source and binary forms, with or without 755714Skris * modification, are permitted provided that the following conditions 8280304Sjkim * are met: 955714Skris * 1. Redistributions of source code must retain the above copyright 1055714Skris * notice, this list of conditions and the following disclaimer. 1155714Skris * 2. Redistributions in binary form must reproduce the above copyright 1255714Skris * notice, this list of conditions and the following disclaimer in the 1355714Skris * documentation and/or other materials provided with the distribution. 1455714Skris * 15280304Sjkim * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 1655714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1755714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1855714Skris * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 1955714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2055714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2155714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22280304Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2355714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2455714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2555714Skris * SUCH DAMAGE. 2655714Skris * 2755714Skris * $FreeBSD: stable/10/usr.sbin/bhyve/pci_lpc.c 257396 2013-10-30 20:42:09Z neel $ 2855714Skris */ 2955714Skris 3055714Skris#include <sys/cdefs.h> 3155714Skris__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/pci_lpc.c 257396 2013-10-30 20:42:09Z neel $"); 3255714Skris 3355714Skris#include <sys/types.h> 3455714Skris 3555714Skris#include <stdio.h> 3655714Skris#include <stdlib.h> 37280304Sjkim#include <string.h> 3855714Skris 3955714Skris#include "inout.h" 40280304Sjkim#include "ioapic.h" 4155714Skris#include "pci_emul.h" 4255714Skris#include "uart_emul.h" 4355714Skris 4455714Skrisstatic struct pci_devinst *lpc_bridge; 4555714Skris 4655714Skris#define LPC_UART_NUM 2 4755714Skrisstatic struct lpc_uart_softc { 4855714Skris struct uart_softc *uart_softc; 4955714Skris const char *opts; 5055714Skris int iobase; 5155714Skris int irq; 52280304Sjkim} lpc_uart_softc[LPC_UART_NUM]; 5355714Skris 5455714Skrisstatic const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2" }; 5555714Skris 5655714Skris/* 5755714Skris * LPC device configuration is in the following form: 58100928Snectar * <lpc_device_name>[,<options>] 59238405Sjkim * For e.g. "com1,stdio" 60100928Snectar */ 61100928Snectarint 62100928Snectarlpc_device_parse(const char *opts) 63100928Snectar{ 64100928Snectar int unit, error; 65100928Snectar char *str, *cpy, *lpcdev; 66280304Sjkim 67100928Snectar error = -1; 68100928Snectar str = cpy = strdup(opts); 69100928Snectar lpcdev = strsep(&str, ","); 70100928Snectar if (lpcdev != NULL) { 71100928Snectar for (unit = 0; unit < LPC_UART_NUM; unit++) { 72100928Snectar if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) { 73100928Snectar lpc_uart_softc[unit].opts = str; 74100928Snectar error = 0; 75100928Snectar goto done; 76100928Snectar } 77100928Snectar } 78100928Snectar } 79100928Snectar 80100928Snectardone: 81100928Snectar if (error) 82100928Snectar free(cpy); 83100928Snectar 84100928Snectar return (error); 85100928Snectar} 86100928Snectar 87100928Snectarstatic void 88100928Snectarlpc_uart_intr_assert(void *arg) 89100928Snectar{ 90100928Snectar struct lpc_uart_softc *sc = arg; 91100928Snectar 92100928Snectar assert(sc->irq >= 0); 93100928Snectar 94100928Snectar ioapic_assert_pin(lpc_bridge->pi_vmctx, sc->irq); 95100928Snectar} 96100928Snectar 97100928Snectarstatic void 98100928Snectarlpc_uart_intr_deassert(void *arg) 99100928Snectar{ 100100928Snectar struct lpc_uart_softc *sc = arg; 101100928Snectar 102100928Snectar assert(sc->irq >= 0); 103100928Snectar 104100928Snectar ioapic_deassert_pin(lpc_bridge->pi_vmctx, sc->irq); 105100928Snectar} 106100928Snectar 107100928Snectarstatic int 108100928Snectarlpc_uart_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 109100928Snectar uint32_t *eax, void *arg) 110100928Snectar{ 111238405Sjkim int offset; 112238405Sjkim struct lpc_uart_softc *sc = arg; 113238405Sjkim 114238405Sjkim if (bytes != 1) 115238405Sjkim return (-1); 116238405Sjkim 117238405Sjkim offset = port - sc->iobase; 118238405Sjkim 119238405Sjkim if (in) 120238405Sjkim *eax = uart_read(sc->uart_softc, offset); 121238405Sjkim else 122238405Sjkim uart_write(sc->uart_softc, offset, *eax); 123238405Sjkim 124238405Sjkim return (0); 125238405Sjkim} 126238405Sjkim 127238405Sjkimstatic int 128238405Sjkimlpc_init(void) 129238405Sjkim{ 130238405Sjkim struct lpc_uart_softc *sc; 131238405Sjkim struct inout_port iop; 132238405Sjkim const char *name; 133238405Sjkim int unit, error; 134238405Sjkim 135238405Sjkim /* COM1 and COM2 */ 136238405Sjkim for (unit = 0; unit < LPC_UART_NUM; unit++) { 13755714Skris sc = &lpc_uart_softc[unit]; 13855714Skris name = lpc_uart_names[unit]; 139109998Smarkm 140109998Smarkm if (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) { 14155714Skris fprintf(stderr, "Unable to allocate resources for " 14255714Skris "LPC device %s\n", name); 143280304Sjkim return (-1); 144280304Sjkim } 145280304Sjkim 146280304Sjkim sc->uart_softc = uart_init(lpc_uart_intr_assert, 147280304Sjkim lpc_uart_intr_deassert, sc); 148280304Sjkim 149280304Sjkim if (uart_set_backend(sc->uart_softc, sc->opts) != 0) { 150280304Sjkim fprintf(stderr, "Unable to initialize backend '%s' " 15155714Skris "for LPC device %s\n", sc->opts, name); 152280304Sjkim return (-1); 153280304Sjkim } 154280304Sjkim 155280304Sjkim bzero(&iop, sizeof(struct inout_port)); 156280304Sjkim iop.name = name; 157280304Sjkim iop.port = sc->iobase; 158280304Sjkim iop.size = UART_IO_BAR_SIZE; 159280304Sjkim iop.flags = IOPORT_F_INOUT; 160280304Sjkim iop.handler = lpc_uart_io_handler; 161238405Sjkim iop.arg = sc; 162280304Sjkim 163109998Smarkm error = register_inout(&iop); 164280304Sjkim assert(error == 0); 165280304Sjkim } 166280304Sjkim 167280304Sjkim return (0); 168280304Sjkim} 169280304Sjkim 17055714Skrisstatic void 17155714Skrispci_lpc_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 172280304Sjkim int baridx, uint64_t offset, int size, uint64_t value) 17355714Skris{ 174280304Sjkim} 175280304Sjkim 176280304Sjkimuint64_t 177280304Sjkimpci_lpc_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 178280304Sjkim int baridx, uint64_t offset, int size) 179280304Sjkim{ 180280304Sjkim return (0); 181280304Sjkim} 182280304Sjkim 183280304Sjkim#define LPC_DEV 0x7000 184280304Sjkim#define LPC_VENDOR 0x8086 18555714Skris 186280304Sjkimstatic int 187280304Sjkimpci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 188280304Sjkim{ 189280304Sjkim /* 190280304Sjkim * Do not allow more than one LPC bridge to be configured. 191280304Sjkim */ 192280304Sjkim if (lpc_bridge != NULL) 193280304Sjkim return (-1); 194280304Sjkim 195280304Sjkim if (lpc_init() != 0) 19655714Skris return (-1); 197280304Sjkim 198280304Sjkim /* initialize config space */ 199280304Sjkim pci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV); 200280304Sjkim pci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR); 201280304Sjkim pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); 202280304Sjkim pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); 203280304Sjkim 204280304Sjkim lpc_bridge = pi; 205280304Sjkim 20655714Skris return (0); 207280304Sjkim} 208280304Sjkim 209280304Sjkimstruct pci_devemu pci_de_lpc = { 210280304Sjkim .pe_emu = "lpc", 211280304Sjkim .pe_init = pci_lpc_init, 212280304Sjkim .pe_barwrite = pci_lpc_write, 213280304Sjkim .pe_barread = pci_lpc_read 214280304Sjkim}; 21555714SkrisPCI_EMUL_SET(pci_de_lpc); 216280304Sjkim