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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [acpi/] [pci_root.c] - Blame information for rev 67

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $)
3
 *
4
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6
 *
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or (at
12
 *  your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful, but
15
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 *  General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License along
20
 *  with this program; if not, write to the Free Software Foundation, Inc.,
21
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22
 *
23
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24
 */
25
 
26
#include <linux/kernel.h>
27
#include <linux/module.h>
28
#include <linux/init.h>
29
#include <linux/types.h>
30
#include <linux/proc_fs.h>
31
#include <linux/spinlock.h>
32
#include <linux/pm.h>
33
#include <linux/pci.h>
34
#include <linux/acpi.h>
35
#include <acpi/acpi_bus.h>
36
#include <acpi/acpi_drivers.h>
37
 
38
#define _COMPONENT              ACPI_PCI_COMPONENT
39
ACPI_MODULE_NAME("pci_root");
40
#define ACPI_PCI_ROOT_CLASS             "pci_bridge"
41
#define ACPI_PCI_ROOT_DEVICE_NAME       "PCI Root Bridge"
42
static int acpi_pci_root_add(struct acpi_device *device);
43
static int acpi_pci_root_remove(struct acpi_device *device, int type);
44
static int acpi_pci_root_start(struct acpi_device *device);
45
 
46
static struct acpi_device_id root_device_ids[] = {
47
        {"PNP0A03", 0},
48
        {"", 0},
49
};
50
MODULE_DEVICE_TABLE(acpi, root_device_ids);
51
 
52
static struct acpi_driver acpi_pci_root_driver = {
53
        .name = "pci_root",
54
        .class = ACPI_PCI_ROOT_CLASS,
55
        .ids = root_device_ids,
56
        .ops = {
57
                .add = acpi_pci_root_add,
58
                .remove = acpi_pci_root_remove,
59
                .start = acpi_pci_root_start,
60
                },
61
};
62
 
63
struct acpi_pci_root {
64
        struct list_head node;
65
        struct acpi_device * device;
66
        struct acpi_pci_id id;
67
        struct pci_bus *bus;
68
};
69
 
70
static LIST_HEAD(acpi_pci_roots);
71
 
72
static struct acpi_pci_driver *sub_driver;
73
 
74
int acpi_pci_register_driver(struct acpi_pci_driver *driver)
75
{
76
        int n = 0;
77
        struct list_head *entry;
78
 
79
        struct acpi_pci_driver **pptr = &sub_driver;
80
        while (*pptr)
81
                pptr = &(*pptr)->next;
82
        *pptr = driver;
83
 
84
        if (!driver->add)
85
                return 0;
86
 
87
        list_for_each(entry, &acpi_pci_roots) {
88
                struct acpi_pci_root *root;
89
                root = list_entry(entry, struct acpi_pci_root, node);
90
                driver->add(root->device->handle);
91
                n++;
92
        }
93
 
94
        return n;
95
}
96
 
97
EXPORT_SYMBOL(acpi_pci_register_driver);
98
 
99
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
100
{
101
        struct list_head *entry;
102
 
103
        struct acpi_pci_driver **pptr = &sub_driver;
104
        while (*pptr) {
105
                if (*pptr == driver)
106
                        break;
107
                pptr = &(*pptr)->next;
108
        }
109
        BUG_ON(!*pptr);
110
        *pptr = (*pptr)->next;
111
 
112
        if (!driver->remove)
113
                return;
114
 
115
        list_for_each(entry, &acpi_pci_roots) {
116
                struct acpi_pci_root *root;
117
                root = list_entry(entry, struct acpi_pci_root, node);
118
                driver->remove(root->device->handle);
119
        }
120
}
121
 
122
EXPORT_SYMBOL(acpi_pci_unregister_driver);
123
 
124
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
125
{
126
        struct acpi_pci_root *tmp;
127
 
128
        list_for_each_entry(tmp, &acpi_pci_roots, node) {
129
                if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
130
                        return tmp->device->handle;
131
        }
132
        return NULL;
133
}
134
 
135
EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
136
 
137
static acpi_status
138
get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
139
{
140
        int *busnr = data;
141
        struct acpi_resource_address64 address;
142
 
143
        if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
144
            resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
145
            resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
146
                return AE_OK;
147
 
148
        acpi_resource_to_address64(resource, &address);
149
        if ((address.address_length > 0) &&
150
            (address.resource_type == ACPI_BUS_NUMBER_RANGE))
151
                *busnr = address.minimum;
152
 
153
        return AE_OK;
154
}
155
 
156
static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
157
{
158
        acpi_status status;
159
 
160
        *busnum = -1;
161
        status =
162
            acpi_walk_resources(handle, METHOD_NAME__CRS,
163
                                get_root_bridge_busnr_callback, busnum);
164
        if (ACPI_FAILURE(status))
165
                return status;
166
        /* Check if we really get a bus number from _CRS */
167
        if (*busnum == -1)
168
                return AE_ERROR;
169
        return AE_OK;
170
}
171
 
172
static void acpi_pci_bridge_scan(struct acpi_device *device)
173
{
174
        int status;
175
        struct acpi_device *child = NULL;
176
 
177
        if (device->flags.bus_address)
178
                if (device->parent && device->parent->ops.bind) {
179
                        status = device->parent->ops.bind(device);
180
                        if (!status) {
181
                                list_for_each_entry(child, &device->children, node)
182
                                        acpi_pci_bridge_scan(child);
183
                        }
184
                }
185
}
186
 
187
static int acpi_pci_root_add(struct acpi_device *device)
188
{
189
        int result = 0;
190
        struct acpi_pci_root *root = NULL;
191
        struct acpi_pci_root *tmp;
192
        acpi_status status = AE_OK;
193
        unsigned long value = 0;
194
        acpi_handle handle = NULL;
195
        struct acpi_device *child;
196
 
197
 
198
        if (!device)
199
                return -EINVAL;
200
 
201
        root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
202
        if (!root)
203
                return -ENOMEM;
204
        INIT_LIST_HEAD(&root->node);
205
 
206
        root->device = device;
207
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
208
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
209
        acpi_driver_data(device) = root;
210
 
211
        device->ops.bind = acpi_pci_bind;
212
 
213
        /*
214
         * Segment
215
         * -------
216
         * Obtained via _SEG, if exists, otherwise assumed to be zero (0).
217
         */
218
        status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
219
                                       &value);
220
        switch (status) {
221
        case AE_OK:
222
                root->id.segment = (u16) value;
223
                break;
224
        case AE_NOT_FOUND:
225
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
226
                                  "Assuming segment 0 (no _SEG)\n"));
