linux-old/drivers/hotplug/cpqphp_nvram.c
<<
>>
Prefs
   1/*
   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
  47struct 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
  62struct 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
  73struct ev_hrt_header {
  74        u8 Version;
  75        u8 num_of_ctrl;
  76        u8 next;
  77};
  78
  79struct 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
  91static u8 evbuffer_init;
  92static u8 evbuffer_length;
  93static u8 evbuffer[1024];
  94
  95static void *compaq_int15_entry_point;
  96
  97static 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
 110static 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
 125static 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 */
 144static 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
 168static 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 */
 200static 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 */
 234static 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
 426void 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
 438int 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        
 637int 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
 653
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.