OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pci/] [hotplug/] [pciehp_pci.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * PCI Express Hot Plug Controller Driver
3
 *
4
 * Copyright (C) 1995,2001 Compaq Computer Corporation
5
 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6
 * Copyright (C) 2001 IBM Corp.
7
 * Copyright (C) 2003-2004 Intel Corporation
8
 *
9
 * All rights reserved.
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 2 of the License, or (at
14
 * your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful, but
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19
 * NON INFRINGEMENT.  See the GNU General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
 *
26
 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
27
 *
28
 */
29
 
30
#include <linux/module.h>
31
#include <linux/kernel.h>
32
#include <linux/types.h>
33
#include <linux/pci.h>
34
#include "../pci.h"
35
#include "pciehp.h"
36
 
37
static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
38
{
39
        u16 pci_cmd, pci_bctl;
40
 
41
        if (hpp->revision > 1) {
42
                printk(KERN_WARNING "%s: Rev.%d type0 record not supported\n",
43
                       __FUNCTION__, hpp->revision);
44
                return;
45
        }
46
 
47
        pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size);
48
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer);
49
        pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
50
        if (hpp->enable_serr)
51
                pci_cmd |= PCI_COMMAND_SERR;
52
        else
53
                pci_cmd &= ~PCI_COMMAND_SERR;
54
        if (hpp->enable_perr)
55
                pci_cmd |= PCI_COMMAND_PARITY;
56
        else
57
                pci_cmd &= ~PCI_COMMAND_PARITY;
58
        pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
59
 
60
        /* Program bridge control value */
61
        if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
62
                pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
63
                                      hpp->latency_timer);
64
                pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
65
                if (hpp->enable_serr)
66
                        pci_bctl |= PCI_BRIDGE_CTL_SERR;
67
                else
68
                        pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
69
                if (hpp->enable_perr)
70
                        pci_bctl |= PCI_BRIDGE_CTL_PARITY;
71
                else
72
                        pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
73
                pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
74
        }
75
}
76
 
77
static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
78
{
79
        int pos;
80
        u16 reg16;
81
        u32 reg32;
82
 
83
        if (hpp->revision > 1) {
84
                printk(KERN_WARNING "%s: Rev.%d type2 record not supported\n",
85
                       __FUNCTION__, hpp->revision);
86
                return;
87
        }
88
 
89
        /* Find PCI Express capability */
90
        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
91
        if (!pos)
92
                return;
93
 
94
        /* Initialize Device Control Register */
95
        pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
96
        reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or;
97
        pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
98
 
99
        /* Initialize Link Control Register */
100
        if (dev->subordinate) {
101
                pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &reg16);
102
                reg16 = (reg16 & hpp->pci_exp_lnkctl_and)
103
                        | hpp->pci_exp_lnkctl_or;
104
                pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16);
105
        }
106
 
107
        /* Find Advanced Error Reporting Enhanced Capability */
108
        pos = 256;
109
        do {
110
                pci_read_config_dword(dev, pos, &reg32);
111
                if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
112
                        break;
113
        } while ((pos = PCI_EXT_CAP_NEXT(reg32)));
114
        if (!pos)
115
                return;
116
 
117
        /* Initialize Uncorrectable Error Mask Register */
118
        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
119
        reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or;
120
        pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
121
 
122
        /* Initialize Uncorrectable Error Severity Register */
123
        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
124
        reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or;
125
        pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
126
 
127
        /* Initialize Correctable Error Mask Register */
128
        pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
129
        reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or;
130
        pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
131
 
132
        /* Initialize Advanced Error Capabilities and Control Register */
133
        pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
134
        reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or;
135
        pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
136
 
137
        /*
138
         * FIXME: The following two registers are not supported yet.
139
         *
140
         *   o Secondary Uncorrectable Error Severity Register
141
         *   o Secondary Uncorrectable Error Mask Register
142
         */
143
}
144
 
