From patchwork Mon May 8 15:09:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinath Mannam X-Patchwork-Id: 9716387 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 33D156035D for ; Mon, 8 May 2017 15:10:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2723526B39 for ; Mon, 8 May 2017 15:10:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 137B128614; Mon, 8 May 2017 15:10:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 788852843C for ; Mon, 8 May 2017 15:10:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755519AbdEHPKL (ORCPT ); Mon, 8 May 2017 11:10:11 -0400 Received: from mail-qk0-f182.google.com ([209.85.220.182]:35190 "EHLO mail-qk0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755240AbdEHPKJ (ORCPT ); Mon, 8 May 2017 11:10:09 -0400 Received: by mail-qk0-f182.google.com with SMTP id a72so38274033qkj.2 for ; Mon, 08 May 2017 08:10:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id; bh=RMn2Dgau/EZTcpMc0R5eR0sOGATIdvHQqmp2ssQPZUo=; b=ZdSB6a3PgO0eIolTg4XrYAqoS5QbDqsFkSmJ/0fYMWgXonKsCCPQf2H5JG/zNxI784 L8c8IlOquO+ZQj/FjB+0izozmMOhokCpJL/XmXXyGvIGESEwVYQ1Ym1nsUoJ2cu5X4V+ Yq32sEu0d3qdcuvEy0lQyRF1mYxnbUS2jzpwI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=RMn2Dgau/EZTcpMc0R5eR0sOGATIdvHQqmp2ssQPZUo=; b=S6zLJcJRgTFbqGab1oEDlBjU8LDC8TTN8THe9+F3scn7T3TTL1usTBTdsmh5JQHMhm YQnbVRw4gsurU8gFO5R45gfDhoOaX/aRxpu7exd00ENgp+1ghWkyZkkEj83J8NBVTmSG gBZKEthRyIfxoVd1bEux5+zHokqWcuTXGw0kzvOzZMIH19zsOdzxoKr0xPMN3HDR9xJa nyZex+jy9VGcwyJleFICT7U8zNg22ijo7alEogyXgGdOYMnN7mmgq1UfUHBKtJ2Gog2S hhbY1ihLqq+TW7WKI5a4MxWUF9JB3KsATsEDbysZU/d7oLesG9ZpvDht/bLxPBf1GSp8 BaaA== X-Gm-Message-State: AODbwcASbM49e0pkVoZEUxdBo7EAIG9GCyJm+k7/X98WNaS7gsB5Be8x CNhhXNqrYRm29ABy X-Received: by 10.55.109.5 with SMTP id i5mr10116995qkc.29.1494256208332; Mon, 08 May 2017 08:10:08 -0700 (PDT) Received: from mannams-OptiPlex-7010.dhcp.avagotech.net ([192.19.237.250]) by smtp.gmail.com with ESMTPSA id p48sm11265645qte.4.2017.05.08.08.10.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 08 May 2017 08:10:07 -0700 (PDT) From: Srinath Mannam To: bhelgaas@google.com Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, bcm-kernel-feedback-list@broadcom.com, Srinath Mannam Subject: [RFC PATCH] pci: Concurrency issue in NVMe Init through PCIe switch Date: Mon, 8 May 2017 20:39:50 +0530 Message-Id: <1494256190-28993-1-git-send-email-srinath.mannam@broadcom.com> X-Mailer: git-send-email 2.7.4 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We found a concurrency issue in NVMe Init when we initialize multiple NVMe connected over PCIe switch. Setup details: - SMP system with 8 ARMv8 cores running Linux kernel(4.11). - Two NVMe cards are connected to PCIe RC through bridge as shown in the below figure. [RC] | [BRIDGE] | ----------- | | [NVMe] [NVMe] Issue description: After PCIe enumeration completed NVMe driver probe function called for both the devices from two CPUS simultaneously. From nvme_probe, pci_enable_device_mem called for both the EPs. This function called pci_enable_bridge enable recursively until RC. Inside pci_enable_bridge function, at two places concurrency issue is observed. Place 1: CPU 0: 1. Done Atomic increment dev->enable_cnt in pci_enable_device_flags 2. Inside pci_enable_resources 3. Completed pci_read_config_word(dev, PCI_COMMAND, &cmd) 4. Ready to set PCI_COMMAND_MEMORY (0x2) in pci_write_config_word(dev, PCI_COMMAND, cmd) CPU 1: 1. Check pci_is_enabled in function pci_enable_bridge and it is true 2. Check (!dev->is_busmaster) also true 3. Gone into pci_set_master 4. Completed pci_read_config_word(dev, PCI_COMMAND, &old_cmd) 5. Ready to set PCI_COMMAND_MASTER (0x4) in pci_write_config_word(dev, PCI_COMMAND, cmd) By the time of last point for both the CPUs are read value 0 and ready to write 2 and 4. After last point final value in PCI_COMMAND register is 4 instead of 6. Place 2: CPU 0: 1. Done Atomic increment dev->enable_cnt in pci_enable_device_flags 2. Inside pci_enable_resources 3. Completed pci_read_config_word(dev, PCI_COMMAND, &cmd) 4. Ready to set PCI_COMMAND_MEMORY (0x2) in pci_write_config_word(dev, PCI_COMMAND, cmd); CPU 1: 1. Done Atomic increment dev->enable_cnt in function pci_enable_device_flag fail return 0 from there 2. Gone into pci_set_master 3. Completed pci_read_config_word(dev, PCI_COMMAND, &old_cmd) 4. Ready to set PCI_COMMAND_MASTER (0x4) in pci_write_config_word(dev, PCI_COMMAND, cmd) By the time of last point for both the CPUs are read value 0 and ready to write 2 and 4. After last point final value in PCI_COMMAND register is 4 instead of 6. Signed-off-by: Srinath Mannam diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7904d02..6c5744e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1345,21 +1345,39 @@ static void pci_enable_bridge(struct pci_dev *dev) { struct pci_dev *bridge; int retval; + int err; + int i; + unsigned int bars = 0; + unsigned long flags = IORESOURCE_MEM | IORESOURCE_IO; bridge = pci_upstream_bridge(dev); if (bridge) pci_enable_bridge(bridge); - if (pci_is_enabled(dev)) { - if (!dev->is_busmaster) - pci_set_master(dev); + if (dev->pm_cap) { + u16 pmcsr; + + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); + } + + if (atomic_inc_return(&dev->enable_cnt) > 1) + return; /* already enabled */ + + /* only skip sriov related */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + + err = do_pci_enable_device(dev, bars); + if (err < 0) { + atomic_dec(&dev->enable_cnt); return; } - retval = pci_enable_device(dev); - if (retval) - dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", - retval); pci_set_master(dev); }