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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * This file is subject to the terms and conditions of the GNU General Public
3
 * License.  See the file "COPYING" in the main directory of this archive
4
 * for more details.
5
 *
6
 * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved.
7
 *
8
 * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
9
 * Work to add BIOS PROM support was completed by Mike Habeck.
10
 */
11
 
12
#include <linux/init.h>
13
#include <linux/kernel.h>
14
#include <linux/module.h>
15
#include <linux/pci.h>
16
#include <linux/pci_hotplug.h>
17
#include <linux/proc_fs.h>
18
#include <linux/types.h>
19
#include <linux/mutex.h>
20
 
21
#include <asm/sn/addrs.h>
22
#include <asm/sn/geo.h>
23
#include <asm/sn/l1.h>
24
#include <asm/sn/module.h>
25
#include <asm/sn/pcibr_provider.h>
26
#include <asm/sn/pcibus_provider_defs.h>
27
#include <asm/sn/pcidev.h>
28
#include <asm/sn/sn_feature_sets.h>
29
#include <asm/sn/sn_sal.h>
30
#include <asm/sn/types.h>
31
#include <linux/acpi.h>
32
#include <asm/sn/acpi.h>
33
 
34
#include "../pci.h"
35
 
36
MODULE_LICENSE("GPL");
37
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
38
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
39
 
40
 
41
/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
42
#define PCI_SLOT_ALREADY_UP             2       /* slot already up */
43
#define PCI_SLOT_ALREADY_DOWN           3       /* slot already down */
44
#define PCI_L1_ERR                      7       /* L1 console command error */
45
#define PCI_EMPTY_33MHZ                 15      /* empty 33 MHz bus */
46
 
47
 
48
#define PCIIO_ASIC_TYPE_TIOCA           4
49
#define PCI_L1_QSIZE                    128     /* our L1 message buffer size */
50
#define SN_MAX_HP_SLOTS                 32      /* max hotplug slots */
51
#define SN_SLOT_NAME_SIZE               33      /* size of name string */
52
 
53
/* internal list head */
54
static struct list_head sn_hp_list;
55
 
56
/* hotplug_slot struct's private pointer */
57
struct slot {
58
        int device_num;
59
        struct pci_bus *pci_bus;
60
        /* this struct for glue internal only */
61
        struct hotplug_slot *hotplug_slot;
62
        struct list_head hp_list;
63
        char physical_path[SN_SLOT_NAME_SIZE];
64
};
65
 
66
struct pcibr_slot_enable_resp {
67
        int resp_sub_errno;
68
        char resp_l1_msg[PCI_L1_QSIZE + 1];
69
};
70
 
71
struct pcibr_slot_disable_resp {
72
        int resp_sub_errno;
73
        char resp_l1_msg[PCI_L1_QSIZE + 1];
74
};
75
 
76
enum sn_pci_req_e {
77
        PCI_REQ_SLOT_ELIGIBLE,
78
        PCI_REQ_SLOT_DISABLE
79
};
80
 
81
static int enable_slot(struct hotplug_slot *slot);
82
static int disable_slot(struct hotplug_slot *slot);
83
static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
84
 
85
static struct hotplug_slot_ops sn_hotplug_slot_ops = {
86
        .owner                  = THIS_MODULE,
87
        .enable_slot            = enable_slot,
88
        .disable_slot           = disable_slot,
89
        .get_power_status       = get_power_status,
90
};
91
 
92
static DEFINE_MUTEX(sn_hotplug_mutex);
93
 
94
static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
95
                          char *buf)
96
{
97
        int retval = -ENOENT;
98
        struct slot *slot = bss_hotplug_slot->private;
99
 
100
        if (!slot)
101
                return retval;
102
 
103
        retval = sprintf (buf, "%s\n", slot->physical_path);
104
        return retval;
105
}
106
 
107
static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
108
 
