From patchwork Mon May 17 11:06:09 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Hartkopp X-Patchwork-Id: 52784 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 040A1B7D93 for ; Mon, 17 May 2010 21:18:00 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753179Ab0EQLRo (ORCPT ); Mon, 17 May 2010 07:17:44 -0400 Received: from mo-p00-ob.rzone.de ([81.169.146.160]:38335 "EHLO mo-p00-ob.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751872Ab0EQLRn (ORCPT ); Mon, 17 May 2010 07:17:43 -0400 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; t=1274095062; l=2893; s=domk; d=hartkopp.net; h=Content-Transfer-Encoding:Content-Type:Subject:CC:To:MIME-Version: From:Date:X-RZG-CLASS-ID:X-RZG-AUTH; bh=ev1iEFZJpRPceJWKxJXDiAoeLKo=; b=VRh6k1gIzApAPkH1L8r3fiBLrJXjQqm4YTfsnYvHvDgYdmt3yMrt2e4Dx3fmHTKtjQZ islxMHGRTEXaVksZjzT0yP+Mo+XcmgUuYF/qr27itlQSaNYj8oZdi+JNYWk1K6zep5Ht8 tWD68TmcKncmoesvP/enSw2v4QtMEhPBfq4= X-RZG-AUTH: :P2MHfkW8eP4Mre39l357AZT/I7AY/7nT2yrAyK0j4gdocU+J8sQnrkVeY257pLE2 X-RZG-CLASS-ID: mo00 Received: from [109.43.62.175] (ip-109-43-62-175.web.vodafone.de [109.43.62.175]) by post.strato.de (jimi mo9) (RZmta 23.2) with ESMTP id m00374m4H9miPi ; Mon, 17 May 2010 13:06:07 +0200 (MEST) Message-ID: <4BF12321.6080506@hartkopp.net> Date: Mon, 17 May 2010 13:06:09 +0200 From: Oliver Hartkopp User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100411 Icedove/3.0.4 MIME-Version: 1.0 To: David Miller CC: Wolfgang Grandegger , stable@kernel.org, Linux Netdev List , SocketCAN Core Mailing List Subject: [PATCH] Fix SJA1000 command register writes on SMP systems Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The SJA1000 command register is concurrently written in the rx-path to free the receive buffer _and_ in the tx-path to start the transmission. On SMP systems this leads to a write stall in the tx-path, which can be solved by adding some locking for the command register in the SMP case. Thanks to Klaus Hitschler for the original fix and detailed problem description. This patch applies on net-2.6 and (with some small offsets) on net-next-2.6. It is also a candidate for the stable series. Signed-off-by: Oliver Hartkopp Acked-by: Wolfgang Grandegger --- -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 145b1a7..2760085 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -84,6 +84,27 @@ static struct can_bittiming_const sja1000_bittiming_const = { .brp_inc = 1, }; +static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val) +{ + /* the command register needs some locking on SMP systems */ + +#ifdef CONFIG_SMP + + unsigned long flags; + + spin_lock_irqsave(&priv->cmdreg_lock, flags); + priv->write_reg(priv, REG_CMR, val); + priv->read_reg(priv, REG_SR); + spin_unlock_irqrestore(&priv->cmdreg_lock, flags); + +#else + + /* write to the command register without locking */ + priv->write_reg(priv, REG_CMR, val); + +#endif +} + static int sja1000_probe_chip(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); @@ -297,7 +318,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, can_put_echo_skb(skb, dev, 0); - priv->write_reg(priv, REG_CMR, CMD_TR); + sja1000_write_cmdreg(priv, CMD_TR); return NETDEV_TX_OK; } @@ -346,7 +367,7 @@ static void sja1000_rx(struct net_device *dev) cf->can_id = id; /* release receive buffer */ - priv->write_reg(priv, REG_CMR, CMD_RRB); + sja1000_write_cmdreg(priv, CMD_RRB); netif_rx(skb); @@ -374,7 +395,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ + sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */ } if (isrc & IRQ_EI) { diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index 97a622b..4527d95 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -168,6 +168,10 @@ struct sja1000_priv { void __iomem *reg_base; /* ioremap'ed address to registers */ unsigned long irq_flags; /* for request_irq() */ +#ifdef CONFIG_SMP + spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */ +#endif + u16 flags; /* custom mode flags */ u8 ocr; /* output control register */ u8 cdr; /* clock divider register */