From patchwork Sun Dec 13 13:11:33 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 67026 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nBDDiTUT011509 for ; Sun, 13 Dec 2009 13:45:18 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753355AbZLMNpR (ORCPT ); Sun, 13 Dec 2009 08:45:17 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753356AbZLMNpR (ORCPT ); Sun, 13 Dec 2009 08:45:17 -0500 Received: from smtp-noauth7.primus.ca ([216.254.180.38]:60272 "HELO mail-06.primus.ca" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with SMTP id S1753355AbZLMNpQ (ORCPT ); Sun, 13 Dec 2009 08:45:16 -0500 Received: from dsl-173-206-141-177.tor.primus.ca ([173.206.141.177] helo=harry.int.wil.cx) by mail-06.primus.ca with esmtp (Exim 4.69) (envelope-from ) id 1NJoKz-0002HY-28; Sun, 13 Dec 2009 08:18:13 -0500 Received: by harry.int.wil.cx (Postfix, from userid 1000) id 9DF2E1E2EA; Sun, 13 Dec 2009 08:11:41 -0500 (EST) From: Matthew Wilcox To: linux-pci@vger.kernel.org, jbarnes@virtuousgeek.org Cc: Matthew Wilcox , Matthew Wilcox Subject: [PATCH 3/5] Add support for detection of PCIe and PCI-X bus speeds Date: Sun, 13 Dec 2009 08:11:33 -0500 Message-Id: <1260709895-9510-3-git-send-email-matthew@wil.cx> X-Mailer: git-send-email 1.6.5 In-Reply-To: <1260709895-9510-2-git-send-email-matthew@wil.cx> References: <1260709895-9510-1-git-send-email-matthew@wil.cx> <1260709895-9510-2-git-send-email-matthew@wil.cx> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 58eab10..e31c49c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -393,6 +393,25 @@ static struct pci_bus * pci_alloc_bus(void) return b; } +static unsigned char pcix_bus_speed[] = { + PCI_SPEED_UNKNOWN, /* 0 */ + PCI_SPEED_66MHz_PCIX, /* 1 */ + PCI_SPEED_100MHz_PCIX, /* 2 */ + PCI_SPEED_133MHz_PCIX, /* 3 */ + PCI_SPEED_UNKNOWN, /* 4 */ + PCI_SPEED_66MHz_PCIX_ECC, /* 5 */ + PCI_SPEED_100MHz_PCIX_ECC, /* 6 */ + PCI_SPEED_133MHz_PCIX_ECC, /* 7 */ + PCI_SPEED_UNKNOWN, /* 8 */ + PCI_SPEED_66MHz_PCIX_266, /* 9 */ + PCI_SPEED_100MHz_PCIX_266, /* A */ + PCI_SPEED_133MHz_PCIX_266, /* B */ + PCI_SPEED_UNKNOWN, /* C */ + PCI_SPEED_66MHz_PCIX_533, /* D */ + PCI_SPEED_100MHz_PCIX_533, /* E */ + PCI_SPEED_133MHz_PCIX_533 /* F */ +}; + static unsigned char pcie_link_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCIE_SPEED_2_5GT, /* 1 */ @@ -418,6 +437,51 @@ void pcie_update_link_speed(struct pci_bus *bus, u16 linksta) } EXPORT_SYMBOL_GPL(pcie_update_link_speed); +static void pci_set_bus_speed(struct pci_bus *bus) +{ + struct pci_dev *bridge = bus->self; + int pos; + + pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX); + if (pos) { + u16 status; + enum pci_bus_speed max; + pci_read_config_word(bridge, pos + 2, &status); + + if (status & 0x8000) { + max = PCI_SPEED_133MHz_PCIX_533; + } else if (status & 0x4000) { + max = PCI_SPEED_133MHz_PCIX_266; + } else if (status & 0x0002) { + if (((status >> 12) & 0x3) == 2) { + max = PCI_SPEED_133MHz_PCIX_ECC; + } else { + max = PCI_SPEED_133MHz_PCIX; + } + } else { + max = PCI_SPEED_66MHz_PCIX; + } + + bus->max_bus_speed = max; + bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf]; + + return; + } + + pos = pci_find_capability(bridge, PCI_CAP_ID_EXP); + if (pos) { + u32 linkcap; + u16 linksta; + + pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap); + bus->max_bus_speed = pcie_link_speed[linkcap & 0xf]; + + pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta); + pcie_update_link_speed(bus, linksta); + } +} + + static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { @@ -457,6 +521,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, child->self = bridge; child->bridge = get_device(&bridge->dev); + pci_set_bus_speed(child); + /* Set up default resource pointers and names.. */ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];