From 4ab777b1b0f310e59b52a57c79efa0571506942a Mon Sep 17 00:00:00 2001 From: wh94709 Date: Wed, 19 Apr 2006 16:08:32 -0700 Subject: 6391344 Move virutal channels API versioning negotiation to the glvc driver --HG-- rename : usr/src/uts/sun4v/io/glvc.c => usr/src/uts/sun4v/io/glvc/glvc.c --- usr/src/uts/sun4v/Makefile.files | 2 +- usr/src/uts/sun4v/Makefile.rules | 13 + usr/src/uts/sun4v/io/glvc.c | 1031 ------------------------------ usr/src/uts/sun4v/io/glvc/glvc.c | 1088 ++++++++++++++++++++++++++++++++ usr/src/uts/sun4v/io/glvc/glvc_hcall.s | 141 +++++ usr/src/uts/sun4v/ml/hcall.s | 101 --- usr/src/uts/sun4v/os/hsvc.c | 7 +- usr/src/uts/sun4v/sys/glvc.h | 31 +- usr/src/uts/sun4v/sys/hypervisor_api.h | 6 - 9 files changed, 1272 insertions(+), 1148 deletions(-) delete mode 100644 usr/src/uts/sun4v/io/glvc.c create mode 100644 usr/src/uts/sun4v/io/glvc/glvc.c create mode 100644 usr/src/uts/sun4v/io/glvc/glvc_hcall.s (limited to 'usr/src') diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files index 8b6b89aca1..8fd0f3f1af 100644 --- a/usr/src/uts/sun4v/Makefile.files +++ b/usr/src/uts/sun4v/Makefile.files @@ -109,7 +109,7 @@ MEMTEST_OBJS += memtest.o memtest_asm.o \ # QCN_OBJS = qcn.o VNEX_OBJS = vnex.o -GLVC_OBJS = glvc.o +GLVC_OBJS = glvc.o glvc_hcall.o MDESC_OBJS = mdesc.o # diff --git a/usr/src/uts/sun4v/Makefile.rules b/usr/src/uts/sun4v/Makefile.rules index d97c91bc9e..8b49649880 100644 --- a/usr/src/uts/sun4v/Makefile.rules +++ b/usr/src/uts/sun4v/Makefile.rules @@ -76,6 +76,13 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/fpc/%.c $(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/fpc/%.s $(COMPILE.s) -o $@ $< +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/glvc/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/glvc/%.s + $(COMPILE.s) -o $@ $< + $(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/vm/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -141,6 +148,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/fpc/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/fpc/%.s @($(LHEAD) $(LINT.s) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/glvc/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/glvc/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/ml/%.s @($(LHEAD) $(LINT.s) $< $(LTAIL)) diff --git a/usr/src/uts/sun4v/io/glvc.c b/usr/src/uts/sun4v/io/glvc.c deleted file mode 100644 index 0743b9d329..0000000000 --- a/usr/src/uts/sun4v/io/glvc.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Global Variables - can be patched from Solaris - * ============================================== - */ - -/* bit defination in virtual device register */ -#define GLVC_REG_RECV 0x0001 -#define GLVC_REG_RECV_ENA 0x0002 -#define GLVC_REG_SEND 0x0004 -#define GLVC_REG_SEND_ENA 0x0008 -#define GLVC_REG_ERR 0x8000 - -/* - * For interrupt mode - */ -#define GLVC_MODE_NONE 0 -#define GLVC_POLLING_MODE 1 -#define GLVC_INTR_MODE 2 - -/* - * For open - */ -#define GLVC_NO_OPEN 0 -#define GLVC_OPEN 1 -#define GLVC_EXCL_OPEN 2 - -/* - * For timeout polling, in microsecond. - */ -#define GLVC_TIMEOUT_POLL 5000000 /* Timeout in intr mode */ -#define GLVC_POLLMODE_POLL 500000 /* Interval in polling mode */ - -/* - * For debug printing - */ -#define _PRINTF printf -#define DPRINTF(args) if (glvc_debug) _PRINTF args; - -/* - * Driver entry points - */ -static int glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); -static int glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); -static int glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); -static int glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p); -static int glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, - cred_t *cred_p, int *rval_p); -static int glvc_read(dev_t dev, struct uio *uiop, cred_t *credp); -static int glvc_write(dev_t dev, struct uio *uiop, cred_t *credp); - -static struct cb_ops glvc_cb_ops = { - glvc_open, /* open */ - glvc_close, /* close */ - nodev, /* strategy() */ - nodev, /* print() */ - nodev, /* dump() */ - glvc_read, /* read() */ - glvc_write, /* write() */ - glvc_ioctl, /* ioctl() */ - nodev, /* devmap() */ - nodev, /* mmap() */ - ddi_segmap, /* segmap() */ - nochpoll, /* poll() */ - ddi_prop_op, /* prop_op() */ - NULL, /* cb_str */ - D_NEW | D_MP /* cb_flag */ -}; - - -static struct dev_ops glvc_ops = { - DEVO_REV, - 0, /* ref count */ - ddi_getinfo_1to1, /* getinfo() */ - nulldev, /* identify() */ - nulldev, /* probe() */ - glvc_attach, /* attach() */ - glvc_detach, /* detach */ - nodev, /* reset */ - &glvc_cb_ops, /* pointer to cb_ops structure */ - (struct bus_ops *)NULL, - nulldev /* power() */ -}; - -/* - * Loadable module support. - */ -extern struct mod_ops mod_driverops; - -static struct modldrv modldrv = { - &mod_driverops, /* Type of module. This is a driver */ - "Sun4v virtual channel driver", /* Name of the module */ - &glvc_ops /* pointer to the dev_ops structure */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modldrv, - NULL -}; - -typedef struct glvc_soft_state { - dev_info_t *dip; /* dev info of myself */ - uint64_t s_id; /* service id for this node */ - uint64_t mtu; /* max transmit unit size */ - uint64_t flag; /* flag register */ - kmutex_t open_mutex; /* protect open_state flag */ - uint8_t open_state; /* no-open, open or open exclusively */ - kmutex_t recv_mutex; - kmutex_t send_complete_mutex; - uint8_t send_complete_flag; /* 1 = send completed */ - uint8_t intr_mode; /* 1 = polling mode, 2 = interrupt mode */ - clock_t polling_interval; - ddi_softintr_t poll_mode_softint_id; - kcondvar_t recv_cv; - kcondvar_t send_complete_cv; - kmutex_t statusreg_mutex; /* Protects status register */ - char *mb_recv_buf; - char *mb_send_buf; - uint64_t mb_recv_buf_pa; - uint64_t mb_send_buf_pa; -} glvc_soft_state_t; - -/* - * Module Variables - * ================ - */ - -/* - * functions local to this driver. - */ -static int glvc_add_intr_handlers(dev_info_t *dip); -static int glvc_remove_intr_handlers(dev_info_t *dip); -static uint_t glvc_intr(caddr_t arg); -static int glvc_peek(glvc_soft_state_t *softsp, - glvc_xport_msg_peek_t *msg_peek); -static uint_t glvc_soft_intr(caddr_t arg); -static int glvc_emap_h2s(uint64_t hv_errcode); -static int glvc_ioctl_opt_op(glvc_soft_state_t *softsp, - intptr_t arg, int mode); - -/* - * Driver globals - */ -static void *glvc_ssp; /* pointer to driver soft state */ - -static uint_t glvc_debug = 0; - -int -_init(void) -{ - int error = 0; - - if ((error = ddi_soft_state_init(&glvc_ssp, - sizeof (glvc_soft_state_t), 1)) != 0) - return (error); - - error = mod_install(&modlinkage); - - return (error); -} - - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - - -int -_fini(void) -{ - int error = 0; - - error = mod_remove(&modlinkage); - if (error) - return (error); - - ddi_soft_state_fini(&glvc_ssp); - return (0); -} - - -static int -glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - int instance; - int err; - glvc_soft_state_t *softsp; - - switch (cmd) { - case DDI_ATTACH: - instance = ddi_get_instance(dip); - - if (ddi_soft_state_zalloc(glvc_ssp, instance) - != DDI_SUCCESS) - return (DDI_FAILURE); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - /* Set the dip in the soft state */ - softsp->dip = dip; - - softsp->open_state = GLVC_NO_OPEN; - softsp->send_complete_flag = 1; - - glvc_debug = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, - softsp->dip, DDI_PROP_DONTPASS, "glvc_debug", glvc_debug); - - if ((softsp->s_id = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, - softsp->dip, DDI_PROP_DONTPASS, "channel#", -1)) - == -1) { - cmn_err(CE_WARN, "Failed to get channel#"); - goto bad; - } - - if ((softsp->mtu = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, - softsp->dip, DDI_PROP_DONTPASS, "mtu", -1)) - <= 0) { - cmn_err(CE_WARN, "Failed to get mtu"); - goto bad; - } - - softsp->mb_recv_buf = - (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); - if (softsp->mb_recv_buf == NULL) { - cmn_err(CE_WARN, "Failed to alloc mem for recv buf"); - goto bad; - } - softsp->mb_recv_buf_pa = - va_to_pa((caddr_t)softsp->mb_recv_buf); - - softsp->mb_send_buf = - (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); - if (softsp->mb_send_buf == NULL) { - kmem_free(softsp->mb_recv_buf, softsp->mtu); - cmn_err(CE_WARN, "Failed to alloc mem for send buf"); - goto bad; - } - softsp->mb_send_buf_pa = - va_to_pa((caddr_t)softsp->mb_send_buf); - - err = ddi_create_minor_node(dip, "glvc", S_IFCHR, - instance, DDI_PSEUDO, NULL); - if (err != DDI_SUCCESS) { - kmem_free(softsp->mb_recv_buf, softsp->mtu); - kmem_free(softsp->mb_send_buf, softsp->mtu); - cmn_err(CE_WARN, "Failed to create minor node"); - goto bad; - } - - mutex_init(&(softsp->open_mutex), NULL, MUTEX_DRIVER, NULL); - mutex_init(&(softsp->recv_mutex), NULL, MUTEX_DRIVER, NULL); - mutex_init(&(softsp->send_complete_mutex), NULL, - MUTEX_DRIVER, NULL); - mutex_init(&(softsp->statusreg_mutex), NULL, - MUTEX_DRIVER, NULL); - cv_init(&(softsp->recv_cv), NULL, CV_DRIVER, NULL); - cv_init(&(softsp->send_complete_cv), NULL, CV_DRIVER, NULL); - - /* - * Add the handlers which watch for unsolicited messages - * and post event to Sysevent Framework. - */ - err = glvc_add_intr_handlers(dip); - if (err != DDI_SUCCESS) { - cmn_err(CE_WARN, "Failed to add intr handler"); - kmem_free(softsp->mb_recv_buf, softsp->mtu); - kmem_free(softsp->mb_send_buf, softsp->mtu); - ddi_remove_minor_node(dip, NULL); - goto bad1; - } - - /* - * Trigger soft interrupt to start polling device if - * we are in the polling mode - */ - if (softsp->intr_mode == GLVC_POLLING_MODE) - ddi_trigger_softintr(softsp->poll_mode_softint_id); - - ddi_report_dev(dip); - - DPRINTF(("glvc instance %d, s_id %lu," - "mtu %lu attached", instance, softsp->s_id, - softsp->mtu)); - - return (DDI_SUCCESS); - case DDI_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - -bad1: - cv_destroy(&(softsp->send_complete_cv)); - cv_destroy(&(softsp->recv_cv)); - mutex_destroy(&(softsp->open_mutex)); - mutex_destroy(&(softsp->send_complete_mutex)); - mutex_destroy(&(softsp->recv_mutex)); - mutex_destroy(&(softsp->statusreg_mutex)); - -bad: - cmn_err(CE_WARN, "glvc: attach failed for instance %d\n", instance); - ddi_soft_state_free(glvc_ssp, instance); - return (DDI_FAILURE); -} - - -static int -glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - int instance; - int err; - glvc_soft_state_t *softsp; - - - switch (cmd) { - case DDI_DETACH: - instance = ddi_get_instance(dip); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - cv_destroy(&(softsp->send_complete_cv)); - cv_destroy(&(softsp->recv_cv)); - mutex_destroy(&(softsp->open_mutex)); - mutex_destroy(&(softsp->statusreg_mutex)); - mutex_destroy(&(softsp->send_complete_mutex)); - mutex_destroy(&(softsp->recv_mutex)); - - kmem_free(softsp->mb_recv_buf, softsp->mtu); - kmem_free(softsp->mb_send_buf, softsp->mtu); - - err = glvc_remove_intr_handlers(dip); - - if (err != DDI_SUCCESS) { - cmn_err(CE_WARN, "Failed to remove event handlers"); - return (DDI_FAILURE); - } - - ddi_remove_minor_node(dip, NULL); - - ddi_soft_state_free(glvc_ssp, instance); - - return (DDI_SUCCESS); - case DDI_SUSPEND: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } -} - -static int -glvc_add_intr_handlers(dev_info_t *dip) -{ - int instance; - glvc_soft_state_t *softsp; - int err = DDI_FAILURE; - uint64_t polling_interval; - - instance = ddi_get_instance(dip); - softsp = ddi_get_soft_state(glvc_ssp, instance); - - if ((uint64_t)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, - DDI_PROP_DONTPASS, "flags", -1) != -1) { - err = ddi_add_intr(dip, 0, NULL, NULL, glvc_intr, - (caddr_t)softsp); - if (err != DDI_SUCCESS) - cmn_err(CE_NOTE, "glvc, instance %d" - " ddi_add_intr() failed, using" - " polling mode", instance); - } - - if (err == DDI_SUCCESS) { - softsp->intr_mode = GLVC_INTR_MODE; - polling_interval = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, - softsp->dip, DDI_PROP_DONTPASS, "intrmode_poll", - GLVC_TIMEOUT_POLL); - DPRINTF(("glvc instance %d polling_interval = %lu", - instance, polling_interval)); - softsp->polling_interval = drv_usectohz(polling_interval); - } else { - DPRINTF(("glvc, instance %d intr support not found, " - "err = %d , use polling mode", instance, err)); - softsp->intr_mode = GLVC_POLLING_MODE; - polling_interval = - (uint64_t)ddi_getprop(DDI_DEV_T_ANY, - softsp->dip, DDI_PROP_DONTPASS, "pollmode_poll", - GLVC_POLLMODE_POLL); - DPRINTF(("glvc instance %d polling_interval = %lu", - instance, polling_interval)); - softsp->polling_interval = - drv_usectohz(polling_interval); - } - - /* Now enable interrupt bits in the status register */ - if (softsp->intr_mode == GLVC_INTR_MODE) { - err = hv_service_setstatus(softsp->s_id, - GLVC_REG_RECV_ENA|GLVC_REG_SEND_ENA); - if (err != H_EOK) { - cmn_err(CE_NOTE, "glvc instance %d" - " cannot enable receive interrupt", - instance); - return (DDI_FAILURE); - } - } - - - err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, - &softsp->poll_mode_softint_id, NULL, NULL, - glvc_soft_intr, (caddr_t)softsp); - - return (err); -} - -static int -glvc_remove_intr_handlers(dev_info_t *dip) -{ - int instance; - glvc_soft_state_t *softsp; - - instance = ddi_get_instance(dip); - softsp = ddi_get_soft_state(glvc_ssp, instance); - - if (softsp->intr_mode == GLVC_INTR_MODE) - ddi_remove_intr(dip, 0, NULL); - - ddi_remove_softintr(softsp->poll_mode_softint_id); - - softsp->intr_mode = GLVC_MODE_NONE; - softsp->polling_interval = 0; - - return (DDI_SUCCESS); -} - -static uint_t -glvc_soft_intr(caddr_t arg) -{ - /* - * Call the interrupt handle routine to check the register - * status. - */ - (uint_t)glvc_intr(arg); - - return (DDI_INTR_CLAIMED); -} - -/*ARGSUSED*/ -static int -glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) -{ - int error = 0; - int instance; - glvc_soft_state_t *softsp; - - instance = getminor(*dev_p); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - mutex_enter(&softsp->open_mutex); - - switch (softsp->open_state) { - case GLVC_NO_OPEN: - if (flag & FEXCL) - softsp->open_state = GLVC_EXCL_OPEN; - else - softsp->open_state = GLVC_OPEN; - break; - - case GLVC_OPEN: - if (flag & FEXCL) - error = EBUSY; - break; - - case GLVC_EXCL_OPEN: - error = EBUSY; - break; - - default: - /* Should not happen */ - cmn_err(CE_WARN, "glvc_open: bad open state %d.", - softsp->open_state); - error = ENXIO; - break; - } - - mutex_exit(&softsp->open_mutex); - - return (error); -} - -/*ARGSUSED*/ -static int -glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p) -{ - glvc_soft_state_t *softsp; - int instance; - int error = 0; - - instance = getminor(dev); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - mutex_enter(&softsp->open_mutex); - if (softsp->open_state == GLVC_NO_OPEN) { - cmn_err(CE_WARN, - "glvc_close: device already closed"); - error = ENXIO; - } else { - softsp->open_state = GLVC_NO_OPEN; - } - mutex_exit(&softsp->open_mutex); - - return (error); -} - -/*ARGSUSED*/ -static int -glvc_read(dev_t dev, struct uio *uiop, cred_t *credp) -{ - glvc_soft_state_t *softsp; - int instance; - int rv, error = DDI_SUCCESS; - uint64_t hverr, recv_count = 0; - uint64_t status_reg; - clock_t tick; - - instance = getminor(dev); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - mutex_enter(&softsp->recv_mutex); - - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", - hverr, status_reg)); - - - /* - * If no data available, we wait till we get some. - * Notice we still holding the recv_mutex lock at this - * point. - */ - while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != - GLVC_REG_RECV) { - tick = ddi_get_lbolt() + softsp->polling_interval; - rv = cv_timedwait_sig(&softsp->recv_cv, - &softsp->recv_mutex, tick); - if (rv == 0) { - /* - * We got interrupted. - */ - mutex_exit(&softsp->recv_mutex); - return (EINTR); - } - if (rv == -1) { - /* - * Timeout wait, trigger a soft intr in case - * we miss an interrupt or in polling mode. - */ - ddi_trigger_softintr(softsp->poll_mode_softint_id); - } - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", - hverr, status_reg)); - } - - /* Read data into kernel buffer */ - hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, - softsp->mtu, &recv_count); - - DPRINTF(("Instance %d glvc_read returns error = %ld, recv_count = %lu", - instance, hverr, recv_count)); - - if (hverr == H_EOK) { - if (uiop->uio_resid < recv_count) { - DPRINTF(("Instance %d, glvc_read user buffer " - "size(%lu) smaller than number of bytes " - "received(%lu).", instance, uiop->uio_resid, - recv_count)); - mutex_exit(&softsp->recv_mutex); - return (EINVAL); - } - /* move data from kernel to user space */ - error = uiomove(softsp->mb_recv_buf, recv_count, - UIO_READ, uiop); - } else { - error = glvc_emap_h2s(hverr); - } - - /* Clear the RECV data interrupt bit on device register */ - if (hv_service_clrstatus(softsp->s_id, GLVC_REG_RECV) != H_EOK) { - cmn_err(CE_WARN, "glvc_read clear status reg failed"); - } - - /* Set RECV interrupt enable bit so we can receive interrupt */ - if (softsp->intr_mode == GLVC_INTR_MODE) - if (hv_service_setstatus(softsp->s_id, GLVC_REG_RECV_ENA) - != H_EOK) { - cmn_err(CE_WARN, "glvc_read set status reg failed"); - } - - mutex_exit(&softsp->recv_mutex); - - return (error); -} - -/*ARGSUSED*/ -static int -glvc_write(dev_t dev, struct uio *uiop, cred_t *credp) -{ - glvc_soft_state_t *softsp; - int instance; - int rv, error = DDI_SUCCESS; - uint64_t hverr, send_count = 0; - clock_t tick; - - instance = getminor(dev); - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - if (uiop->uio_resid > softsp->mtu) - return (EINVAL); - - send_count = uiop->uio_resid; - DPRINTF(("instance %d glvc_write: request to send %lu bytes", - instance, send_count)); - - mutex_enter(&softsp->send_complete_mutex); - while (softsp->send_complete_flag == 0) { - tick = ddi_get_lbolt() + softsp->polling_interval; - rv = cv_timedwait_sig(&softsp->send_complete_cv, - &softsp->send_complete_mutex, tick); - if (rv == 0) { - /* - * We got interrupted. - */ - mutex_exit(&softsp->send_complete_mutex); - return (EINTR); - } - if (rv == -1) { - /* - * Timeout wait, trigger a soft intr in case - * we miss an interrupt or in polling mode. - */ - ddi_trigger_softintr(softsp->poll_mode_softint_id); - } - } - - /* move data from to user to kernel space */ - error = uiomove(softsp->mb_send_buf, send_count, - UIO_WRITE, uiop); - - if (error == 0) { - hverr = hv_service_send(softsp->s_id, - softsp->mb_send_buf_pa, send_count, &send_count); - error = glvc_emap_h2s(hverr); - } - - DPRINTF(("instance %d glvc_write write check error = %d," - " send_count = %lu", instance, error, send_count)); - - softsp->send_complete_flag = 0; - - mutex_exit(&softsp->send_complete_mutex); - - return (error); -} - -/* - * Interrupt handler - */ -static uint_t -glvc_intr(caddr_t arg) -{ - glvc_soft_state_t *softsp = (glvc_soft_state_t *)arg; - uint64_t status_reg; - int error = DDI_INTR_UNCLAIMED; - uint64_t hverr = H_EOK; - uint64_t clr_bits = 0; - - mutex_enter(&softsp->recv_mutex); - mutex_enter(&softsp->send_complete_mutex); - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - DPRINTF(("glvc_intr: err = %ld, getstatus = 0x%lx", - hverr, status_reg)); - - /* - * Clear SEND_COMPLETE bit and disable RECV interrupt - */ - if (status_reg & GLVC_REG_SEND) - clr_bits |= GLVC_REG_SEND; - if ((softsp->intr_mode == GLVC_INTR_MODE) && - (status_reg & GLVC_REG_RECV)) - clr_bits |= GLVC_REG_RECV_ENA; - - if ((hverr = hv_service_clrstatus(softsp->s_id, clr_bits)) - != H_EOK) { - cmn_err(CE_WARN, "glvc_intr clear status reg failed" - "error = %ld", hverr); - mutex_exit(&softsp->send_complete_mutex); - mutex_exit(&softsp->recv_mutex); - return (DDI_INTR_UNCLAIMED); - } - - if (status_reg & GLVC_REG_RECV) { - cv_broadcast(&softsp->recv_cv); - error = DDI_INTR_CLAIMED; - } - - if (status_reg & GLVC_REG_SEND) { - softsp->send_complete_flag = 1; - cv_broadcast(&softsp->send_complete_cv); - error = DDI_INTR_CLAIMED; - } - - mutex_exit(&softsp->send_complete_mutex); - mutex_exit(&softsp->recv_mutex); - - return (error); -} - -/* - * Peek to see if there is data received. If no data available, - * we sleep wait. If there is data, read from hypervisor and copy - * to ioctl buffer. We don't clear the receive data interrupt bit. - */ -static int -glvc_peek(glvc_soft_state_t *softsp, glvc_xport_msg_peek_t *msg_peek) -{ - int rv, error = 0; - uint64_t hverr = H_EOK; - uint64_t recv_count = 0; - uint64_t status_reg; - clock_t tick; - - mutex_enter(&softsp->recv_mutex); - - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", - hverr, status_reg)); - - /* - * If no data available, we wait till we get some. - * Notice we still holding the recv_mutex lock at - * this point. - */ - while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != - GLVC_REG_RECV) { - tick = ddi_get_lbolt() + softsp->polling_interval; - rv = cv_timedwait_sig(&softsp->recv_cv, - &softsp->recv_mutex, tick); - if (rv == 0) { - /* - * We got interrupted. - */ - mutex_exit(&softsp->recv_mutex); - return (EINTR); - } - if (rv == -1) { - /* - * Timeout wait, trigger a soft intr in case - * we miss an interrupt or in polling mode. - */ - ddi_trigger_softintr(softsp->poll_mode_softint_id); - } - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", - hverr, status_reg)); - } - - /* Read data into kernel buffer */ - hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, - softsp->mtu, &recv_count); - DPRINTF(("glvc_peek recv data, error = %ld, recv_count = %lu", - hverr, recv_count)); - - if (hverr == H_EOK && recv_count > 0) { - (void *) memcpy(msg_peek->buf, - softsp->mb_recv_buf, recv_count); - msg_peek->buflen = recv_count; - } else { - error = glvc_emap_h2s(hverr); - } - - mutex_exit(&softsp->recv_mutex); - - return (error); -} - -static int -glvc_ioctl_opt_op(glvc_soft_state_t *softsp, intptr_t arg, int mode) -{ - glvc_xport_opt_op_t glvc_xport_cmd; - uint64_t status_reg; - int retval = 0; - uint64_t hverr; - - if (ddi_copyin((caddr_t)arg, (caddr_t)&glvc_xport_cmd, - sizeof (glvc_xport_opt_op_t), mode) != 0) { - return (EFAULT); - } - - switch (glvc_xport_cmd.opt_sel) { - case GLVC_XPORT_OPT_MTU_SZ: - if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { - glvc_xport_cmd.opt_val = softsp->mtu; - retval = ddi_copyout((caddr_t)&glvc_xport_cmd, - (caddr_t)arg, sizeof (glvc_xport_opt_op_t), - mode); - } else - retval = ENOTSUP; - - break; - - case GLVC_XPORT_OPT_REG_STATUS: - if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { - mutex_enter(&softsp->statusreg_mutex); - hverr = hv_service_getstatus(softsp->s_id, &status_reg); - mutex_exit(&softsp->statusreg_mutex); - if (hverr == H_EOK) { - glvc_xport_cmd.opt_val = (uint32_t)status_reg; - retval = ddi_copyout((caddr_t)&glvc_xport_cmd, - (caddr_t)arg, sizeof (glvc_xport_opt_op_t), - mode); - } else { - retval = EIO; - } - } else { - retval = ENOTSUP; - } - - break; - - default: - retval = ENOTSUP; - break; - } - - return (retval); -} - - -/*ARGSUSED*/ -static int -glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, - int *rval_p) -{ - glvc_soft_state_t *softsp; - int instance = getminor(dev); - glvc_xport_msg_peek_t glvc_peek_msg, msg_peek_cmd; - glvc_xport_msg_peek32_t msg_peek_cmd32; - - int retval = 0; - - softsp = ddi_get_soft_state(glvc_ssp, instance); - - switch (cmd) { - case GLVC_XPORT_IOCTL_OPT_OP: - retval = glvc_ioctl_opt_op(softsp, arg, mode); - break; - - case GLVC_XPORT_IOCTL_DATA_PEEK: - glvc_peek_msg.buf = - (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); - if (glvc_peek_msg.buf == NULL) - return (EBUSY); - retval = glvc_peek(softsp, &glvc_peek_msg); - if (retval == 0) { - switch (ddi_model_convert_from(mode)) { - case DDI_MODEL_ILP32: - if (ddi_copyin((caddr_t)arg, - (caddr_t)&msg_peek_cmd32, - sizeof (glvc_xport_msg_peek32_t), - mode) == -1) { - retval = EFAULT; - break; - } - - if (msg_peek_cmd32.buflen32 == 0) { - retval = EINVAL; - break; - } - - if (msg_peek_cmd32.buflen32 > - glvc_peek_msg.buflen) - msg_peek_cmd32.buflen32 = - glvc_peek_msg.buflen; - - if (ddi_copyout((caddr_t)glvc_peek_msg.buf, - (caddr_t)(uintptr_t)msg_peek_cmd32.buf32, - msg_peek_cmd32.buflen32, mode) == -1) { - retval = EFAULT; - break; - } - - if (ddi_copyout((caddr_t)&msg_peek_cmd32, - (caddr_t)arg, - sizeof (glvc_xport_msg_peek32_t), mode) - == -1) - retval = EFAULT; - break; - - case DDI_MODEL_NONE: - if (ddi_copyin((caddr_t)arg, - (caddr_t)&msg_peek_cmd, - sizeof (glvc_xport_msg_peek_t), mode) == -1) - retval = EFAULT; - - if (msg_peek_cmd.buflen == 0) { - retval = EINVAL; - break; - } - - if (msg_peek_cmd.buflen > glvc_peek_msg.buflen) - msg_peek_cmd.buflen = - glvc_peek_msg.buflen; - - if (ddi_copyout((caddr_t)glvc_peek_msg.buf, - (caddr_t)msg_peek_cmd.buf, - msg_peek_cmd.buflen, mode) == -1) { - retval = EFAULT; - break; - } - - if (ddi_copyout((caddr_t)&msg_peek_cmd, - (caddr_t)arg, - sizeof (glvc_xport_msg_peek_t), mode) == -1) - retval = EFAULT; - break; - - default: - retval = EFAULT; - break; - } - } - kmem_free(glvc_peek_msg.buf, softsp->mtu); - break; - - default: - retval = ENOTSUP; - break; - } - return (retval); -} - -/* - * Map hypervisor error code to solaris. Only - * H_EOK, H_EINVA, H_EWOULDBLOCK and H_EIO are meaningful - * to this device. All other error codes are mapped to EIO. - */ -static int -glvc_emap_h2s(uint64_t hv_errcode) -{ - int s_errcode; - - switch (hv_errcode) { - case H_EOK: - s_errcode = 0; - break; - - case H_EINVAL: - s_errcode = EINVAL; - break; - - case H_EWOULDBLOCK: - s_errcode = EWOULDBLOCK; - break; - - case H_EIO: - s_errcode = EIO; - break; - - default: - /* should not happen */ - DPRINTF(("Unexpected device error code %ld received, " - "mapped to EIO", hv_errcode)); - s_errcode = EIO; - break; - } - - return (s_errcode); -} diff --git a/usr/src/uts/sun4v/io/glvc/glvc.c b/usr/src/uts/sun4v/io/glvc/glvc.c new file mode 100644 index 0000000000..2b3b9e24a8 --- /dev/null +++ b/usr/src/uts/sun4v/io/glvc/glvc.c @@ -0,0 +1,1088 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Global Variables - can be patched from Solaris + * ============================================== + */ + +/* bit defination in virtual device register */ +#define GLVC_REG_RECV 0x0001 +#define GLVC_REG_RECV_ENA 0x0002 +#define GLVC_REG_SEND 0x0004 +#define GLVC_REG_SEND_ENA 0x0008 +#define GLVC_REG_ERR 0x8000 + +/* + * For interrupt mode + */ +#define GLVC_MODE_NONE 0 +#define GLVC_POLLING_MODE 1 +#define GLVC_INTR_MODE 2 + +/* + * For open + */ +#define GLVC_NO_OPEN 0 +#define GLVC_OPEN 1 +#define GLVC_EXCL_OPEN 2 + +/* + * For timeout polling, in microsecond. + */ +#define GLVC_TIMEOUT_POLL 5000000 /* Timeout in intr mode */ +#define GLVC_POLLMODE_POLL 500000 /* Interval in polling mode */ + +/* + * For debug printing + */ +#define _PRINTF printf +#define DPRINTF(args) if (glvc_debug) _PRINTF args; + +/* + * Driver entry points + */ +static int glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static int glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); +static int glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p); +static int glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p); +static int glvc_read(dev_t dev, struct uio *uiop, cred_t *credp); +static int glvc_write(dev_t dev, struct uio *uiop, cred_t *credp); + +static struct cb_ops glvc_cb_ops = { + glvc_open, /* open */ + glvc_close, /* close */ + nodev, /* strategy() */ + nodev, /* print() */ + nodev, /* dump() */ + glvc_read, /* read() */ + glvc_write, /* write() */ + glvc_ioctl, /* ioctl() */ + nodev, /* devmap() */ + nodev, /* mmap() */ + ddi_segmap, /* segmap() */ + nochpoll, /* poll() */ + ddi_prop_op, /* prop_op() */ + NULL, /* cb_str */ + D_NEW | D_MP /* cb_flag */ +}; + + +static struct dev_ops glvc_ops = { + DEVO_REV, + 0, /* ref count */ + ddi_getinfo_1to1, /* getinfo() */ + nulldev, /* identify() */ + nulldev, /* probe() */ + glvc_attach, /* attach() */ + glvc_detach, /* detach */ + nodev, /* reset */ + &glvc_cb_ops, /* pointer to cb_ops structure */ + (struct bus_ops *)NULL, + nulldev /* power() */ +}; + +/* + * Loadable module support. + */ +extern struct mod_ops mod_driverops; + +static struct modldrv modldrv = { + &mod_driverops, /* Type of module. This is a driver */ + "Sun4v virtual channel driver 2.0", /* Name of the module */ + &glvc_ops /* pointer to the dev_ops structure */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, + &modldrv, + NULL +}; + +typedef struct glvc_soft_state { + dev_info_t *dip; /* dev info of myself */ + uint64_t s_id; /* service id for this node */ + uint64_t mtu; /* max transmit unit size */ + uint64_t flag; /* flag register */ + kmutex_t open_mutex; /* protect open_state flag */ + uint8_t open_state; /* no-open, open or open exclusively */ + kmutex_t recv_mutex; + kmutex_t send_complete_mutex; + uint8_t send_complete_flag; /* 1 = send completed */ + uint8_t intr_mode; /* 1 = polling mode, 2 = interrupt mode */ + clock_t polling_interval; + ddi_softintr_t poll_mode_softint_id; + kcondvar_t recv_cv; + kcondvar_t send_complete_cv; + kmutex_t statusreg_mutex; /* Protects status register */ + char *mb_recv_buf; + char *mb_send_buf; + uint64_t mb_recv_buf_pa; + uint64_t mb_send_buf_pa; +} glvc_soft_state_t; + +/* + * Hypervisor VSC api versioning information for glvc driver. + */ +static uint64_t glvc_vsc_min_ver; /* Negotiated VSC API minor version */ +static uint_t glvc_vsc_users = 0; /* VSC API users */ +static kmutex_t glvc_vsc_users_mutex; /* Mutex to protect user count */ + +static hsvc_info_t glvc_hsvc = { + HSVC_REV_1, NULL, HSVC_GROUP_VSC, GLVC_VSC_MAJOR_VER, + GLVC_VSC_MINOR_VER, "glvc" +}; + +/* + * Module Variables + * ================ + */ + +/* + * functions local to this driver. + */ +static int glvc_add_intr_handlers(dev_info_t *dip); +static int glvc_remove_intr_handlers(dev_info_t *dip); +static uint_t glvc_intr(caddr_t arg); +static int glvc_peek(glvc_soft_state_t *softsp, + glvc_xport_msg_peek_t *msg_peek); +static uint_t glvc_soft_intr(caddr_t arg); +static int glvc_emap_h2s(uint64_t hv_errcode); +static int glvc_ioctl_opt_op(glvc_soft_state_t *softsp, + intptr_t arg, int mode); + +/* + * Driver globals + */ +static void *glvc_ssp; /* pointer to driver soft state */ + +static uint_t glvc_debug = 0; + +int +_init(void) +{ + int error = 0; + + if ((error = ddi_soft_state_init(&glvc_ssp, + sizeof (glvc_soft_state_t), 1)) != 0) + return (error); + + /* + * Initialize the mutex for global data structure + */ + mutex_init(&glvc_vsc_users_mutex, NULL, MUTEX_DRIVER, NULL); + + error = mod_install(&modlinkage); + + return (error); +} + + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + + +int +_fini(void) +{ + int error = 0; + + error = mod_remove(&modlinkage); + if (error) + return (error); + + mutex_destroy(&glvc_vsc_users_mutex); + + ddi_soft_state_fini(&glvc_ssp); + return (0); +} + + +static int +glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int instance; + int err; + glvc_soft_state_t *softsp; + + switch (cmd) { + case DDI_ATTACH: + instance = ddi_get_instance(dip); + + /* + * Negotiate the API version for VSC hypervisor services. + */ + mutex_enter(&glvc_vsc_users_mutex); + if (glvc_vsc_users == 0 && + (err = hsvc_register(&glvc_hsvc, &glvc_vsc_min_ver)) + != 0) { + cmn_err(CE_WARN, "%s: cannot negotiate hypervisor " + "services group: 0x%lx major: 0x%lx minor: 0x%lx " + "errno: %d\n", glvc_hsvc.hsvc_modname, + glvc_hsvc.hsvc_group, glvc_hsvc.hsvc_major, + glvc_hsvc.hsvc_minor, err); + + mutex_exit(&glvc_vsc_users_mutex); + return (DDI_FAILURE); + } else { + glvc_vsc_users++; + mutex_exit(&glvc_vsc_users_mutex); + } + + DPRINTF(("Glvc instance %d negotiated VSC API version, " + " major 0x%lx minor 0x%lx\n", + instance, glvc_hsvc.hsvc_major, glvc_vsc_min_ver)); + + if (ddi_soft_state_zalloc(glvc_ssp, instance) + != DDI_SUCCESS) { + mutex_enter(&glvc_vsc_users_mutex); + if (--glvc_vsc_users == 0) + (void) hsvc_unregister(&glvc_hsvc); + mutex_exit(&glvc_vsc_users_mutex); + return (DDI_FAILURE); + } + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + /* Set the dip in the soft state */ + softsp->dip = dip; + + softsp->open_state = GLVC_NO_OPEN; + softsp->send_complete_flag = 1; + + glvc_debug = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, + softsp->dip, DDI_PROP_DONTPASS, "glvc_debug", glvc_debug); + + if ((softsp->s_id = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, + softsp->dip, DDI_PROP_DONTPASS, "channel#", -1)) + == -1) { + cmn_err(CE_WARN, "Failed to get channel#"); + goto bad; + } + + if ((softsp->mtu = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, + softsp->dip, DDI_PROP_DONTPASS, "mtu", -1)) + <= 0) { + cmn_err(CE_WARN, "Failed to get mtu"); + goto bad; + } + + softsp->mb_recv_buf = + (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); + if (softsp->mb_recv_buf == NULL) { + cmn_err(CE_WARN, "Failed to alloc mem for recv buf"); + goto bad; + } + softsp->mb_recv_buf_pa = + va_to_pa((caddr_t)softsp->mb_recv_buf); + + softsp->mb_send_buf = + (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); + if (softsp->mb_send_buf == NULL) { + kmem_free(softsp->mb_recv_buf, softsp->mtu); + cmn_err(CE_WARN, "Failed to alloc mem for send buf"); + goto bad; + } + softsp->mb_send_buf_pa = + va_to_pa((caddr_t)softsp->mb_send_buf); + + err = ddi_create_minor_node(dip, "glvc", S_IFCHR, + instance, DDI_PSEUDO, NULL); + if (err != DDI_SUCCESS) { + kmem_free(softsp->mb_recv_buf, softsp->mtu); + kmem_free(softsp->mb_send_buf, softsp->mtu); + cmn_err(CE_WARN, "Failed to create minor node"); + goto bad; + } + + mutex_init(&(softsp->open_mutex), NULL, MUTEX_DRIVER, NULL); + mutex_init(&(softsp->recv_mutex), NULL, MUTEX_DRIVER, NULL); + mutex_init(&(softsp->send_complete_mutex), NULL, + MUTEX_DRIVER, NULL); + mutex_init(&(softsp->statusreg_mutex), NULL, + MUTEX_DRIVER, NULL); + cv_init(&(softsp->recv_cv), NULL, CV_DRIVER, NULL); + cv_init(&(softsp->send_complete_cv), NULL, CV_DRIVER, NULL); + + /* + * Add the handlers which watch for unsolicited messages + * and post event to Sysevent Framework. + */ + err = glvc_add_intr_handlers(dip); + if (err != DDI_SUCCESS) { + cmn_err(CE_WARN, "Failed to add intr handler"); + kmem_free(softsp->mb_recv_buf, softsp->mtu); + kmem_free(softsp->mb_send_buf, softsp->mtu); + ddi_remove_minor_node(dip, NULL); + goto bad1; + } + + /* + * Trigger soft interrupt to start polling device if + * we are in the polling mode + */ + if (softsp->intr_mode == GLVC_POLLING_MODE) + ddi_trigger_softintr(softsp->poll_mode_softint_id); + + ddi_report_dev(dip); + + DPRINTF(("glvc instance %d, s_id %lu," + "mtu %lu attached\n", instance, softsp->s_id, + softsp->mtu)); + + return (DDI_SUCCESS); + case DDI_RESUME: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + +bad1: + cv_destroy(&(softsp->send_complete_cv)); + cv_destroy(&(softsp->recv_cv)); + mutex_destroy(&(softsp->open_mutex)); + mutex_destroy(&(softsp->send_complete_mutex)); + mutex_destroy(&(softsp->recv_mutex)); + mutex_destroy(&(softsp->statusreg_mutex)); + +bad: + mutex_enter(&glvc_vsc_users_mutex); + if (--glvc_vsc_users == 0) + (void) hsvc_unregister(&glvc_hsvc); + mutex_exit(&glvc_vsc_users_mutex); + cmn_err(CE_WARN, "glvc: attach failed for instance %d\n", instance); + ddi_soft_state_free(glvc_ssp, instance); + return (DDI_FAILURE); +} + + +static int +glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int instance; + int err; + glvc_soft_state_t *softsp; + + + switch (cmd) { + case DDI_DETACH: + instance = ddi_get_instance(dip); + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + cv_destroy(&(softsp->send_complete_cv)); + cv_destroy(&(softsp->recv_cv)); + mutex_destroy(&(softsp->open_mutex)); + mutex_destroy(&(softsp->statusreg_mutex)); + mutex_destroy(&(softsp->send_complete_mutex)); + mutex_destroy(&(softsp->recv_mutex)); + + kmem_free(softsp->mb_recv_buf, softsp->mtu); + kmem_free(softsp->mb_send_buf, softsp->mtu); + + err = glvc_remove_intr_handlers(dip); + + if (err != DDI_SUCCESS) { + cmn_err(CE_WARN, "Failed to remove event handlers"); + return (DDI_FAILURE); + } + + ddi_remove_minor_node(dip, NULL); + + ddi_soft_state_free(glvc_ssp, instance); + + mutex_enter(&glvc_vsc_users_mutex); + if (--glvc_vsc_users == 0) + (void) hsvc_unregister(&glvc_hsvc); + mutex_exit(&glvc_vsc_users_mutex); + + return (DDI_SUCCESS); + case DDI_SUSPEND: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } +} + +static int +glvc_add_intr_handlers(dev_info_t *dip) +{ + int instance; + glvc_soft_state_t *softsp; + int err = DDI_FAILURE; + uint64_t polling_interval; + + instance = ddi_get_instance(dip); + softsp = ddi_get_soft_state(glvc_ssp, instance); + + if ((uint64_t)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, + DDI_PROP_DONTPASS, "flags", -1) != -1) { + err = ddi_add_intr(dip, 0, NULL, NULL, glvc_intr, + (caddr_t)softsp); + if (err != DDI_SUCCESS) + cmn_err(CE_NOTE, "glvc, instance %d" + " ddi_add_intr() failed, using" + " polling mode", instance); + } + + if (err == DDI_SUCCESS) { + softsp->intr_mode = GLVC_INTR_MODE; + polling_interval = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, + softsp->dip, DDI_PROP_DONTPASS, "intrmode_poll", + GLVC_TIMEOUT_POLL); + DPRINTF(("glvc instance %d polling_interval = %lu\n", + instance, polling_interval)); + softsp->polling_interval = drv_usectohz(polling_interval); + } else { + DPRINTF(("glvc, instance %d intr support not found, " + "err = %d , use polling mode", instance, err)); + softsp->intr_mode = GLVC_POLLING_MODE; + polling_interval = + (uint64_t)ddi_getprop(DDI_DEV_T_ANY, + softsp->dip, DDI_PROP_DONTPASS, "pollmode_poll", + GLVC_POLLMODE_POLL); + DPRINTF(("glvc instance %d polling_interval = %lu\n", + instance, polling_interval)); + softsp->polling_interval = + drv_usectohz(polling_interval); + } + + /* Now enable interrupt bits in the status register */ + if (softsp->intr_mode == GLVC_INTR_MODE) { + err = hv_service_setstatus(softsp->s_id, + GLVC_REG_RECV_ENA|GLVC_REG_SEND_ENA); + if (err != H_EOK) { + cmn_err(CE_NOTE, "glvc instance %d" + " cannot enable receive interrupt\n", + instance); + return (DDI_FAILURE); + } + } + + + err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, + &softsp->poll_mode_softint_id, NULL, NULL, + glvc_soft_intr, (caddr_t)softsp); + + return (err); +} + +static int +glvc_remove_intr_handlers(dev_info_t *dip) +{ + int instance; + glvc_soft_state_t *softsp; + + instance = ddi_get_instance(dip); + softsp = ddi_get_soft_state(glvc_ssp, instance); + + if (softsp->intr_mode == GLVC_INTR_MODE) + ddi_remove_intr(dip, 0, NULL); + + ddi_remove_softintr(softsp->poll_mode_softint_id); + + softsp->intr_mode = GLVC_MODE_NONE; + softsp->polling_interval = 0; + + return (DDI_SUCCESS); +} + +static uint_t +glvc_soft_intr(caddr_t arg) +{ + /* + * Call the interrupt handle routine to check the register + * status. + */ + (uint_t)glvc_intr(arg); + + return (DDI_INTR_CLAIMED); +} + +/*ARGSUSED*/ +static int +glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) +{ + int error = 0; + int instance; + glvc_soft_state_t *softsp; + + instance = getminor(*dev_p); + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + mutex_enter(&softsp->open_mutex); + + switch (softsp->open_state) { + case GLVC_NO_OPEN: + if (flag & FEXCL) + softsp->open_state = GLVC_EXCL_OPEN; + else + softsp->open_state = GLVC_OPEN; + break; + + case GLVC_OPEN: + if (flag & FEXCL) + error = EBUSY; + break; + + case GLVC_EXCL_OPEN: + error = EBUSY; + break; + + default: + /* Should not happen */ + cmn_err(CE_WARN, "glvc_open: bad open state %d.", + softsp->open_state); + error = ENXIO; + break; + } + + mutex_exit(&softsp->open_mutex); + + return (error); +} + +/*ARGSUSED*/ +static int +glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p) +{ + glvc_soft_state_t *softsp; + int instance; + int error = 0; + + instance = getminor(dev); + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + mutex_enter(&softsp->open_mutex); + if (softsp->open_state == GLVC_NO_OPEN) { + cmn_err(CE_WARN, + "glvc_close: device already closed"); + error = ENXIO; + } else { + softsp->open_state = GLVC_NO_OPEN; + } + mutex_exit(&softsp->open_mutex); + + return (error); +} + +/*ARGSUSED*/ +static int +glvc_read(dev_t dev, struct uio *uiop, cred_t *credp) +{ + glvc_soft_state_t *softsp; + int instance; + int rv, error = DDI_SUCCESS; + uint64_t hverr, recv_count = 0; + uint64_t status_reg; + clock_t tick; + + instance = getminor(dev); + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + mutex_enter(&softsp->recv_mutex); + + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", + hverr, status_reg)); + + + /* + * If no data available, we wait till we get some. + * Notice we still holding the recv_mutex lock at this + * point. + */ + while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != + GLVC_REG_RECV) { + tick = ddi_get_lbolt() + softsp->polling_interval; + rv = cv_timedwait_sig(&softsp->recv_cv, + &softsp->recv_mutex, tick); + if (rv == 0) { + /* + * We got interrupted. + */ + mutex_exit(&softsp->recv_mutex); + return (EINTR); + } + if (rv == -1) { + /* + * Timeout wait, trigger a soft intr in case + * we miss an interrupt or in polling mode. + */ + ddi_trigger_softintr(softsp->poll_mode_softint_id); + } + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", + hverr, status_reg)); + } + + /* Read data into kernel buffer */ + hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, + softsp->mtu, &recv_count); + + DPRINTF(("Instance %d glvc_read returns error = %ld, recv_count = %lu", + instance, hverr, recv_count)); + + if (hverr == H_EOK) { + if (uiop->uio_resid < recv_count) { + DPRINTF(("Instance %d, glvc_read user buffer " + "size(%lu) smaller than number of bytes " + "received(%lu).", instance, uiop->uio_resid, + recv_count)); + mutex_exit(&softsp->recv_mutex); + return (EINVAL); + } + /* move data from kernel to user space */ + error = uiomove(softsp->mb_recv_buf, recv_count, + UIO_READ, uiop); + } else { + error = glvc_emap_h2s(hverr); + } + + /* Clear the RECV data interrupt bit on device register */ + if (hv_service_clrstatus(softsp->s_id, GLVC_REG_RECV) != H_EOK) { + cmn_err(CE_WARN, "glvc_read clear status reg failed"); + } + + /* Set RECV interrupt enable bit so we can receive interrupt */ + if (softsp->intr_mode == GLVC_INTR_MODE) + if (hv_service_setstatus(softsp->s_id, GLVC_REG_RECV_ENA) + != H_EOK) { + cmn_err(CE_WARN, "glvc_read set status reg failed"); + } + + mutex_exit(&softsp->recv_mutex); + + return (error); +} + +/*ARGSUSED*/ +static int +glvc_write(dev_t dev, struct uio *uiop, cred_t *credp) +{ + glvc_soft_state_t *softsp; + int instance; + int rv, error = DDI_SUCCESS; + uint64_t hverr, send_count = 0; + clock_t tick; + + instance = getminor(dev); + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + if (uiop->uio_resid > softsp->mtu) + return (EINVAL); + + send_count = uiop->uio_resid; + DPRINTF(("instance %d glvc_write: request to send %lu bytes", + instance, send_count)); + + mutex_enter(&softsp->send_complete_mutex); + while (softsp->send_complete_flag == 0) { + tick = ddi_get_lbolt() + softsp->polling_interval; + rv = cv_timedwait_sig(&softsp->send_complete_cv, + &softsp->send_complete_mutex, tick); + if (rv == 0) { + /* + * We got interrupted. + */ + mutex_exit(&softsp->send_complete_mutex); + return (EINTR); + } + if (rv == -1) { + /* + * Timeout wait, trigger a soft intr in case + * we miss an interrupt or in polling mode. + */ + ddi_trigger_softintr(softsp->poll_mode_softint_id); + } + } + + /* move data from to user to kernel space */ + error = uiomove(softsp->mb_send_buf, send_count, + UIO_WRITE, uiop); + + if (error == 0) { + hverr = hv_service_send(softsp->s_id, + softsp->mb_send_buf_pa, send_count, &send_count); + error = glvc_emap_h2s(hverr); + } + + DPRINTF(("instance %d glvc_write write check error = %d," + " send_count = %lu", instance, error, send_count)); + + softsp->send_complete_flag = 0; + + mutex_exit(&softsp->send_complete_mutex); + + return (error); +} + +/* + * Interrupt handler + */ +static uint_t +glvc_intr(caddr_t arg) +{ + glvc_soft_state_t *softsp = (glvc_soft_state_t *)arg; + uint64_t status_reg; + int error = DDI_INTR_UNCLAIMED; + uint64_t hverr = H_EOK; + uint64_t clr_bits = 0; + + mutex_enter(&softsp->recv_mutex); + mutex_enter(&softsp->send_complete_mutex); + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + DPRINTF(("glvc_intr: err = %ld, getstatus = 0x%lx", + hverr, status_reg)); + + /* + * Clear SEND_COMPLETE bit and disable RECV interrupt + */ + if (status_reg & GLVC_REG_SEND) + clr_bits |= GLVC_REG_SEND; + if ((softsp->intr_mode == GLVC_INTR_MODE) && + (status_reg & GLVC_REG_RECV)) + clr_bits |= GLVC_REG_RECV_ENA; + + if ((hverr = hv_service_clrstatus(softsp->s_id, clr_bits)) + != H_EOK) { + cmn_err(CE_WARN, "glvc_intr clear status reg failed" + "error = %ld", hverr); + mutex_exit(&softsp->send_complete_mutex); + mutex_exit(&softsp->recv_mutex); + return (DDI_INTR_UNCLAIMED); + } + + if (status_reg & GLVC_REG_RECV) { + cv_broadcast(&softsp->recv_cv); + error = DDI_INTR_CLAIMED; + } + + if (status_reg & GLVC_REG_SEND) { + softsp->send_complete_flag = 1; + cv_broadcast(&softsp->send_complete_cv); + error = DDI_INTR_CLAIMED; + } + + mutex_exit(&softsp->send_complete_mutex); + mutex_exit(&softsp->recv_mutex); + + return (error); +} + +/* + * Peek to see if there is data received. If no data available, + * we sleep wait. If there is data, read from hypervisor and copy + * to ioctl buffer. We don't clear the receive data interrupt bit. + */ +static int +glvc_peek(glvc_soft_state_t *softsp, glvc_xport_msg_peek_t *msg_peek) +{ + int rv, error = 0; + uint64_t hverr = H_EOK; + uint64_t recv_count = 0; + uint64_t status_reg; + clock_t tick; + + mutex_enter(&softsp->recv_mutex); + + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", + hverr, status_reg)); + + /* + * If no data available, we wait till we get some. + * Notice we still holding the recv_mutex lock at + * this point. + */ + while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != + GLVC_REG_RECV) { + tick = ddi_get_lbolt() + softsp->polling_interval; + rv = cv_timedwait_sig(&softsp->recv_cv, + &softsp->recv_mutex, tick); + if (rv == 0) { + /* + * We got interrupted. + */ + mutex_exit(&softsp->recv_mutex); + return (EINTR); + } + if (rv == -1) { + /* + * Timeout wait, trigger a soft intr in case + * we miss an interrupt or in polling mode. + */ + ddi_trigger_softintr(softsp->poll_mode_softint_id); + } + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", + hverr, status_reg)); + } + + /* Read data into kernel buffer */ + hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, + softsp->mtu, &recv_count); + DPRINTF(("glvc_peek recv data, error = %ld, recv_count = %lu", + hverr, recv_count)); + + if (hverr == H_EOK && recv_count > 0) { + (void *) memcpy(msg_peek->buf, + softsp->mb_recv_buf, recv_count); + msg_peek->buflen = recv_count; + } else { + error = glvc_emap_h2s(hverr); + } + + mutex_exit(&softsp->recv_mutex); + + return (error); +} + +static int +glvc_ioctl_opt_op(glvc_soft_state_t *softsp, intptr_t arg, int mode) +{ + glvc_xport_opt_op_t glvc_xport_cmd; + uint64_t status_reg; + int retval = 0; + uint64_t hverr; + + if (ddi_copyin((caddr_t)arg, (caddr_t)&glvc_xport_cmd, + sizeof (glvc_xport_opt_op_t), mode) != 0) { + return (EFAULT); + } + + switch (glvc_xport_cmd.opt_sel) { + case GLVC_XPORT_OPT_MTU_SZ: + if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { + glvc_xport_cmd.opt_val = softsp->mtu; + retval = ddi_copyout((caddr_t)&glvc_xport_cmd, + (caddr_t)arg, sizeof (glvc_xport_opt_op_t), + mode); + } else + retval = ENOTSUP; + + break; + + case GLVC_XPORT_OPT_REG_STATUS: + if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { + mutex_enter(&softsp->statusreg_mutex); + hverr = hv_service_getstatus(softsp->s_id, &status_reg); + mutex_exit(&softsp->statusreg_mutex); + if (hverr == H_EOK) { + glvc_xport_cmd.opt_val = (uint32_t)status_reg; + retval = ddi_copyout((caddr_t)&glvc_xport_cmd, + (caddr_t)arg, sizeof (glvc_xport_opt_op_t), + mode); + } else { + retval = EIO; + } + } else { + retval = ENOTSUP; + } + + break; + + default: + retval = ENOTSUP; + break; + } + + return (retval); +} + + +/*ARGSUSED*/ +static int +glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, + int *rval_p) +{ + glvc_soft_state_t *softsp; + int instance = getminor(dev); + glvc_xport_msg_peek_t glvc_peek_msg, msg_peek_cmd; + glvc_xport_msg_peek32_t msg_peek_cmd32; + + int retval = 0; + + softsp = ddi_get_soft_state(glvc_ssp, instance); + + switch (cmd) { + case GLVC_XPORT_IOCTL_OPT_OP: + retval = glvc_ioctl_opt_op(softsp, arg, mode); + break; + + case GLVC_XPORT_IOCTL_DATA_PEEK: + glvc_peek_msg.buf = + (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); + if (glvc_peek_msg.buf == NULL) + return (EBUSY); + retval = glvc_peek(softsp, &glvc_peek_msg); + if (retval == 0) { + switch (ddi_model_convert_from(mode)) { + case DDI_MODEL_ILP32: + if (ddi_copyin((caddr_t)arg, + (caddr_t)&msg_peek_cmd32, + sizeof (glvc_xport_msg_peek32_t), + mode) == -1) { + retval = EFAULT; + break; + } + + if (msg_peek_cmd32.buflen32 == 0) { + retval = EINVAL; + break; + } + + if (msg_peek_cmd32.buflen32 > + glvc_peek_msg.buflen) + msg_peek_cmd32.buflen32 = + glvc_peek_msg.buflen; + + if (ddi_copyout((caddr_t)glvc_peek_msg.buf, + (caddr_t)(uintptr_t)msg_peek_cmd32.buf32, + msg_peek_cmd32.buflen32, mode) == -1) { + retval = EFAULT; + break; + } + + if (ddi_copyout((caddr_t)&msg_peek_cmd32, + (caddr_t)arg, + sizeof (glvc_xport_msg_peek32_t), mode) + == -1) + retval = EFAULT; + break; + + case DDI_MODEL_NONE: + if (ddi_copyin((caddr_t)arg, + (caddr_t)&msg_peek_cmd, + sizeof (glvc_xport_msg_peek_t), mode) == -1) + retval = EFAULT; + + if (msg_peek_cmd.buflen == 0) { + retval = EINVAL; + break; + } + + if (msg_peek_cmd.buflen > glvc_peek_msg.buflen) + msg_peek_cmd.buflen = + glvc_peek_msg.buflen; + + if (ddi_copyout((caddr_t)glvc_peek_msg.buf, + (caddr_t)msg_peek_cmd.buf, + msg_peek_cmd.buflen, mode) == -1) { + retval = EFAULT; + break; + } + + if (ddi_copyout((caddr_t)&msg_peek_cmd, + (caddr_t)arg, + sizeof (glvc_xport_msg_peek_t), mode) == -1) + retval = EFAULT; + break; + + default: + retval = EFAULT; + break; + } + } + kmem_free(glvc_peek_msg.buf, softsp->mtu); + break; + + default: + retval = ENOTSUP; + break; + } + return (retval); +} + +/* + * Map hypervisor error code to solaris. Only + * H_EOK, H_EINVA, H_EWOULDBLOCK and H_EIO are meaningful + * to this device. All other error codes are mapped to EIO. + */ +static int +glvc_emap_h2s(uint64_t hv_errcode) +{ + int s_errcode; + + switch (hv_errcode) { + case H_EOK: + s_errcode = 0; + break; + + case H_EINVAL: + s_errcode = EINVAL; + break; + + case H_EWOULDBLOCK: + s_errcode = EWOULDBLOCK; + break; + + case H_EIO: + s_errcode = EIO; + break; + + default: + /* should not happen */ + DPRINTF(("Unexpected device error code %ld received, " + "mapped to EIO", hv_errcode)); + s_errcode = EIO; + break; + } + + return (s_errcode); +} diff --git a/usr/src/uts/sun4v/io/glvc/glvc_hcall.s b/usr/src/uts/sun4v/io/glvc/glvc_hcall.s new file mode 100644 index 0000000000..e3717f245c --- /dev/null +++ b/usr/src/uts/sun4v/io/glvc/glvc_hcall.s @@ -0,0 +1,141 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Hypervisor calls called by glvc driver. +*/ + +#include +#include +#include + +#if defined(lint) || defined(__lint) + +/*ARGSUSED*/ +uint64_t +hv_service_recv(uint64_t s_id, uint64_t buf_pa, uint64_t size, + uint64_t *recv_bytes) +{ return (0); } + +/*ARGSUSED*/ +uint64_t +hv_service_send(uint64_t s_id, uint64_t buf_pa, uint64_t size, + uint64_t *send_bytes) +{ return (0); } + +/*ARGSUSED*/ +uint64_t +hv_service_getstatus(uint64_t s_id, uint64_t *vreg) +{ return (0); } + +/*ARGSUSED*/ +uint64_t +hv_service_setstatus(uint64_t s_id, uint64_t bits) +{ return (0); } + +/*ARGSUSED*/ +uint64_t +hv_service_clrstatus(uint64_t s_id, uint64_t bits) +{ return (0); } + +#else /* lint || __lint */ + + /* + * hv_service_recv(uint64_t s_id, uint64_t buf_pa, + * uint64_t size, uint64_t *recv_bytes); + */ + ENTRY(hv_service_recv) + save %sp, -SA(MINFRAME), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov SVC_RECV, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stx %o1, [%i3] +1: + ret + restore + SET_SIZE(hv_service_recv) + + /* + * hv_service_send(uint64_t s_id, uint64_t buf_pa, + * uint64_t size, uint64_t *recv_bytes); + */ + ENTRY(hv_service_send) + save %sp, -SA(MINFRAME), %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + mov SVC_SEND, %o5 + ta FAST_TRAP + brnz %o0, 1f + mov %o0, %i0 + stx %o1, [%i3] +1: + ret + restore + SET_SIZE(hv_service_send) + + /* + * hv_service_getstatus(uint64_t s_id, uint64_t *vreg); + */ + ENTRY(hv_service_getstatus) + mov %o1, %o4 ! save datap + mov SVC_GETSTATUS, %o5 + ta FAST_TRAP + brz,a %o0, 1f + stx %o1, [%o4] +1: + retl + nop + SET_SIZE(hv_service_getstatus) + + /* + * hv_service_setstatus(uint64_t s_id, uint64_t bits); + */ + ENTRY(hv_service_setstatus) + mov SVC_SETSTATUS, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_service_setstatus) + + /* + * hv_service_clrstatus(uint64_t s_id, uint64_t bits); + */ + ENTRY(hv_service_clrstatus) + mov SVC_CLRSTATUS, %o5 + ta FAST_TRAP + retl + nop + SET_SIZE(hv_service_clrstatus) + +#endif /* lint || __lint */ diff --git a/usr/src/uts/sun4v/ml/hcall.s b/usr/src/uts/sun4v/ml/hcall.s index b216f0448e..d445127644 100644 --- a/usr/src/uts/sun4v/ml/hcall.s +++ b/usr/src/uts/sun4v/ml/hcall.s @@ -127,33 +127,6 @@ uint64_t hv_cpu_yield(void) { return (0); } -/*ARGSUSED*/ -uint64_t -hv_service_recv(uint64_t s_id, uint64_t buf_pa, uint64_t size, - uint64_t *recv_bytes) -{ return (0); } - -/*ARGSUSED*/ -uint64_t -hv_service_send(uint64_t s_id, uint64_t buf_pa, uint64_t size, - uint64_t *send_bytes) -{ return (0); } - -/*ARGSUSED*/ -uint64_t -hv_service_getstatus(uint64_t s_id, uint64_t *vreg) -{ return (0); } - -/*ARGSUSED*/ -uint64_t -hv_service_setstatus(uint64_t s_id, uint64_t bits) -{ return (0); } - -/*ARGSUSED*/ -uint64_t -hv_service_clrstatus(uint64_t s_id, uint64_t bits) -{ return (0); } - /*ARGSUSED*/ uint64_t hv_cpu_state(uint64_t cpuid, uint64_t *cpu_state) @@ -454,80 +427,6 @@ hv_hpriv(void *func, uint64_t arg1, uint64_t arg2, uint64_t arg3) nop SET_SIZE(hv_cpu_yield) - /* - * hv_service_recv(uint64_t s_id, uint64_t buf_pa, - * uint64_t size, uint64_t *recv_bytes); - */ - ENTRY(hv_service_recv) - save %sp, -SA(MINFRAME), %sp - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - mov SVC_RECV, %o5 - ta FAST_TRAP - brnz %o0, 1f - mov %o0, %i0 - stx %o1, [%i3] -1: - ret - restore - SET_SIZE(hv_service_recv) - - /* - * hv_service_send(uint64_t s_id, uint64_t buf_pa, - * uint64_t size, uint64_t *recv_bytes); - */ - ENTRY(hv_service_send) - save %sp, -SA(MINFRAME), %sp - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - mov SVC_SEND, %o5 - ta FAST_TRAP - brnz %o0, 1f - mov %o0, %i0 - stx %o1, [%i3] -1: - ret - restore - SET_SIZE(hv_service_send) - - /* - * hv_service_getstatus(uint64_t s_id, uint64_t *vreg); - */ - ENTRY(hv_service_getstatus) - mov %o1, %o4 ! save datap - mov SVC_GETSTATUS, %o5 - ta FAST_TRAP - brz,a %o0, 1f - stx %o1, [%o4] -1: - retl - nop - SET_SIZE(hv_service_getstatus) - - /* - * hv_service_setstatus(uint64_t s_id, uint64_t bits); - */ - ENTRY(hv_service_setstatus) - mov SVC_SETSTATUS, %o5 - ta FAST_TRAP - retl - nop - SET_SIZE(hv_service_setstatus) - - /* - * hv_service_clrstatus(uint64_t s_id, uint64_t bits); - */ - ENTRY(hv_service_clrstatus) - mov SVC_CLRSTATUS, %o5 - ta FAST_TRAP - retl - nop - SET_SIZE(hv_service_clrstatus) - /* * int hv_cpu_state(uint64_t cpuid, uint64_t *cpu_state); */ diff --git a/usr/src/uts/sun4v/os/hsvc.c b/usr/src/uts/sun4v/os/hsvc.c index 689c1cc8c5..4b88b60222 100644 --- a/usr/src/uts/sun4v/os/hsvc.c +++ b/usr/src/uts/sun4v/os/hsvc.c @@ -653,15 +653,12 @@ hsvc_init(void) * uses hypervisor services belonging to the HSVC_GROUP_CORE API * group only for itself. * - * Rest of the API groups are currently negotiated on behalf - * of the pcitool and glvc support. In future, when these drivers - * are modified to do the negotiation themselves, corresponding - * entry should be removed from the table below. + * Note that the HSVC_GROUP_DIAG is negotiated on behalf of + * any driver/module using DIAG services. */ static hsvc_info_t hsvcinfo_unix[] = { {HSVC_REV_1, NULL, HSVC_GROUP_SUN4V, 1, 0, NULL}, {HSVC_REV_1, NULL, HSVC_GROUP_CORE, 1, 0, NULL}, - {HSVC_REV_1, NULL, HSVC_GROUP_VSC, 1, 0, NULL}, {HSVC_REV_1, NULL, HSVC_GROUP_DIAG, 1, 0, NULL} }; diff --git a/usr/src/uts/sun4v/sys/glvc.h b/usr/src/uts/sun4v/sys/glvc.h index 993aefaa6d..13f27e3158 100644 --- a/usr/src/uts/sun4v/sys/glvc.h +++ b/usr/src/uts/sun4v/sys/glvc.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +32,28 @@ extern "C" { #endif +/* + * Service channel related Hypervisor function numbers. + */ +#define SVC_SEND 0x80 +#define SVC_RECV 0x81 +#define SVC_GETSTATUS 0x82 +#define SVC_SETSTATUS 0x83 +#define SVC_CLRSTATUS 0x84 + +#ifndef _ASM + +/* + * VSC API versioning. + * + * Current glvc driver supports VSC API version 1.0. + */ +#define GLVC_VSC_MAJOR_VER_1 0x1ull +#define GLVC_VSC_MAJOR_VER GLVC_VSC_MAJOR_VER_1 + +#define GLVC_VSC_MINOR_VER_0 0x0ull +#define GLVC_VSC_MINOR_VER GLVC_VSC_MINOR_VER_0 + /* for ioctl */ #define GLVC_XPORT_IOCTL_DATA_PEEK 1 #define GLVC_XPORT_IOCTL_OPT_OP 2 @@ -62,6 +83,8 @@ typedef struct glvc_xport_opt_op { uint32_t opt_val; /* option value to use */ } glvc_xport_opt_op_t; +#endif /* _ASM */ + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sun4v/sys/hypervisor_api.h b/usr/src/uts/sun4v/sys/hypervisor_api.h index 3b4aad6910..57e4808a75 100644 --- a/usr/src/uts/sun4v/sys/hypervisor_api.h +++ b/usr/src/uts/sun4v/sys/hypervisor_api.h @@ -104,12 +104,6 @@ extern "C" { #define CONS_READ 0x60 #define CONS_WRITE 0x61 -#define SVC_SEND 0x80 -#define SVC_RECV 0x81 -#define SVC_GETSTATUS 0x82 -#define SVC_SETSTATUS 0x83 -#define SVC_CLRSTATUS 0x84 - #define TTRACE_BUF_CONF 0x90 #define TTRACE_BUF_INFO 0x91 #define TTRACE_ENABLE 0x92 -- cgit v1.2.3