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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [amd76x_pm.c] - Blame information for rev 1275

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * ACPI sytle PM for SMP AMD-760MP(X) based systems.
3
 * For use until the ACPI project catches up. :-)
4
 *
5
 * Copyright (C) 2002 Johnathan Hicks <thetech@folkwolf.net>
6
 *
7
 * History:
8
 *
9
 *   20020702 - amd-smp-idle: Tony Lindgren <tony@atomide.com>
10
 *      Influenced by Vcool, and LVCool. Rewrote everything from scratch to
11
 *      use the PCI features in Linux, and to support SMP systems. Provides
12
 *      C2 idling on SMP AMD-760MP systems.
13
 *
14
 *   20020722: JH
15
 *      I adapted Tony's code for the AMD-765/766 southbridge and adapted it
16
 *      according to the AMD-768 data sheet to provide the same capability for
17
 *      SMP AMD-760MPX systems. Posted to acpi-devel list.
18
 *
19
 *   20020722: Alan Cox
20
 *      Replaces non-functional amd76x_pm code in -ac tree.
21
 *
22
 *   20020730: JH
23
 *      Added ability to do normal throttling (the non-thermal kind), C3 idling
24
 *      and Power On Suspend (S1 sleep). It would be very easy to tie swsusp
25
 *      into activate_amd76x_SLP(). C3 idling doesn't happen yet; see my note
26
 *      in amd76x_smp_idle(). I've noticed that when NTH and idling are both
27
 *      enabled, my hardware locks and requires a hard reset, so I have
28
 *      #ifndefed around the idle loop setting to prevent this. POS locks it up
29
 *      too, both ought to be fixable. I've also noticed that idling and NTH
30
 *      make some interference that is picked up by the onboard sound chip on
31
 *      my ASUS A7M266-D motherboard.
32
 *
33
 *
34
 * TODO: Thermal throttling (TTH).
35
 *       /proc interface for normal throttling level.
36
 *       /proc interface for POS.
37
 *
38
 *
39
 *    <Notes from 20020722-ac revision>
40
 *
41
 * Processor idle mode module for AMD SMP 760MP(X) based systems
42
 *
43
 * Copyright (C) 2002 Tony Lindgren <tony@atomide.com>
44
 *                    Johnathan Hicks (768 support)
45
 *
46
 * Using this module saves about 70 - 90W of energy in the idle mode compared
47
 * to the default idle mode. Waking up from the idle mode is fast to keep the
48
 * system response time good. Currently no CPU load calculation is done, the
49
 * system exits the idle mode if the idle function runs twice on the same
50
 * processor in a row. This only works on SMP systems, but maybe the idle mode
51
 * enabling can be integrated to ACPI to provide C2 mode at some point.
52
 *
53
 * NOTE: Currently there's a bug somewhere where the reading the
54
 *       P_LVL2 for the first time causes the system to sleep instead of
55
 *       idling. This means that you need to hit the power button once to
56
 *       wake the system after loading the module for the first time after
57
 *       reboot. After that the system idles as supposed.
58
 *
59
 *
60
 * Influenced by Vcool, and LVCool. Rewrote everything from scratch to
61
 * use the PCI features in Linux, and to support SMP systems.
62
 *
63
 * Currently only tested on a TYAN S2460 (760MP) system (Tony) and an
64
 * ASUS A7M266-D (760MPX) system (Johnathan). Adding support for other Athlon
65
 * SMP or single processor systems should be easy if desired.
66
 *
67
 * This software is licensed under GNU General Public License Version 2
68
 * as specified in file COPYING in the Linux kernel source tree main
69
 * directory.
70
 *
71
 *   </Notes from 20020722-ac revision>
72
 */
73
 
74
 
75
#include <linux/config.h>
76
#include <linux/module.h>
77
#include <linux/slab.h>
78
#include <linux/pci.h>
79
#include <linux/delay.h>
80
#include <linux/pm.h>
81
#include <linux/init.h>
82
 
