1181624Skmacy/****************************************************************************** 2181624Skmacy * evtchn.c 3181624Skmacy * 4181624Skmacy * Xenolinux driver for receiving and demuxing event-channel signals. 5181624Skmacy * 6181624Skmacy * Copyright (c) 2004, K A Fraser 7181624Skmacy */ 8181624Skmacy 9181624Skmacy#include <sys/cdefs.h> 10181624Skmacy__FBSDID("$FreeBSD$"); 11181624Skmacy 12181624Skmacy#include <sys/param.h> 13181624Skmacy#include <sys/systm.h> 14181624Skmacy#include <sys/uio.h> 15181624Skmacy#include <sys/bus.h> 16181624Skmacy#include <sys/malloc.h> 17181624Skmacy#include <sys/kernel.h> 18181624Skmacy#include <sys/lock.h> 19181624Skmacy#include <sys/mutex.h> 20181624Skmacy#include <sys/selinfo.h> 21181624Skmacy#include <sys/poll.h> 22181624Skmacy#include <sys/conf.h> 23181624Skmacy#include <sys/fcntl.h> 24181624Skmacy#include <sys/ioccom.h> 25255040Sgibbs#include <sys/rman.h> 26181624Skmacy 27255040Sgibbs#include <xen/xen-os.h> 28255040Sgibbs#include <xen/evtchn.h> 29186557Skmacy#include <xen/xen_intr.h> 30255040Sgibbs 31181624Skmacy#include <machine/bus.h> 32181624Skmacy#include <machine/resource.h> 33181624Skmacy#include <machine/xen/synch_bitops.h> 34181624Skmacy 35255040Sgibbs#include <xen/evtchn/evtchnvar.h> 36181624Skmacy 37181624Skmacytypedef struct evtchn_sotfc { 38181624Skmacy 39181624Skmacy struct selinfo ev_rsel; 40181624Skmacy} evtchn_softc_t; 41181624Skmacy 42181624Skmacy/* Only one process may open /dev/xen/evtchn at any time. */ 43181624Skmacystatic unsigned long evtchn_dev_inuse; 44181624Skmacy 45181624Skmacy/* Notification ring, accessed via /dev/xen/evtchn. */ 46181624Skmacy 47181624Skmacy#define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */ 48181624Skmacy 49181624Skmacy#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) 50181624Skmacystatic uint16_t *ring; 51181624Skmacystatic unsigned int ring_cons, ring_prod, ring_overflow; 52181624Skmacy 53181624Skmacy/* Which ports is user-space bound to? */ 54181624Skmacystatic uint32_t bound_ports[32]; 55181624Skmacy 56181624Skmacy/* Unique address for processes to sleep on */ 57181624Skmacystatic void *evtchn_waddr = ˚ 58181624Skmacy 59181624Skmacystatic struct mtx lock, upcall_lock; 60181624Skmacy 61181624Skmacystatic d_read_t evtchn_read; 62181624Skmacystatic d_write_t evtchn_write; 63181624Skmacystatic d_ioctl_t evtchn_ioctl; 64181624Skmacystatic d_poll_t evtchn_poll; 65181624Skmacystatic d_open_t evtchn_open; 66181624Skmacystatic d_close_t evtchn_close; 67181624Skmacy 68181624Skmacy 69181624Skmacyvoid 70255040Sgibbsevtchn_device_upcall(evtchn_port_t port) 71181624Skmacy{ 72181624Skmacy mtx_lock(&upcall_lock); 73181624Skmacy 74255040Sgibbs evtchn_mask_port(port); 75255040Sgibbs evtchn_clear_port(port); 76181624Skmacy 77181624Skmacy if ( ring != NULL ) { 78181624Skmacy if ( (ring_prod - ring_cons) < EVTCHN_RING_SIZE ) { 79181624Skmacy ring[EVTCHN_RING_MASK(ring_prod)] = (uint16_t)port; 80181624Skmacy if ( ring_cons == ring_prod++ ) { 81181624Skmacy wakeup(evtchn_waddr); 82181624Skmacy } 83181624Skmacy } 84181624Skmacy else { 85181624Skmacy ring_overflow = 1; 86181624Skmacy } 87181624Skmacy } 88181624Skmacy 89181624Skmacy mtx_unlock(&upcall_lock); 90181624Skmacy} 91181624Skmacy 92181624Skmacystatic void 93181624Skmacy__evtchn_reset_buffer_ring(void) 94181624Skmacy{ 95181624Skmacy /* Initialise the ring to empty. Clear errors. */ 96181624Skmacy ring_cons = ring_prod = ring_overflow = 0; 97181624Skmacy} 98181624Skmacy 99181624Skmacystatic int 100181624Skmacyevtchn_read(struct cdev *dev, struct uio *uio, int ioflag) 101181624Skmacy{ 102181624Skmacy int rc; 103181624Skmacy unsigned int count, c, p, sst = 0, bytes1 = 0, bytes2 = 0; 104181624Skmacy count = uio->uio_resid; 105181624Skmacy 106181624Skmacy count &= ~1; /* even number of bytes */ 107181624Skmacy 108181624Skmacy if ( count == 0 ) 109181624Skmacy { 110181624Skmacy rc = 0; 111181624Skmacy goto out; 112181624Skmacy } 113181624Skmacy 114181624Skmacy if ( count > PAGE_SIZE ) 115181624Skmacy count = PAGE_SIZE; 116181624Skmacy 117181624Skmacy for ( ; ; ) { 118181624Skmacy if ( (c = ring_cons) != (p = ring_prod) ) 119181624Skmacy break; 120181624Skmacy 121181624Skmacy if ( ring_overflow ) { 122181624Skmacy rc = EFBIG; 123181624Skmacy goto out; 124181624Skmacy } 125181624Skmacy 126181624Skmacy if (sst != 0) { 127181624Skmacy rc = EINTR; 128181624Skmacy goto out; 129181624Skmacy } 130181624Skmacy 131181624Skmacy /* PCATCH == check for signals before and after sleeping 132181624Skmacy * PWAIT == priority of waiting on resource 133181624Skmacy */ 134181624Skmacy sst = tsleep(evtchn_waddr, PWAIT|PCATCH, "evchwt", 10); 135181624Skmacy } 136181624Skmacy 137181624Skmacy /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ 138181624Skmacy if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 ) { 139181624Skmacy bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(uint16_t); 140181624Skmacy bytes2 = EVTCHN_RING_MASK(p) * sizeof(uint16_t); 141181624Skmacy } 142181624Skmacy else { 143181624Skmacy bytes1 = (p - c) * sizeof(uint16_t); 144181624Skmacy bytes2 = 0; 145181624Skmacy } 146181624Skmacy 147181624Skmacy /* Truncate chunks according to caller's maximum byte count. */ 148181624Skmacy if ( bytes1 > count ) { 149181624Skmacy bytes1 = count; 150181624Skmacy bytes2 = 0; 151181624Skmacy } 152181624Skmacy else if ( (bytes1 + bytes2) > count ) { 153181624Skmacy bytes2 = count - bytes1; 154181624Skmacy } 155181624Skmacy 156181624Skmacy if ( uiomove(&ring[EVTCHN_RING_MASK(c)], bytes1, uio) || 157181624Skmacy ((bytes2 != 0) && uiomove(&ring[0], bytes2, uio))) 158181624Skmacy /* keeping this around as its replacement is not equivalent 159181624Skmacy * copyout(&ring[0], &buf[bytes1], bytes2) 160181624Skmacy */ 161181624Skmacy { 162181624Skmacy rc = EFAULT; 163181624Skmacy goto out; 164181624Skmacy } 165181624Skmacy 166181624Skmacy ring_cons += (bytes1 + bytes2) / sizeof(uint16_t); 167181624Skmacy 168181624Skmacy rc = bytes1 + bytes2; 169181624Skmacy 170181624Skmacy out: 171181624Skmacy 172181624Skmacy return rc; 173181624Skmacy} 174181624Skmacy 175181624Skmacystatic int 176181624Skmacyevtchn_write(struct cdev *dev, struct uio *uio, int ioflag) 177181624Skmacy{ 178181624Skmacy int rc, i, count; 179181624Skmacy 180181624Skmacy count = uio->uio_resid; 181181624Skmacy 182181624Skmacy uint16_t *kbuf = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 183181624Skmacy 184181624Skmacy 185181624Skmacy if ( kbuf == NULL ) 186181624Skmacy return ENOMEM; 187181624Skmacy 188181624Skmacy count &= ~1; /* even number of bytes */ 189181624Skmacy 190181624Skmacy if ( count == 0 ) { 191181624Skmacy rc = 0; 192181624Skmacy goto out; 193181624Skmacy } 194181624Skmacy 195181624Skmacy if ( count > PAGE_SIZE ) 196181624Skmacy count = PAGE_SIZE; 197181624Skmacy 198181624Skmacy if ( uiomove(kbuf, count, uio) != 0 ) { 199181624Skmacy rc = EFAULT; 200181624Skmacy goto out; 201181624Skmacy } 202181624Skmacy 203181624Skmacy mtx_lock_spin(&lock); 204181624Skmacy for ( i = 0; i < (count/2); i++ ) 205181624Skmacy if ( test_bit(kbuf[i], &bound_ports[0]) ) 206255040Sgibbs evtchn_unmask_port(kbuf[i]); 207181624Skmacy mtx_unlock_spin(&lock); 208181624Skmacy 209181624Skmacy rc = count; 210181624Skmacy 211181624Skmacy out: 212181624Skmacy free(kbuf, M_DEVBUF); 213181624Skmacy return rc; 214181624Skmacy} 215181624Skmacy 216181624Skmacystatic int 217181624Skmacyevtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, 218181624Skmacy int mode, struct thread *td __unused) 219181624Skmacy{ 220181624Skmacy int rc = 0; 221181624Skmacy 222255040Sgibbs#ifdef NOTYET 223181624Skmacy mtx_lock_spin(&lock); 224181624Skmacy 225181624Skmacy switch ( cmd ) 226181624Skmacy { 227181624Skmacy case EVTCHN_RESET: 228181624Skmacy __evtchn_reset_buffer_ring(); 229181624Skmacy break; 230181624Skmacy case EVTCHN_BIND: 231189699Sdfr if ( !synch_test_and_set_bit((uintptr_t)arg, &bound_ports[0]) ) 232189699Sdfr unmask_evtchn((uintptr_t)arg); 233181624Skmacy else 234181624Skmacy rc = EINVAL; 235181624Skmacy break; 236181624Skmacy case EVTCHN_UNBIND: 237189699Sdfr if ( synch_test_and_clear_bit((uintptr_t)arg, &bound_ports[0]) ) 238189699Sdfr mask_evtchn((uintptr_t)arg); 239181624Skmacy else 240181624Skmacy rc = EINVAL; 241181624Skmacy break; 242181624Skmacy default: 243181624Skmacy rc = ENOSYS; 244181624Skmacy break; 245181624Skmacy } 246181624Skmacy 247181624Skmacy mtx_unlock_spin(&lock); 248255040Sgibbs#endif 249181624Skmacy 250181624Skmacy return rc; 251181624Skmacy} 252181624Skmacy 253181624Skmacystatic int 254181624Skmacyevtchn_poll(struct cdev *dev, int poll_events, struct thread *td) 255181624Skmacy{ 256181624Skmacy 257181624Skmacy evtchn_softc_t *sc; 258181624Skmacy unsigned int mask = POLLOUT | POLLWRNORM; 259181624Skmacy 260181624Skmacy sc = dev->si_drv1; 261181624Skmacy 262181624Skmacy if ( ring_cons != ring_prod ) 263181624Skmacy mask |= POLLIN | POLLRDNORM; 264181624Skmacy else if ( ring_overflow ) 265181624Skmacy mask = POLLERR; 266181624Skmacy else 267181624Skmacy selrecord(td, &sc->ev_rsel); 268181624Skmacy 269181624Skmacy 270181624Skmacy return mask; 271181624Skmacy} 272181624Skmacy 273181624Skmacy 274181624Skmacystatic int 275181624Skmacyevtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td) 276181624Skmacy{ 277181624Skmacy uint16_t *_ring; 278181624Skmacy 279181624Skmacy if (flag & O_NONBLOCK) 280181624Skmacy return EBUSY; 281181624Skmacy 282181624Skmacy if ( synch_test_and_set_bit(0, &evtchn_dev_inuse) ) 283181624Skmacy return EBUSY; 284181624Skmacy 285181624Skmacy if ( (_ring = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK)) == NULL ) 286181624Skmacy return ENOMEM; 287181624Skmacy 288181624Skmacy mtx_lock_spin(&lock); 289181624Skmacy ring = _ring; 290181624Skmacy __evtchn_reset_buffer_ring(); 291181624Skmacy mtx_unlock_spin(&lock); 292181624Skmacy 293181624Skmacy 294181624Skmacy return 0; 295181624Skmacy} 296181624Skmacy 297181624Skmacystatic int 298181624Skmacyevtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused) 299181624Skmacy{ 300181624Skmacy int i; 301181624Skmacy 302181624Skmacy if (ring != NULL) { 303181624Skmacy free(ring, M_DEVBUF); 304181624Skmacy ring = NULL; 305181624Skmacy } 306204159Skmacy mtx_lock_spin(&lock); 307181624Skmacy for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) 308181624Skmacy if ( synch_test_and_clear_bit(i, &bound_ports[0]) ) 309255040Sgibbs evtchn_mask_port(i); 310181624Skmacy mtx_unlock_spin(&lock); 311181624Skmacy 312181624Skmacy evtchn_dev_inuse = 0; 313181624Skmacy 314181624Skmacy return 0; 315181624Skmacy} 316181624Skmacy 317181624Skmacystatic struct cdevsw evtchn_devsw = { 318228162Sjhb .d_version = D_VERSION, 319228162Sjhb .d_open = evtchn_open, 320228162Sjhb .d_close = evtchn_close, 321228162Sjhb .d_read = evtchn_read, 322228162Sjhb .d_write = evtchn_write, 323228162Sjhb .d_ioctl = evtchn_ioctl, 324228162Sjhb .d_poll = evtchn_poll, 325228162Sjhb .d_name = "evtchn", 326181624Skmacy}; 327181624Skmacy 328181624Skmacy 329181624Skmacy/* XXX - if this device is ever supposed to support use by more than one process 330181624Skmacy * this global static will have to go away 331181624Skmacy */ 332181624Skmacystatic struct cdev *evtchn_dev; 333181624Skmacy 334181624Skmacy 335181624Skmacy 336181624Skmacystatic int 337181865Skmacyevtchn_dev_init(void *dummy __unused) 338181624Skmacy{ 339181624Skmacy /* XXX I believe we don't need these leaving them here for now until we 340181624Skmacy * have some semblance of it working 341181624Skmacy */ 342181624Skmacy mtx_init(&upcall_lock, "evtchup", NULL, MTX_DEF); 343181624Skmacy 344181624Skmacy /* (DEVFS) create '/dev/misc/evtchn'. */ 345181624Skmacy evtchn_dev = make_dev(&evtchn_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "xen/evtchn"); 346181624Skmacy 347181624Skmacy mtx_init(&lock, "evch", NULL, MTX_SPIN | MTX_NOWITNESS); 348181624Skmacy 349181624Skmacy evtchn_dev->si_drv1 = malloc(sizeof(evtchn_softc_t), M_DEVBUF, M_WAITOK); 350181624Skmacy bzero(evtchn_dev->si_drv1, sizeof(evtchn_softc_t)); 351181624Skmacy 352189699Sdfr if (bootverbose) 353189699Sdfr printf("Event-channel device installed.\n"); 354181624Skmacy 355181624Skmacy return 0; 356181624Skmacy} 357181624Skmacy 358181865SkmacySYSINIT(evtchn_dev_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, evtchn_dev_init, NULL); 359