From patchwork Thu Feb 18 06:39:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 8346491 X-Patchwork-Delegate: agross@codeaurora.org Return-Path: X-Original-To: patchwork-linux-arm-msm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DE7CDC0553 for ; Thu, 18 Feb 2016 06:39:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D8A5F20395 for ; Thu, 18 Feb 2016 06:39:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B5F3D20383 for ; Thu, 18 Feb 2016 06:39:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1425311AbcBRGjS (ORCPT ); Thu, 18 Feb 2016 01:39:18 -0500 Received: from mail-pf0-f176.google.com ([209.85.192.176]:34268 "EHLO mail-pf0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1425260AbcBRGjL (ORCPT ); Thu, 18 Feb 2016 01:39:11 -0500 Received: by mail-pf0-f176.google.com with SMTP id x65so25757413pfb.1 for ; Wed, 17 Feb 2016 22:39:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2WPYM3tYuYpGe32BFRhXQ9rg57gX/xMMc/HCdG0wNQQ=; b=eWuLMqq4OhaKdQIKiubmpdmC5Dp13X2u+Fl7VccKcjZ4DKYVNj7JgmVCbtq9U8BfrW //uutte/itxklYSGaWqjh5UaaSb1qAoDLDabJ47XBflcHGPhtcQosX7a2m3tNK6tXDnC H3KSr6NaTolefc9YxJsyHjZHrXsqaCuW3dadQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2WPYM3tYuYpGe32BFRhXQ9rg57gX/xMMc/HCdG0wNQQ=; b=NpTmg9IGAVXJN9HVKuNc4QgQcC9fs8cDuKp8R+NFFGOsefIC6aF50FuXDgUCxJiBNz gAxEp4rSh8GkAo5SAdSs4urmOXbaS/ZmsRZNrOrSm1uTZaQqW6X7SldGNNiPRIj46s+k jDBiOhQsKlu2Pi41u3qzSb3ZKxSfUUo/XOK6hTX0A2d0BdTD0ztNIlVVjaX32j4bxlEw w6HuCr1V9j3mEx2yoGj8Szvgm+UDeuxHjEHTB1XgatJ4V6ruKAvAwFVYage5Ew2A8hL3 eK5GPBxLthODxn+BgzD7C7qOT8uK4PeaGmYO1FTKhnlK8dXkPKtobXX2AwXgG8tulfDA MKOw== X-Gm-Message-State: AG10YOSdbTtYEZk2qyBU3Uc7+w6JSY7jtlJ5rJXwFqJHeRi/riX5dyhVtI1E3tGBSyFWAo6i X-Received: by 10.98.9.219 with SMTP id 88mr8033096pfj.0.1455777550807; Wed, 17 Feb 2016 22:39:10 -0800 (PST) Received: from tuxbot.san.rr.com (cpe-76-167-68-231.natsow.res.rr.com. [76.167.68.231]) by smtp.gmail.com with ESMTPSA id fl9sm7117315pab.30.2016.02.17.22.39.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 17 Feb 2016 22:39:10 -0800 (PST) From: Bjorn Andersson To: Andy Gross , David Brown Cc: Srinivas Kandagatla , Fengwei Yin , linux-arm-msm@vger.kernel.org, linux-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Bjorn Andersson Subject: [PATCH v3 2/5] soc: qcom: smd: Split discovery and state change work Date: Wed, 17 Feb 2016 22:39:03 -0800 Message-Id: <1455777546-19280-3-git-send-email-bjorn.andersson@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1455777546-19280-1-git-send-email-bjorn.andersson@linaro.org> References: <1455777546-19280-1-git-send-email-bjorn.andersson@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Bjorn Andersson Split the two steps of channel discovery and state change handling into two different workers. This allows for new channels to be found while we're are probing, which is required as we introduce multi-channel support. Signed-off-by: Bjorn Andersson Signed-off-by: Bjorn Andersson --- Changes since v2: - channels_lock is kept as spinlock - qcom_smd_edge_intr() is smarter about which worker to kick Changes since v1: - New patch drivers/soc/qcom/smd.c | 58 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index c357842b92e1..e8972ddfee85 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -106,9 +106,9 @@ static const struct { * @channels: list of all channels detected on this edge * @channels_lock: guard for modifications of @channels * @allocated: array of bitmaps representing already allocated channels - * @need_rescan: flag that the @work needs to scan smem for new channels * @smem_available: last available amount of smem triggering a channel scan - * @work: work item for edge house keeping + * @scan_work: work item for discovering new channels + * @state_work: work item for edge state changes */ struct qcom_smd_edge { struct qcom_smd *smd; @@ -127,10 +127,10 @@ struct qcom_smd_edge { DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE); - bool need_rescan; unsigned smem_available; - struct work_struct work; + struct work_struct scan_work; + struct work_struct state_work; }; /* @@ -614,7 +614,8 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) struct qcom_smd_edge *edge = data; struct qcom_smd_channel *channel; unsigned available; - bool kick_worker = false; + bool kick_scanner = false; + bool kick_state = false; /* * Handle state changes or data on each of the channels on this edge @@ -622,7 +623,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) spin_lock(&edge->channels_lock); list_for_each_entry(channel, &edge->channels, list) { spin_lock(&channel->recv_lock); - kick_worker |= qcom_smd_channel_intr(channel); + kick_state |= qcom_smd_channel_intr(channel); spin_unlock(&channel->recv_lock); } spin_unlock(&edge->channels_lock); @@ -635,12 +636,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) available = qcom_smem_get_free_space(edge->remote_pid); if (available != edge->smem_available) { edge->smem_available = available; - edge->need_rescan = true; - kick_worker = true; + kick_scanner = true; } - if (kick_worker) - schedule_work(&edge->work); + if (kick_scanner) + schedule_work(&edge->scan_work); + if (kick_state) + schedule_work(&edge->state_work); return IRQ_HANDLED; } @@ -1098,8 +1100,9 @@ free_name_and_channel: * qcom_smd_create_channel() to create representations of these and add * them to the edge's list of channels. */ -static void qcom_discover_channels(struct qcom_smd_edge *edge) +static void qcom_channel_scan_worker(struct work_struct *work) { + struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge, scan_work); struct qcom_smd_alloc_entry *alloc_tbl; struct qcom_smd_alloc_entry *entry; struct qcom_smd_channel *channel; @@ -1152,7 +1155,7 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge) } } - schedule_work(&edge->work); + schedule_work(&edge->state_work); } /* @@ -1160,29 +1163,23 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge) * then scans all registered channels for state changes that should be handled * by creating or destroying smd client devices for the registered channels. * - * LOCKING: edge->channels_lock is not needed to be held during the traversal - * of the channels list as it's done synchronously with the only writer. + * LOCKING: edge->channels_lock only needs to cover the list operations, as the + * worker is killed before any channels are deallocated */ static void qcom_channel_state_worker(struct work_struct *work) { struct qcom_smd_channel *channel; struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge, - work); + state_work); unsigned remote_state; - - /* - * Rescan smem if we have reason to belive that there are new channels. - */ - if (edge->need_rescan) { - edge->need_rescan = false; - qcom_discover_channels(edge); - } + unsigned long flags; /* * Register a device for any closed channel where the remote processor * is showing interest in opening the channel. */ + spin_lock_irqsave(&edge->channels_lock, flags); list_for_each_entry(channel, &edge->channels, list) { if (channel->state != SMD_CHANNEL_CLOSED) continue; @@ -1192,7 +1189,9 @@ static void qcom_channel_state_worker(struct work_struct *work) remote_state != SMD_CHANNEL_OPENED) continue; + spin_unlock_irqrestore(&edge->channels_lock, flags); qcom_smd_create_device(channel); + spin_lock_irqsave(&edge->channels_lock, flags); } /* @@ -1209,8 +1208,11 @@ static void qcom_channel_state_worker(struct work_struct *work) remote_state == SMD_CHANNEL_OPENED) continue; + spin_unlock_irqrestore(&edge->channels_lock, flags); qcom_smd_destroy_device(channel); + spin_lock_irqsave(&edge->channels_lock, flags); } + spin_unlock_irqrestore(&edge->channels_lock, flags); } /* @@ -1228,7 +1230,8 @@ static int qcom_smd_parse_edge(struct device *dev, INIT_LIST_HEAD(&edge->channels); spin_lock_init(&edge->channels_lock); - INIT_WORK(&edge->work, qcom_channel_state_worker); + INIT_WORK(&edge->scan_work, qcom_channel_scan_worker); + INIT_WORK(&edge->state_work, qcom_channel_state_worker); edge->of_node = of_node_get(node); @@ -1317,8 +1320,7 @@ static int qcom_smd_probe(struct platform_device *pdev) if (ret) continue; - edge->need_rescan = true; - schedule_work(&edge->work); + schedule_work(&edge->scan_work); } platform_set_drvdata(pdev, smd); @@ -1341,8 +1343,10 @@ static int qcom_smd_remove(struct platform_device *pdev) edge = &smd->edges[i]; disable_irq(edge->irq); - cancel_work_sync(&edge->work); + cancel_work_sync(&edge->scan_work); + cancel_work_sync(&edge->state_work); + /* No need to lock here, because the writer is gone */ list_for_each_entry(channel, &edge->channels, list) { if (!channel->qsdev) continue;