83
#include "amd76x_pm.h"
84
 
85
#define VERSION "20020730"
86
 
87
// #define AMD76X_C3  1
88
// #define AMD76X_NTH 1
89
// #define AMD76X_POS 1
90
 
91
 
92
extern void default_idle(void);
93
static void amd76x_smp_idle(void);
94
static int amd76x_pm_main(void);
95
static int __devinit amd_nb_init(struct pci_dev *pdev,
96
                                 const struct pci_device_id *ent);
97
static void amd_nb_remove(struct pci_dev *pdev);
98
static int __devinit amd_sb_init(struct pci_dev *pdev,
99
                                 const struct pci_device_id *ent);
100
static void amd_sb_remove(struct pci_dev *pdev);
101
 
102
 
103
static struct pci_dev *pdev_nb;
104
static struct pci_dev *pdev_sb;
105
 
106
struct PM_cfg {
107
        unsigned int status_reg;
108
        unsigned int C2_reg;
109
        unsigned int C3_reg;
110
        unsigned int NTH_reg;
111
        unsigned int slp_reg;
112
        unsigned int resume_reg;
113
        void (*orig_idle) (void);
114
        void (*curr_idle) (void);
115
        unsigned long C2_cnt, C3_cnt;
116
        int last_pr;
117
};
118
static struct PM_cfg amd76x_pm_cfg;
119
 
120
struct cpu_idle_state {
121
        int idle;
122
        int count;
123
};
124
static struct cpu_idle_state prs[2];
125
 