109
static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
110
{
111
        struct pcibus_info *pcibus_info;
112
        u16 busnum, segment, ioboard_type;
113
 
114
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
115
 
116
        /* Check to see if this is a valid slot on 'pci_bus' */
117
        if (!(pcibus_info->pbi_valid_devices & (1 << device)))
118
                return -EPERM;
119
 
120
        ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
121
        busnum = pcibus_info->pbi_buscommon.bs_persist_busnum;
122
        segment = pci_domain_nr(pci_bus) & 0xf;
123
 
124
        /* Do not allow hotplug operations on base I/O cards */
125
        if ((ioboard_type == L1_BRICKTYPE_IX ||
126
             ioboard_type == L1_BRICKTYPE_IA) &&
127
            (segment == 1 && busnum == 0 && device != 1))
128
                return -EPERM;
129
 
130
        return 1;
131
}
132
 
133
static int sn_pci_bus_valid(struct pci_bus *pci_bus)
134
{
135
        struct pcibus_info *pcibus_info;
136
        u32 asic_type;
137
        u16 ioboard_type;
138
 
139
        /* Don't register slots hanging off the TIOCA bus */
140
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
141
        asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
142
        if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
143
                return -EPERM;
144
 
145
        /* Only register slots in I/O Bricks that support hotplug */
146
        ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
147
        switch (ioboard_type) {
148
                case L1_BRICKTYPE_IX:
149
                case L1_BRICKTYPE_PX:
150
                case L1_BRICKTYPE_IA:
151
                case L1_BRICKTYPE_PA:
152
                case L1_BOARDTYPE_PCIX3SLOT:
153
                        return 1;
154
                        break;
155
                default:
156
                        return -EPERM;
157
                        break;
158
        }
159
 
160
        return -EIO;
161
}
162
 
163
static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
164
                                    struct pci_bus *pci_bus, int device)
165
{
166
        struct pcibus_info *pcibus_info;
167
        struct slot *slot;
168
 
169
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
170
 
171
        slot = kzalloc(sizeof(*slot), GFP_KERNEL);
172
        if (!slot)
173
                return -ENOMEM;
174
        bss_hotplug_slot->private = slot;
175
 
176
        bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL);
177
        if (!bss_hotplug_slot->name) {
178
                kfree(bss_hotplug_slot->private);
179
                return -ENOMEM;
180
        }
181
 
182
        slot->device_num = device;
183
        slot->pci_bus = pci_bus;
184
        sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x",
185
                pci_domain_nr(pci_bus),
186
                ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
187
                device + 1);
188
 
189
        sn_generate_path(pci_bus, slot->physical_path);
190
 
191
        slot->hotplug_slot = bss_hotplug_slot;
192
        list_add(&slot->hp_list, &sn_hp_list);
193
 
194
        return 0;
195
}
196
 
197
static struct hotplug_slot * sn_hp_destroy(void)
198
{
199
        struct slot *slot;
200
        struct hotplug_slot *bss_hotplug_slot = NULL;
201
 
202
        list_for_each_entry(slot, &sn_hp_list, hp_list) {
203
                bss_hotplug_slot = slot->hotplug_slot;
204
                list_del(&((struct slot *)bss_hotplug_slot->private)->
205
                         hp_list);
206
                sysfs_remove_file(&bss_hotplug_slot->kobj,
207
                                  &sn_slot_path_attr.attr);
208
                break;
209
        }
210
        return bss_hotplug_slot;
211
}
212
 
213
static void sn_bus_free_data(struct pci_dev *dev)
214
{
215
        struct pci_bus *subordinate_bus;
216
        struct pci_dev *child;
217
 
218
        /* Recursively clean up sn_irq_info structs */
219
        if (dev->subordinate) {
220
                subordinate_bus = dev->subordinate;
221
                list_for_each_entry(child, &subordinate_bus->devices, bus_list)
222
                        sn_bus_free_data(child);
223
        }
224
        /*
225
         * Some drivers may use dma accesses during the
226
         * driver remove function. We release the sysdata
227
         * areas after the driver remove functions have
228
         * been called.
229
         */
230
        sn_bus_store_sysdata(dev);
231
        sn_pci_unfixup_slot(dev);
232
}
233
 
234
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
235
                          int device_num, char **ssdt)
