brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · 2a6979e Raw
283 lines · c
1/*2 * Copyright (c) 2004 Topspin Communications.  All rights reserved.3 *4 * This software is available to you under a choice of one of two5 * licenses.  You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 *     Redistribution and use in source and binary forms, with or11 *     without modification, are permitted provided that the following12 *     conditions are met:13 *14 *      - Redistributions of source code must retain the above15 *        copyright notice, this list of conditions and the following16 *        disclaimer.17 *18 *      - Redistributions in binary form must reproduce the above19 *        copyright notice, this list of conditions and the following20 *        disclaimer in the documentation and/or other materials21 *        provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32 33#include <linux/errno.h>34#include <linux/pci.h>35#include <linux/delay.h>36#include <linux/slab.h>37 38#include "mthca_dev.h"39#include "mthca_cmd.h"40 41int mthca_reset(struct mthca_dev *mdev)42{43	int i;44	int err = 0;45	u32 *hca_header    = NULL;46	u32 *bridge_header = NULL;47	struct pci_dev *bridge = NULL;48	int bridge_pcix_cap = 0;49	int hca_pcie_cap = 0;50	int hca_pcix_cap = 0;51 52	u16 devctl;53	u16 linkctl;54 55#define MTHCA_RESET_OFFSET 0xf001056#define MTHCA_RESET_VALUE  swab32(1)57 58	/*59	 * Reset the chip.  This is somewhat ugly because we have to60	 * save off the PCI header before reset and then restore it61	 * after the chip reboots.  We skip config space offsets 2262	 * and 23 since those have a special meaning.63	 *64	 * To make matters worse, for Tavor (PCI-X HCA) we have to65	 * find the associated bridge device and save off its PCI66	 * header as well.67	 */68 69	if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) {70		/* Look for the bridge -- its device ID will be 2 more71		   than HCA's device ID. */72		while ((bridge = pci_get_device(mdev->pdev->vendor,73						mdev->pdev->device + 2,74						bridge)) != NULL) {75			if (bridge->hdr_type    == PCI_HEADER_TYPE_BRIDGE &&76			    bridge->subordinate == mdev->pdev->bus) {77				mthca_dbg(mdev, "Found bridge: %s\n",78					  pci_name(bridge));79				break;80			}81		}82 83		if (!bridge) {84			/*85			 * Didn't find a bridge for a Tavor device --86			 * assume we're in no-bridge mode and hope for87			 * the best.88			 */89			mthca_warn(mdev, "No bridge found for %s\n",90				  pci_name(mdev->pdev));91		}92 93	}94 95	/* For Arbel do we need to save off the full 4K PCI Express header?? */96	hca_header = kmalloc(256, GFP_KERNEL);97	if (!hca_header) {98		err = -ENOMEM;99		goto put_dev;100	}101 102	for (i = 0; i < 64; ++i) {103		if (i == 22 || i == 23)104			continue;105		if (pci_read_config_dword(mdev->pdev, i * 4, hca_header + i)) {106			err = -ENODEV;107			mthca_err(mdev, "Couldn't save HCA "108				  "PCI header, aborting.\n");109			goto free_hca;110		}111	}112 113	hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);114	hca_pcie_cap = pci_pcie_cap(mdev->pdev);115 116	if (bridge) {117		bridge_header = kmalloc(256, GFP_KERNEL);118		if (!bridge_header) {119			err = -ENOMEM;120			goto free_hca;121		}122 123		for (i = 0; i < 64; ++i) {124			if (i == 22 || i == 23)125				continue;126			if (pci_read_config_dword(bridge, i * 4, bridge_header + i)) {127				err = -ENODEV;128				mthca_err(mdev, "Couldn't save HCA bridge "129					  "PCI header, aborting.\n");130				goto free_bh;131			}132		}133		bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX);134		if (!bridge_pcix_cap) {135				err = -ENODEV;136				mthca_err(mdev, "Couldn't locate HCA bridge "137					  "PCI-X capability, aborting.\n");138				goto free_bh;139		}140	}141 142	/* actually hit reset */143	{144		void __iomem *reset = ioremap(pci_resource_start(mdev->pdev, 0) +145					      MTHCA_RESET_OFFSET, 4);146 147		if (!reset) {148			err = -ENOMEM;149			mthca_err(mdev, "Couldn't map HCA reset register, "150				  "aborting.\n");151			goto free_bh;152		}153 154		writel(MTHCA_RESET_VALUE, reset);155		iounmap(reset);156	}157 158	/* Docs say to wait one second before accessing device */159	msleep(1000);160 161	/* Now wait for PCI device to start responding again */162	{163		u32 v;164		int c = 0;165 166		for (c = 0; c < 100; ++c) {167			if (pci_read_config_dword(bridge ? bridge : mdev->pdev, 0, &v)) {168				err = -ENODEV;169				mthca_err(mdev, "Couldn't access HCA after reset, "170					  "aborting.\n");171				goto free_bh;172			}173 174			if (v != 0xffffffff)175				goto good;176 177			msleep(100);178		}179 180		err = -ENODEV;181		mthca_err(mdev, "PCI device did not come back after reset, "182			  "aborting.\n");183		goto free_bh;184	}185 186good:187	/* Now restore the PCI headers */188	if (bridge) {189		if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8,190				 bridge_header[(bridge_pcix_cap + 0x8) / 4])) {191			err = -ENODEV;192			mthca_err(mdev, "Couldn't restore HCA bridge Upstream "193				  "split transaction control, aborting.\n");194			goto free_bh;195		}196		if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc,197				 bridge_header[(bridge_pcix_cap + 0xc) / 4])) {198			err = -ENODEV;199			mthca_err(mdev, "Couldn't restore HCA bridge Downstream "200				  "split transaction control, aborting.\n");201			goto free_bh;202		}203		/*204		 * Bridge control register is at 0x3e, so we'll205		 * naturally restore it last in this loop.206		 */207		for (i = 0; i < 16; ++i) {208			if (i * 4 == PCI_COMMAND)209				continue;210 211			if (pci_write_config_dword(bridge, i * 4, bridge_header[i])) {212				err = -ENODEV;213				mthca_err(mdev, "Couldn't restore HCA bridge reg %x, "214					  "aborting.\n", i);215				goto free_bh;216			}217		}218 219		if (pci_write_config_dword(bridge, PCI_COMMAND,220					   bridge_header[PCI_COMMAND / 4])) {221			err = -ENODEV;222			mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, "223				  "aborting.\n");224			goto free_bh;225		}226	}227 228	if (hca_pcix_cap) {229		if (pci_write_config_dword(mdev->pdev, hca_pcix_cap,230				 hca_header[hca_pcix_cap / 4])) {231			err = -ENODEV;232			mthca_err(mdev, "Couldn't restore HCA PCI-X "233				  "command register, aborting.\n");234			goto free_bh;235		}236	}237 238	if (hca_pcie_cap) {239		devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4];240		if (pcie_capability_write_word(mdev->pdev, PCI_EXP_DEVCTL,241					       devctl)) {242			err = -ENODEV;243			mthca_err(mdev, "Couldn't restore HCA PCI Express "244				  "Device Control register, aborting.\n");245			goto free_bh;246		}247		linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4];248		if (pcie_capability_write_word(mdev->pdev, PCI_EXP_LNKCTL,249					       linkctl)) {250			err = -ENODEV;251			mthca_err(mdev, "Couldn't restore HCA PCI Express "252				  "Link control register, aborting.\n");253			goto free_bh;254		}255	}256 257	for (i = 0; i < 16; ++i) {258		if (i * 4 == PCI_COMMAND)259			continue;260 261		if (pci_write_config_dword(mdev->pdev, i * 4, hca_header[i])) {262			err = -ENODEV;263			mthca_err(mdev, "Couldn't restore HCA reg %x, "264				  "aborting.\n", i);265			goto free_bh;266		}267	}268 269	if (pci_write_config_dword(mdev->pdev, PCI_COMMAND,270				   hca_header[PCI_COMMAND / 4])) {271		err = -ENODEV;272		mthca_err(mdev, "Couldn't restore HCA COMMAND, "273			  "aborting.\n");274	}275free_bh:276	kfree(bridge_header);277free_hca:278	kfree(hca_header);279put_dev:280	pci_dev_put(bridge);281	return err;282}283