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