linux/drivers/pci/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/module.h>
  30#include <linux/kernel.h>
  31#include <linux/types.h>
  32#include <linux/proc_fs.h>
  33#include <linux/slab.h>
  34#include <linux/workqueue.h>
  35#include <linux/pci.h>
  36#include <linux/pci_hotplug.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 __iomem *compaq_int15_entry_point;
  96
  97/* lock for ordering int15_bios_call() */
  98static spinlock_t int15_lock;
  99
 100
 101/* This is a series of function that deals with
 102 * setting & getting the hotplug resource table in some environment variable.
 103 */
 104
 105/*
 106 * We really shouldn't be doing this unless there is a _very_ good reason to!!!
 107 * greg k-h
 108 */
 109
 110
 111static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail)
 112{
 113        u8 **tByte;
 114
 115        if ((*used + 1) > *avail)
 116                return(1);
 117
 118        *((u8*)*p_buffer) = value;
 119        tByte = (u8**)p_buffer;
 120        (*tByte)++;
 121        *used+=1;
 122        return(0);
 123}
 124
 125
 126static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail)
 127{
 128        if ((*used + 4) > *avail)
 129                return(1);
 130
 131        **p_buffer = value;
 132        (*p_buffer)++;
 133        *used+=4;
 134        return(0);
 135}
 136
 137
 138/*
 139 * check_for_compaq_ROM
 140 *
 141 * this routine verifies that the ROM OEM string is 'COMPAQ'
 142 *
 143 * returns 0 for non-Compaq ROM, 1 for Compaq ROM
 144 */
 145static int check_for_compaq_ROM (void __iomem *rom_start)
 146{
 147        u8 temp1, temp2, temp3, temp4, temp5, temp6;
 148        int result = 0;
 149
 150        temp1 = readb(rom_start + 0xffea + 0);
 151        temp2 = readb(rom_start + 0xffea + 1);
 152        temp3 = readb(rom_start + 0xffea + 2);
 153        temp4 = readb(rom_start + 0xffea + 3);
 154        temp5 = readb(rom_start + 0xffea + 4);
 155        temp6 = readb(rom_start + 0xffea + 5);
 156        if ((temp1 == 'C') &&
 157            (temp2 == 'O') &&
 158            (temp3 == 'M') &&
 159            (temp4 == 'P') &&
 160            (temp5 == 'A') &&
 161            (temp6 == 'Q')) {
 162                result = 1;
 163        }
 164        dbg ("%s - returned %d\n", __func__, result);
 165        return result;
 166}
 167
 168
 169static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
 170{
 171        unsigned long flags;
 172        int op = operation;
 173        int ret_val;
 174
 175        if (!compaq_int15_entry_point)
 176                return -ENODEV;
 177
 178        spin_lock_irqsave(&int15_lock, flags);
 179        __asm__ (
 180                "xorl   %%ebx,%%ebx\n" \
 181                "xorl    %%edx,%%edx\n" \
 182                "pushf\n" \
 183                "push %%cs\n" \
 184                "cli\n" \
 185                "call *%6\n"
 186                : "=c" (*buf_size), "=a" (ret_val)
 187                : "a" (op), "c" (*buf_size), "S" (ev_name),
 188                "D" (buffer), "m" (compaq_int15_entry_point)
 189                : "%ebx", "%edx");
 190        spin_unlock_irqrestore(&int15_lock, flags);
 191
 192        return((ret_val & 0xFF00) >> 8);
 193}
 194
 195
 196/*
 197 * load_HRT
 198 *
 199 * Read the hot plug Resource Table from NVRAM
 200 */
 201static int load_HRT (void __iomem *rom_start)
 202{
 203        u32 available;
 204        u32 temp_dword;
 205        u8 temp_byte = 0xFF;
 206        u32 rc;
 207
 208        if (!check_for_compaq_ROM(rom_start)) {
 209                return -ENODEV;
 210        }
 211
 212        available = 1024;
 213
 214        /* Now load the EV */
 215        temp_dword = available;
 216
 217        rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
 218
 219        evbuffer_length = temp_dword;
 220
 221        /* We're maintaining the resource lists so write FF to invalidate old
 222         * info
 223         */
 224        temp_dword = 1;
 225
 226        rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
 227
 228        return rc;
 229}
 230
 231
 232/*
 233 * store_HRT
 234 *
 235 * Save the hot plug Resource Table in NVRAM
 236 */
 237static u32 store_HRT (void __iomem *rom_start)
 238{
 239        u32 *buffer;
 240        u32 *pFill;
 241        u32 usedbytes;
 242        u32 available;
 243        u32 temp_dword;
 244        u32 rc;
 245        u8 loop;
 246        u8 numCtrl = 0;
 247        struct controller *ctrl;
 248        struct pci_resource *resNode;
 249        struct ev_hrt_header *p_EV_header;
 250        struct ev_hrt_ctrl *p_ev_ctrl;
 251
 252        available = 1024;
 253
 254        if (!check_for_compaq_ROM(rom_start)) {
 255                return(1);
 256        }
 257
 258        buffer = (u32*) evbuffer;
 259
 260        if (!buffer)
 261                return(1);
 262
 263        pFill = buffer;
 264        usedbytes = 0;
 265
 266        p_EV_header = (struct ev_hrt_header *) pFill;
 267
 268        ctrl = cpqhp_ctrl_list;
 269
 270        /* The revision of this structure */
 271        rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
 272        if (rc)
 273                return(rc);
 274
 275        /* The number of controllers */
 276        rc = add_byte( &pFill, 1, &usedbytes, &available);
 277        if (rc)
 278                return(rc);
 279
 280        while (ctrl) {
 281                p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
 282
 283                numCtrl++;
 284
 285                /* The bus number */
 286                rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
 287                if (rc)
 288                        return(rc);
 289
 290                /* The device Number */
 291                rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
 292                if (rc)
 293                        return(rc);
 294
 295                /* The function Number */
 296                rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
 297                if (rc)
 298                        return(rc);
 299
 300                /* Skip the number of available entries */
 301                rc = add_dword( &pFill, 0, &usedbytes, &available);
 302                if (rc)
 303                        return(rc);
 304
 305                /* Figure out memory Available */
 306
 307                resNode = ctrl->mem_head;
 308
 309                loop = 0;
 310
 311                while (resNode) {
 312                        loop ++;
 313
 314                        /* base */
 315                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
 316                        if (rc)
 317                                return(rc);
 318
 319                        /* length */
 320                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
 321                        if (rc)
 322                                return(rc);
 323
 324                        resNode = resNode->next;
 325                }
 326
 327                /* Fill in the number of entries */
 328                p_ev_ctrl->mem_avail = loop;
 329
 330                /* Figure out prefetchable memory Available */
 331
 332                resNode = ctrl->p_mem_head;
 333
 334                loop = 0;
 335
 336                while (resNode) {
 337                        loop ++;
 338
 339                        /* base */
 340                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
 341                        if (rc)
 342                                return(rc);
 343
 344                        /* length */
 345                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
 346                        if (rc)
 347                                return(rc);
 348
 349                        resNode = resNode->next;
 350                }
 351
 352                /* Fill in the number of entries */
 353                p_ev_ctrl->p_mem_avail = loop;
 354
 355                /* Figure out IO Available */
 356
 357                resNode = ctrl->io_head;
 358
 359                loop = 0;
 360
 361                while (resNode) {
 362                        loop ++;
 363
 364                        /* base */
 365                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
 366                        if (rc)
 367                                return(rc);
 368
 369                        /* length */
 370                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
 371                        if (rc)
 372                                return(rc);
 373
 374                        resNode = resNode->next;
 375                }
 376
 377                /* Fill in the number of entries */
 378                p_ev_ctrl->io_avail = loop;
 379
 380                /* Figure out bus Available */
 381
 382                resNode = ctrl->bus_head;
 383
 384                loop = 0;
 385
 386                while (resNode) {
 387                        loop ++;
 388
 389                        /* base */
 390                        rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
 391                        if (rc)
 392                                return(rc);
 393
 394                        /* length */
 395                        rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
 396                        if (rc)
 397                                return(rc);
 398
 399                        resNode = resNode->next;
 400                }
 401
 402                /* Fill in the number of entries */
 403                p_ev_ctrl->bus_avail = loop;
 404
 405                ctrl = ctrl->next;
 406        }
 407
 408        p_EV_header->num_of_ctrl = numCtrl;
 409
 410        /* Now store the EV */
 411
 412        temp_dword = usedbytes;
 413
 414        rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword);
 415
 416        dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
 417
 418        evbuffer_length = temp_dword;
 419
 420        if (rc) {
 421                err(msg_unable_to_save);
 422                return(1);
 423        }
 424
 425        return(0);
 426}
 427
 428
 429void compaq_nvram_init (void __iomem *rom_start)
 430{
 431        if (rom_start) {
 432                compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
 433        }
 434        dbg("int15 entry  = %p\n", compaq_int15_entry_point);
 435
 436        /* initialize our int15 lock */
 437        spin_lock_init(&int15_lock);
 438}
 439
 440
 441int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
 442{
 443        u8 bus, device, function;
 444        u8 nummem, numpmem, numio, numbus;
 445        u32 rc;
 446        u8 *p_byte;
 447        struct pci_resource *mem_node;
 448        struct pci_resource *p_mem_node;
 449        struct pci_resource *io_node;
 450        struct pci_resource *bus_node;
 451        struct ev_hrt_ctrl *p_ev_ctrl;
 452        struct ev_hrt_header *p_EV_header;
 453
 454        if (!evbuffer_init) {
 455                /* Read the resource list information in from NVRAM */
 456                if (load_HRT(rom_start))
 457                        memset (evbuffer, 0, 1024);
 458
 459                evbuffer_init = 1;
 460        }
 461
 462        /* If we saved information in NVRAM, use it now */
 463        p_EV_header = (struct ev_hrt_header *) evbuffer;
 464
 465        /* The following code is for systems where version 1.0 of this
 466         * driver has been loaded, but doesn't support the hardware.
 467         * In that case, the driver would incorrectly store something
 468         * in NVRAM.
 469         */
 470        if ((p_EV_header->Version == 2) ||
 471            ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
 472                p_byte = &(p_EV_header->next);
 473
 474                p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
 475
 476                p_byte += 3;
 477
 478                if (p_byte > ((u8*)p_EV_header + evbuffer_length))
 479                        return 2;
 480
 481                bus = p_ev_ctrl->bus;
 482                device = p_ev_ctrl->device;
 483                function = p_ev_ctrl->function;
 484
 485                while ((bus != ctrl->bus) ||
 486                       (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
 487                       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
 488                        nummem = p_ev_ctrl->mem_avail;
 489                        numpmem = p_ev_ctrl->p_mem_avail;
 490                        numio = p_ev_ctrl->io_avail;
 491                        numbus = p_ev_ctrl->bus_avail;
 492
 493                        p_byte += 4;
 494
 495                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
 496                                return 2;
 497
 498                        /* Skip forward to the next entry */
 499                        p_byte += (nummem + numpmem + numio + numbus) * 8;
 500
 501                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
 502                                return 2;
 503
 504                        p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
 505
 506                        p_byte += 3;
 507
 508                        if (p_byte > ((u8*)p_EV_header + evbuffer_length))
 509                                return 2;
 510
 511                        bus = p_ev_ctrl->bus;
 512                        device = p_ev_ctrl->device;
 513                        function = p_ev_ctrl->function;
 514                }
 515
 516                nummem = p_ev_ctrl->mem_avail;
 517                numpmem = p_ev_ctrl->p_mem_avail;
 518                numio = p_ev_ctrl->io_avail;
 519                numbus = p_ev_ctrl->bus_avail;
 520
 521                p_byte += 4;
 522
 523                if (p_byte > ((u8*)p_EV_header + evbuffer_length))
 524                        return 2;
 525
 526                while (nummem--) {
 527                        mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 528
 529                        if (!mem_node)
 530                                break;
 531
 532                        mem_node->base = *(u32*)p_byte;
 533                        dbg("mem base = %8.8x\n",mem_node->base);
 534                        p_byte += 4;
 535
 536                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 537                                kfree(mem_node);
 538                                return 2;
 539                        }
 540
 541                        mem_node->length = *(u32*)p_byte;
 542                        dbg("mem length = %8.8x\n",mem_node->length);
 543                        p_byte += 4;
 544
 545                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 546                                kfree(mem_node);
 547                                return 2;
 548                        }
 549
 550                        mem_node->next = ctrl->mem_head;
 551                        ctrl->mem_head = mem_node;
 552                }
 553
 554                while (numpmem--) {
 555                        p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 556
 557                        if (!p_mem_node)
 558                                break;
 559
 560                        p_mem_node->base = *(u32*)p_byte;
 561                        dbg("pre-mem base = %8.8x\n",p_mem_node->base);
 562                        p_byte += 4;
 563
 564                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 565                                kfree(p_mem_node);
 566                                return 2;
 567                        }
 568
 569                        p_mem_node->length = *(u32*)p_byte;
 570                        dbg("pre-mem length = %8.8x\n",p_mem_node->length);
 571                        p_byte += 4;
 572
 573                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 574                                kfree(p_mem_node);
 575                                return 2;
 576                        }
 577
 578                        p_mem_node->next = ctrl->p_mem_head;
 579                        ctrl->p_mem_head = p_mem_node;
 580                }
 581
 582                while (numio--) {
 583                        io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 584
 585                        if (!io_node)
 586                                break;
 587
 588                        io_node->base = *(u32*)p_byte;
 589                        dbg("io base = %8.8x\n",io_node->base);
 590                        p_byte += 4;
 591
 592                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 593                                kfree(io_node);
 594                                return 2;
 595                        }
 596
 597                        io_node->length = *(u32*)p_byte;
 598                        dbg("io length = %8.8x\n",io_node->length);
 599                        p_byte += 4;
 600
 601                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 602                                kfree(io_node);
 603                                return 2;
 604                        }
 605
 606                        io_node->next = ctrl->io_head;
 607                        ctrl->io_head = io_node;
 608                }
 609
 610                while (numbus--) {
 611                        bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 612
 613                        if (!bus_node)
 614                                break;
 615
 616                        bus_node->base = *(u32*)p_byte;
 617                        p_byte += 4;
 618
 619                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 620                                kfree(bus_node);
 621                                return 2;
 622                        }
 623
 624                        bus_node->length = *(u32*)p_byte;
 625                        p_byte += 4;
 626
 627                        if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
 628                                kfree(bus_node);
 629                                return 2;
 630                        }
 631
 632                        bus_node->next = ctrl->bus_head;
 633                        ctrl->bus_head = bus_node;
 634                }
 635
 636                /* If all of the following fail, we don't have any resources for
 637                 * hot plug add
 638                 */
 639                rc = 1;
 640                rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
 641                rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
 642                rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
 643                rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
 644
 645                if (rc)
 646                        return(rc);
 647        } else {
 648                if ((evbuffer[0] != 0) && (!ctrl->push_flag))
 649                        return 1;
 650        }
 651
 652        return 0;
 653}
 654
 655
 656int compaq_nvram_store (void __iomem *rom_start)
 657{
 658        int rc = 1;
 659
 660        if (rom_start == NULL)
 661                return -ENODEV;
 662
 663        if (evbuffer_init) {
 664                rc = store_HRT(rom_start);
 665                if (rc) {
 666                        err(msg_unable_to_save);
 667                }
 668        }
 669        return rc;
 670}
 671
 672