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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [hotplug/] [cpqphp_nvram.c] - Blame information for rev 1774

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Compaq 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
 *
8
 * All rights reserved.
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or (at
13
 * your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful, but
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
18
 * NON INFRINGEMENT.  See the GNU General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, write to the Free Software
23
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
 *
25
 * Send feedback to <greg@kroah.com>
26
 *
27
 */
28
 
29
#include <linux/config.h>
30
#include <linux/module.h>
31
#include <linux/kernel.h>
32
#include <linux/types.h>
33
#include <linux/proc_fs.h>
34
#include <linux/miscdevice.h>
35
#include <linux/slab.h>
36
#include <linux/pci.h>
37
#include <linux/init.h>
38
#include <asm/uaccess.h>
39
#include "cpqphp.h"
40
#include "cpqphp_nvram.h"
41
 
42
 
43
#define ROM_INT15_PHY_ADDR              0x0FF859
44
#define READ_EV                         0xD8A4
45
#define WRITE_EV                        0xD8A5
46
 
47
struct register_foo {
48
        union {
49
                unsigned long lword;            /* eax */
50
                unsigned short word;            /* ax */
51
 
52
                struct {
53
                        unsigned char low;      /* al */
54
                        unsigned char high;     /* ah */
55
                } byte;
56
        } data;
57
 
58
        unsigned char opcode;   /* see below */
59
        unsigned long length;   /* if the reg. is a pointer, how much data */
60
} __attribute__ ((packed));
61
 
62
struct all_reg {
63
        struct register_foo eax_reg;
64
        struct register_foo ebx_reg;
65
        struct register_foo ecx_reg;
66
        struct register_foo edx_reg;
67
        struct register_foo edi_reg;
68
        struct register_foo esi_reg;
69
        struct register_foo eflags_reg;
70
} __attribute__ ((packed));
71
 
72
 
73
struct ev_hrt_header {
74
        u8 Version;
75
        u8 num_of_ctrl;
76
        u8 next;
77
};
78
 
79
struct ev_hrt_ctrl {
80
        u8 bus;
81
        u8 device;
82
        u8 function;
83
        u8 mem_avail;
84
        u8 p_mem_avail;
85
        u8 io_avail;
86
        u8 bus_avail;
87
        u8 next;
88
};
89
 
90
 
91
static u8 evbuffer_init;
92
static u8 evbuffer_length;
93
static u8 evbuffer[1024];
94
 
95
static void *compaq_int15_entry_point;
96
 
97
static spinlock_t int15_lock;           /* lock for ordering int15_bios_call() */
98
 
99
 
100
/* This is a series of function that deals with
101
   setting & getting the hotplug resource table in some environment variable.
102
*/
103
 
104
/*
105
 * We really shouldn't be doing this unless there is a _very_ good reason to!!!
106
 * greg k-h
107
 */
108
 
109
 
110
static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail)
111
{
112
        u8 **tByte;
113
 
114
        if ((*used + 1) > *avail)
115
                return(1);
116
 
117
        *((u8*)*p_buffer) = value;
118
        tByte = (u8**)p_buffer;
119
        (*tByte)++;
120
        *used+=1;
121
        return(0);
122
}
123
 
124
 
125
static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail)
126
{
127
        if ((*used + 4) > *avail)
128
                return(1);
129
 
130
        **p_buffer = value;
131
        (*p_buffer)++;
132
        *used+=4;
133
        return(0);
134
}
135
 
136
 
137
/*
138
 * check_for_compaq_ROM
139
 *
140
 * this routine verifies that the ROM OEM string is 'COMPAQ'
141
 *
142
 * returns 0 for non-Compaq ROM, 1 for Compaq ROM
143
 */
144
static int check_for_compaq_ROM (void *rom_start)
145
{
146
        u8 temp1, temp2, temp3, temp4, temp5, temp6;
147
        int result = 0;
148
 
149
        temp1 = readb(rom_start + 0xffea + 0);
150
        temp2 = readb(rom_start + 0xffea + 1);
151
        temp3 = readb(rom_start + 0xffea + 2);
152
        temp4 = readb(rom_start + 0xffea + 3);
153
        temp5 = readb(rom_start + 0xffea + 4);
154
        temp6 = readb(rom_start + 0xffea + 5);
155
        if ((temp1 == 'C') &&
156
            (temp2 == 'O') &&
157
            (temp3 == 'M') &&
158
            (temp4 == 'P') &&
159
            (temp5 == 'A') &&
160
            (temp6 == 'Q')) {
161
                result = 1;
162
        }
163
        dbg ("%s - returned %d\n",__FUNCTION__, result);
164
        return result;
165
}
166
 
