From patchwork Mon Dec 7 17:37:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell King X-Patchwork-Id: 553477 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 C628114030D for ; Tue, 8 Dec 2015 04:37:48 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=arm.linux.org.uk header.i=@arm.linux.org.uk header.b=UonEAtWK; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756131AbbLGRhn (ORCPT ); Mon, 7 Dec 2015 12:37:43 -0500 Received: from pandora.arm.linux.org.uk ([78.32.30.218]:60263 "EHLO pandora.arm.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756118AbbLGRhj (ORCPT ); Mon, 7 Dec 2015 12:37:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=arm.linux.org.uk; s=pandora-2014; h=Date:Sender:Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References:In-Reply-To; bh=cJlls71/nZIoQeyJLGQVBlY+I0sAodVlz/NpTTyYyUY=; b=UonEAtWKT6TghzwCi8gOYzb57o+JCRd7wBtBGgZWeMsDnZAMGr2m+OuqnjH6GRvMQDIqpvzzPy9IhhTqHDbUWVMq8enGRfk9uY0sc+xtwXr3/UNg3w4E95xWXLGoLXav+a8mbP9F/ad8DVL5d+fvuNXmZWCLuxjE1bHNRwpg61Y=; Received: from e0022681537dd.dyn.arm.linux.org.uk ([fd8f:7570:feb6:1:222:68ff:fe15:37dd]:51136 helo=rmk-PC.arm.linux.org.uk) by pandora.arm.linux.org.uk with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.82_1-5b7a7c0-XX) (envelope-from ) id 1a5zjF-0003aE-TV; Mon, 07 Dec 2015 17:37:37 +0000 Received: from rmk by rmk-PC.arm.linux.org.uk with local (Exim 4.82_1-5b7a7c0-XX) (envelope-from ) id 1a5zjF-00074s-1E; Mon, 07 Dec 2015 17:37:37 +0000 In-Reply-To: <20151207173553.GU8644@n2100.arm.linux.org.uk> References: <20151207173553.GU8644@n2100.arm.linux.org.uk> From: Russell King To: Florian Fainelli , Thomas Petazzoni Cc: netdev@vger.kernel.org Subject: [PATCH RFC 05/26] phy: improve safety of fixed-phy MII register reading MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Mon, 07 Dec 2015 17:37:37 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org There is no prevention of a concurrent call to both fixed_mdio_read() and fixed_phy_update_state(), which can result in the state being modified while it's being inspected. Fix this by using a seqcount to detect modifications, and memcpy()ing the state. We remain slightly naughty here, calling link_update() and updating the link status within the read-side loop - which would need rework of the design to change. Signed-off-by: Russell King Reviewed-by: Florian Fainelli --- drivers/net/phy/fixed_phy.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 66555da2ef27..474cc39a5457 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "swphy.h" @@ -35,6 +36,7 @@ struct fixed_mdio_bus { struct fixed_phy { int addr; struct phy_device *phydev; + seqcount_t seqcount; struct fixed_phy_status status; int (*link_update)(struct net_device *, struct fixed_phy_status *); struct list_head node; @@ -59,13 +61,21 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) list_for_each_entry(fp, &fmb->phys, node) { if (fp->addr == phy_addr) { - /* Issue callback if user registered it. */ - if (fp->link_update) { - fp->link_update(fp->phydev->attached_dev, - &fp->status); - fixed_phy_update(fp); - } - return swphy_read_reg(reg_num, &fp->status); + struct fixed_phy_status state; + int s; + + do { + s = read_seqcount_begin(&fp->seqcount); + /* Issue callback if user registered it. */ + if (fp->link_update) { + fp->link_update(fp->phydev->attached_dev, + &fp->status); + fixed_phy_update(fp); + } + state = fp->status; + } while (read_seqcount_retry(&fp->seqcount, s)); + + return swphy_read_reg(reg_num, &state); } } @@ -117,6 +127,7 @@ int fixed_phy_update_state(struct phy_device *phydev, list_for_each_entry(fp, &fmb->phys, node) { if (fp->addr == phydev->addr) { + write_seqcount_begin(&fp->seqcount); #define _UPD(x) if (changed->x) \ fp->status.x = status->x _UPD(link); @@ -126,6 +137,7 @@ int fixed_phy_update_state(struct phy_device *phydev, _UPD(asym_pause); #undef _UPD fixed_phy_update(fp); + write_seqcount_end(&fp->seqcount); return 0; } } @@ -150,6 +162,8 @@ int fixed_phy_add(unsigned int irq, int phy_addr, if (!fp) return -ENOMEM; + seqcount_init(&fp->seqcount); + fmb->irqs[phy_addr] = irq; fp->addr = phy_addr;