1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 /* 4 * Xen para-virtual sound device 5 * 6 * Copyright (C) 2016-2018 EPAM Systems Inc. 7 * 8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> 9 */ 10 11 #include <linux/delay.h> 12 #include <linux/module.h> 13 14 #include <xen/page.h> 15 #include <xen/platform_pci.h> 16 #include <xen/xen.h> 17 #include <xen/xenbus.h> 18 19 #include <xen/xen-front-pgdir-shbuf.h> 20 #include <xen/interface/io/sndif.h> 21 22 #include "xen_snd_front.h" 23 #include "xen_snd_front_alsa.h" 24 #include "xen_snd_front_evtchnl.h" 25 26 static struct xensnd_req * 27 be_stream_prepare_req(struct xen_snd_front_evtchnl *evtchnl, u8 operation) 28 { 29 struct xensnd_req *req; 30 31 req = RING_GET_REQUEST(&evtchnl->u.req.ring, 32 evtchnl->u.req.ring.req_prod_pvt); 33 req->operation = operation; 34 req->id = evtchnl->evt_next_id++; 35 evtchnl->evt_id = req->id; 36 return req; 37 } 38 39 static int be_stream_do_io(struct xen_snd_front_evtchnl *evtchnl) 40 { 41 if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED)) 42 return -EIO; 43 44 reinit_completion(&evtchnl->u.req.completion); 45 xen_snd_front_evtchnl_flush(evtchnl); 46 return 0; 47 } 48 49 static int be_stream_wait_io(struct xen_snd_front_evtchnl *evtchnl) 50 { 51 if (wait_for_completion_timeout(&evtchnl->u.req.completion, 52 msecs_to_jiffies(VSND_WAIT_BACK_MS)) <= 0) 53 return -ETIMEDOUT; 54 55 return evtchnl->u.req.resp_status; 56 } 57 58 int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, 59 struct xensnd_query_hw_param *hw_param_req, 60 struct xensnd_query_hw_param *hw_param_resp) 61 { 62 struct xensnd_req *req; 63 int ret; 64 65 guard(mutex)(&evtchnl->u.req.req_io_lock); 66 67 scoped_guard(mutex, &evtchnl->ring_io_lock) { 68 req = be_stream_prepare_req(evtchnl, XENSND_OP_HW_PARAM_QUERY); 69 req->op.hw_param = *hw_param_req; 70 } 71 72 ret = be_stream_do_io(evtchnl); 73 74 if (ret == 0) 75 ret = be_stream_wait_io(evtchnl); 76 77 if (ret == 0) 78 *hw_param_resp = evtchnl->u.req.resp.hw_param; 79 80 return ret; 81 } 82 83 int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, 84 struct xen_front_pgdir_shbuf *shbuf, 85 u8 format, unsigned int channels, 86 unsigned int rate, u32 buffer_sz, 87 u32 period_sz) 88 { 89 struct xensnd_req *req; 90 int ret; 91 92 guard(mutex)(&evtchnl->u.req.req_io_lock); 93 94 scoped_guard(mutex, &evtchnl->ring_io_lock) { 95 req = be_stream_prepare_req(evtchnl, XENSND_OP_OPEN); 96 req->op.open.pcm_format = format; 97 req->op.open.pcm_channels = channels; 98 req->op.open.pcm_rate = rate; 99 req->op.open.buffer_sz = buffer_sz; 100 req->op.open.period_sz = period_sz; 101 req->op.open.gref_directory = 102 xen_front_pgdir_shbuf_get_dir_start(shbuf); 103 } 104 105 ret = be_stream_do_io(evtchnl); 106 107 if (ret == 0) 108 ret = be_stream_wait_io(evtchnl); 109 110 return ret; 111 } 112 113 int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl) 114 { 115 __always_unused struct xensnd_req *req; 116 int ret; 117 118 guard(mutex)(&evtchnl->u.req.req_io_lock); 119 120 scoped_guard(mutex, &evtchnl->ring_io_lock) { 121 req = be_stream_prepare_req(evtchnl, XENSND_OP_CLOSE); 122 } 123 124 ret = be_stream_do_io(evtchnl); 125 126 if (ret == 0) 127 ret = be_stream_wait_io(evtchnl); 128 129 return ret; 130 } 131 132 int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl, 133 unsigned long pos, unsigned long count) 134 { 135 struct xensnd_req *req; 136 int ret; 137 138 guard(mutex)(&evtchnl->u.req.req_io_lock); 139 140 scoped_guard(mutex, &evtchnl->ring_io_lock) { 141 req = be_stream_prepare_req(evtchnl, XENSND_OP_WRITE); 142 req->op.rw.length = count; 143 req->op.rw.offset = pos; 144 } 145 146 ret = be_stream_do_io(evtchnl); 147 148 if (ret == 0) 149 ret = be_stream_wait_io(evtchnl); 150 151 return ret; 152 } 153 154 int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl, 155 unsigned long pos, unsigned long count) 156 { 157 struct xensnd_req *req; 158 int ret; 159 160 guard(mutex)(&evtchnl->u.req.req_io_lock); 161 162 scoped_guard(mutex, &evtchnl->ring_io_lock) { 163 req = be_stream_prepare_req(evtchnl, XENSND_OP_READ); 164 req->op.rw.length = count; 165 req->op.rw.offset = pos; 166 } 167 168 ret = be_stream_do_io(evtchnl); 169 170 if (ret == 0) 171 ret = be_stream_wait_io(evtchnl); 172 173 return ret; 174 } 175 176 int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl *evtchnl, 177 int type) 178 { 179 struct xensnd_req *req; 180 int ret; 181 182 guard(mutex)(&evtchnl->u.req.req_io_lock); 183 184 scoped_guard(mutex, &evtchnl->ring_io_lock) { 185 req = be_stream_prepare_req(evtchnl, XENSND_OP_TRIGGER); 186 req->op.trigger.type = type; 187 } 188 189 ret = be_stream_do_io(evtchnl); 190 191 if (ret == 0) 192 ret = be_stream_wait_io(evtchnl); 193 194 return ret; 195 } 196 197 static void xen_snd_drv_fini(struct xen_snd_front_info *front_info) 198 { 199 xen_snd_front_alsa_fini(front_info); 200 xen_snd_front_evtchnl_free_all(front_info); 201 } 202 203 static int sndback_initwait(struct xen_snd_front_info *front_info) 204 { 205 int num_streams; 206 int ret; 207 208 ret = xen_snd_front_cfg_card(front_info, &num_streams); 209 if (ret < 0) 210 return ret; 211 212 /* create event channels for all streams and publish */ 213 ret = xen_snd_front_evtchnl_create_all(front_info, num_streams); 214 if (ret < 0) 215 return ret; 216 217 return xen_snd_front_evtchnl_publish_all(front_info); 218 } 219 220 static int sndback_connect(struct xen_snd_front_info *front_info) 221 { 222 return xen_snd_front_alsa_init(front_info); 223 } 224 225 static void sndback_disconnect(struct xen_snd_front_info *front_info) 226 { 227 xen_snd_drv_fini(front_info); 228 xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising); 229 } 230 231 static void sndback_changed(struct xenbus_device *xb_dev, 232 enum xenbus_state backend_state) 233 { 234 struct xen_snd_front_info *front_info = dev_get_drvdata(&xb_dev->dev); 235 int ret; 236 237 dev_dbg(&xb_dev->dev, "Backend state is %s, front is %s\n", 238 xenbus_strstate(backend_state), 239 xenbus_strstate(xb_dev->state)); 240 241 switch (backend_state) { 242 case XenbusStateReconfiguring: 243 case XenbusStateReconfigured: 244 case XenbusStateInitialised: 245 break; 246 247 case XenbusStateInitialising: 248 /* Recovering after backend unexpected closure. */ 249 sndback_disconnect(front_info); 250 break; 251 252 case XenbusStateInitWait: 253 /* Recovering after backend unexpected closure. */ 254 sndback_disconnect(front_info); 255 256 ret = sndback_initwait(front_info); 257 if (ret < 0) 258 xenbus_dev_fatal(xb_dev, ret, "initializing frontend"); 259 else 260 xenbus_switch_state(xb_dev, XenbusStateInitialised); 261 break; 262 263 case XenbusStateConnected: 264 if (xb_dev->state != XenbusStateInitialised) 265 break; 266 267 ret = sndback_connect(front_info); 268 if (ret < 0) 269 xenbus_dev_fatal(xb_dev, ret, "initializing frontend"); 270 else 271 xenbus_switch_state(xb_dev, XenbusStateConnected); 272 break; 273 274 case XenbusStateClosing: 275 /* 276 * In this state backend starts freeing resources, 277 * so let it go into closed state first, so we can also 278 * remove ours. 279 */ 280 break; 281 282 case XenbusStateUnknown: 283 case XenbusStateClosed: 284 if (xb_dev->state == XenbusStateClosed) 285 break; 286 287 sndback_disconnect(front_info); 288 break; 289 } 290 } 291 292 static int xen_drv_probe(struct xenbus_device *xb_dev, 293 const struct xenbus_device_id *id) 294 { 295 struct xen_snd_front_info *front_info; 296 297 front_info = devm_kzalloc(&xb_dev->dev, 298 sizeof(*front_info), GFP_KERNEL); 299 if (!front_info) 300 return -ENOMEM; 301 302 front_info->xb_dev = xb_dev; 303 dev_set_drvdata(&xb_dev->dev, front_info); 304 305 return xenbus_switch_state(xb_dev, XenbusStateInitialising); 306 } 307 308 static void xen_drv_remove(struct xenbus_device *dev) 309 { 310 struct xen_snd_front_info *front_info = dev_get_drvdata(&dev->dev); 311 int to = 100; 312 313 xenbus_switch_state(dev, XenbusStateClosing); 314 315 /* 316 * On driver removal it is disconnected from XenBus, 317 * so no backend state change events come via .otherend_changed 318 * callback. This prevents us from exiting gracefully, e.g. 319 * signaling the backend to free event channels, waiting for its 320 * state to change to XenbusStateClosed and cleaning at our end. 321 * Normally when front driver removed backend will finally go into 322 * XenbusStateInitWait state. 323 * 324 * Workaround: read backend's state manually and wait with time-out. 325 */ 326 while ((xenbus_read_unsigned(front_info->xb_dev->otherend, "state", 327 XenbusStateUnknown) != XenbusStateInitWait) && 328 --to) 329 msleep(10); 330 331 if (!to) { 332 unsigned int state; 333 334 state = xenbus_read_unsigned(front_info->xb_dev->otherend, 335 "state", XenbusStateUnknown); 336 pr_err("Backend state is %s while removing driver\n", 337 xenbus_strstate(state)); 338 } 339 340 xen_snd_drv_fini(front_info); 341 xenbus_frontend_closed(dev); 342 } 343 344 static const struct xenbus_device_id xen_drv_ids[] = { 345 { XENSND_DRIVER_NAME }, 346 { "" } 347 }; 348 349 static struct xenbus_driver xen_driver = { 350 .ids = xen_drv_ids, 351 .probe = xen_drv_probe, 352 .remove = xen_drv_remove, 353 .otherend_changed = sndback_changed, 354 .not_essential = true, 355 }; 356 357 static int __init xen_drv_init(void) 358 { 359 if (!xen_domain()) 360 return -ENODEV; 361 362 if (!xen_has_pv_devices()) 363 return -ENODEV; 364 365 /* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */ 366 if (XEN_PAGE_SIZE != PAGE_SIZE) { 367 pr_err(XENSND_DRIVER_NAME ": different kernel and Xen page sizes are not supported: XEN_PAGE_SIZE (%lu) != PAGE_SIZE (%lu)\n", 368 XEN_PAGE_SIZE, PAGE_SIZE); 369 return -ENODEV; 370 } 371 372 pr_info("Initialising Xen " XENSND_DRIVER_NAME " frontend driver\n"); 373 return xenbus_register_frontend(&xen_driver); 374 } 375 376 static void __exit xen_drv_fini(void) 377 { 378 pr_info("Unregistering Xen " XENSND_DRIVER_NAME " frontend driver\n"); 379 xenbus_unregister_driver(&xen_driver); 380 } 381 382 module_init(xen_drv_init); 383 module_exit(xen_drv_fini); 384 385 MODULE_DESCRIPTION("Xen virtual sound device frontend"); 386 MODULE_LICENSE("GPL"); 387 MODULE_ALIAS("xen:" XENSND_DRIVER_NAME); 388