root/sound/xen/xen_snd_front_evtchnl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. evtchnl_interrupt_req
  2. evtchnl_interrupt_evt
  3. xen_snd_front_evtchnl_flush
  4. evtchnl_free
  5. xen_snd_front_evtchnl_free_all
  6. evtchnl_alloc
  7. xen_snd_front_evtchnl_create_all
  8. evtchnl_publish
  9. xen_snd_front_evtchnl_publish_all
  10. xen_snd_front_evtchnl_pair_set_connected
  11. xen_snd_front_evtchnl_pair_clear

   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 <xen/events.h>
  12 #include <xen/grant_table.h>
  13 #include <xen/xen.h>
  14 #include <xen/xenbus.h>
  15 
  16 #include "xen_snd_front.h"
  17 #include "xen_snd_front_alsa.h"
  18 #include "xen_snd_front_cfg.h"
  19 #include "xen_snd_front_evtchnl.h"
  20 
  21 static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id)
  22 {
  23         struct xen_snd_front_evtchnl *channel = dev_id;
  24         struct xen_snd_front_info *front_info = channel->front_info;
  25         struct xensnd_resp *resp;
  26         RING_IDX i, rp;
  27 
  28         if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
  29                 return IRQ_HANDLED;
  30 
  31         mutex_lock(&channel->ring_io_lock);
  32 
  33 again:
  34         rp = channel->u.req.ring.sring->rsp_prod;
  35         /* Ensure we see queued responses up to rp. */
  36         rmb();
  37 
  38         /*
  39          * Assume that the backend is trusted to always write sane values
  40          * to the ring counters, so no overflow checks on frontend side
  41          * are required.
  42          */
  43         for (i = channel->u.req.ring.rsp_cons; i != rp; i++) {
  44                 resp = RING_GET_RESPONSE(&channel->u.req.ring, i);
  45                 if (resp->id != channel->evt_id)
  46                         continue;
  47                 switch (resp->operation) {
  48                 case XENSND_OP_OPEN:
  49                         /* fall through */
  50                 case XENSND_OP_CLOSE:
  51                         /* fall through */
  52                 case XENSND_OP_READ:
  53                         /* fall through */
  54                 case XENSND_OP_WRITE:
  55                         /* fall through */
  56                 case XENSND_OP_TRIGGER:
  57                         channel->u.req.resp_status = resp->status;
  58                         complete(&channel->u.req.completion);
  59                         break;
  60                 case XENSND_OP_HW_PARAM_QUERY:
  61                         channel->u.req.resp_status = resp->status;
  62                         channel->u.req.resp.hw_param =
  63                                         resp->resp.hw_param;
  64                         complete(&channel->u.req.completion);
  65                         break;
  66 
  67                 default:
  68                         dev_err(&front_info->xb_dev->dev,
  69                                 "Operation %d is not supported\n",
  70                                 resp->operation);
  71                         break;
  72                 }
  73         }
  74 
  75         channel->u.req.ring.rsp_cons = i;
  76         if (i != channel->u.req.ring.req_prod_pvt) {
  77                 int more_to_do;
  78 
  79                 RING_FINAL_CHECK_FOR_RESPONSES(&channel->u.req.ring,
  80                                                more_to_do);
  81                 if (more_to_do)
  82                         goto again;
  83         } else {
  84                 channel->u.req.ring.sring->rsp_event = i + 1;
  85         }
  86 
  87         mutex_unlock(&channel->ring_io_lock);
  88         return IRQ_HANDLED;
  89 }
  90 
  91 static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id)
  92 {
  93         struct xen_snd_front_evtchnl *channel = dev_id;
  94         struct xensnd_event_page *page = channel->u.evt.page;
  95         u32 cons, prod;
  96 
  97         if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
  98                 return IRQ_HANDLED;
  99 
 100         mutex_lock(&channel->ring_io_lock);
 101 
 102         prod = page->in_prod;
 103         /* Ensure we see ring contents up to prod. */
 104         virt_rmb();
 105         if (prod == page->in_cons)
 106                 goto out;
 107 
 108         /*
 109          * Assume that the backend is trusted to always write sane values
 110          * to the ring counters, so no overflow checks on frontend side
 111          * are required.
 112          */
 113         for (cons = page->in_cons; cons != prod; cons++) {
 114                 struct xensnd_evt *event;
 115 
 116                 event = &XENSND_IN_RING_REF(page, cons);
 117                 if (unlikely(event->id != channel->evt_id++))
 118                         continue;
 119 
 120                 switch (event->type) {
 121                 case XENSND_EVT_CUR_POS:
 122                         xen_snd_front_alsa_handle_cur_pos(channel,
 123                                                           event->op.cur_pos.position);
 124                         break;
 125                 }
 126         }
 127 
 128         page->in_cons = cons;
 129         /* Ensure ring contents. */
 130         virt_wmb();
 131 
 132 out:
 133         mutex_unlock(&channel->ring_io_lock);
 134         return IRQ_HANDLED;
 135 }
 136 
 137 void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel)
 138 {
 139         int notify;
 140 
 141         channel->u.req.ring.req_prod_pvt++;
 142         RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&channel->u.req.ring, notify);
 143         if (notify)
 144                 notify_remote_via_irq(channel->irq);
 145 }
 146 
 147 static void evtchnl_free(struct xen_snd_front_info *front_info,
 148                          struct xen_snd_front_evtchnl *channel)
 149 {
 150         unsigned long page = 0;
 151 
 152         if (channel->type == EVTCHNL_TYPE_REQ)
 153                 page = (unsigned long)channel->u.req.ring.sring;
 154         else if (channel->type == EVTCHNL_TYPE_EVT)
 155                 page = (unsigned long)channel->u.evt.page;
 156 
 157         if (!page)
 158                 return;
 159 
 160         channel->state = EVTCHNL_STATE_DISCONNECTED;
 161         if (channel->type == EVTCHNL_TYPE_REQ) {
 162                 /* Release all who still waits for response if any. */
 163                 channel->u.req.resp_status = -EIO;
 164                 complete_all(&channel->u.req.completion);
 165         }
 166 
 167         if (channel->irq)
 168                 unbind_from_irqhandler(channel->irq, channel);
 169 
 170         if (channel->port)
 171                 xenbus_free_evtchn(front_info->xb_dev, channel->port);
 172 
 173         /* End access and free the page. */
 174         if (channel->gref != GRANT_INVALID_REF)
 175                 gnttab_end_foreign_access(channel->gref, 0, page);
 176         else
 177                 free_page(page);
 178 
 179         memset(channel, 0, sizeof(*channel));
 180 }
 181 
 182 void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info)
 183 {
 184         int i;
 185 
 186         if (!front_info->evt_pairs)
 187                 return;
 188 
 189         for (i = 0; i < front_info->num_evt_pairs; i++) {
 190                 evtchnl_free(front_info, &front_info->evt_pairs[i].req);
 191                 evtchnl_free(front_info, &front_info->evt_pairs[i].evt);
 192         }
 193 
 194         kfree(front_info->evt_pairs);
 195         front_info->evt_pairs = NULL;
 196 }
 197 
 198 static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
 199                          struct xen_snd_front_evtchnl *channel,
 200                          enum xen_snd_front_evtchnl_type type)
 201 {
 202         struct xenbus_device *xb_dev = front_info->xb_dev;
 203         unsigned long page;
 204         grant_ref_t gref;
 205         irq_handler_t handler;
 206         char *handler_name = NULL;
 207         int ret;
 208 
 209         memset(channel, 0, sizeof(*channel));
 210         channel->type = type;
 211         channel->index = index;
 212         channel->front_info = front_info;
 213         channel->state = EVTCHNL_STATE_DISCONNECTED;
 214         channel->gref = GRANT_INVALID_REF;
 215         page = get_zeroed_page(GFP_KERNEL);
 216         if (!page) {
 217                 ret = -ENOMEM;
 218                 goto fail;
 219         }
 220 
 221         handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME,
 222                                  type == EVTCHNL_TYPE_REQ ?
 223                                  XENSND_FIELD_RING_REF :
 224                                  XENSND_FIELD_EVT_RING_REF);
 225         if (!handler_name) {
 226                 ret = -ENOMEM;
 227                 goto fail;
 228         }
 229 
 230         mutex_init(&channel->ring_io_lock);
 231 
 232         if (type == EVTCHNL_TYPE_REQ) {
 233                 struct xen_sndif_sring *sring = (struct xen_sndif_sring *)page;
 234 
 235                 init_completion(&channel->u.req.completion);
 236                 mutex_init(&channel->u.req.req_io_lock);
 237                 SHARED_RING_INIT(sring);
 238                 FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
 239 
 240                 ret = xenbus_grant_ring(xb_dev, sring, 1, &gref);
 241                 if (ret < 0) {
 242                         channel->u.req.ring.sring = NULL;
 243                         goto fail;
 244                 }
 245 
 246                 handler = evtchnl_interrupt_req;
 247         } else {
 248                 ret = gnttab_grant_foreign_access(xb_dev->otherend_id,
 249                                                   virt_to_gfn((void *)page), 0);
 250                 if (ret < 0)
 251                         goto fail;
 252 
 253                 channel->u.evt.page = (struct xensnd_event_page *)page;
 254                 gref = ret;
 255                 handler = evtchnl_interrupt_evt;
 256         }
 257 
 258         channel->gref = gref;
 259 
 260         ret = xenbus_alloc_evtchn(xb_dev, &channel->port);
 261         if (ret < 0)
 262                 goto fail;
 263 
 264         ret = bind_evtchn_to_irq(channel->port);
 265         if (ret < 0) {
 266                 dev_err(&xb_dev->dev,
 267                         "Failed to bind IRQ for domid %d port %d: %d\n",
 268                         front_info->xb_dev->otherend_id, channel->port, ret);
 269                 goto fail;
 270         }
 271 
 272         channel->irq = ret;
 273 
 274         ret = request_threaded_irq(channel->irq, NULL, handler,
 275                                    IRQF_ONESHOT, handler_name, channel);
 276         if (ret < 0) {
 277                 dev_err(&xb_dev->dev, "Failed to request IRQ %d: %d\n",
 278                         channel->irq, ret);
 279                 goto fail;
 280         }
 281 
 282         kfree(handler_name);
 283         return 0;
 284 
 285 fail:
 286         if (page)
 287                 free_page(page);
 288         kfree(handler_name);
 289         dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret);
 290         return ret;
 291 }
 292 
 293 int xen_snd_front_evtchnl_create_all(struct xen_snd_front_info *front_info,
 294                                      int num_streams)
 295 {
 296         struct xen_front_cfg_card *cfg = &front_info->cfg;
 297         struct device *dev = &front_info->xb_dev->dev;
 298         int d, ret = 0;
 299 
 300         front_info->evt_pairs =
 301                         kcalloc(num_streams,
 302                                 sizeof(struct xen_snd_front_evtchnl_pair),
 303                                 GFP_KERNEL);
 304         if (!front_info->evt_pairs)
 305                 return -ENOMEM;
 306 
 307         /* Iterate over devices and their streams and create event channels. */
 308         for (d = 0; d < cfg->num_pcm_instances; d++) {
 309                 struct xen_front_cfg_pcm_instance *pcm_instance;
 310                 int s, index;
 311 
 312                 pcm_instance = &cfg->pcm_instances[d];
 313 
 314                 for (s = 0; s < pcm_instance->num_streams_pb; s++) {
 315                         index = pcm_instance->streams_pb[s].index;
 316 
 317                         ret = evtchnl_alloc(front_info, index,
 318                                             &front_info->evt_pairs[index].req,
 319                                             EVTCHNL_TYPE_REQ);
 320                         if (ret < 0) {
 321                                 dev_err(dev, "Error allocating control channel\n");
 322                                 goto fail;
 323                         }
 324 
 325                         ret = evtchnl_alloc(front_info, index,
 326                                             &front_info->evt_pairs[index].evt,
 327                                             EVTCHNL_TYPE_EVT);
 328                         if (ret < 0) {
 329                                 dev_err(dev, "Error allocating in-event channel\n");
 330                                 goto fail;
 331                         }
 332                 }
 333 
 334                 for (s = 0; s < pcm_instance->num_streams_cap; s++) {
 335                         index = pcm_instance->streams_cap[s].index;
 336 
 337                         ret = evtchnl_alloc(front_info, index,
 338                                             &front_info->evt_pairs[index].req,
 339                                             EVTCHNL_TYPE_REQ);
 340                         if (ret < 0) {
 341                                 dev_err(dev, "Error allocating control channel\n");
 342                                 goto fail;
 343                         }
 344 
 345                         ret = evtchnl_alloc(front_info, index,
 346                                             &front_info->evt_pairs[index].evt,
 347                                             EVTCHNL_TYPE_EVT);
 348                         if (ret < 0) {
 349                                 dev_err(dev, "Error allocating in-event channel\n");
 350                                 goto fail;
 351                         }
 352                 }
 353         }
 354 
 355         front_info->num_evt_pairs = num_streams;
 356         return 0;
 357 
 358 fail:
 359         xen_snd_front_evtchnl_free_all(front_info);
 360         return ret;
 361 }
 362 
 363 static int evtchnl_publish(struct xenbus_transaction xbt,
 364                            struct xen_snd_front_evtchnl *channel,
 365                            const char *path, const char *node_ring,
 366                            const char *node_chnl)
 367 {
 368         struct xenbus_device *xb_dev = channel->front_info->xb_dev;
 369         int ret;
 370 
 371         /* Write control channel ring reference. */
 372         ret = xenbus_printf(xbt, path, node_ring, "%u", channel->gref);
 373         if (ret < 0) {
 374                 dev_err(&xb_dev->dev, "Error writing ring-ref: %d\n", ret);
 375                 return ret;
 376         }
 377 
 378         /* Write event channel ring reference. */
 379         ret = xenbus_printf(xbt, path, node_chnl, "%u", channel->port);
 380         if (ret < 0) {
 381                 dev_err(&xb_dev->dev, "Error writing event channel: %d\n", ret);
 382                 return ret;
 383         }
 384 
 385         return 0;
 386 }
 387 
 388 int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info)
 389 {
 390         struct xen_front_cfg_card *cfg = &front_info->cfg;
 391         struct xenbus_transaction xbt;
 392         int ret, d;
 393 
 394 again:
 395         ret = xenbus_transaction_start(&xbt);
 396         if (ret < 0) {
 397                 xenbus_dev_fatal(front_info->xb_dev, ret,
 398                                  "starting transaction");
 399                 return ret;
 400         }
 401 
 402         for (d = 0; d < cfg->num_pcm_instances; d++) {
 403                 struct xen_front_cfg_pcm_instance *pcm_instance;
 404                 int s, index;
 405 
 406                 pcm_instance = &cfg->pcm_instances[d];
 407 
 408                 for (s = 0; s < pcm_instance->num_streams_pb; s++) {
 409                         index = pcm_instance->streams_pb[s].index;
 410 
 411                         ret = evtchnl_publish(xbt,
 412                                               &front_info->evt_pairs[index].req,
 413                                               pcm_instance->streams_pb[s].xenstore_path,
 414                                               XENSND_FIELD_RING_REF,
 415                                               XENSND_FIELD_EVT_CHNL);
 416                         if (ret < 0)
 417                                 goto fail;
 418 
 419                         ret = evtchnl_publish(xbt,
 420                                               &front_info->evt_pairs[index].evt,
 421                                               pcm_instance->streams_pb[s].xenstore_path,
 422                                               XENSND_FIELD_EVT_RING_REF,
 423                                               XENSND_FIELD_EVT_EVT_CHNL);
 424                         if (ret < 0)
 425                                 goto fail;
 426                 }
 427 
 428                 for (s = 0; s < pcm_instance->num_streams_cap; s++) {
 429                         index = pcm_instance->streams_cap[s].index;
 430 
 431                         ret = evtchnl_publish(xbt,
 432                                               &front_info->evt_pairs[index].req,
 433                                               pcm_instance->streams_cap[s].xenstore_path,
 434                                               XENSND_FIELD_RING_REF,
 435                                               XENSND_FIELD_EVT_CHNL);
 436                         if (ret < 0)
 437                                 goto fail;
 438 
 439                         ret = evtchnl_publish(xbt,
 440                                               &front_info->evt_pairs[index].evt,
 441                                               pcm_instance->streams_cap[s].xenstore_path,
 442                                               XENSND_FIELD_EVT_RING_REF,
 443                                               XENSND_FIELD_EVT_EVT_CHNL);
 444                         if (ret < 0)
 445                                 goto fail;
 446                 }
 447         }
 448         ret = xenbus_transaction_end(xbt, 0);
 449         if (ret < 0) {
 450                 if (ret == -EAGAIN)
 451                         goto again;
 452 
 453                 xenbus_dev_fatal(front_info->xb_dev, ret,
 454                                  "completing transaction");
 455                 goto fail_to_end;
 456         }
 457         return 0;
 458 fail:
 459         xenbus_transaction_end(xbt, 1);
 460 fail_to_end:
 461         xenbus_dev_fatal(front_info->xb_dev, ret, "writing XenStore");
 462         return ret;
 463 }
 464 
 465 void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair,
 466                                               bool is_connected)
 467 {
 468         enum xen_snd_front_evtchnl_state state;
 469 
 470         if (is_connected)
 471                 state = EVTCHNL_STATE_CONNECTED;
 472         else
 473                 state = EVTCHNL_STATE_DISCONNECTED;
 474 
 475         mutex_lock(&evt_pair->req.ring_io_lock);
 476         evt_pair->req.state = state;
 477         mutex_unlock(&evt_pair->req.ring_io_lock);
 478 
 479         mutex_lock(&evt_pair->evt.ring_io_lock);
 480         evt_pair->evt.state = state;
 481         mutex_unlock(&evt_pair->evt.ring_io_lock);
 482 }
 483 
 484 void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair)
 485 {
 486         mutex_lock(&evt_pair->req.ring_io_lock);
 487         evt_pair->req.evt_next_id = 0;
 488         mutex_unlock(&evt_pair->req.ring_io_lock);
 489 
 490         mutex_lock(&evt_pair->evt.ring_io_lock);
 491         evt_pair->evt.evt_next_id = 0;
 492         mutex_unlock(&evt_pair->evt.ring_io_lock);
 493 }
 494 

/* [<][>][^][v][top][bottom][index][help] */