The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mthca/mthca_reset.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
    3  *
    4  * This software is available to you under a choice of one of two
    5  * licenses.  You may choose to be licensed under the terms of the GNU
    6  * General Public License (GPL) Version 2, available from the file
    7  * COPYING in the main directory of this source tree, or the
    8  * OpenIB.org BSD license below:
    9  *
   10  *     Redistribution and use in source and binary forms, with or
   11  *     without modification, are permitted provided that the following
   12  *     conditions are met:
   13  *
   14  *      - Redistributions of source code must retain the above
   15  *        copyright notice, this list of conditions and the following
   16  *        disclaimer.
   17  *
   18  *      - Redistributions in binary form must reproduce the above
   19  *        copyright notice, this list of conditions and the following
   20  *        disclaimer in the documentation and/or other materials
   21  *        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 OF
   25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   30  * 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 
   41 int mthca_reset(struct mthca_dev *mdev)
   42 {
   43         int i;
   44         int err = 0;
   45         u32 *hca_header    = NULL;
   46 #ifdef __linux__
   47         u32 *bridge_header = NULL;
   48 #endif
   49         struct pci_dev *bridge = NULL;
   50 #ifdef __linux__
   51         int bridge_pcix_cap = 0;
   52 #endif
   53         int hca_pcie_cap = 0;
   54         int hca_pcix_cap = 0;
   55 
   56         u16 devctl;
   57         u16 linkctl;
   58 
   59 #define MTHCA_RESET_OFFSET 0xf0010
   60 #define MTHCA_RESET_VALUE  swab32(1)
   61 
   62         /*
   63          * Reset the chip.  This is somewhat ugly because we have to
   64          * save off the PCI header before reset and then restore it
   65          * after the chip reboots.  We skip config space offsets 22
   66          * and 23 since those have a special meaning.
   67          *
   68          * To make matters worse, for Tavor (PCI-X HCA) we have to
   69          * find the associated bridge device and save off its PCI
   70          * header as well.
   71          */
   72 
   73         if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) {
   74                 /* Look for the bridge -- its device ID will be 2 more
   75                    than HCA's device ID. */
   76 #ifdef __linux__
   77                 while ((bridge = pci_get_device(mdev->pdev->vendor,
   78                                                 mdev->pdev->device + 2,
   79                                                 bridge)) != NULL) {
   80                         if (bridge->hdr_type    == PCI_HEADER_TYPE_BRIDGE &&
   81                             bridge->subordinate == mdev->pdev->bus) {
   82                                 mthca_dbg(mdev, "Found bridge: %s\n",
   83                                           pci_name(bridge));
   84                                 break;
   85                         }
   86                 }
   87 
   88                 if (!bridge) {
   89                         /*
   90                          * Didn't find a bridge for a Tavor device --
   91                          * assume we're in no-bridge mode and hope for
   92                          * the best.
   93                          */
   94                         mthca_warn(mdev, "No bridge found for %s\n",
   95                                   pci_name(mdev->pdev));
   96                 }
   97 #else
   98                 mthca_warn(mdev, "Reset on PCI-X is not supported.\n");
   99                 goto out;
  100 
  101 #endif
  102         }
  103 
  104         /* For Arbel do we need to save off the full 4K PCI Express header?? */
  105         hca_header = kmalloc(256, GFP_KERNEL);
  106         if (!hca_header) {
  107                 err = -ENOMEM;
  108                 mthca_err(mdev, "Couldn't allocate memory to save HCA "
  109                           "PCI header, aborting.\n");
  110                 goto out;
  111         }
  112 
  113         for (i = 0; i < 64; ++i) {
  114                 if (i == 22 || i == 23)
  115                         continue;
  116                 if (pci_read_config_dword(mdev->pdev, i * 4, hca_header + i)) {
  117                         err = -ENODEV;
  118                         mthca_err(mdev, "Couldn't save HCA "
  119                                   "PCI header, aborting.\n");
  120                         goto out;
  121                 }
  122         }
  123 
  124         hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);
  125         hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
  126 
  127 #ifdef __linux__
  128         if (bridge) {
  129                 bridge_header = kmalloc(256, GFP_KERNEL);
  130                 if (!bridge_header) {
  131                         err = -ENOMEM;
  132                         mthca_err(mdev, "Couldn't allocate memory to save HCA "
  133                                   "bridge PCI header, aborting.\n");
  134                         goto out;
  135                 }
  136 
  137                 for (i = 0; i < 64; ++i) {
  138                         if (i == 22 || i == 23)
  139                                 continue;
  140                         if (pci_read_config_dword(bridge, i * 4, bridge_header + i)) {
  141                                 err = -ENODEV;
  142                                 mthca_err(mdev, "Couldn't save HCA bridge "
  143                                           "PCI header, aborting.\n");
  144                                 goto out;
  145                         }
  146                 }
  147                 bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
  148                 if (!bridge_pcix_cap) {
  149                                 err = -ENODEV;
  150                                 mthca_err(mdev, "Couldn't locate HCA bridge "
  151                                           "PCI-X capability, aborting.\n");
  152                                 goto out;
  153                 }
  154         }
  155 #endif
  156 
  157         /* actually hit reset */
  158         {
  159                 void __iomem *reset = ioremap(pci_resource_start(mdev->pdev, 0) +
  160                                               MTHCA_RESET_OFFSET, 4);
  161 
  162                 if (!reset) {
  163                         err = -ENOMEM;
  164                         mthca_err(mdev, "Couldn't map HCA reset register, "
  165                                   "aborting.\n");
  166                         goto out;
  167                 }
  168 
  169                 writel(MTHCA_RESET_VALUE, reset);
  170                 iounmap(reset);
  171         }
  172 
  173         /* Docs say to wait one second before accessing device */
  174         msleep(1000);
  175 
  176         /* Now wait for PCI device to start responding again */
  177         {
  178                 u32 v;
  179                 int c = 0;
  180 
  181                 for (c = 0; c < 100; ++c) {
  182                         if (pci_read_config_dword(bridge ? bridge : mdev->pdev, 0, &v)) {
  183                                 err = -ENODEV;
  184                                 mthca_err(mdev, "Couldn't access HCA after reset, "
  185                                           "aborting.\n");
  186                                 goto out;
  187                         }
  188 
  189                         if (v != 0xffffffff)
  190                                 goto good;
  191 
  192                         msleep(100);
  193                 }
  194 
  195                 err = -ENODEV;
  196                 mthca_err(mdev, "PCI device did not come back after reset, "
  197                           "aborting.\n");
  198                 goto out;
  199         }
  200 
  201 good:
  202 #ifdef __linux__
  203         /* Now restore the PCI headers */
  204         if (bridge) {
  205                 if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8,
  206                                  bridge_header[(bridge_pcix_cap + 0x8) / 4])) {
  207                         err = -ENODEV;
  208                         mthca_err(mdev, "Couldn't restore HCA bridge Upstream "
  209                                   "split transaction control, aborting.\n");
  210                         goto out;
  211                 }
  212                 if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc,
  213                                  bridge_header[(bridge_pcix_cap + 0xc) / 4])) {
  214                         err = -ENODEV;
  215                         mthca_err(mdev, "Couldn't restore HCA bridge Downstream "
  216                                   "split transaction control, aborting.\n");
  217                         goto out;
  218                 }
  219                 /*
  220                  * Bridge control register is at 0x3e, so we'll
  221                  * naturally restore it last in this loop.
  222                  */
  223                 for (i = 0; i < 16; ++i) {
  224                         if (i * 4 == PCI_COMMAND)
  225                                 continue;
  226 
  227                         if (pci_write_config_dword(bridge, i * 4, bridge_header[i])) {
  228                                 err = -ENODEV;
  229                                 mthca_err(mdev, "Couldn't restore HCA bridge reg %x, "
  230                                           "aborting.\n", i);
  231                                 goto out;
  232                         }
  233                 }
  234 
  235                 if (pci_write_config_dword(bridge, PCI_COMMAND,
  236                                            bridge_header[PCI_COMMAND / 4])) {
  237                         err = -ENODEV;
  238                         mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, "
  239                                   "aborting.\n");
  240                         goto out;
  241                 }
  242         }
  243 #endif
  244 
  245         if (hca_pcix_cap) {
  246                 if (pci_write_config_dword(mdev->pdev, hca_pcix_cap,
  247                                  hca_header[hca_pcix_cap / 4])) {
  248                         err = -ENODEV;
  249                         mthca_err(mdev, "Couldn't restore HCA PCI-X "
  250                                   "command register, aborting.\n");
  251                         goto out;
  252                 }
  253         }
  254 
  255         if (hca_pcie_cap) {
  256                 devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4];
  257                 if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL,
  258                                            devctl)) {
  259                         err = -ENODEV;
  260                         mthca_err(mdev, "Couldn't restore HCA PCI Express "
  261                                   "Device Control register, aborting.\n");
  262                         goto out;
  263                 }
  264                 linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4];
  265                 if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL,
  266                                            linkctl)) {
  267                         err = -ENODEV;
  268                         mthca_err(mdev, "Couldn't restore HCA PCI Express "
  269                                   "Link control register, aborting.\n");
  270                         goto out;
  271                 }
  272         }
  273 
  274         for (i = 0; i < 16; ++i) {
  275                 if (i * 4 == PCI_COMMAND)
  276                         continue;
  277 
  278                 if (pci_write_config_dword(mdev->pdev, i * 4, hca_header[i])) {
  279                         err = -ENODEV;
  280                         mthca_err(mdev, "Couldn't restore HCA reg %x, "
  281                                   "aborting.\n", i);
  282                         goto out;
  283                 }
  284         }
  285 
  286         if (pci_write_config_dword(mdev->pdev, PCI_COMMAND,
  287                                    hca_header[PCI_COMMAND / 4])) {
  288                 err = -ENODEV;
  289                 mthca_err(mdev, "Couldn't restore HCA COMMAND, "
  290                           "aborting.\n");
  291                 goto out;
  292         }
  293 
  294 out:
  295 #ifdef __linux__
  296         if (bridge)
  297                 pci_dev_put(bridge);
  298         kfree(bridge_header);
  299 #endif
  300         kfree(hca_header);
  301 
  302         return err;
  303 }

Cache object: 448b6ffbd178a3487b66350d7260647a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.