Received: by 10.192.165.156 with SMTP id m28csp1599248imm; Sat, 14 Apr 2018 02:07:50 -0700 (PDT) X-Google-Smtp-Source: AIpwx48XatlZl0735dvxhXG9BzCq4dcUypRiAi5NlEScLOTFspFNsmZsgUiOzOj83eQwR5d32eh6 X-Received: by 10.98.194.142 with SMTP id w14mr14478579pfk.226.1523696870526; Sat, 14 Apr 2018 02:07:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523696870; cv=none; d=google.com; s=arc-20160816; b=VrfIwy7VN3rxN0b/9c/LXeA57QzMGOZM95MSCgT0mO/rw7btBjv9KffMvoO3041/ae m7wP/2yvvHHwF1A+E/nXSEJoiUXp2LCoq52Qhqxrj3WVLAPZFJzFa/ZWaFQfVGV1udL7 ZY8qdQVFKVBo8NzfE0FOXVn89so8zSLCQqWIWrMsaPC4MXPI2T0KFlh85dc3AQL/HOBy zMwSZ7nu0sN1TJq8eayecLnZsD9wrgIh7dpoIgGj6M8MBucTNHCGQ4CYyvapyA+8lRhG iuVNJLNdTE7N4lx6+hfftu1USLc5twrOM7Jezv3FgicT+3WNQAkG7IjF8aX/vHsXgwu/ +QJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=/+DwFnlKi08N9Ec2bjfcUDMWa7xS3D3tGyj12HGBMJQ=; b=iYCJczCcpU1A4B2GHs7MYwxakcoyxjSIrUfTp4vUWhJBWYPbA4vBIPVbA/LnTMHHO9 R87wUWVvTdz2bZDu0qTdFKcEfjY50hPlv5x/m59xjedwrogw9fykPWrdtGJ5VTsgTnhy W398cpXpLwE+PSoFojh6YoKzNhxV8yNy6ikz9XPMmBrTdrczRCUpg9To/GVybzuKnMjH NvQbMYWxlMmXLvakPWR6GH4i/hrgNSq83GF5U07+8FAvcxTjvv+NHpJxsxHdirliVAcI yyT0a88sSBgVgbxX7qCqlBDxGGxrYv488kOlpXZR7hD8fJXwafJMOH9zvatMRJvh42vF Q2VQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d1-v6si7607974plo.328.2018.04.14.02.07.11; Sat, 14 Apr 2018 02:07:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750930AbeDNJEZ (ORCPT + 99 others); Sat, 14 Apr 2018 05:04:25 -0400 Received: from smtprz14.163.net ([106.3.154.247]:38000 "HELO smtp.tom.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with SMTP id S1750849AbeDNJEX (ORCPT ); Sat, 14 Apr 2018 05:04:23 -0400 X-Greylist: delayed 810 seconds by postgrey-1.27 at vger.kernel.org; Sat, 14 Apr 2018 05:04:23 EDT Received: from antispam1.tom.com (unknown [172.25.16.55]) by my-app02.tom.com (SMTP) with ESMTP id C921D9C1132 for ; Sat, 14 Apr 2018 16:50:40 +0800 (CST) Received: from antispam1.tom.com (antispam1.tom.com [127.0.0.1]) by antispam1.tom.com (Postfix) with ESMTP id C6ACB1001072 for ; Sat, 14 Apr 2018 16:50:40 +0800 (CST) X-Virus-Scanned: Debian amavisd-new at antispam1.tom.com Received: from antispam1.tom.com ([127.0.0.1]) by antispam1.tom.com (antispam1.tom.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DHnxTGJFPOSU for ; Sat, 14 Apr 2018 16:50:39 +0800 (CST) Received: from localhost (unknown [171.221.128.242]) by antispam1.tom.com (Postfix) with ESMTPA id 7592B1001078; Sat, 14 Apr 2018 16:50:39 +0800 (CST) From: Liu Xiang To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, liuxiang_1999@126.com, Liu Xiang Subject: [PATCH v3] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine Date: Sat, 14 Apr 2018 16:50:34 +0800 Message-Id: <1523695834-6261-1-git-send-email-liu.xiang6@zte.com.cn> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in phy operation during the dm9000_timeout() routine. --- v3: When a task enters dm9000_timeout() and gets the main spinlock, another task that wants to do asynchronous phy operation must be running on another cpu.Because of different cpus, this asynchronous task will be blocked in dm9000_phy_write() until dm9000_timeout() routine is completed. --- Signed-off-by: Liu Xiang --- drivers/net/ethernet/davicom/dm9000.c | 39 +++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 50222b7..56df77d 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -112,7 +112,7 @@ struct board_info { u8 imr_all; unsigned int flags; - unsigned int in_timeout:1; + int timeout_cpu; unsigned int in_suspend:1; unsigned int wake_supported:1; @@ -158,6 +158,17 @@ static inline struct board_info *to_dm9000_board(struct net_device *dev) return netdev_priv(dev); } +static bool dm9000_current_in_timeout(struct board_info *db) +{ + bool ret = false; + + preempt_disable(); + ret = (db->timeout_cpu == smp_processor_id()); + preempt_enable(); + + return ret; +} + /* DM9000 network board routine ---------------------------- */ /* @@ -276,7 +287,7 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count) */ static void dm9000_msleep(struct board_info *db, unsigned int ms) { - if (db->in_suspend || db->in_timeout) + if (db->in_suspend || dm9000_current_in_timeout(db)) mdelay(ms); else msleep(ms); @@ -335,12 +346,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) struct board_info *db = netdev_priv(dev); unsigned long flags; unsigned long reg_save; + bool in_timeout = dm9000_current_in_timeout(db); dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) + if (!in_timeout) { mutex_lock(&db->addr_lock); - - spin_lock_irqsave(&db->lock, flags); + spin_lock_irqsave(&db->lock, flags); + } /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,11 +368,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock, flags); + if (!in_timeout) + spin_unlock_irqrestore(&db->lock, flags); dm9000_msleep(db, 1); /* Wait write complete */ - spin_lock_irqsave(&db->lock, flags); + if (!in_timeout) + spin_lock_irqsave(&db->lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -368,9 +382,10 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock, flags); - if (!db->in_timeout) + if (!in_timeout) { + spin_unlock_irqrestore(&db->lock, flags); mutex_unlock(&db->addr_lock); + } } /* dm9000_set_io @@ -980,7 +995,7 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ spin_lock_irqsave(&db->lock, flags); - db->in_timeout = 1; + db->timeout_cpu = smp_processor_id(); reg_save = readb(db->io_addr); netif_stop_queue(dev); @@ -992,7 +1007,7 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); - db->in_timeout = 0; + db->timeout_cpu = -1; spin_unlock_irqrestore(&db->lock, flags); } @@ -1670,6 +1685,8 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) db->mii.mdio_read = dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write; + db->timeout_cpu = -1; + mac_src = "eeprom"; /* try reading the node address from the attached EEPROM */ -- 1.9.1