126
static struct pci_device_id amd_nb_tbl[] __devinitdata = {
127
        {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
128
        {0,}
129
};
130
 
131
static struct pci_device_id amd_sb_tbl[] __devinitdata = {
132
        {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
133
        {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
134
        {0,}
135
};
136
 
137
static struct pci_driver amd_nb_driver = {
138
        name:"amd76x_pm-nb",
139
        id_table:amd_nb_tbl,
140
        probe:amd_nb_init,
141
        remove:__devexit_p(amd_nb_remove),
142
};
143
 
144
static struct pci_driver amd_sb_driver = {
145
        name:"amd76x_pm-sb",
146
        id_table:amd_sb_tbl,
147
        probe:amd_sb_init,
148
        remove:__devexit_p(amd_sb_remove),
149
};
150
 
151
 
152
static int __devinit
153
amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
154
{
155
        pdev_nb = pdev;
156
        printk(KERN_INFO "amd76x_pm: Initializing northbridge %s\n",
157
               pdev_nb->name);
158
 
159
        return 0;
160
}
161
 
162
 
163
static void __devexit
164
amd_nb_remove(struct pci_dev *pdev)
165
{
166
}
167
 
168
 
169
static int __devinit
170
amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
171
{
172
        pdev_sb = pdev;
173
        printk(KERN_INFO "amd76x_pm: Initializing southbridge %s\n",
174
               pdev_sb->name);
175
 
176
        return 0;
177
}
178
 
179
 
180
static void __devexit
181
amd_sb_remove(struct pci_dev *pdev)
182
{
183
}
184
 
185
 
186
/*
187
 * Configures the AMD-762 northbridge to support PM calls
188
 */
189
static int
190
config_amd762(int enable)
191
{
192
        unsigned int regdword;
193
 
194
        /* Enable STPGNT in BIU Status/Control for cpu0 */
195
        pci_read_config_dword(pdev_nb, 0x60, &regdword);
196
        regdword |= (1 << 17);
197
        pci_write_config_dword(pdev_nb, 0x60, regdword);
198
 
199
        /* Enable STPGNT in BIU Status/Control for cpu1 */
200
        pci_read_config_dword(pdev_nb, 0x68, &regdword);
201
        regdword |= (1 << 17);
202
        pci_write_config_dword(pdev_nb, 0x68, regdword);
203
 
204
        /* DRAM refresh enable */
205
        pci_read_config_dword(pdev_nb, 0x58, &regdword);
206
        regdword &= ~(1 << 19);
207
        pci_write_config_dword(pdev_nb, 0x58, regdword);
208
 
209
        /* Self refresh enable */
210
        pci_read_config_dword(pdev_nb, 0x70, &regdword);
211
        regdword |= (1 << 18);
212
        pci_write_config_dword(pdev_nb, 0x70, regdword);
213
 
214
        return 0;
215
}
216
 
217
 
218
/*
219
 * Get the base PMIO address and set the pm registers in amd76x_pm_cfg.
220
 */
221
static void
222
amd76x_get_PM(void)
223
{
224
        unsigned int regdword;
225
 
226
        /* Get the address for pm status, P_LVL2, etc */
227
        pci_read_config_dword(pdev_sb, 0x58, &regdword);
228
        regdword &= 0xff80;
229
        amd76x_pm_cfg.status_reg = (regdword + 0x00);
230
        amd76x_pm_cfg.slp_reg =    (regdword + 0x04);
231
        amd76x_pm_cfg.NTH_reg =    (regdword + 0x10);
232
        amd76x_pm_cfg.C2_reg =     (regdword + 0x14);
233
        amd76x_pm_cfg.C3_reg =     (regdword + 0x15);
234
        amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */
235
}
236
 
237
 
238
/*
239
 * En/Disable PMIO and configure W4SG & STPGNT.
240
 */
241
static int
242
config_PMIO_amd76x(int is_766, int enable)
243
{
244
        unsigned char regbyte;
245
 
246
        /* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well.
247
         * AMD-766: C3A41; page 59 in AMD-766 doc
248
         * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */
249
        pci_read_config_byte(pdev_sb, 0x41, &regbyte);
250
        if(enable) {
251
                regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7));
252
        }
253
        else {
254
                regbyte |= (0 << 7);
255
        }
256
        pci_write_config_byte(pdev_sb, 0x41, regbyte);
257
 
258
        return 0;
259
}
260
 
261
/*
262
 * C2 idle support for AMD-766.
263
 */
264
static void
265
config_amd766_C2(int enable)
266
{
267
        unsigned int regdword;
268
 
269
        /* Set C2 options in C3A50, page 63 in AMD-766 doc */
270
        pci_read_config_dword(pdev_sb, 0x50, &regdword);
271
        if(enable) {
272
                regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
273
                                        CPURST_EN) << C2_REGS);
274
                regdword |= (STPCLK_EN  /* ~ 20 Watt savings max */
275
                         |  CPUSLP_EN)  /* Additional ~ 70 Watts max! */
276
                         << C2_REGS;
277
        }
278
        else
279
                regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
280
        pci_write_config_dword(pdev_sb, 0x50, regdword);
281
}
282
 
283
 
284
#ifdef AMD76X_C3
285
/*
286
 * Untested C3 idle support for AMD-766.
287
 */
288
static void
289
config_amd766_C3(int enable)
290
{
291
        unsigned int regdword;
292
 
293
        /* Set C3 options in C3A50, page 63 in AMD-766 doc */
294
        pci_read_config_dword(pdev_sb, 0x50, &regdword);
295
        if(enable) {
296
                regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
297
                                << C3_REGS);
298
                regdword |= (STPCLK_EN  /* ~ 20 Watt savings max */
299
                         |  CPUSLP_EN   /* Additional ~ 70 Watts max! */
300
                         |  CPUSTP_EN)  /* yet more savings! */
301
                         << C3_REGS;
302
        }
303
        else
304
                regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
305
        pci_write_config_dword(pdev_sb, 0x50, regdword);
306
}
307
#endif
308
 
309
 
