Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp9068089rwd; Wed, 21 Jun 2023 02:33:12 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5Wnu5/o6xWnEIyH3b1NV5lte9rKRsh3YqY5duVKm2/55VKR87g5QbPbarNfPiX6ENU6ny5 X-Received: by 2002:aca:2313:0:b0:39e:a606:544e with SMTP id e19-20020aca2313000000b0039ea606544emr15661144oie.32.1687339992489; Wed, 21 Jun 2023 02:33:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687339992; cv=none; d=google.com; s=arc-20160816; b=E8DEqVrwvJuGciROvHPQ26FdZQ1apAM+IfPKXWELpHIDJ7UuD62MNYTGAMQKQwFJRc r3vERC6wmBfni9U3UMOYpLeRtz1qmDjGStG+/NSQQ7I4ldpWG86i46N9CfvM8JMMUV5M nKlnIzu2EloBzwqxd2jFhOhH0tcGDuyHk8ajN3m25TLGXioV5CMADiiMeXfm1dFl/vO6 eqTDCFGlPYrIlNnGgrR+vmycKEUbDsujaBy20knLtek2ctnrsUjyhhwu8/ig7cNjZWBI X/erc3vOIN6UXtyyRVzOEYlw04XsIrxtZCeCd/XaMCJ31x+/XzpWtnBxh1cR39WbtH0V M7eA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=UURWqBUXOBW/vgexjIMqvywbeKsg0EBaKHEuKuyo96o=; b=VhOsoEArAkCC9fKTpdVsay/PWfcNVX+zqiBsngS3+9QpC9XfVuLF+tAXTN7/bir6gG qkEus91vWZN2QyVAX3ZWg7enh2T768T9sjMXdBu1xUrpscUTnHCZ48WfPsTquEazZymH fvyqDQcmfOL1awIPlQqzB8JwBzuMcMZebc6NIBAALBBAuYucGDtzFRZHdBwfU+J3cc87 T2+EJq9lf2ZpV04ifL7QzDzyOy2BGSADUldyf5eXa6EUmITFC0PuPKV69kQGOGYXPfdz CkMUoPZpZsfOXdy+zw33Pvu2MSZcNWqHUanXisayz7GT0Fz13ZILaTcML1hOldyTVmN3 U18Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20221208.gappssmtp.com header.s=20221208 header.b=O4mT4gGy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id u11-20020a63b54b000000b0054fdafd5b45si3492518pgo.740.2023.06.21.02.32.59; Wed, 21 Jun 2023 02:33:12 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20221208.gappssmtp.com header.s=20221208 header.b=O4mT4gGy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231944AbjFUJZE (ORCPT + 99 others); Wed, 21 Jun 2023 05:25:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231350AbjFUJYZ (ORCPT ); Wed, 21 Jun 2023 05:24:25 -0400 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7322B1BC3 for ; Wed, 21 Jun 2023 02:24:06 -0700 (PDT) Received: by mail-wr1-x42d.google.com with SMTP id ffacd0b85a97d-307d20548adso4592124f8f.0 for ; Wed, 21 Jun 2023 02:24:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1687339445; x=1689931445; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UURWqBUXOBW/vgexjIMqvywbeKsg0EBaKHEuKuyo96o=; b=O4mT4gGylvPiW0VFn3USiYztPupBUDZj+DJB0DhCa19DiFIOSt+vzlu4yV7TWEh6R0 QfUJMBOlykfgzF17rzLqLM7O3y67yYzI7a275Dzp6BtU6abmDMbHMs4a9yJbruonrlS+ 3yUxVM9fJKBPe8lUV3IVUMiU1e7wkf5bR1n+72DL0fMLmabpq5HNQuzwm0EhSyr7+Epb B75mjtHp8kO0FMFZR7ClCI2XeNYQ11QkIxWOzM5mLCTRkXj2tJM5oLtV3MXiY3mgDcJT +JHVi9fmMzN+5hLKWn5BP3eWC5m4KQThNmRd0o36Wnfwx8dJdAWUfAXmOozQ+8MGiNbq yyeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687339445; x=1689931445; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UURWqBUXOBW/vgexjIMqvywbeKsg0EBaKHEuKuyo96o=; b=GW6xE/Bo32WMA6AcT735yO3uEKbBA1nax6qZ/R3rRQgTi/h0PfjsFgpy2Mh1mcIY2/ 52SipF8fEGALQAZSBE2XNh9Qa80IIe3S5J5qhCcockyrytggp1ts5rIoXKHxyiupX2lG mo89CeCWo/EfC+TQq3XjwX/eZ8hUn7wG8SvREsK8eWsIk0x/ydNqTM/kuzyO+tD+kIJF vbvKnaWCQbATYcRPAcVEkg3WTV9QIQFALDn/dWB6RTAJpSqEmsfOKKbGaxbnX6RwKNlG th4E4QWjVu57488dq6anDBlFKXB0EOowIMdqA4mxFd4kRBHqzEf+nsU7C7w3l04zxjKV sBjg== X-Gm-Message-State: AC+VfDx0qKeFvWAZczYx0gvCwIwfrtDdEf3CSNUDvAL1y8Q4aZ3OtLQp jVwn2vfzh/IwV5t1MjXIU5icYQ== X-Received: by 2002:adf:fa06:0:b0:30f:be04:5b5e with SMTP id m6-20020adffa06000000b0030fbe045b5emr9288732wrr.37.1687339444992; Wed, 21 Jun 2023 02:24:04 -0700 (PDT) Received: from blmsp.fritz.box ([2001:4091:a247:82fa:b762:4f68:e1ed:5041]) by smtp.gmail.com with ESMTPSA id i11-20020adffdcb000000b002fda1b12a0bsm4022115wrs.2.2023.06.21.02.24.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jun 2023 02:24:04 -0700 (PDT) From: Markus Schneider-Pargmann To: Marc Kleine-Budde , Chandrasekar Ramakrishnan , Wolfgang Grandegger Cc: Vincent MAILHOL , Simon Horman , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-can@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Julien Panis , Markus Schneider-Pargmann Subject: [PATCH v4 08/12] can: m_can: Use the workqueue as queue Date: Wed, 21 Jun 2023 11:23:46 +0200 Message-Id: <20230621092350.3130866-9-msp@baylibre.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230621092350.3130866-1-msp@baylibre.com> References: <20230621092350.3130866-1-msp@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current implementation uses the workqueue for peripheral chips to submit work. Only a single work item is queued and used at any time. To be able to keep more than one transmit in flight at a time, prepare the workqueue to support multiple transmits at the same time. Each work item now has a separate storage for a skb and a pointer to cdev. This assures that each workitem can be processed individually. The workqueue is replaced by an ordered workqueue which makes sure that only a single worker processes the items queued on the workqueue. Also items are ordered by the order they were enqueued. This removes most of the concurrency the workqueue normally offers. It is not necessary for this driver. The cleanup functions have to be adopted a bit to handle this new mechanism. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman --- drivers/net/can/m_can/m_can.c | 109 ++++++++++++++++++++-------------- drivers/net/can/m_can/m_can.h | 14 ++++- 2 files changed, 75 insertions(+), 48 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 40acd78cc0ed..88c8d6a418f0 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -466,17 +466,16 @@ static void m_can_clean(struct net_device *net) { struct m_can_classdev *cdev = netdev_priv(net); - if (cdev->tx_skb) { - u32 putidx = 0; + for (int i = 0; i != cdev->tx_fifo_size; ++i) { + if (!cdev->tx_ops[i].skb) + continue; net->stats.tx_errors++; - if (cdev->version > 30) - putidx = FIELD_GET(TXFQS_TFQPI_MASK, - m_can_read(cdev, M_CAN_TXFQS)); - - can_free_echo_skb(cdev->net, putidx, NULL); - cdev->tx_skb = NULL; + cdev->tx_ops[i].skb = NULL; } + + for (int i = 0; i != cdev->can.echo_skb_max; ++i) + can_free_echo_skb(cdev->net, i, NULL); } /* For peripherals, pass skb to rx-offload, which will push skb from @@ -1663,8 +1662,9 @@ static int m_can_close(struct net_device *dev) m_can_clk_stop(cdev); free_irq(dev->irq, dev); + m_can_clean(dev); + if (cdev->is_peripheral) { - cdev->tx_skb = NULL; destroy_workqueue(cdev->tx_wq); cdev->tx_wq = NULL; can_rx_offload_disable(&cdev->offload); @@ -1691,21 +1691,19 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, u32 putidx) return !!cdev->can.echo_skb[next_idx]; } -static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) +static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, + struct sk_buff *skb) { - struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data; + struct canfd_frame *cf = (struct canfd_frame *)skb->data; u8 len_padded = DIV_ROUND_UP(cf->len, 4); struct m_can_fifo_element fifo_element; struct net_device *dev = cdev->net; - struct sk_buff *skb = cdev->tx_skb; struct id_and_dlc fifo_header; u32 cccr, fdflags; u32 txfqs; int err; u32 putidx; - cdev->tx_skb = NULL; - /* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id & CAN_EFF_FLAG) { @@ -1829,10 +1827,36 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) static void m_can_tx_work_queue(struct work_struct *ws) { - struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev, - tx_work); + struct m_can_tx_op *op = container_of(ws, struct m_can_tx_op, work); + struct m_can_classdev *cdev = op->cdev; + struct sk_buff *skb = op->skb; - m_can_tx_handler(cdev); + op->skb = NULL; + m_can_tx_handler(cdev, skb); +} + +static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb) +{ + cdev->tx_ops[cdev->next_tx_op].skb = skb; + queue_work(cdev->tx_wq, &cdev->tx_ops[cdev->next_tx_op].work); + + ++cdev->next_tx_op; + if (cdev->next_tx_op >= cdev->tx_fifo_size) + cdev->next_tx_op = 0; +} + +static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev, + struct sk_buff *skb) +{ + if (cdev->can.state == CAN_STATE_BUS_OFF) { + m_can_clean(cdev->net); + return NETDEV_TX_OK; + } + + netif_stop_queue(cdev->net); + m_can_tx_queue_skb(cdev, skb); + + return NETDEV_TX_OK; } static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, @@ -1843,30 +1867,10 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; - if (cdev->is_peripheral) { - if (cdev->tx_skb) { - netdev_err(dev, "hard_xmit called while tx busy\n"); - return NETDEV_TX_BUSY; - } - - if (cdev->can.state == CAN_STATE_BUS_OFF) { - m_can_clean(dev); - } else { - /* Need to stop the queue to avoid numerous requests - * from being sent. Suggested improvement is to create - * a queueing mechanism that will queue the skbs and - * process them in order. - */ - cdev->tx_skb = skb; - netif_stop_queue(cdev->net); - queue_work(cdev->tx_wq, &cdev->tx_work); - } - } else { - cdev->tx_skb = skb; - return m_can_tx_handler(cdev); - } - - return NETDEV_TX_OK; + if (cdev->is_peripheral) + return m_can_start_peripheral_xmit(cdev, skb); + else + return m_can_tx_handler(cdev, skb); } static int m_can_open(struct net_device *dev) @@ -1894,15 +1898,17 @@ static int m_can_open(struct net_device *dev) /* register interrupt handler */ if (cdev->is_peripheral) { - cdev->tx_skb = NULL; - cdev->tx_wq = alloc_workqueue("mcan_wq", - WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + cdev->tx_wq = alloc_ordered_workqueue("mcan_wq", + WQ_FREEZABLE | WQ_MEM_RECLAIM); if (!cdev->tx_wq) { err = -ENOMEM; goto out_wq_fail; } - INIT_WORK(&cdev->tx_work, m_can_tx_work_queue); + for (int i = 0; i != cdev->tx_fifo_size; ++i) { + cdev->tx_ops[i].cdev = cdev; + INIT_WORK(&cdev->tx_ops[i].work, m_can_tx_work_queue); + } err = request_threaded_irq(dev->irq, NULL, m_can_isr, IRQF_ONESHOT, @@ -2172,6 +2178,19 @@ int m_can_class_register(struct m_can_classdev *cdev) { int ret; + cdev->tx_fifo_size = max(1, min(cdev->mcfg[MRAM_TXB].num, + cdev->mcfg[MRAM_TXE].num)); + if (cdev->is_peripheral) { + cdev->tx_ops = + devm_kzalloc(cdev->dev, + cdev->tx_fifo_size * sizeof(*cdev->tx_ops), + GFP_KERNEL); + if (!cdev->tx_ops) { + dev_err(cdev->dev, "Failed to allocate tx_ops for workqueue\n"); + return -ENOMEM; + } + } + if (cdev->pm_clock_support) { ret = m_can_clk_start(cdev); if (ret) diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 548ae908ac4e..38b154fea04b 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -70,6 +70,12 @@ struct m_can_ops { int (*init)(struct m_can_classdev *cdev); }; +struct m_can_tx_op { + struct m_can_classdev *cdev; + struct work_struct work; + struct sk_buff *skb; +}; + struct m_can_classdev { struct can_priv can; struct can_rx_offload offload; @@ -80,8 +86,6 @@ struct m_can_classdev { struct clk *cclk; struct workqueue_struct *tx_wq; - struct work_struct tx_work; - struct sk_buff *tx_skb; struct phy *transceiver; struct hrtimer irq_timer; @@ -103,7 +107,11 @@ struct m_can_classdev { u32 tx_coalesce_usecs_irq; // Store this internally to avoid fetch delays on peripheral chips - int tx_fifo_putidx; + u32 tx_fifo_putidx; + + struct m_can_tx_op *tx_ops; + int tx_fifo_size; + int next_tx_op; struct mram_cfg mcfg[MRAM_CFG_NUM]; }; -- 2.40.1