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 DEFINE_SPINLOCK(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
 420
 421int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
 422{
 423        u8 bus, device, function;
 424        u8 nummem, numpmem, numio, numbus;
 425        u32 rc;
 426        u8 *p_byte;
 427        struct pci_resource *mem_node;
 428        struct pci_resource *p_mem_node;
 429        struct pci_resource *io_node;
 430        struct pci_resource *bus_node;
 431        struct ev_hrt_ctrl *p_ev_ctrl;
 432        struct ev_hrt_header *p_EV_header;
 433
 434        if (!evbuffer_init) {
 435                /* Read the resource list information in from NVRAM */
 436                if (load_HRT(rom_start))
 437                        memset(evbuffer, 0, 1024);
 438
 439                evbuffer_init = 1;
 440        }
 441
 442        /* If we saved information in NVRAM, use it now */
 443        p_EV_header = (struct ev_hrt_header *) evbuffer;
 444
 445        /* The following code is for systems where version 1.0 of this
 446         * driver has been loaded, but doesn't support the hardware.
 447         * In that case, the driver would incorrectly store something
 448         * in NVRAM.
 449         */
 450        if ((p_EV_header->Version == 2) ||
 451            ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
 452                p_byte = &(p_EV_header->next);
 453
 454                p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
 455
 456                p_byte += 3;
 457
 458                if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
 459                        return 2;
 460
 461                bus = p_ev_ctrl->bus;
 462                device = p_ev_ctrl->device;
 463                function = p_ev_ctrl->function;
 464
 465                while ((bus != ctrl->bus) ||
 466                       (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
 467                       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
 468                        nummem = p_ev_ctrl->mem_avail;
 469                        numpmem = p_ev_ctrl->p_mem_avail;
 470                        numio = p_ev_ctrl->io_avail;
 471                        numbus = p_ev_ctrl->bus_avail;
 472
 473                        p_byte += 4;
 474
 475                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
 476                                return 2;
 477
 478                        /* Skip forward to the next entry */
 479                        p_byte += (nummem + numpmem + numio + numbus) * 8;
 480
 481                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
 482                                return 2;
 483
 484                        p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
 485
 486                        p_byte += 3;
 487
 488                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
 489                                return 2;
 490
 491                        bus = p_ev_ctrl->bus;
 492                        device = p_ev_ctrl->device;
 493                        function = p_ev_ctrl->function;
 494                }
 495
 496                nummem = p_ev_ctrl->mem_avail;
 497                numpmem = p_ev_ctrl->p_mem_avail;
 498                numio = p_ev_ctrl->io_avail;
 499                numbus = p_ev_ctrl->bus_avail;
 500
 501                p_byte += 4;
 502
 503                if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
 504                        return 2;
 505
 506                while (nummem--) {
 507                        mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 508
 509                        if (!mem_node)
 510                                break;
 511
 512                        mem_node->base = *(u32 *)p_byte;
 513                        dbg("mem base = %8.8x\n", mem_node->base);
 514                        p_byte += 4;
 515
 516                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 517                                kfree(mem_node);
 518                                return 2;
 519                        }
 520
 521                        mem_node->length = *(u32 *)p_byte;
 522                        dbg("mem length = %8.8x\n", mem_node->length);
 523                        p_byte += 4;
 524
 525                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 526                                kfree(mem_node);
 527                                return 2;
 528                        }
 529
 530                        mem_node->next = ctrl->mem_head;
 531                        ctrl->mem_head = mem_node;
 532                }
 533
 534                while (numpmem--) {
 535                        p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 536
 537                        if (!p_mem_node)
 538                                break;
 539
 540                        p_mem_node->base = *(u32 *)p_byte;
 541                        dbg("pre-mem base = %8.8x\n", p_mem_node->base);
 542                        p_byte += 4;
 543
 544                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 545                                kfree(p_mem_node);
 546                                return 2;
 547                        }
 548
 549                        p_mem_node->length = *(u32 *)p_byte;
 550                        dbg("pre-mem length = %8.8x\n", p_mem_node->length);
 551                        p_byte += 4;
 552
 553                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 554                                kfree(p_mem_node);
 555                                return 2;
 556                        }
 557
 558                        p_mem_node->next = ctrl->p_mem_head;
 559                        ctrl->p_mem_head = p_mem_node;
 560                }
 561
 562                while (numio--) {
 563                        io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 564
 565                        if (!io_node)
 566                                break;
 567
 568                        io_node->base = *(u32 *)p_byte;
 569                        dbg("io base = %8.8x\n", io_node->base);
 570                        p_byte += 4;
 571
 572                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 573                                kfree(io_node);
 574                                return 2;
 575                        }
 576
 577                        io_node->length = *(u32 *)p_byte;
 578                        dbg("io length = %8.8x\n", io_node->length);
 579                        p_byte += 4;
 580
 581                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 582                                kfree(io_node);
 583                                return 2;
 584                        }
 585
 586                        io_node->next = ctrl->io_head;
 587                        ctrl->io_head = io_node;
 588                }
 589
 590                while (numbus--) {
 591                        bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 592
 593                        if (!bus_node)
 594                                break;
 595
 596                        bus_node->base = *(u32 *)p_byte;
 597                        p_byte += 4;
 598
 599                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 600                                kfree(bus_node);
 601                                return 2;
 602                        }
 603
 604                        bus_node->length = *(u32 *)p_byte;
 605                        p_byte += 4;
 606
 607                        if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
 608                                kfree(bus_node);
 609                                return 2;
 610                        }
 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                 */
 619                rc = 1;
 620                rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
 621                rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
 622                rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
 623                rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
 624
 625                if (rc)
 626                        return(rc);
 627        } else {
 628                if ((evbuffer[0] != 0) && (!ctrl->push_flag))
 629                        return 1;
 630        }
 631
 632        return 0;
 633}
 634
 635
 636int compaq_nvram_store(void __iomem *rom_start)
 637{
 638        int rc = 1;
 639
 640        if (rom_start == NULL)
 641                return -ENODEV;
 642
 643        if (evbuffer_init) {
 644                rc = store_HRT(rom_start);
 645                if (rc)
 646                        err(msg_unable_to_save);
 647        }
 648        return rc;
 649}
 650
 651