310
#ifdef AMD76X_POS
311
static void
312
config_amd766_POS(int enable)
313
{
314
        unsigned int regdword;
315
 
316
        /* Set C3 options in C3A50, page 63 in AMD-766 doc */
317
        pci_read_config_dword(pdev_sb, 0x50, &regdword);
318
        if(enable) {
319
                regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
320
                regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
321
                                        CPUSLP_EN | SUSPND_EN) << POS_REGS);
322
        }
323
        else
324
                regdword ^= (0xff << POS_REGS);
325
        pci_write_config_dword(pdev_sb, 0x50, regdword);
326
}
327
#endif
328
 
329
 
330
/*
331
 * Configures the 765 & 766 southbridges.
332
 */
333
static int
334
config_amd766(int enable)
335
{
336
        amd76x_get_PM();
337
        config_PMIO_amd76x(1, 1);
338
 
339
        config_amd766_C2(enable);
340
#ifdef AMD76X_C3
341
        config_amd766_C3(enable);
342
#endif
343
#ifdef AMD76X_POS
344
        config_amd766_POS(enable);
345
#endif
346
 
347
        return 0;
348
}
349
 
350
 
351
/*
352
 * C2 idling support for AMD-768.
353
 */
354
static void
355
config_amd768_C2(int enable)
356
{
357
        unsigned char regbyte;
358
 
359
        /* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */
360
        pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
361
        if(enable)
362
                regbyte |= C2EN;
363
        else
364
                regbyte ^= C2EN;
365
        pci_write_config_byte(pdev_sb, 0x4F, regbyte);
366
}
367
 
368
 
369
#ifdef AMD76X_C3
370
/*
371
 * C3 idle support for AMD-768. The idle loop would need some extra
372
 * handling for C3, but it would make more sense for ACPI to handle CX level
373
 * transitions like it is supposed to. Unfortunately ACPI doesn't do CX
374
 * levels on SMP systems yet.
375
 */
376
static void
377
config_amd768_C3(int enable)
378
{
379
        unsigned char regbyte;
380
 
381
        /* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */
382
        pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
383
        if(enable)
384
                regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */);
385
        else
386
                regbyte ^= C3EN;
387
        pci_write_config_byte(pdev_sb, 0x4F, regbyte);
388
}
389
#endif
390
 
391
 
392
#ifdef AMD76X_POS
393
/*
394
 * Untested Power On Suspend support for AMD-768. This should also be handled
395
 * by ACPI.
396
 */
397
static void
398
config_amd768_POS(int enable)
399
{
400
        unsigned int regdword;
401
 
402
        /* Set POS options in DevB:3x50, page 101 in AMD-768 doc */
403
        pci_read_config_dword(pdev_sb, 0x50, &regdword);
404
        if(enable)
405
                regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
406
        else
407
                regdword ^= POSEN;
408
        pci_write_config_dword(pdev_sb, 0x50, regdword);
409
}
410
#endif
411
 
412
 
413
#ifdef AMD76X_NTH
414
/*
415
 * Normal Throttling support for AMD-768. There are several settings
416
 * that can be set depending on how long you want some of the delays to be.
417
 * I'm not sure if this is even neccessary at all as the 766 doesn't need this.
418
 */
419
static void
420
config_amd768_NTH(int enable, int ntper, int thminen)
421
{
422
        unsigned char regbyte;
423
 
424
        /* DevB:3x40, pg 93 of 768 doc */
425
        pci_read_config_byte(pdev_sb, 0x40, &regbyte);
426
        /* Is it neccessary to use THMINEN at ANY time? */
427
        regbyte |= (NTPER(ntper) | THMINEN(thminen));
428
        pci_write_config_byte(pdev_sb, 0x40, regbyte);
429
}
430
#endif
431
 
432
 
433
/*
434
 * Configures the 768 southbridge to support idle calls, and gets
435
 * the processor idle call register location.
436
 */