167
 
168
static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
169
{
170
        unsigned long flags;
171
        int op = operation;
172
        int ret_val;
173
 
174
        if (!compaq_int15_entry_point)
175
                return -ENODEV;
176
 
177
        spin_lock_irqsave(&int15_lock, flags);
178
        __asm__ (
179
                "xorl   %%ebx,%%ebx \n"
180
                "xorl   %%edx,%%edx \n"
181
                "pushf              \n"
182
                "push    %%cs       \n"
183
                "cli                \n"
184
                "call    *%6        \n"
185
                : "=c" (*buf_size), "=a" (ret_val)
186
                : "a" (op), "c" (*buf_size), "S" (ev_name),
187
                "D" (buffer), "m" (compaq_int15_entry_point)
188
                : "%ebx", "%edx");
189
        spin_unlock_irqrestore(&int15_lock, flags);
190
 
191
        return((ret_val & 0xFF00) >> 8);
192
}
193
 
194
 
195
/*
196
 * load_HRT
197
 *
198
 * Read the hot plug Resource Table from NVRAM
199
 */
200
static int load_HRT (void *rom_start)
201
{
202
        u32 available;
203
        u32 temp_dword;
204
        u8 temp_byte = 0xFF;
205
        u32 rc;
206
 
207
        if (!check_for_compaq_ROM(rom_start)) {
208
                return -ENODEV;
209
        }
210
 
211
        available = 1024;
212
 
213
        // Now load the EV
214
        temp_dword = available;
215
 
216
        rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
217
 
218
        evbuffer_length = temp_dword;
219
 
220
        // We're maintaining the resource lists so write FF to invalidate old info
221
        temp_dword = 1;
222
 
223
        rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
224
 
225
        return rc;
226
}
227
 
228
 
229
/*
230
 * store_HRT
231
 *
232
 * Save the hot plug Resource Table in NVRAM
233
 */
234
static u32 store_HRT (void *rom_start)
235
{
236
        u32 *buffer;
237
        u32 *pFill;
238
        u32 usedbytes;
239
        u32 available;
240
        u32 temp_dword;
241
        u32 rc;
242
        u8 loop;
243
        u8 numCtrl = 0;
244
        struct controller *ctrl;
245
        struct pci_resource *resNode;
246
        struct ev_hrt_header *p_EV_header;
247
        struct ev_hrt_ctrl *p_ev_ctrl;
248
 
249
        available = 1024;
250
 
251
        if (!check_for_compaq_ROM(rom_start)) {
252
                return(1);
253
        }
254
 
255
        buffer = (u32*) evbuffer;
256
 
257
        if (!buffer)
258
                return(1);
259
 
260
        pFill = buffer;
261
        usedbytes = 0;
262
 
263
        p_EV_header = (struct ev_hrt_header *) pFill;
264
 
265
        ctrl = cpqhp_ctrl_list;
266
 
267
        // The revision of this structure
268
        rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
269
        if (rc)
270
                return(rc);
271
 
272
        // The number of controllers
273
        rc = add_byte( &pFill, 1, &usedbytes, &available);
274
        if (rc)
275
                return(rc);
276
 
277
        while (ctrl) {
278
                p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
279
 
280
                numCtrl++;
281
 
282
                // The bus number
283
                rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
284
                if (rc)
285
                        return(rc);
286
 
287
                // The device Number
288
                rc = add_byte( &pFill, ctrl->device, &usedbytes, &available);
289
                if (rc)
290
                        return(rc);
291
 
292
                // The function Number
293
                rc = add_byte( &pFill, ctrl->function, &usedbytes, &available);
294
                if (rc)
295
                        return(rc);
296
 
297
                // Skip the number of available entries
298
                rc = add_dword( &pFill, 0, &usedbytes, &available);
299
                if (rc)
300
                        return(rc);
301
 
302
                // Figure out memory Available
303
 
304
                resNode = ctrl->mem_head;
305
 
306
                loop = 0;
307
 
308
                while (resNode) {
309
                        loop ++;
310
 
311
                        // base
312
                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
313
                        if (rc)
314
                                return(rc);
315
 
316
                        // length
317
                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
318
                        if (rc)
319
                                return(rc);
320
 
321
                        resNode = resNode->next;
322
                }
323
 
324
                // Fill in the number of entries
325
                p_ev_ctrl->mem_avail = loop;
326
 
327
                // Figure out prefetchable memory Available
328
 
329
                resNode = ctrl->p_mem_head;
330
 
331
                loop = 0;
332
 
333
                while (resNode) {
334
                        loop ++;
335
 
336
                        // base
337
                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
338
                        if (rc)
339
                                return(rc);
340
 
341
                        // length
342
                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
343
                        if (rc)
344
                                return(rc);
345
 
346
                        resNode = resNode->next;
347
                }
348
 
349
                // Fill in the number of entries
350
                p_ev_ctrl->p_mem_avail = loop;
351
 
352
                // Figure out IO Available
353
 
354
                resNode = ctrl->io_head;
355
 
356
                loop = 0;
357
 
358
                while (resNode) {
359
                        loop ++;
360
 
361
                        // base
362
                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
363
                        if (rc)
364
                                return(rc);
365
 
366
                        // length
367
                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
368
                        if (rc)
369
                                return(rc);
370
 
371
                        resNode = resNode->next;
372
                }
373
 
374
                // Fill in the number of entries
375
                p_ev_ctrl->io_avail = loop;
376
 
377
                // Figure out bus Available
378
 
379
                resNode = ctrl->bus_head;
380
 
381
                loop = 0;
382
 
383
                while (resNode) {
384
                        loop ++;
385
 
386
                        // base
387
                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
388
                        if (rc)
389
                                return(rc);
390
 
391
                        // length
392
                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
393
                        if (rc)
394
                                return(rc);
395
 
396
                        resNode = resNode->next;
397
                }
398
 
399
                // Fill in the number of entries
400
                p_ev_ctrl->bus_avail = loop;
401
 
402
                ctrl = ctrl->next;
403
        }
404
 
405
        p_EV_header->num_of_ctrl = numCtrl;
406
 
407
        // Now store the EV
408
 
409
        temp_dword = usedbytes;
410
 
411
        rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword);