236
{
237
        struct slot *slot = bss_hotplug_slot->private;
238
        struct pcibus_info *pcibus_info;
239
        struct pcibr_slot_enable_resp resp;
240
        int rc;
241
 
242
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
243
 
244
        /*
245
         * Power-on and initialize the slot in the SN
246
         * PCI infrastructure.
247
         */
248
        rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
249
 
250
 
251
        if (rc == PCI_SLOT_ALREADY_UP) {
252
                dev_dbg(&slot->pci_bus->self->dev, "is already active\n");
253
                return 1; /* return 1 to user */
254
        }
255
 
256
        if (rc == PCI_L1_ERR) {
257
                dev_dbg(&slot->pci_bus->self->dev,
258
                        "L1 failure %d with message: %s",
259
                        resp.resp_sub_errno, resp.resp_l1_msg);
260
                return -EPERM;
261
        }
262
 
263
        if (rc) {
264
                dev_dbg(&slot->pci_bus->self->dev,
265
                        "insert failed with error %d sub-error %d\n",
266
                        rc, resp.resp_sub_errno);
267
                return -EIO;
268
        }
269
 
270
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
271
        pcibus_info->pbi_enabled_devices |= (1 << device_num);
272
 
273
        return 0;
274
}
275
 
276
static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
277
                           int device_num, int action)
278
{
279
        struct slot *slot = bss_hotplug_slot->private;
280
        struct pcibus_info *pcibus_info;
281
        struct pcibr_slot_disable_resp resp;
282
        int rc;
283
 
284
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
285
 
286
        rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);
287
 
288
        if ((action == PCI_REQ_SLOT_ELIGIBLE) &&
289
            (rc == PCI_SLOT_ALREADY_DOWN)) {
290
                dev_dbg(&slot->pci_bus->self->dev, "Slot %s already inactive\n", slot->physical_path);
291
                return 1; /* return 1 to user */
292
        }
293
 
294
        if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) {
295
                dev_dbg(&slot->pci_bus->self->dev,
296
                        "Cannot remove last 33MHz card\n");
297
                return -EPERM;
298
        }
299
 
300
        if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) {
301
                dev_dbg(&slot->pci_bus->self->dev,
302
                        "L1 failure %d with message \n%s\n",
303
                        resp.resp_sub_errno, resp.resp_l1_msg);
304
                return -EPERM;
305
        }
306
 
307
        if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) {
308
                dev_dbg(&slot->pci_bus->self->dev,
309
                        "remove failed with error %d sub-error %d\n",
310
                        rc, resp.resp_sub_errno);
311
                return -EIO;
312
        }
313
 
314
        if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc)
315
                return 0;
316
 
317
        if ((action == PCI_REQ_SLOT_DISABLE) && !rc) {
318
                pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
319
                pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
320
                dev_dbg(&slot->pci_bus->self->dev, "remove successful\n");
321
                return 0;
322
        }
323
 
324
        if ((action == PCI_REQ_SLOT_DISABLE) && rc) {
325
                dev_dbg(&slot->pci_bus->self->dev,"remove failed rc = %d\n", rc);
326
        }
327
 
328
        return rc;
329
}
330
 
331
/*
332
 * Power up and configure the slot via a SAL call to PROM.
333
 * Scan slot (and any children), do any platform specific fixup,
334
 * and find device driver.
335
 */
336
static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
337
{
338
        struct slot *slot = bss_hotplug_slot->private;
339
        struct pci_bus *new_bus = NULL;
340
        struct pci_dev *dev;
341
        int func, num_funcs;
342
        int new_ppb = 0;
343
        int rc;
344
        char *ssdt = NULL;
345
        void pcibios_fixup_device_resources(struct pci_dev *);
346
 
347
        /* Serialize the Linux PCI infrastructure */
348
        mutex_lock(&sn_hotplug_mutex);
349
 
350
        /*
351
         * Power-on and initialize the slot in the SN
352
         * PCI infrastructure. Also, retrieve the ACPI SSDT
353
         * table for the slot (if ACPI capable PROM).
354
         */
355
        rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
356
        if (rc) {
357
                mutex_unlock(&sn_hotplug_mutex);
358
                return rc;
359
        }
360
 
361
        if (ssdt)
362
                ssdt = __va(ssdt);
363
        /* Add the new SSDT for the slot to the ACPI namespace */
364
        if (SN_ACPI_BASE_SUPPORT() && ssdt) {
365
                acpi_status ret;
366
 
367
                ret = acpi_load_table((struct acpi_table_header *)ssdt);
368
                if (ACPI_FAILURE(ret)) {
369
                        printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
370
                               __FUNCTION__, ret);
371
                        /* try to continue on */
372
                }
373
        }