227
                root->id.segment = 0;
228
                break;
229
        default:
230
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
231
                result = -ENODEV;
232
                goto end;
233
        }
234
 
235
        /*
236
         * Bus
237
         * ---
238
         * Obtained via _BBN, if exists, otherwise assumed to be zero (0).
239
         */
240
        status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL,
241
                                       &value);
242
        switch (status) {
243
        case AE_OK:
244
                root->id.bus = (u16) value;
245
                break;
246
        case AE_NOT_FOUND:
247
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
248
                root->id.bus = 0;
249
                break;
250
        default:
251
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN"));
252
                result = -ENODEV;
253
                goto end;
254
        }
255
 
256
        /* Some systems have wrong _BBN */
257
        list_for_each_entry(tmp, &acpi_pci_roots, node) {
258
                if ((tmp->id.segment == root->id.segment)
259
                    && (tmp->id.bus == root->id.bus)) {
260
                        int bus = 0;
261
                        acpi_status status;
262
 
263
                        printk(KERN_ERR PREFIX
264
                                    "Wrong _BBN value, reboot"
265
                                    " and use option 'pci=noacpi'\n");
266
 
267
                        status = try_get_root_bridge_busnr(device->handle, &bus);
268
                        if (ACPI_FAILURE(status))
269
                                break;
270
                        if (bus != root->id.bus) {
271
                                printk(KERN_INFO PREFIX
272
                                       "PCI _CRS %d overrides _BBN 0\n", bus);
273
                                root->id.bus = bus;
274
                        }
275
                        break;
276
                }
277
        }