412
 
413
        dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
414
 
415
        evbuffer_length = temp_dword;
416
 
417
        if (rc) {
418
                err(msg_unable_to_save);
419
                return(1);
420
        }
421
 
422
        return(0);
423
}
424
 
425
 
426
void compaq_nvram_init (void *rom_start)
427
{
428
        if (rom_start) {
429
                compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
430
        }
431
        dbg("int15 entry  = %p\n", compaq_int15_entry_point);
432
 
433
        /* initialize our int15 lock */
434
        spin_lock_init(&int15_lock);
435
}
436
 
437
 
438
int compaq_nvram_load (void *rom_start, struct controller *ctrl)
439
{
440
        u8 bus, device, function;
441
        u8 nummem, numpmem, numio, numbus;
442
        u32 rc;
443
        u8 *p_byte;
444
        struct pci_resource *mem_node;
445
        struct pci_resource *p_mem_node;
446
        struct pci_resource *io_node;
447
        struct pci_resource *bus_node;
448
        struct ev_hrt_ctrl *p_ev_ctrl;
449
        struct ev_hrt_header *p_EV_header;
450
 
451
        if (!evbuffer_init) {
452
                // Read the resource list information in from NVRAM
453
                if (load_HRT(rom_start))
454
                        memset (evbuffer, 0, 1024);
455
 
456
                evbuffer_init = 1;
457
        }
458
 
459
        // If we saved information in NVRAM, use it now
460
        p_EV_header = (struct ev_hrt_header *) evbuffer;
461
 
462
        // The following code is for systems where version 1.0 of this
463
        // driver has been loaded, but doesn't support the hardware.
464
        // In that case, the driver would incorrectly store something
465
        // in NVRAM.
466
        if ((p_EV_header->Version == 2) ||
467
            ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
468
                p_byte = &(p_EV_header->next);
469
 
470
                p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
471
 
472
                p_byte += 3;
473
 
474
                if (p_byte > ((u8*)p_EV_header + evbuffer_length))
475
                        return(2);
476
 
477
                bus = p_ev_ctrl->bus;
478
                device = p_ev_ctrl->device;
479
                function = p_ev_ctrl->function;
480
 
481
                while ((bus != ctrl->bus) || (device != ctrl->device)
482
                       || (function != ctrl->function)) {
483
                        nummem = p_ev_ctrl->mem_avail;
484
                        numpmem = p_ev_ctrl->p_mem_avail;
485
                        numio = p_ev_ctrl->io_avail;
486
                        numbus = p_ev_ctrl->bus_avail;
487
 
488
                        p_byte += 4;
489
 
490
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
491
                                return(2);
492
 
493
                        // Skip forward to the next entry
494
                        p_byte += (nummem + numpmem + numio + numbus) * 8;
495
 
496
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
497
                                return(2);
498
 
499
                        p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
500
 
501
                        p_byte += 3;
502
 
503
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
504
                                return(2);
505
 
506
                        bus = p_ev_ctrl->bus;
507
                        device = p_ev_ctrl->device;
508
                        function = p_ev_ctrl->function;
509
                }
510
 
511
                nummem = p_ev_ctrl->mem_avail;
512
                numpmem = p_ev_ctrl->p_mem_avail;
513
                numio = p_ev_ctrl->io_avail;
514
                numbus = p_ev_ctrl->bus_avail;
515
 
516
                p_byte += 4;
517
 
518
                if (p_byte > ((u8*)p_EV_header + evbuffer_length))
519
                        return(2);
520
 
521
                while (nummem--) {
522
                        mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
523
 
524
                        if (!mem_node)
525
                                break;
526
 
527
                        mem_node->base = *(u32*)p_byte;
528
                        dbg("mem base = %8.8x\n",mem_node->base);
529
                        p_byte += 4;
530
 
531
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
532
                                return(2);
533
 
534
                        mem_node->length = *(u32*)p_byte;
535
                        dbg("mem length = %8.8x\n",mem_node->length);
536
                        p_byte += 4;
537
 
538
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
539
                                return(2);
540
 
541
                        mem_node->next = ctrl->mem_head;
542
                        ctrl->mem_head = mem_node;
543
                }
544
 
545
                while (numpmem--) {
546
                        p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
547
 
548
                        if (!p_mem_node)
549
                                break;
550
 
551
                        p_mem_node->base = *(u32*)p_byte;
552
                        dbg("pre-mem base = %8.8x\n",p_mem_node->base);
553
                        p_byte += 4;
554
 
555
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
556
                                return(2);
557
 
558
                        p_mem_node->length = *(u32*)p_byte;
559
                        dbg("pre-mem length = %8.8x\n",p_mem_node->length);
560
                        p_byte += 4;
561
 
562
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
563
                                return(2);
564
 
565
                        p_mem_node->next = ctrl->p_mem_head;
566
                        ctrl->p_mem_head = p_mem_node;
567
                }
568
 
569
                while (numio--) {
570
                        io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
571
 
572
                        if (!io_node)
573
                                break;
574
 
575
                        io_node->base = *(u32*)p_byte;
576
                        dbg("io base = %8.8x\n",io_node->base);
577
                        p_byte += 4;
578
 
579
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
580
                                return(2);
581
 
582
                        io_node->length = *(u32*)p_byte;
583
                        dbg("io length = %8.8x\n",io_node->length);
584
                        p_byte += 4;
585
 
586
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
587
                                return(2);
588
 
589
                        io_node->next = ctrl->io_head;
590
                        ctrl->io_head = io_node;
591
                }
592
 
593
                while (numbus--) {
594
                        bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
595
 
596
                        if (!bus_node)
597
                                break;
598
 
599
                        bus_node->base = *(u32*)p_byte;
600
                        p_byte += 4;
601
 
602
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
603
                                return(2);
604
 
605
                        bus_node->length = *(u32*)p_byte;
606
                        p_byte += 4;
607
 
608
 
609
                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
610
                                return(2);
611
 
612
                        bus_node->next = ctrl->bus_head;
613
                        ctrl->bus_head = bus_node;
614
                }
615
 
616
                // If all of the following fail, we don't have any resources for
617
                // hot plug add
618
                rc = 1;
619
                rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
620
                rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
621
                rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
622
                rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
623
 
624
                if (rc) {
625
                        return(rc);
626
                }
627
        } else {
628
                if ((evbuffer[0] != 0) && (!ctrl->push_flag)) {
629
                        return(1);
630
                }
631
        }
632
 
633
        return 0;
634
}
635
 
636
 
637
int compaq_nvram_store (void *rom_start)
638
{
639
        int rc = 1;
640
 
641
        if (rom_start == NULL)
642
                return -ENODEV;
643
 
644
        if (evbuffer_init) {
645
                rc = store_HRT(rom_start);
646
                if (rc) {
647
                        err(msg_unable_to_save);
648
                }
649
        }
650
        return rc;
651
}
652
 

powered by: WebSVN 2.1.0

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