Received: by 10.192.165.156 with SMTP id m28csp625902imm; Mon, 16 Apr 2018 06:14:27 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+9AlTkrVQ6qTFXODlyYp1Xvej97D3dxuAsi2CH1xDtBHTrEtsEKVkNv52c3gbOJKM6IrGs X-Received: by 10.101.82.4 with SMTP id o4mr12678842pgp.273.1523884467515; Mon, 16 Apr 2018 06:14:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523884467; cv=none; d=google.com; s=arc-20160816; b=cgwb+XDF4vw7tXE0z1tbY/CKIS7Fe/udhdYOfMt0sU/mfRRsuyLCk1B7ihxjGfPKOu lzUz4y79E5qoNegaKzjATeyWbxMUJnysBIu5bBDNUYr152jqbyAfUJukf1Ch9Jryyvnb poODJzIF7qxhJH8CptRT0f3OPYj1Fl9mcQD6tHzLTcAsgG6GdU+XXJha34kIk0Gq8B8j g/PNhBentQ4GPa8xR15yujsANLdEB1ellxbpuu1H895so9vktwaOMhpLaEVb6rxNvrBD ivGL1w5eK0MquFNASo2WXk6TpV0TGRFFgp7GCzRK0QICUyzNx7AjnhDqEyXATHJhzswC yPOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:arc-authentication-results; bh=OO1eDrG1rk3buH4eJNy3zF6CWXbVc6u9+MOeYpoj+CI=; b=J766PtyfRdGUksnn95Wz2C4Uff6ytsOYCEMm4WWP4HAXaJCQkhcf3AVX6Ww1Rg4F0V QMlhBZVO5w5siLBTr4T6fbgbOkUoGPLLDUHFiaZqDqWQx/hINuSKcJTTzXR6caZ06fw7 xpch5X0SmVbmvXmuDFiWYqVDxDCXXlCOltczIei3XYyeJJwjF0RqolTm4j9jffINYJo7 2DhLSLG40G4hb6d5Sr+54y/blQvtZaq6rCxa38jPWy3O39b9WaZ2M7poMQDB4sgRK1Ih fN1820apoBjPvPmeK6bUNB721sR22EfwU1M6wT0MNEM0HW0FF4vrNVJ5kI9M7Kh4gPqA ECEQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w11si9364894pgq.333.2018.04.16.06.13.50; Mon, 16 Apr 2018 06:14:27 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754584AbeDPNMb (ORCPT + 99 others); Mon, 16 Apr 2018 09:12:31 -0400 Received: from mx2.suse.de ([195.135.220.15]:46853 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752578AbeDPNMa (ORCPT ); Mon, 16 Apr 2018 09:12:30 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 8327CAD65; Mon, 16 Apr 2018 13:12:28 +0000 (UTC) Subject: Re: [PATCH v2 3/5] ALSA: xen-front: Implement Xen event channel handling To: Oleksandr Andrushchenko , xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org, boris.ostrovsky@oracle.com, konrad.wilk@oracle.com, perex@perex.cz, tiwai@suse.com Cc: Oleksandr Andrushchenko References: <20180416062453.24743-1-andr2000@gmail.com> <20180416062453.24743-4-andr2000@gmail.com> From: Juergen Gross Message-ID: Date: Mon, 16 Apr 2018 15:12:26 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <20180416062453.24743-4-andr2000@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 16/04/18 08:24, Oleksandr Andrushchenko wrote: > From: Oleksandr Andrushchenko > > Handle Xen event channels: > - create for all configured streams and publish > corresponding ring references and event channels in Xen store, > so backend can connect > - implement event channels interrupt handlers > - create and destroy event channels with respect to Xen bus state > > Signed-off-by: Oleksandr Andrushchenko > --- > sound/xen/Makefile | 3 +- > sound/xen/xen_snd_front.c | 10 +- > sound/xen/xen_snd_front.h | 7 + > sound/xen/xen_snd_front_evtchnl.c | 474 ++++++++++++++++++++++++++++++++++++++ > sound/xen/xen_snd_front_evtchnl.h | 92 ++++++++ > 5 files changed, 584 insertions(+), 2 deletions(-) > create mode 100644 sound/xen/xen_snd_front_evtchnl.c > create mode 100644 sound/xen/xen_snd_front_evtchnl.h > > diff --git a/sound/xen/Makefile b/sound/xen/Makefile > index 06705bef61fa..03c669984000 100644 > --- a/sound/xen/Makefile > +++ b/sound/xen/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0 OR MIT > > snd_xen_front-objs := xen_snd_front.o \ > - xen_snd_front_cfg.o > + xen_snd_front_cfg.o \ > + xen_snd_front_evtchnl.o > > obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o > diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c > index 65d2494a9d14..eb46bf4070f9 100644 > --- a/sound/xen/xen_snd_front.c > +++ b/sound/xen/xen_snd_front.c > @@ -18,9 +18,11 @@ > #include > > #include "xen_snd_front.h" > +#include "xen_snd_front_evtchnl.h" Does it really make sense to have multiple driver-private headers? I think those can be merged. > > static void xen_snd_drv_fini(struct xen_snd_front_info *front_info) > { > + xen_snd_front_evtchnl_free_all(front_info); > } > > static int sndback_initwait(struct xen_snd_front_info *front_info) > @@ -32,7 +34,12 @@ static int sndback_initwait(struct xen_snd_front_info *front_info) > if (ret < 0) > return ret; > > - return 0; > + /* create event channels for all streams and publish */ > + ret = xen_snd_front_evtchnl_create_all(front_info, num_streams); > + if (ret < 0) > + return ret; > + > + return xen_snd_front_evtchnl_publish_all(front_info); > } > > static int sndback_connect(struct xen_snd_front_info *front_info) > @@ -122,6 +129,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev, > return -ENOMEM; > > front_info->xb_dev = xb_dev; > + spin_lock_init(&front_info->io_lock); > dev_set_drvdata(&xb_dev->dev, front_info); > > return xenbus_switch_state(xb_dev, XenbusStateInitialising); > diff --git a/sound/xen/xen_snd_front.h b/sound/xen/xen_snd_front.h > index b52226cb30bc..9c2ffbb4e4b8 100644 > --- a/sound/xen/xen_snd_front.h > +++ b/sound/xen/xen_snd_front.h > @@ -13,9 +13,16 @@ > > #include "xen_snd_front_cfg.h" > > +struct xen_snd_front_evtchnl_pair; > + > struct xen_snd_front_info { > struct xenbus_device *xb_dev; > > + /* serializer for backend IO: request/response */ > + spinlock_t io_lock; > + int num_evt_pairs; > + struct xen_snd_front_evtchnl_pair *evt_pairs; > + > struct xen_front_cfg_card cfg; > }; > > diff --git a/sound/xen/xen_snd_front_evtchnl.c b/sound/xen/xen_snd_front_evtchnl.c > new file mode 100644 > index 000000000000..9ece39f938f8 > --- /dev/null > +++ b/sound/xen/xen_snd_front_evtchnl.c > @@ -0,0 +1,474 @@ > +// SPDX-License-Identifier: GPL-2.0 OR MIT > + > +/* > + * Xen para-virtual sound device > + * > + * Copyright (C) 2016-2018 EPAM Systems Inc. > + * > + * Author: Oleksandr Andrushchenko > + */ > + > +#include > +#include > +#include > +#include > + > +#include "xen_snd_front.h" > +#include "xen_snd_front_cfg.h" > +#include "xen_snd_front_evtchnl.h" > + > +static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id) > +{ > + struct xen_snd_front_evtchnl *channel = dev_id; > + struct xen_snd_front_info *front_info = channel->front_info; > + struct xensnd_resp *resp; > + RING_IDX i, rp; > + unsigned long flags; > + > + if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) > + return IRQ_HANDLED; > + > + spin_lock_irqsave(&front_info->io_lock, flags); > + > +again: > + rp = channel->u.req.ring.sring->rsp_prod; > + /* ensure we see queued responses up to rp */ > + rmb(); > + > + for (i = channel->u.req.ring.rsp_cons; i != rp; i++) { > + resp = RING_GET_RESPONSE(&channel->u.req.ring, i); > + if (resp->id != channel->evt_id) > + continue; > + switch (resp->operation) { > + case XENSND_OP_OPEN: > + /* fall through */ > + case XENSND_OP_CLOSE: > + /* fall through */ > + case XENSND_OP_READ: > + /* fall through */ > + case XENSND_OP_WRITE: > + /* fall through */ > + case XENSND_OP_TRIGGER: > + channel->u.req.resp_status = resp->status; > + complete(&channel->u.req.completion); > + break; > + case XENSND_OP_HW_PARAM_QUERY: > + channel->u.req.resp_status = resp->status; > + channel->u.req.resp.hw_param = > + resp->resp.hw_param; > + complete(&channel->u.req.completion); > + break; > + > + default: > + dev_err(&front_info->xb_dev->dev, > + "Operation %d is not supported\n", > + resp->operation); > + break; > + } > + } > + > + channel->u.req.ring.rsp_cons = i; > + if (i != channel->u.req.ring.req_prod_pvt) { > + int more_to_do; > + > + RING_FINAL_CHECK_FOR_RESPONSES(&channel->u.req.ring, > + more_to_do); > + if (more_to_do) > + goto again; > + } else { > + channel->u.req.ring.sring->rsp_event = i + 1; > + } > + > + spin_unlock_irqrestore(&front_info->io_lock, flags); > + return IRQ_HANDLED; > +} > + > +static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id) > +{ > + struct xen_snd_front_evtchnl *channel = dev_id; > + struct xen_snd_front_info *front_info = channel->front_info; > + struct xensnd_event_page *page = channel->u.evt.page; > + u32 cons, prod; > + unsigned long flags; > + > + if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) > + return IRQ_HANDLED; > + > + spin_lock_irqsave(&front_info->io_lock, flags); > + > + prod = page->in_prod; > + /* ensure we see ring contents up to prod */ > + virt_rmb(); > + if (prod == page->in_cons) > + goto out; > + > + for (cons = page->in_cons; cons != prod; cons++) { > + struct xensnd_evt *event; > + > + event = &XENSND_IN_RING_REF(page, cons); > + if (unlikely(event->id != channel->evt_id++)) > + continue; > + > + switch (event->type) { > + case XENSND_EVT_CUR_POS: > + /* do nothing at the moment */ > + break; > + } > + } > + > + page->in_cons = cons; > + /* ensure ring contents */ > + virt_wmb(); > + > +out: > + spin_unlock_irqrestore(&front_info->io_lock, flags); > + return IRQ_HANDLED; > +} > + > +void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel) > +{ > + int notify; > + > + channel->u.req.ring.req_prod_pvt++; > + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&channel->u.req.ring, notify); > + if (notify) > + notify_remote_via_irq(channel->irq); > +} > + > +static void evtchnl_free(struct xen_snd_front_info *front_info, > + struct xen_snd_front_evtchnl *channel) > +{ > + unsigned long page = 0; > + > + if (channel->type == EVTCHNL_TYPE_REQ) > + page = (unsigned long)channel->u.req.ring.sring; > + else if (channel->type == EVTCHNL_TYPE_EVT) > + page = (unsigned long)channel->u.evt.page; > + > + if (!page) > + return; > + > + channel->state = EVTCHNL_STATE_DISCONNECTED; > + if (channel->type == EVTCHNL_TYPE_REQ) { > + /* release all who still waits for response if any */ > + channel->u.req.resp_status = -EIO; > + complete_all(&channel->u.req.completion); > + } > + > + if (channel->irq) > + unbind_from_irqhandler(channel->irq, channel); > + > + if (channel->port) > + xenbus_free_evtchn(front_info->xb_dev, channel->port); > + > + /* end access and free the page */ > + if (channel->gref != GRANT_INVALID_REF) > + gnttab_end_foreign_access(channel->gref, 0, page); Free page? > + > + memset(channel, 0, sizeof(*channel)); > +} > + > +void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info) > +{ > + int i; > + > + if (!front_info->evt_pairs) > + return; > + > + for (i = 0; i < front_info->num_evt_pairs; i++) { > + evtchnl_free(front_info, &front_info->evt_pairs[i].req); > + evtchnl_free(front_info, &front_info->evt_pairs[i].evt); > + } > + > + kfree(front_info->evt_pairs); > + front_info->evt_pairs = NULL; > +} > + > +static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, > + struct xen_snd_front_evtchnl *channel, > + enum xen_snd_front_evtchnl_type type) > +{ > + struct xenbus_device *xb_dev = front_info->xb_dev; > + unsigned long page; > + grant_ref_t gref; > + irq_handler_t handler; > + char *handler_name = NULL; > + int ret; > + > + memset(channel, 0, sizeof(*channel)); > + channel->type = type; > + channel->index = index; > + channel->front_info = front_info; > + channel->state = EVTCHNL_STATE_DISCONNECTED; > + channel->gref = GRANT_INVALID_REF; > + page = get_zeroed_page(GFP_NOIO | __GFP_HIGH); Why GFP_NOIO | __GFP_HIGH? Could it be you copied that from blkfront driver? I believe swapping via sound card is rather uncommon. > + if (!page) { > + ret = -ENOMEM; > + goto fail; > + } > + > + handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME, > + type == EVTCHNL_TYPE_REQ ? > + XENSND_FIELD_RING_REF : > + XENSND_FIELD_EVT_RING_REF); > + if (!handler_name) { > + ret = -ENOMEM; Missing free_page(page)? Maybe you rather add it in the common fail path instead of the numerous instances below? Juergen