374
 
375
        num_funcs = pci_scan_slot(slot->pci_bus,
376
                                  PCI_DEVFN(slot->device_num + 1, 0));
377
        if (!num_funcs) {
378
                dev_dbg(&slot->pci_bus->self->dev, "no device in slot\n");
379
                mutex_unlock(&sn_hotplug_mutex);
380
                return -ENODEV;
381
        }
382
 
383
        /*
384
         * Map SN resources for all functions on the card
385
         * to the Linux PCI interface and tell the drivers
386
         * about them.
387
         */
388
        for (func = 0; func < num_funcs;  func++) {
389
                dev = pci_get_slot(slot->pci_bus,
390
                                   PCI_DEVFN(slot->device_num + 1,
391
                                             PCI_FUNC(func)));
392
                if (dev) {
393
                        /* Need to do slot fixup on PPB before fixup of children
394
                         * (PPB's pcidev_info needs to be in pcidev_info list
395
                         * before child's SN_PCIDEV_INFO() call to setup
396
                         * pdi_host_pcidev_info).
397
                         */
398
                        pcibios_fixup_device_resources(dev);
399
                        if (SN_ACPI_BASE_SUPPORT())
400
                                sn_acpi_slot_fixup(dev);
401
                        else
402
                                sn_io_slot_fixup(dev);
403
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
404
                                unsigned char sec_bus;
405
                                pci_read_config_byte(dev, PCI_SECONDARY_BUS,
406
                                                     &sec_bus);
407
                                new_bus = pci_add_new_bus(dev->bus, dev,
408
                                                          sec_bus);
409
                                pci_scan_child_bus(new_bus);
410
                                new_ppb = 1;
411
                        }
412
                        pci_dev_put(dev);
413
                }
414
        }
415
 
416
        /*
417
         * Add the slot's devices to the ACPI infrastructure */
418
        if (SN_ACPI_BASE_SUPPORT() && ssdt) {
419
                unsigned long adr;
420
                struct acpi_device *pdevice;
421
                struct acpi_device *device;
422
                acpi_handle phandle;
423
                acpi_handle chandle = NULL;
424
                acpi_handle rethandle;
425
                acpi_status ret;
426
 
427
                phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
428
 
429
                if (acpi_bus_get_device(phandle, &pdevice)) {
430
                        dev_dbg(&slot->pci_bus->self->dev,
431
                                "no parent device, assuming NULL\n");
432
                        pdevice = NULL;
433
                }
434
 
435
                /*
436
                 * Walk the rootbus node's immediate children looking for
437
                 * the slot's device node(s). There can be more than
438
                 * one for multifunction devices.
439
                 */
440
                for (;;) {
441
                        rethandle = NULL;
442
                        ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
443
                                                   phandle, chandle,
444
                                                   &rethandle);
445
 
446
                        if (ret == AE_NOT_FOUND || rethandle == NULL)
447
                                break;
448
 
449
                        chandle = rethandle;
450
 
451
                        ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
452
                                                    NULL, &adr);
453
 
454
                        if (ACPI_SUCCESS(ret) &&
455
                            (adr>>16) == (slot->device_num + 1)) {
456
 
457
                                ret = acpi_bus_add(&device, pdevice, chandle,
458
                                                   ACPI_BUS_TYPE_DEVICE);
459
                                if (ACPI_FAILURE(ret)) {
460
                                        printk(KERN_ERR "%s: acpi_bus_add "
461
                                               "failed (0x%x) for slot %d "
462
                                               "func %d\n", __FUNCTION__,
463
                                               ret, (int)(adr>>16),
464
                                               (int)(adr&0xffff));
465
                                        /* try to continue on */
466
                                } else {
467
                                        acpi_bus_start(device);
468
                                }
469
                        }
470
                }
471
        }
472
 
473
        /* Call the driver for the new device */
474
        pci_bus_add_devices(slot->pci_bus);
475
        /* Call the drivers for the new devices subordinate to PPB */
476
        if (new_ppb)
477
                pci_bus_add_devices(new_bus);
478
 
479
        mutex_unlock(&sn_hotplug_mutex);