145
static void program_fw_provided_values(struct pci_dev *dev)
146
{
147
        struct pci_dev *cdev;
148
        struct hotplug_params hpp;
149
 
150
        /* Program hpp values for this device */
151
        if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
152
                        (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
153
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
154
                return;
155
 
156
        if (pciehp_get_hp_params_from_firmware(dev, &hpp)) {
157
                printk(KERN_WARNING "%s: Could not get hotplug parameters\n",
158
                       __FUNCTION__);
159
                return;
160
        }
161
 
162
        if (hpp.t2)
163
                program_hpp_type2(dev, hpp.t2);
164
        if (hpp.t0)
165
                program_hpp_type0(dev, hpp.t0);
166
 
167
        /* Program child devices */
168
        if (dev->subordinate) {
169
                list_for_each_entry(cdev, &dev->subordinate->devices,
170
                                    bus_list)
171
                        program_fw_provided_values(cdev);
172
        }
173
}
174
 
175
static int pciehp_add_bridge(struct pci_dev *dev)
176
{
177
        struct pci_bus *parent = dev->bus;
178
        int pass, busnr, start = parent->secondary;
179
        int end = parent->subordinate;
180
 
181
        for (busnr = start; busnr <= end; busnr++) {
182
                if (!pci_find_bus(pci_domain_nr(parent), busnr))
183
                        break;
184
        }
185
        if (busnr-- > end) {
186
                err("No bus number available for hot-added bridge %s\n",
187
                                pci_name(dev));
188
                return -1;
189
        }
190
        for (pass = 0; pass < 2; pass++)
191
                busnr = pci_scan_bridge(parent, dev, busnr, pass);
192
        if (!dev->subordinate)
193
                return -1;
194
        pci_bus_size_bridges(dev->subordinate);
195
        pci_bus_assign_resources(parent);
196
        pci_enable_bridges(parent);
197
        pci_bus_add_devices(parent);
198
        return 0;
199
}
200
 
201
int pciehp_configure_device(struct slot *p_slot)
202
{
203
        struct pci_dev *dev;
204
        struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
205
        int num, fn;
206
 
207
        dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
208
        if (dev) {
209
                err("Device %s already exists at %x:%x, cannot hot-add\n",
210
                                pci_name(dev), p_slot->bus, p_slot->device);
211
                pci_dev_put(dev);
212
                return -EINVAL;
213
        }
214
 
215
        num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
216
        if (num == 0) {
217
                err("No new device found\n");
218
                return -ENODEV;
219
        }
220
 
221
        for (fn = 0; fn < 8; fn++) {
222
                dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
223
                if (!dev)
224
                        continue;
225
                if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
226
                        err("Cannot hot-add display device %s\n",
227
                                        pci_name(dev));
228
                        pci_dev_put(dev);
229
                        continue;
230
                }
231
                if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
232
                                (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
233
                        pciehp_add_bridge(dev);
234
                }
235
                program_fw_provided_values(dev);
236
                pci_dev_put(dev);
237
        }
238
 
239
        pci_bus_assign_resources(parent);
240
        pci_bus_add_devices(parent);
241
        return 0;
242
}
243
 
244
int pciehp_unconfigure_device(struct slot *p_slot)
245
{
246
        int ret, rc = 0;
247
        int j;
248
        u8 bctl = 0;
249
        u8 presence = 0;
250
        struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
251
 
252
        dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
253
                                p_slot->device);
254
 
255
        for (j=0; j<8 ; j++) {
256
                struct pci_dev* temp = pci_get_slot(parent,
257
                                (p_slot->device << 3) | j);
258
                if (!temp)
259
                        continue;
260
                if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
261
                        err("Cannot remove display device %s\n",
262
                                        pci_name(temp));
263
                        pci_dev_put(temp);
264
                        continue;
265
                }
266
                if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
267
                        ret = p_slot->hpc_ops->get_adapter_status(p_slot,
268
                                                                &presence);
269
                        if (!ret && presence) {
270
                                pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
271
                                        &bctl);
272
                                if (bctl & PCI_BRIDGE_CTL_VGA) {
273
                                        err("Cannot remove display device %s\n",
274
                                                pci_name(temp));
275
                                        pci_dev_put(temp);
276
                                        continue;
277
                                }
278
                        }
279
                }
280
                pci_remove_bus_device(temp);
281
                pci_dev_put(temp);
282
        }
283
        /*
284
         * Some PCI Express root ports require fixup after hot-plug operation.
285
         */
286
        if (pcie_mch_quirk)
287
                pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
288
 
289
        return rc;
290
}
291
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.