278
        /*
279
         * Device & Function
280
         * -----------------
281
         * Obtained from _ADR (which has already been evaluated for us).
282
         */
283
        root->id.device = device->pnp.bus_address >> 16;
284
        root->id.function = device->pnp.bus_address & 0xFFFF;
285
 
286
        /*
287
         * TBD: Need PCI interface for enumeration/configuration of roots.
288
         */
289
 
290
        /* TBD: Locking */
291
        list_add_tail(&root->node, &acpi_pci_roots);
292
 
293
        printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
294
               acpi_device_name(device), acpi_device_bid(device),
295
               root->id.segment, root->id.bus);
296
 
297
        /*
298
         * Scan the Root Bridge
299
         * --------------------
300
         * Must do this prior to any attempt to bind the root device, as the
301
         * PCI namespace does not get created until this call is made (and
302
         * thus the root bridge's pci_dev does not exist).
303
         */
304
        root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
305
        if (!root->bus) {
306
                printk(KERN_ERR PREFIX
307
                            "Bus %04x:%02x not present in PCI namespace\n",
308
                            root->id.segment, root->id.bus);
309
                result = -ENODEV;
310
                goto end;
311
        }
312
 
313
        /*
314
         * Attach ACPI-PCI Context
315
         * -----------------------
316
         * Thus binding the ACPI and PCI devices.
317
         */
318
        result = acpi_pci_bind_root(device, &root->id, root->bus);
319
        if (result)
320
                goto end;
321
 
322
        /*
323
         * PCI Routing Table
324
         * -----------------
325
         * Evaluate and parse _PRT, if exists.
326
         */
327
        status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
328
        if (ACPI_SUCCESS(status))
329
                result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
330
                                              root->id.bus);
331
 
332
        /*
333
         * Scan and bind all _ADR-Based Devices
334
         */
335
        list_for_each_entry(child, &device->children, node)
336
                acpi_pci_bridge_scan(child);
337
 
338
      end:
339
        if (result) {
340
                if (!list_empty(&root->node))
341
                        list_del(&root->node);
342
                kfree(root);
343
        }
344
 
345
        return result;
346
}
347
 
348
static int acpi_pci_root_start(struct acpi_device *device)
349
{
350
        struct acpi_pci_root *root;
351
 
352
 
353
        list_for_each_entry(root, &acpi_pci_roots, node) {
354
                if (root->device == device) {
355
                        pci_bus_add_devices(root->bus);
356
                        return 0;
357
                }
358
        }
359
        return -ENODEV;
360
}
361
 
362
static int acpi_pci_root_remove(struct acpi_device *device, int type)
363
{
364
        struct acpi_pci_root *root = NULL;
365
 
366
 
367
        if (!device || !acpi_driver_data(device))
368
                return -EINVAL;
369
 
370
        root = acpi_driver_data(device);
371
 
372
        kfree(root);
373
 
374
        return 0;
375
}
376
 
377
static int __init acpi_pci_root_init(void)
378
{
379
 
380
        if (acpi_pci_disabled)
381
                return 0;
382
 
383
        /* DEBUG:
384
           acpi_dbg_layer = ACPI_PCI_COMPONENT;
385
           acpi_dbg_level = 0xFFFFFFFF;
386
         */
387
 
388
        if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
389
                return -ENODEV;
390
 
391
        return 0;
392
}
393
 
394
subsys_initcall(acpi_pci_root_init);

powered by: WebSVN 2.1.0

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