Received: by 2002:a05:7412:2a8c:b0:e2:908c:2ebd with SMTP id u12csp4124026rdh; Fri, 29 Sep 2023 11:49:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGYhUZC97sWbIB7C9OAgoCXipwAaqpo9F46841AnIPBn4wrlCu9ch8N0Hl/jOcxNe+ajlRD X-Received: by 2002:a17:90a:db56:b0:279:856:b036 with SMTP id u22-20020a17090adb5600b002790856b036mr4681211pjx.6.1696013383662; Fri, 29 Sep 2023 11:49:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696013383; cv=none; d=google.com; s=arc-20160816; b=xMf0IYU3ULflrSoCJVanJc4lVaHBOA1TIdtV3745n7wkkfzo0ryikU2EXo7Mue7E4c KLvZEafIGXPTLH//X8sfXpYroeV4xXpkabg60wSKJyNzkkyXvRdQQgOUMCxcbWBcyIEZ MyWwg0r08qL9EbUZNQbFNaoVEpKl2s/sM+k0yP6bLW5beNDzcVY8cQ9URR0TpFXSarKp vrY43YSdMqD4XyLXw+UmdR0DZg3byFeNraOhbd7n6+k8JVcvcy2wrP0sS2GzmvDAEfte fEWi8s8VhjbZaMTXHZittJQr0Icnx6ssIc1GloMqLwNenh+kejxKgrPNOINrb6LBTeWP D0iA== 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=j2zHWwvcVZnmnLgXt7QMbcfSPEZ0TtF4vjzI06Pfh/I=; fh=EtuWLR14IhIbZM+E+fYn4isj1Y+iLrncbbgmHIVUFEQ=; b=NmzY4TpgLKON/tkeiaWQkac4e9xhLjZFG27tvcyBOtYY3kXwZbvLXdw4XL0een4zPt IwUHOr56kZvrG1nx1sizO01MEqa9tcHqQfWTjs1zWmq9aSa4f+pw4nl40ci4++1IsJGA nNEJS/Nm7JgjI+jxE1GfTu0HPIYlffCNt9rGky51gYZofaeRppRQwSOp9JN+lXuF8607 w3F1hiVTL9rn5KXMuX6jUfxkqPjqcc+2pVaXsw2+UHHECLoAhoMn8adhH92xDYu2QxHx inAV2ftbHGa35gn84ONkiuM64Wg88iuC0PTfo/zE+nzMR6WxWvEJvAOvp2cRugV1USiT Y5dw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20230601.gappssmtp.com header.s=20230601 header.b=HhotOffd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id b10-20020a17090a6aca00b0027749a98349si2213972pjm.4.2023.09.29.11.49.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Sep 2023 11:49:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20230601.gappssmtp.com header.s=20230601 header.b=HhotOffd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id 47FBD82F05F4; Fri, 29 Sep 2023 07:14:06 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233480AbjI2ONt (ORCPT + 99 others); Fri, 29 Sep 2023 10:13:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233395AbjI2ONb (ORCPT ); Fri, 29 Sep 2023 10:13:31 -0400 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8C242CD2 for ; Fri, 29 Sep 2023 07:13:23 -0700 (PDT) Received: by mail-wm1-x335.google.com with SMTP id 5b1f17b1804b1-405417465aaso134989585e9.1 for ; Fri, 29 Sep 2023 07:13:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1695996801; x=1696601601; darn=vger.kernel.org; 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=j2zHWwvcVZnmnLgXt7QMbcfSPEZ0TtF4vjzI06Pfh/I=; b=HhotOffd7AeTtSLdQvpb3C1ojWtYjgyjId8wQjqpSL8XfBLwRBP1LG3eFNnS8NdUHq LeG2nBVbzJQSPaymUwNcUCwBYpCDcjiVaAMXvNlhmMQz6AfXb9F/nCPUQUBolykAVftG vCEklQf9nFTz2g+9NQJJmUJNln6IRKwCv64QcLAnRPuNBGztY3h21gA2NCwv4dPlqIU4 rMXc5s5EARwoKLq24AL1ZQrHfSGx6UcKvIr1OvuKzfZCFfopsrK7FC5gWTKP1YO7D/nO gWEq3lZV2tJ6ADk8GaJlTQCFvdnPj0yWPrlyO6OJV4bu6/oEvrAS3gXMUSGV50IptOTf M0Lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695996801; x=1696601601; 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=j2zHWwvcVZnmnLgXt7QMbcfSPEZ0TtF4vjzI06Pfh/I=; b=Y4AaSFRbo8H0hnqmjhP3ORfoJXdNFsxvH4Vq9KAirSoBFFbXF17kgh9+LaPOqHNQiY ytjnJ4rrV/trlURJH/PgH6JvTngSg9wL0UGqrtjcO3fGK0jLnQqcQNcdckNWbCNHusP4 9/CAGnYhZq8Q271fPvwDq+UAxgzszrtAm2rE/jfOoRfEPNLypdsE2TLCNZvhAgWhtGcF tComsIkDrq2HWC8A5N0vA2TAhBxa2UltKqvF1Yb1nqH43ZCZpfAZCidbEHs/AQnVPEKI vHBw9UDj8ALjAZ1JTBUv4JTZJvWbDZLAWct6kMfhrdg+5PNj8CVnSk2HumjcR2NvvyTF /cog== X-Gm-Message-State: AOJu0YxJPtC6TueaBAEF/tPS9EDzKjExI9rd22fyQN7e1I1iQza4c0fM J80LQLNUcAcJuz6O9HGLPw64NA== X-Received: by 2002:a7b:c409:0:b0:406:3f62:e583 with SMTP id k9-20020a7bc409000000b004063f62e583mr4053531wmi.40.1695996801725; Fri, 29 Sep 2023 07:13:21 -0700 (PDT) Received: from blmsp.fritz.box ([2001:4091:a246:8222:dbda:9cd9:39cc:f174]) by smtp.gmail.com with ESMTPSA id t25-20020a7bc3d9000000b00405391f485fsm1513068wmj.41.2023.09.29.07.13.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Sep 2023 07:13:21 -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 , Judith Mendez , Markus Schneider-Pargmann Subject: [PATCH v6 10/14] can: m_can: Use the workqueue as queue Date: Fri, 29 Sep 2023 16:13:00 +0200 Message-Id: <20230929141304.3934380-11-msp@baylibre.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230929141304.3934380-1-msp@baylibre.com> References: <20230929141304.3934380-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 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 X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Fri, 29 Sep 2023 07:14:06 -0700 (PDT) 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 645ce0c9fd01..1c3dc5e347b5 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -484,17 +484,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 @@ -1684,8 +1683,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); @@ -1712,20 +1712,18 @@ 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; 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) { @@ -1849,10 +1847,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, @@ -1863,30 +1887,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 enum hrtimer_restart hrtimer_callback(struct hrtimer *timer) @@ -1926,15 +1930,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, @@ -2227,6 +2233,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 0de42fc5ef1e..be1d2119bd53 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; ktime_t irq_timer_wait; @@ -102,7 +106,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