162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/errno.h> 3462306a36Sopenharmony_ci#include <linux/pci.h> 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "mthca_dev.h" 3962306a36Sopenharmony_ci#include "mthca_cmd.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciint mthca_reset(struct mthca_dev *mdev) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci int i; 4462306a36Sopenharmony_ci int err = 0; 4562306a36Sopenharmony_ci u32 *hca_header = NULL; 4662306a36Sopenharmony_ci u32 *bridge_header = NULL; 4762306a36Sopenharmony_ci struct pci_dev *bridge = NULL; 4862306a36Sopenharmony_ci int bridge_pcix_cap = 0; 4962306a36Sopenharmony_ci int hca_pcie_cap = 0; 5062306a36Sopenharmony_ci int hca_pcix_cap = 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci u16 devctl; 5362306a36Sopenharmony_ci u16 linkctl; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define MTHCA_RESET_OFFSET 0xf0010 5662306a36Sopenharmony_ci#define MTHCA_RESET_VALUE swab32(1) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * Reset the chip. This is somewhat ugly because we have to 6062306a36Sopenharmony_ci * save off the PCI header before reset and then restore it 6162306a36Sopenharmony_ci * after the chip reboots. We skip config space offsets 22 6262306a36Sopenharmony_ci * and 23 since those have a special meaning. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * To make matters worse, for Tavor (PCI-X HCA) we have to 6562306a36Sopenharmony_ci * find the associated bridge device and save off its PCI 6662306a36Sopenharmony_ci * header as well. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) { 7062306a36Sopenharmony_ci /* Look for the bridge -- its device ID will be 2 more 7162306a36Sopenharmony_ci than HCA's device ID. */ 7262306a36Sopenharmony_ci while ((bridge = pci_get_device(mdev->pdev->vendor, 7362306a36Sopenharmony_ci mdev->pdev->device + 2, 7462306a36Sopenharmony_ci bridge)) != NULL) { 7562306a36Sopenharmony_ci if (bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE && 7662306a36Sopenharmony_ci bridge->subordinate == mdev->pdev->bus) { 7762306a36Sopenharmony_ci mthca_dbg(mdev, "Found bridge: %s\n", 7862306a36Sopenharmony_ci pci_name(bridge)); 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (!bridge) { 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * Didn't find a bridge for a Tavor device -- 8662306a36Sopenharmony_ci * assume we're in no-bridge mode and hope for 8762306a36Sopenharmony_ci * the best. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci mthca_warn(mdev, "No bridge found for %s\n", 9062306a36Sopenharmony_ci pci_name(mdev->pdev)); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* For Arbel do we need to save off the full 4K PCI Express header?? */ 9662306a36Sopenharmony_ci hca_header = kmalloc(256, GFP_KERNEL); 9762306a36Sopenharmony_ci if (!hca_header) { 9862306a36Sopenharmony_ci err = -ENOMEM; 9962306a36Sopenharmony_ci goto put_dev; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci for (i = 0; i < 64; ++i) { 10362306a36Sopenharmony_ci if (i == 22 || i == 23) 10462306a36Sopenharmony_ci continue; 10562306a36Sopenharmony_ci if (pci_read_config_dword(mdev->pdev, i * 4, hca_header + i)) { 10662306a36Sopenharmony_ci err = -ENODEV; 10762306a36Sopenharmony_ci mthca_err(mdev, "Couldn't save HCA " 10862306a36Sopenharmony_ci "PCI header, aborting.\n"); 10962306a36Sopenharmony_ci goto free_hca; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); 11462306a36Sopenharmony_ci hca_pcie_cap = pci_pcie_cap(mdev->pdev); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (bridge) { 11762306a36Sopenharmony_ci bridge_header = kmalloc(256, GFP_KERNEL); 11862306a36Sopenharmony_ci if (!bridge_header) { 11962306a36Sopenharmony_ci err = -ENOMEM; 12062306a36Sopenharmony_ci goto free_hca; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i = 0; i < 64; ++i) { 12462306a36Sopenharmony_ci if (i == 22 || i == 23) 12562306a36Sopenharmony_ci continue; 12662306a36Sopenharmony_ci if (pci_read_config_dword(bridge, i * 4, bridge_header + i)) { 12762306a36Sopenharmony_ci err = -ENODEV; 12862306a36Sopenharmony_ci mthca_err(mdev, "Couldn't save HCA bridge " 12962306a36Sopenharmony_ci "PCI header, aborting.\n"); 13062306a36Sopenharmony_ci goto free_bh; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX); 13462306a36Sopenharmony_ci if (!bridge_pcix_cap) { 13562306a36Sopenharmony_ci err = -ENODEV; 13662306a36Sopenharmony_ci mthca_err(mdev, "Couldn't locate HCA bridge " 13762306a36Sopenharmony_ci "PCI-X capability, aborting.\n"); 13862306a36Sopenharmony_ci goto free_bh; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* actually hit reset */ 14362306a36Sopenharmony_ci { 14462306a36Sopenharmony_ci void __iomem *reset = ioremap(pci_resource_start(mdev->pdev, 0) + 14562306a36Sopenharmony_ci MTHCA_RESET_OFFSET, 4); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!reset) { 14862306a36Sopenharmony_ci err = -ENOMEM; 14962306a36Sopenharmony_ci mthca_err(mdev, "Couldn't map HCA reset register, " 15062306a36Sopenharmony_ci "aborting.\n"); 15162306a36Sopenharmony_ci goto free_bh; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci writel(MTHCA_RESET_VALUE, reset); 15562306a36Sopenharmony_ci iounmap(reset); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Docs say to wait one second before accessing device */ 15962306a36Sopenharmony_ci msleep(1000); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Now wait for PCI device to start responding again */ 16262306a36Sopenharmony_ci { 16362306a36Sopenharmony_ci u32 v; 16462306a36Sopenharmony_ci int c = 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (c = 0; c < 100; ++c) { 16762306a36Sopenharmony_ci if (pci_read_config_dword(bridge ? bridge : mdev->pdev, 0, &v)) { 16862306a36Sopenharmony_ci err = -ENODEV; 16962306a36Sopenharmony_ci mthca_err(mdev, "Couldn't access HCA after reset, " 17062306a36Sopenharmony_ci "aborting.\n"); 17162306a36Sopenharmony_ci goto free_bh; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (v != 0xffffffff) 17562306a36Sopenharmony_ci goto good; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci msleep(100); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci err = -ENODEV; 18162306a36Sopenharmony_ci mthca_err(mdev, "PCI device did not come back after reset, " 18262306a36Sopenharmony_ci "aborting.\n"); 18362306a36Sopenharmony_ci goto free_bh; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cigood: 18762306a36Sopenharmony_ci /* Now restore the PCI headers */ 18862306a36Sopenharmony_ci if (bridge) { 18962306a36Sopenharmony_ci if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8, 19062306a36Sopenharmony_ci bridge_header[(bridge_pcix_cap + 0x8) / 4])) { 19162306a36Sopenharmony_ci err = -ENODEV; 19262306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA bridge Upstream " 19362306a36Sopenharmony_ci "split transaction control, aborting.\n"); 19462306a36Sopenharmony_ci goto free_bh; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc, 19762306a36Sopenharmony_ci bridge_header[(bridge_pcix_cap + 0xc) / 4])) { 19862306a36Sopenharmony_ci err = -ENODEV; 19962306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA bridge Downstream " 20062306a36Sopenharmony_ci "split transaction control, aborting.\n"); 20162306a36Sopenharmony_ci goto free_bh; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Bridge control register is at 0x3e, so we'll 20562306a36Sopenharmony_ci * naturally restore it last in this loop. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci for (i = 0; i < 16; ++i) { 20862306a36Sopenharmony_ci if (i * 4 == PCI_COMMAND) 20962306a36Sopenharmony_ci continue; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (pci_write_config_dword(bridge, i * 4, bridge_header[i])) { 21262306a36Sopenharmony_ci err = -ENODEV; 21362306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA bridge reg %x, " 21462306a36Sopenharmony_ci "aborting.\n", i); 21562306a36Sopenharmony_ci goto free_bh; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (pci_write_config_dword(bridge, PCI_COMMAND, 22062306a36Sopenharmony_ci bridge_header[PCI_COMMAND / 4])) { 22162306a36Sopenharmony_ci err = -ENODEV; 22262306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, " 22362306a36Sopenharmony_ci "aborting.\n"); 22462306a36Sopenharmony_ci goto free_bh; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (hca_pcix_cap) { 22962306a36Sopenharmony_ci if (pci_write_config_dword(mdev->pdev, hca_pcix_cap, 23062306a36Sopenharmony_ci hca_header[hca_pcix_cap / 4])) { 23162306a36Sopenharmony_ci err = -ENODEV; 23262306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA PCI-X " 23362306a36Sopenharmony_ci "command register, aborting.\n"); 23462306a36Sopenharmony_ci goto free_bh; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (hca_pcie_cap) { 23962306a36Sopenharmony_ci devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4]; 24062306a36Sopenharmony_ci if (pcie_capability_write_word(mdev->pdev, PCI_EXP_DEVCTL, 24162306a36Sopenharmony_ci devctl)) { 24262306a36Sopenharmony_ci err = -ENODEV; 24362306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA PCI Express " 24462306a36Sopenharmony_ci "Device Control register, aborting.\n"); 24562306a36Sopenharmony_ci goto free_bh; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4]; 24862306a36Sopenharmony_ci if (pcie_capability_write_word(mdev->pdev, PCI_EXP_LNKCTL, 24962306a36Sopenharmony_ci linkctl)) { 25062306a36Sopenharmony_ci err = -ENODEV; 25162306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA PCI Express " 25262306a36Sopenharmony_ci "Link control register, aborting.\n"); 25362306a36Sopenharmony_ci goto free_bh; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < 16; ++i) { 25862306a36Sopenharmony_ci if (i * 4 == PCI_COMMAND) 25962306a36Sopenharmony_ci continue; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (pci_write_config_dword(mdev->pdev, i * 4, hca_header[i])) { 26262306a36Sopenharmony_ci err = -ENODEV; 26362306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA reg %x, " 26462306a36Sopenharmony_ci "aborting.\n", i); 26562306a36Sopenharmony_ci goto free_bh; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (pci_write_config_dword(mdev->pdev, PCI_COMMAND, 27062306a36Sopenharmony_ci hca_header[PCI_COMMAND / 4])) { 27162306a36Sopenharmony_ci err = -ENODEV; 27262306a36Sopenharmony_ci mthca_err(mdev, "Couldn't restore HCA COMMAND, " 27362306a36Sopenharmony_ci "aborting.\n"); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_cifree_bh: 27662306a36Sopenharmony_ci kfree(bridge_header); 27762306a36Sopenharmony_cifree_hca: 27862306a36Sopenharmony_ci kfree(hca_header); 27962306a36Sopenharmony_ciput_dev: 28062306a36Sopenharmony_ci pci_dev_put(bridge); 28162306a36Sopenharmony_ci return err; 28262306a36Sopenharmony_ci} 283