437
static int
438
config_amd768(int enable)
439
{
440
        amd76x_get_PM();
441
        config_PMIO_amd76x(0, 1);
442
 
443
        config_amd768_C2(enable);
444
#ifdef AMD76X_C3
445
        config_amd768_C3(enable);
446
#endif
447
#ifdef AMD76X_POS
448
        config_amd768_POS(enable);
449
#endif
450
#ifdef AMD76X_NTH
451
        config_amd768_NTH(enable, 1, 2);
452
#endif
453
 
454
        return 0;
455
}
456
 
457
 
458
#ifdef AMD76X_NTH
459
/*
460
 * Activate normal throttling via its ACPI register (P_CNT).
461
 */
462
static void
463
activate_amd76x_NTH(int enable, int ratio)
464
{
465
        unsigned int regdword;
466
 
467
        /* PM10, pg 110 of 768 doc, pg 70 of 766 doc */
468
        regdword=inl(amd76x_pm_cfg.NTH_reg);
469
        if(enable)
470
                regdword |= (NTH_EN | NTH_RATIO(ratio));
471
        else
472
                regdword ^= NTH_EN;
473
        outl(regdword, amd76x_pm_cfg.NTH_reg);
474
}
475
#endif
476
 
477
#ifdef AMD76X_POS
478
/*
479
 * Activate sleep state via its ACPI register (PM1_CNT).
480
 */
481
static void
482
activate_amd76x_SLP(int type)
483
{
484
        unsigned short regshort;
485
 
486
        /* PM04, pg 109 of 768 doc, pg 69 of 766 doc */
487
        regshort=inw(amd76x_pm_cfg.slp_reg);
488
        regshort |= (SLP_EN | SLP_TYP(type)) ;
489
        outw(regshort, amd76x_pm_cfg.slp_reg);
490
}
491
 
492
/*
493
 * Wrapper function to activate POS sleep state.
494
 */
495
static void
496
activate_amd76x_POS(void)
497
{
498
        activate_amd76x_SLP(1);
499
}
500
#endif
501
 
502
 
503
#if 0
504
/*
505
 * Idle loop for single processor systems
506
 */
507
void
508
amd76x_up_idle(void)
509
{
510
        // FIXME: Optionally add non-smp idle loop here
511
}
512
#endif
513
 
514
 
515
/*
516
 * Idle loop for SMP systems, supports currently only 2 processors.
517
 *
518
 * Note; for 2.5 folks - not pre-empt safe
519
 */
520
static void
521
amd76x_smp_idle(void)
522
{
523
 
524
        /*
525
         * Exit idle mode immediately if the CPU does not change.
526
         * Usually that means that we have some load on another CPU.
527
         */
528
        if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
529
                prs[0].idle = 0;
530
                prs[1].idle = 0;
531
                /* This looks redundent as it was just checked in the if() */
532
                /* amd76x_pm_cfg.last_pr = smp_processor_id(); */
533
                return;
534
        }
535
 
536
        prs[smp_processor_id()].count++;
537
 
538
        /* Don't start the idle mode immediately */
539
        if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) {
540
 
541
                /* Put the current processor into idle mode */
542
                prs[smp_processor_id()].idle =
543
                        (prs[smp_processor_id()].idle ? 2 : 1);
544
 
545
                /* Only idle if both processors are idle */
546
                if ((prs[0].idle==1) && (prs[1].idle==1)) {
547
                        amd76x_pm_cfg.C2_cnt++;
548
                        inb(amd76x_pm_cfg.C2_reg);
549
                }
550
        #ifdef AMD76X_C3
551
                /*
552
                 * JH: I've not been able to get into here. Could this have
553
                 * something to do with the way the kernel handles the idle
554
                 * loop, or and error that I've made?
555
                 */
556
                else if ((prs[0].idle==2) && (prs[1].idle==2)) {
557
                        amd76x_pm_cfg.C3_cnt++;
558
                        inb(amd76x_pm_cfg.C3_reg);
559
                }
560
        #endif
561
 
562
                prs[smp_processor_id()].count = 0;
563
 
564
        }