480
 
481
        if (rc == 0)
482
                dev_dbg(&slot->pci_bus->self->dev,
483
                        "insert operation successful\n");
484
        else
485
                dev_dbg(&slot->pci_bus->self->dev,
486
                        "insert operation failed rc = %d\n", rc);
487
 
488
        return rc;
489
}
490
 
491
static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
492
{
493
        struct slot *slot = bss_hotplug_slot->private;
494
        struct pci_dev *dev;
495
        int func;
496
        int rc;
497
        acpi_owner_id ssdt_id = 0;
498
 
499
        /* Acquire update access to the bus */
500
        mutex_lock(&sn_hotplug_mutex);
501
 
502
        /* is it okay to bring this slot down? */
503
        rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
504
                             PCI_REQ_SLOT_ELIGIBLE);
505
        if (rc)
506
                goto leaving;
507
 
508
        /* free the ACPI resources for the slot */
509
        if (SN_ACPI_BASE_SUPPORT() &&
510
            PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
511
                unsigned long adr;
512
                struct acpi_device *device;
513
                acpi_handle phandle;
514
                acpi_handle chandle = NULL;
515
                acpi_handle rethandle;
516
                acpi_status ret;
517
 
518
                /* Get the rootbus node pointer */
519
                phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
520
 
521
                /*
522
                 * Walk the rootbus node's immediate children looking for
523
                 * the slot's device node(s). There can be more than
524
                 * one for multifunction devices.
525
                 */
526
                for (;;) {
527
                        rethandle = NULL;
528
                        ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
529
                                                   phandle, chandle,
530
                                                   &rethandle);
531
 
532
                        if (ret == AE_NOT_FOUND || rethandle == NULL)
533
                                break;
534
 
535
                        chandle = rethandle;
536
 
537
                        ret = acpi_evaluate_integer(chandle,
538
                                                    METHOD_NAME__ADR,
539
                                                    NULL, &adr);
540
                        if (ACPI_SUCCESS(ret) &&
541
                            (adr>>16) == (slot->device_num + 1)) {
542
                                /* retain the owner id */
543
                                acpi_get_id(chandle, &ssdt_id);
544
 
545
                                ret = acpi_bus_get_device(chandle,
546
                                                          &device);
547
                                if (ACPI_SUCCESS(ret))
548
                                        acpi_bus_trim(device, 1);
549
                        }
550
                }
551
 
552
        }
553
 
554
        /* Free the SN resources assigned to the Linux device.*/
555
        for (func = 0; func < 8;  func++) {
556
                dev = pci_get_slot(slot->pci_bus,
557
                                   PCI_DEVFN(slot->device_num + 1,
558
                                             PCI_FUNC(func)));
559
                if (dev) {
560
                        sn_bus_free_data(dev);
561
                        pci_remove_bus_device(dev);
562
                        pci_dev_put(dev);
563
                }
564
        }
565
 
566
        /* Remove the SSDT for the slot from the ACPI namespace */
567
        if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
568
                acpi_status ret;
569
                ret = acpi_unload_table_id(ssdt_id);
570
                if (ACPI_FAILURE(ret)) {
571
                        printk(KERN_ERR "%s: acpi_unload_table_id "
572
                               "failed (0x%x) for id %d\n",
573
                               __FUNCTION__, ret, ssdt_id);
574
                        /* try to continue on */
575
                }
576
        }
577
 
578
        /* free the collected sysdata pointers */
579
        sn_bus_free_sysdata();
580
 
581
        /* Deactivate slot */
582
        rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
583
                             PCI_REQ_SLOT_DISABLE);
584
 leaving:
585
        /* Release the bus lock */
586
        mutex_unlock(&sn_hotplug_mutex);
587
 
588
        return rc;
589
}
590
 
591
static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
592
                                   u8 *value)
593
{
594
        struct slot *slot = bss_hotplug_slot->private;
595
        struct pcibus_info *pcibus_info;
596
        u32 power;
597
 
598
        pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
599
        mutex_lock(&sn_hotplug_mutex);
600
        power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
601
        *value = power ? 1 : 0;
602
        mutex_unlock(&sn_hotplug_mutex);
603
        return 0;
604
}
605
 
