~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/net/ethernet/mellanox/mlx4/reset.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
 
3
 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
 
4
 *
 
5
 * This software is available to you under a choice of one of two
 
6
 * licenses.  You may choose to be licensed under the terms of the GNU
 
7
 * General Public License (GPL) Version 2, available from the file
 
8
 * COPYING in the main directory of this source tree, or the
 
9
 * OpenIB.org BSD license below:
 
10
 *
 
11
 *     Redistribution and use in source and binary forms, with or
 
12
 *     without modification, are permitted provided that the following
 
13
 *     conditions are met:
 
14
 *
 
15
 *      - Redistributions of source code must retain the above
 
16
 *        copyright notice, this list of conditions and the following
 
17
 *        disclaimer.
 
18
 *
 
19
 *      - Redistributions in binary form must reproduce the above
 
20
 *        copyright notice, this list of conditions and the following
 
21
 *        disclaimer in the documentation and/or other materials
 
22
 *        provided with the distribution.
 
23
 *
 
24
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
25
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
26
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
27
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
28
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
29
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
30
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
31
 * SOFTWARE.
 
32
 */
 
33
 
 
34
#include <linux/errno.h>
 
35
#include <linux/pci.h>
 
36
#include <linux/delay.h>
 
37
#include <linux/slab.h>
 
38
#include <linux/jiffies.h>
 
39
 
 
40
#include "mlx4.h"
 
41
 
 
42
int mlx4_reset(struct mlx4_dev *dev)
 
43
{
 
44
        void __iomem *reset;
 
45
        u32 *hca_header = NULL;
 
46
        int pcie_cap;
 
47
        u16 devctl;
 
48
        u16 linkctl;
 
49
        u16 vendor;
 
50
        unsigned long end;
 
51
        u32 sem;
 
52
        int i;
 
53
        int err = 0;
 
54
 
 
55
#define MLX4_RESET_BASE         0xf0000
 
56
#define MLX4_RESET_SIZE           0x400
 
57
#define MLX4_SEM_OFFSET           0x3fc
 
58
#define MLX4_RESET_OFFSET          0x10
 
59
#define MLX4_RESET_VALUE        swab32(1)
 
60
 
 
61
#define MLX4_SEM_TIMEOUT_JIFFIES        (10 * HZ)
 
62
#define MLX4_RESET_TIMEOUT_JIFFIES      (2 * HZ)
 
63
 
 
64
        /*
 
65
         * Reset the chip.  This is somewhat ugly because we have to
 
66
         * save off the PCI header before reset and then restore it
 
67
         * after the chip reboots.  We skip config space offsets 22
 
68
         * and 23 since those have a special meaning.
 
69
         */
 
70
 
 
71
        /* Do we need to save off the full 4K PCI Express header?? */
 
72
        hca_header = kmalloc(256, GFP_KERNEL);
 
73
        if (!hca_header) {
 
74
                err = -ENOMEM;
 
75
                mlx4_err(dev, "Couldn't allocate memory to save HCA "
 
76
                          "PCI header, aborting.\n");
 
77
                goto out;
 
78
        }
 
79
 
 
80
        pcie_cap = pci_pcie_cap(dev->pdev);
 
81
 
 
82
        for (i = 0; i < 64; ++i) {
 
83
                if (i == 22 || i == 23)
 
84
                        continue;
 
85
                if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) {
 
86
                        err = -ENODEV;
 
87
                        mlx4_err(dev, "Couldn't save HCA "
 
88
                                  "PCI header, aborting.\n");
 
89
                        goto out;
 
90
                }
 
91
        }
 
92
 
 
93
        reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE,
 
94
                        MLX4_RESET_SIZE);
 
95
        if (!reset) {
 
96
                err = -ENOMEM;
 
97
                mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n");
 
98
                goto out;
 
99
        }
 
100
 
 
101
        /* grab HW semaphore to lock out flash updates */
 
102
        end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;
 
103
        do {
 
104
                sem = readl(reset + MLX4_SEM_OFFSET);
 
105
                if (!sem)
 
106
                        break;
 
107
 
 
108
                msleep(1);
 
109
        } while (time_before(jiffies, end));
 
110
 
 
111
        if (sem) {
 
112
                mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n");
 
113
                err = -EAGAIN;
 
114
                iounmap(reset);
 
115
                goto out;
 
116
        }
 
117
 
 
118
        /* actually hit reset */
 
119
        writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);
 
120
        iounmap(reset);
 
121
 
 
122
        /* Docs say to wait one second before accessing device */
 
123
        msleep(1000);
 
124
 
 
125
        end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
 
126
        do {
 
127
                if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
 
128
                    vendor != 0xffff)
 
129
                        break;
 
130
 
 
131
                msleep(1);
 
132
        } while (time_before(jiffies, end));
 
133
 
 
134
        if (vendor == 0xffff) {
 
135
                err = -ENODEV;
 
136
                mlx4_err(dev, "PCI device did not come back after reset, "
 
137
                          "aborting.\n");
 
138
                goto out;
 
139
        }
 
140
 
 
141
        /* Now restore the PCI headers */
 
142
        if (pcie_cap) {
 
143
                devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];
 
144
                if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL,
 
145
                                           devctl)) {
 
146
                        err = -ENODEV;
 
147
                        mlx4_err(dev, "Couldn't restore HCA PCI Express "
 
148
                                 "Device Control register, aborting.\n");
 
149
                        goto out;
 
150
                }
 
151
                linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];
 
152
                if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL,
 
153
                                           linkctl)) {
 
154
                        err = -ENODEV;
 
155
                        mlx4_err(dev, "Couldn't restore HCA PCI Express "
 
156
                                 "Link control register, aborting.\n");
 
157
                        goto out;
 
158
                }
 
159
        }
 
160
 
 
161
        for (i = 0; i < 16; ++i) {
 
162
                if (i * 4 == PCI_COMMAND)
 
163
                        continue;
 
164
 
 
165
                if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) {
 
166
                        err = -ENODEV;
 
167
                        mlx4_err(dev, "Couldn't restore HCA reg %x, "
 
168
                                  "aborting.\n", i);
 
169
                        goto out;
 
170
                }
 
171
        }
 
172
 
 
173
        if (pci_write_config_dword(dev->pdev, PCI_COMMAND,
 
174
                                   hca_header[PCI_COMMAND / 4])) {
 
175
                err = -ENODEV;
 
176
                mlx4_err(dev, "Couldn't restore HCA COMMAND, "
 
177
                          "aborting.\n");
 
178
                goto out;
 
179
        }
 
180
 
 
181
out:
 
182
        kfree(hca_header);
 
183
 
 
184
        return err;
 
185
}