565
        amd76x_pm_cfg.last_pr = smp_processor_id();
566
}
567
 
568
 
569
/*
570
 * Finds and initializes the bridges, and then sets the idle function
571
 */
572
static int
573
amd76x_pm_main(void)
574
{
575
        int found;
576
 
577
        /* Find northbridge */
578
        found = pci_register_driver(&amd_nb_driver);
579
        if (found <= 0) {
580
                printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
581
                pci_unregister_driver(&amd_nb_driver);
582
                return 1;
583
        }
584
 
585
        /* Find southbridge */
586
        found = pci_register_driver(&amd_sb_driver);
587
        if (found <= 0) {
588
                printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
589
                pci_unregister_driver(&amd_sb_driver);
590
                pci_unregister_driver(&amd_nb_driver);
591
                return 1;
592
        }
593
 
594
        /* Init southbridge */
595
        switch (pdev_sb->device) {
596
        case PCI_DEVICE_ID_AMD_VIPER_7413:      /* AMD-765 or 766 */
597
                config_amd766(1);
598
                break;
599
        case PCI_DEVICE_ID_AMD_VIPER_7443:      /* AMD-768 */
600
                config_amd768(1);
601
                break;
602
        default:
603
                printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n");
604
                break;
605
        }
606
 
607
        /* Init northbridge and queue the new idle function */
608
        switch (pdev_nb->device) {
609
        case PCI_DEVICE_ID_AMD_FE_GATE_700C:    /* AMD-762 */
610
                config_amd762(1);
611
#ifndef AMD76X_NTH
612
                amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
613
#endif
614
                break;
615
        default:
616
                printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n");
617
                break;
618
        }
619
 
620
#ifndef AMD76X_NTH
621
        if (!amd76x_pm_cfg.curr_idle) {
622
                printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
623
                pci_unregister_driver(&amd_nb_driver);
624
                pci_unregister_driver(&amd_sb_driver);
625
                return 1;
626
        }
627
 
628
        amd76x_pm_cfg.orig_idle = pm_idle;
629
        pm_idle = amd76x_pm_cfg.curr_idle;
630
#endif
631
 
632
#ifdef AMD76X_NTH
633
        /* Turn NTH on with maxium throttling for testing. */
634
        activate_amd76x_NTH(1, 1);
635
#endif
636
 
637
#ifdef AMD76X_POS
638
        /* Testing here only. */
639
        activate_amd76x_POS();
640
#endif
641
 
642
        return 0;
643
}
644
 
645
 
646
static int __init
647
amd76x_pm_init(void)
648
{
649
        printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION);
650
        return amd76x_pm_main();
651
}
652
 
653
 
654
static void __exit
655
amd76x_pm_cleanup(void)
656
{
657
#ifndef AMD76X_NTH
658
        pm_idle = amd76x_pm_cfg.orig_idle;
659
 
660
        /* This isn't really needed. */
661
        printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.C2_cnt);
662
#ifdef AMD76X_C3
663
        printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", amd76x_pm_cfg.C3_cnt);
664
#endif
665
 
666
        /*
667
         * FIXME: We want to wait until all CPUs have set the new
668
         * idle function, otherwise we will oops. This may not be
669
         * the right way to do it, but seems to work.
670
         *
671
         * - Best answer is going to be to ban unload, but when its debugged
672
         *   --- Alan
673
         */
674
        schedule();
675
        mdelay(1000);
676
#endif
677
 
678
#ifdef AMD76X_NTH
679
        /* Turn NTH off*/
680
        activate_amd76x_NTH(0, 0);
681
#endif
682
 
683
        pci_unregister_driver(&amd_nb_driver);
684
        pci_unregister_driver(&amd_sb_driver);
685
 
686
}
687
 
688
 
689
MODULE_LICENSE("GPL");
690
module_init(amd76x_pm_init);
691
module_exit(amd76x_pm_cleanup);

powered by: WebSVN 2.1.0

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