606
static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
607
{
608
        kfree(bss_hotplug_slot->info);
609
        kfree(bss_hotplug_slot->name);
610
        kfree(bss_hotplug_slot->private);
611
        kfree(bss_hotplug_slot);
612
}
613
 
614
static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
615
{
616
        int device;
617
        struct hotplug_slot *bss_hotplug_slot;
618
        int rc = 0;
619
 
620
        /*
621
         * Currently only four devices are supported,
622
         * in the future there maybe more -- up to 32.
623
         */
624
 
625
        for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
626
                if (sn_pci_slot_valid(pci_bus, device) != 1)
627
                        continue;
628
 
629
                bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot),
630
                                           GFP_KERNEL);
631
                if (!bss_hotplug_slot) {
632
                        rc = -ENOMEM;
633
                        goto alloc_err;
634
                }
635
 
636
                bss_hotplug_slot->info =
637
                        kzalloc(sizeof(struct hotplug_slot_info),
638
                                GFP_KERNEL);
639
                if (!bss_hotplug_slot->info) {
640
                        rc = -ENOMEM;
641
                        goto alloc_err;
642
                }
643
 
644
                if (sn_hp_slot_private_alloc(bss_hotplug_slot,
645
                                             pci_bus, device)) {
646
                        rc = -ENOMEM;
647
                        goto alloc_err;
648
                }
649
 
650
                bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
651
                bss_hotplug_slot->release = &sn_release_slot;
652
 
653
                rc = pci_hp_register(bss_hotplug_slot);
654
                if (rc)
655
                        goto register_err;
656
 
657
                rc = sysfs_create_file(&bss_hotplug_slot->kobj,
658
                                       &sn_slot_path_attr.attr);
659
                if (rc)
660
                        goto register_err;
661
        }
662
        dev_dbg(&pci_bus->self->dev, "Registered bus with hotplug\n");
663
        return rc;
664
 
665
register_err:
666
        dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n",
667
                rc);
668
 
669
alloc_err:
670
        if (rc == -ENOMEM)
671
                dev_dbg(&pci_bus->self->dev, "Memory allocation error\n");
672
 
673
        /* destroy THIS element */
674
        if (bss_hotplug_slot)
675
                sn_release_slot(bss_hotplug_slot);
676
 
677
        /* destroy anything else on the list */
678
        while ((bss_hotplug_slot = sn_hp_destroy()))
679
                pci_hp_deregister(bss_hotplug_slot);
680
 
681
        return rc;
682
}
683
 
684
static int sn_pci_hotplug_init(void)
685
{
686
        struct pci_bus *pci_bus = NULL;
687
        int rc;
688
        int registered = 0;
689
 
690
        if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) {
691
                printk(KERN_ERR "%s: PROM version does not support hotplug.\n",
692
                       __FUNCTION__);
693
                return -EPERM;
694
        }
695
 
696
        INIT_LIST_HEAD(&sn_hp_list);
697
 
698
        while ((pci_bus = pci_find_next_bus(pci_bus))) {
699
                if (!pci_bus->sysdata)
700
                        continue;
701
 
702
                rc = sn_pci_bus_valid(pci_bus);
703
                if (rc != 1) {
704
                        dev_dbg(&pci_bus->self->dev, "not a valid hotplug bus\n");
705
                        continue;
706
                }
707
                dev_dbg(&pci_bus->self->dev, "valid hotplug bus\n");
708
 
709
                rc = sn_hotplug_slot_register(pci_bus);
710
                if (!rc) {
711
                        registered = 1;
712
                } else {
713
                        registered = 0;
714
                        break;
715
                }
716
        }
717
 
718
        return registered == 1 ? 0 : -ENODEV;
719
}
720
 
721
static void sn_pci_hotplug_exit(void)
722
{
723
        struct hotplug_slot *bss_hotplug_slot;
724
 
725
        while ((bss_hotplug_slot = sn_hp_destroy()))
726
                pci_hp_deregister(bss_hotplug_slot);
727
 
728
        if (!list_empty(&sn_hp_list))
729
                printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
730
}
731
 
732
module_init(sn_pci_hotplug_init);
733
module_exit(sn_pci_hotplug_exit);

powered by: WebSVN 2.1.0

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