From patchwork Mon Aug 7 11:50:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksandr Andrushchenko X-Patchwork-Id: 9885171 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 904C9603F2 for ; Mon, 7 Aug 2017 11:53:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 82F9528514 for ; Mon, 7 Aug 2017 11:53:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 77E622861F; Mon, 7 Aug 2017 11:53:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.6 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9DD882860D for ; Mon, 7 Aug 2017 11:53:38 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1degYo-0003y5-FX; Mon, 07 Aug 2017 11:51:02 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1degYm-0003xO-SH for xen-devel@lists.xen.org; Mon, 07 Aug 2017 11:51:00 +0000 Received: from [85.158.139.211] by server-11.bemta-5.messagelabs.com id EE/8B-01729-42458895; Mon, 07 Aug 2017 11:51:00 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrIIsWRWlGSWpSXmKPExsVyMfS6s65SSEe kwfQGCYslHxezODB6HN39mymAMYo1My8pvyKBNaOncR5zwU7niua2O4wNjJstuxi5OIQE+hgl TjbvYgVxWAReskj8W7uNGcSREOhnlTj2cy57FyMnkBMncfnhYyYIu0Ji9/02MFtIQFHi67PpT BCjVjJJfJvdxQqSYBMwklh+4wcLiC0iECFx7PEHNhCbWaBU4sb+OcwgtrCAn8TM09PA4iwCqh JLjtwA6+UVcJSY0facDWKZnMTNc51A9RwcnAJOEq1LKyD2Okrc3T2bfQKjwAJGhlWM6sWpRWW pRbomeklFmekZJbmJmTm6hgamermpxcWJ6ak5iUnFesn5uZsYgYHFAAQ7GG/1OR9ilORgUhLl jV/RFinEl5SfUpmRWJwRX1Sak1p8iFGGg0NJgnd/UEekkGBRanpqRVpmDjDEYdISHDxKIrzZI Gne4oLE3OLMdIjUKUZ7jitX1n1h4tiwej2QnHJgO5B8NeH/NyYhlrz8vFQpcV7WYKA2AZC2jN I8uKGwmLzEKCslzMsIdKYQT0FqUW5mCar8K0ZxDkYlYd4HIMt5MvNK4Ha/AjqLCeisN4mtIGe VJCKkpBoYTSNLlfY9C+k4fiDKmrer8Vrwz+SpJ2ycjK77blu0ttFT9PGWKZlfEnR2ferknaVc /ftK2o+aWy8SnnLERtb35a3KOH9N4nZMe3aIwAuOXwsWH57iczLs9Xm1g68PT7t3V3f19kCVX YZTnF63simF7CpWnZ/72d8j/sTsWEcf+2ccOfYsetXHlFiKMxINtZiLihMBLr84scQCAAA= X-Env-Sender: andr2000@gmail.com X-Msg-Ref: server-6.tower-206.messagelabs.com!1502106658!103331077!1 X-Originating-IP: [209.85.215.67] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 60323 invoked from network); 7 Aug 2017 11:50:58 -0000 Received: from mail-lf0-f67.google.com (HELO mail-lf0-f67.google.com) (209.85.215.67) by server-6.tower-206.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 7 Aug 2017 11:50:58 -0000 Received: by mail-lf0-f67.google.com with SMTP id 65so168698lfa.0 for ; Mon, 07 Aug 2017 04:50:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=zNA080u4iv33JRC7/H5Wr7qorJFbcRTjEG/rNidFr6o=; b=Ta71RLcHFVoY0TVDOANPjJtzDs1Y1MRLCh1j8ypOzi2GOJUxQTkaKGxu3oz3LseU60 1FghVrvRk5QQEHnvNJ+aT8ZbqoYpjYPRrrSQW9eTiIn9AyHa5BoOqmHpxeS/S+El1anR xdJ8oi63piT3m4q/HfpsqmETQYwjo2gvJa8GTTtUtDScPzuHVwBb6UWAtAqYRJZfXQBF wyD/tNT6gjMSozFAl7hwyuO0NBhs2Qk5zoKUP93CCFziwsfdNwY7mVmAtwlOFExmt+3z 9u9Rdg/6QR2mUvNP6R8sbgW8EJdieF0aNEeqptgYGlYIopRrGef9MFtDP8aajG17aAhK eCHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=zNA080u4iv33JRC7/H5Wr7qorJFbcRTjEG/rNidFr6o=; b=EVG7Rg/MUV6dohldjNdslVwjjbhHaQ8/6yS3OGYCpZPPKUHCuKW1fw5dfrh/sU8jnL ZLdQgeMQ1TWkn0puvJCRonGQ2u9CqlOxEkep3lOGxd6soovBfQFmO7ReuEqt/i5hG/m9 YhJIQ/OWmD5vTtiG1lXvl327NYd4qU9YwqLD9LjC04j4w7pdCZYC9ePs5+nzzcHYQK76 ERRZ5dB1czgn+NFGtPbDZHtmjG7v0ilDwmeVPCP/mvggkM9WdapByL4AXN1VB7IqtiJo sXK+8Z/YMnhlk9IgGJb38JkrjY8kmD1OJIFfujkFZwz+dFck04WZf52vxuj/ud0S6tDx DMHg== X-Gm-Message-State: AHYfb5gyxFpsg7l3NGOB5LN0joMV+w6fTh1CjsyMHcEK6FVBjN30T4Wk YshukMm9ARWYDw== X-Received: by 10.25.215.104 with SMTP id o101mr84069lfg.24.1502106657689; Mon, 07 Aug 2017 04:50:57 -0700 (PDT) Received: from a2k-HP-ProDesk-600-G2-SFF.kyiv.epam.com (ll-51.209.223.85.sovam.net.ua. [85.223.209.51]) by smtp.gmail.com with ESMTPSA id n88sm2844587lja.43.2017.08.07.04.50.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 07 Aug 2017 04:50:57 -0700 (PDT) From: Oleksandr Andrushchenko To: alsa-devel@alsa-project.org, xen-devel@lists.xen.org, linux-kernel@vger.kernel.org Date: Mon, 7 Aug 2017 14:50:38 +0300 Message-Id: <1502106645-6731-5-git-send-email-andr2000@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1502106645-6731-1-git-send-email-andr2000@gmail.com> References: <1502106645-6731-1-git-send-email-andr2000@gmail.com> Cc: andr2000@gmail.com, Oleksandr Andrushchenko , tiwai@suse.com, perex@perex.cz Subject: [Xen-devel] [PATCH RESEND 04/11] ALSA: vsnd: Implement Xen event channel handling X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Oleksandr Andrushchenko 1. Create event channels for all configured streams and publish corresponding ring references and event channels in Xen store, so backend can connect. 2. Implement event channel interrupt handler. 3. Create and destroy event channels with respect to Xen bus state. Signed-off-by: Oleksandr Andrushchenko --- sound/drivers/xen-front.c | 269 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 268 insertions(+), 1 deletion(-) diff --git a/sound/drivers/xen-front.c b/sound/drivers/xen-front.c index ef48cbf44cf2..a92459b2737e 100644 --- a/sound/drivers/xen-front.c +++ b/sound/drivers/xen-front.c @@ -24,14 +24,40 @@ #include #include +#include +#include #include #include #include +/* + * FIXME: usage of grant reference 0 as invalid grant reference: + * grant reference 0 is valid, but never exposed to a PV driver, + * because of the fact it is already in use/reserved by the PV console. + */ +#define GRANT_INVALID_REF 0 /* maximum number of supported streams */ #define VSND_MAX_STREAM 8 +enum xdrv_evtchnl_state { + EVTCHNL_STATE_DISCONNECTED, + EVTCHNL_STATE_CONNECTED, +}; + +struct xdrv_evtchnl_info { + struct xdrv_info *drv_info; + struct xen_sndif_front_ring ring; + int ring_ref; + int port; + int irq; + struct completion completion; + enum xdrv_evtchnl_state state; + /* latest response status and its corresponding id */ + int resp_status; + uint16_t resp_id; +}; + struct cfg_stream { int unique_id; char *xenstore_path; @@ -65,6 +91,8 @@ struct xdrv_info { struct xenbus_device *xb_dev; spinlock_t io_lock; struct mutex mutex; + int num_evt_channels; + struct xdrv_evtchnl_info *evt_chnls; struct sdev_card_plat_data cfg_plat_data; }; @@ -102,6 +130,244 @@ static struct snd_pcm_hardware sdrv_pcm_hw_default = { .fifo_size = 0, }; +static irqreturn_t xdrv_evtchnl_interrupt(int irq, void *dev_id) +{ + struct xdrv_evtchnl_info *channel = dev_id; + struct xdrv_info *drv_info = channel->drv_info; + struct xensnd_resp *resp; + RING_IDX i, rp; + unsigned long flags; + + spin_lock_irqsave(&drv_info->io_lock, flags); + if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) + goto out; + +again: + rp = channel->ring.sring->rsp_prod; + /* ensure we see queued responses up to rp */ + rmb(); + + for (i = channel->ring.rsp_cons; i != rp; i++) { + resp = RING_GET_RESPONSE(&channel->ring, i); + if (resp->id != channel->resp_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: + channel->resp_status = resp->status; + complete(&channel->completion); + break; + + default: + dev_err(&drv_info->xb_dev->dev, + "Operation %d is not supported\n", + resp->operation); + break; + } + } + + channel->ring.rsp_cons = i; + if (i != channel->ring.req_prod_pvt) { + int more_to_do; + + RING_FINAL_CHECK_FOR_RESPONSES(&channel->ring, more_to_do); + if (more_to_do) + goto again; + } else + channel->ring.sring->rsp_event = i + 1; + +out: + spin_unlock_irqrestore(&drv_info->io_lock, flags); + return IRQ_HANDLED; +} + +static inline void xdrv_evtchnl_flush( + struct xdrv_evtchnl_info *channel) +{ + int notify; + + channel->ring.req_prod_pvt++; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&channel->ring, notify); + if (notify) + notify_remote_via_irq(channel->irq); +} + +static void xdrv_evtchnl_free(struct xdrv_info *drv_info, + struct xdrv_evtchnl_info *channel) +{ + if (!channel->ring.sring) + return; + + channel->state = EVTCHNL_STATE_DISCONNECTED; + channel->resp_status = -EIO; + complete_all(&channel->completion); + + if (channel->irq) + unbind_from_irqhandler(channel->irq, channel); + channel->irq = 0; + + if (channel->port) + xenbus_free_evtchn(drv_info->xb_dev, channel->port); + channel->port = 0; + + if (channel->ring_ref != GRANT_INVALID_REF) + gnttab_end_foreign_access(channel->ring_ref, 0, + (unsigned long)channel->ring.sring); + channel->ring_ref = GRANT_INVALID_REF; + channel->ring.sring = NULL; +} + +static void xdrv_evtchnl_free_all(struct xdrv_info *drv_info) +{ + int i; + + if (!drv_info->evt_chnls) + return; + + for (i = 0; i < drv_info->num_evt_channels; i++) + xdrv_evtchnl_free(drv_info, &drv_info->evt_chnls[i]); + + devm_kfree(&drv_info->xb_dev->dev, drv_info->evt_chnls); + drv_info->evt_chnls = NULL; +} + +static int xdrv_evtchnl_alloc(struct xdrv_info *drv_info, + struct xdrv_evtchnl_info *evt_channel) +{ + struct xenbus_device *xb_dev = drv_info->xb_dev; + struct xen_sndif_sring *sring; + grant_ref_t gref; + int ret; + + evt_channel->drv_info = drv_info; + init_completion(&evt_channel->completion); + evt_channel->state = EVTCHNL_STATE_DISCONNECTED; + evt_channel->ring_ref = GRANT_INVALID_REF; + evt_channel->ring.sring = NULL; + evt_channel->port = 0; + evt_channel->irq = 0; + + sring = (struct xen_sndif_sring *)get_zeroed_page( + GFP_NOIO | __GFP_HIGH); + if (!sring) { + ret = -ENOMEM; + goto fail; + } + + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&evt_channel->ring, sring, XEN_PAGE_SIZE); + ret = xenbus_grant_ring(xb_dev, sring, 1, &gref); + if (ret < 0) + goto fail; + evt_channel->ring_ref = gref; + + ret = xenbus_alloc_evtchn(xb_dev, &evt_channel->port); + if (ret < 0) + goto fail; + + ret = bind_evtchn_to_irqhandler(evt_channel->port, + xdrv_evtchnl_interrupt, 0, xb_dev->devicetype, evt_channel); + if (ret < 0) + goto fail; + + evt_channel->irq = ret; + return 0; + +fail: + dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret); + return ret; +} + +static int xdrv_evtchnl_create(struct xdrv_info *drv_info, + struct xdrv_evtchnl_info *evt_channel, + const char *path) +{ + int ret; + + ret = xdrv_evtchnl_alloc(drv_info, evt_channel); + if (ret < 0) { + dev_err(&drv_info->xb_dev->dev, + "allocating event channel: %d\n", ret); + return ret; + } + + /* + * write values to Xen store, so backend can find ring reference + * and event channel + */ + ret = xenbus_printf(XBT_NIL, path, XENSND_FIELD_RING_REF, "%u", + evt_channel->ring_ref); + if (ret < 0) { + dev_err(&drv_info->xb_dev->dev, + "writing " XENSND_FIELD_RING_REF": %d\n", ret); + return ret; + } + + ret = xenbus_printf(XBT_NIL, path, XENSND_FIELD_EVT_CHNL, "%u", + evt_channel->port); + if (ret < 0) { + dev_err(&drv_info->xb_dev->dev, + "writing " XENSND_FIELD_EVT_CHNL": %d\n", ret); + return ret; + } + return 0; +} + +static int xdrv_evtchnl_create_all(struct xdrv_info *drv_info, + int num_streams) +{ + struct cfg_card *cfg_card; + int d, ret = 0; + + drv_info->evt_chnls = devm_kcalloc(&drv_info->xb_dev->dev, + num_streams, sizeof(struct xdrv_evtchnl_info), GFP_KERNEL); + if (!drv_info->evt_chnls) { + ret = -ENOMEM; + goto fail; + } + + cfg_card = &drv_info->cfg_plat_data.cfg_card; + /* iterate over devices and their streams and create event channels */ + for (d = 0; d < cfg_card->num_pcm_instances; d++) { + struct cfg_pcm_instance *pcm_instance; + int s, stream_idx; + + pcm_instance = &cfg_card->pcm_instances[d]; + + for (s = 0; s < pcm_instance->num_streams_pb; s++) { + stream_idx = pcm_instance->streams_pb[s].unique_id; + ret = xdrv_evtchnl_create(drv_info, + &drv_info->evt_chnls[stream_idx], + pcm_instance->streams_pb[s].xenstore_path); + if (ret < 0) + goto fail; + } + + for (s = 0; s < pcm_instance->num_streams_cap; s++) { + stream_idx = pcm_instance->streams_cap[s].unique_id; + ret = xdrv_evtchnl_create(drv_info, + &drv_info->evt_chnls[stream_idx], + pcm_instance->streams_cap[s].xenstore_path); + if (ret < 0) + goto fail; + } + } + if (ret < 0) + goto fail; + + drv_info->num_evt_channels = num_streams; + return 0; + +fail: + xdrv_evtchnl_free_all(drv_info); + return ret; +} + struct CFG_HW_SAMPLE_RATE { const char *name; unsigned int mask; @@ -556,6 +822,7 @@ static int cfg_card(struct xdrv_info *drv_info, static void xdrv_remove_internal(struct xdrv_info *drv_info) { + xdrv_evtchnl_free_all(drv_info); } static int xdrv_be_on_initwait(struct xdrv_info *drv_info) @@ -568,7 +835,7 @@ static int xdrv_be_on_initwait(struct xdrv_info *drv_info) ret = cfg_card(drv_info, &drv_info->cfg_plat_data, &stream_idx); if (ret < 0) return ret; - return 0; + return xdrv_evtchnl_create_all(drv_info, stream_idx); } static inline int xdrv_be_on_connected(struct xdrv_info *drv_info)