Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Compaq Hot Plug Controller Driver
0004  *
0005  * Copyright (C) 1995,2001 Compaq Computer Corporation
0006  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
0007  * Copyright (C) 2001 IBM Corp.
0008  *
0009  * All rights reserved.
0010  *
0011  * Send feedback to <greg@kroah.com>
0012  *
0013  */
0014 
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/types.h>
0018 #include <linux/proc_fs.h>
0019 #include <linux/slab.h>
0020 #include <linux/workqueue.h>
0021 #include <linux/pci.h>
0022 #include <linux/pci_hotplug.h>
0023 #include <linux/uaccess.h>
0024 #include "cpqphp.h"
0025 #include "cpqphp_nvram.h"
0026 
0027 
0028 #define ROM_INT15_PHY_ADDR      0x0FF859
0029 #define READ_EV             0xD8A4
0030 #define WRITE_EV            0xD8A5
0031 
0032 struct register_foo {
0033     union {
0034         unsigned long lword;        /* eax */
0035         unsigned short word;        /* ax */
0036 
0037         struct {
0038             unsigned char low;  /* al */
0039             unsigned char high; /* ah */
0040         } byte;
0041     } data;
0042 
0043     unsigned char opcode;   /* see below */
0044     unsigned long length;   /* if the reg. is a pointer, how much data */
0045 } __attribute__ ((packed));
0046 
0047 struct all_reg {
0048     struct register_foo eax_reg;
0049     struct register_foo ebx_reg;
0050     struct register_foo ecx_reg;
0051     struct register_foo edx_reg;
0052     struct register_foo edi_reg;
0053     struct register_foo esi_reg;
0054     struct register_foo eflags_reg;
0055 } __attribute__ ((packed));
0056 
0057 
0058 struct ev_hrt_header {
0059     u8 Version;
0060     u8 num_of_ctrl;
0061     u8 next;
0062 };
0063 
0064 struct ev_hrt_ctrl {
0065     u8 bus;
0066     u8 device;
0067     u8 function;
0068     u8 mem_avail;
0069     u8 p_mem_avail;
0070     u8 io_avail;
0071     u8 bus_avail;
0072     u8 next;
0073 };
0074 
0075 
0076 static u8 evbuffer_init;
0077 static u8 evbuffer_length;
0078 static u8 evbuffer[1024];
0079 
0080 static void __iomem *compaq_int15_entry_point;
0081 
0082 /* lock for ordering int15_bios_call() */
0083 static DEFINE_SPINLOCK(int15_lock);
0084 
0085 
0086 /* This is a series of function that deals with
0087  * setting & getting the hotplug resource table in some environment variable.
0088  */
0089 
0090 /*
0091  * We really shouldn't be doing this unless there is a _very_ good reason to!!!
0092  * greg k-h
0093  */
0094 
0095 
0096 static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail)
0097 {
0098     u8 **tByte;
0099 
0100     if ((*used + 1) > *avail)
0101         return(1);
0102 
0103     *((u8 *)*p_buffer) = value;
0104     tByte = (u8 **)p_buffer;
0105     (*tByte)++;
0106     *used += 1;
0107     return(0);
0108 }
0109 
0110 
0111 static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail)
0112 {
0113     if ((*used + 4) > *avail)
0114         return(1);
0115 
0116     **p_buffer = value;
0117     (*p_buffer)++;
0118     *used += 4;
0119     return(0);
0120 }
0121 
0122 
0123 /*
0124  * check_for_compaq_ROM
0125  *
0126  * this routine verifies that the ROM OEM string is 'COMPAQ'
0127  *
0128  * returns 0 for non-Compaq ROM, 1 for Compaq ROM
0129  */
0130 static int check_for_compaq_ROM(void __iomem *rom_start)
0131 {
0132     u8 temp1, temp2, temp3, temp4, temp5, temp6;
0133     int result = 0;
0134 
0135     temp1 = readb(rom_start + 0xffea + 0);
0136     temp2 = readb(rom_start + 0xffea + 1);
0137     temp3 = readb(rom_start + 0xffea + 2);
0138     temp4 = readb(rom_start + 0xffea + 3);
0139     temp5 = readb(rom_start + 0xffea + 4);
0140     temp6 = readb(rom_start + 0xffea + 5);
0141     if ((temp1 == 'C') &&
0142         (temp2 == 'O') &&
0143         (temp3 == 'M') &&
0144         (temp4 == 'P') &&
0145         (temp5 == 'A') &&
0146         (temp6 == 'Q')) {
0147         result = 1;
0148     }
0149     dbg("%s - returned %d\n", __func__, result);
0150     return result;
0151 }
0152 
0153 
0154 static u32 access_EV(u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
0155 {
0156     unsigned long flags;
0157     int op = operation;
0158     int ret_val;
0159 
0160     if (!compaq_int15_entry_point)
0161         return -ENODEV;
0162 
0163     spin_lock_irqsave(&int15_lock, flags);
0164     __asm__ (
0165         "xorl   %%ebx,%%ebx\n" \
0166         "xorl    %%edx,%%edx\n" \
0167         "pushf\n" \
0168         "push %%cs\n" \
0169         "cli\n" \
0170         "call *%6\n"
0171         : "=c" (*buf_size), "=a" (ret_val)
0172         : "a" (op), "c" (*buf_size), "S" (ev_name),
0173         "D" (buffer), "m" (compaq_int15_entry_point)
0174         : "%ebx", "%edx");
0175     spin_unlock_irqrestore(&int15_lock, flags);
0176 
0177     return((ret_val & 0xFF00) >> 8);
0178 }
0179 
0180 
0181 /*
0182  * load_HRT
0183  *
0184  * Read the hot plug Resource Table from NVRAM
0185  */
0186 static int load_HRT(void __iomem *rom_start)
0187 {
0188     u32 available;
0189     u32 temp_dword;
0190     u8 temp_byte = 0xFF;
0191     u32 rc;
0192 
0193     if (!check_for_compaq_ROM(rom_start))
0194         return -ENODEV;
0195 
0196     available = 1024;
0197 
0198     /* Now load the EV */
0199     temp_dword = available;
0200 
0201     rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
0202 
0203     evbuffer_length = temp_dword;
0204 
0205     /* We're maintaining the resource lists so write FF to invalidate old
0206      * info
0207      */
0208     temp_dword = 1;
0209 
0210     rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
0211 
0212     return rc;
0213 }
0214 
0215 
0216 /*
0217  * store_HRT
0218  *
0219  * Save the hot plug Resource Table in NVRAM
0220  */
0221 static u32 store_HRT(void __iomem *rom_start)
0222 {
0223     u32 *buffer;
0224     u32 *pFill;
0225     u32 usedbytes;
0226     u32 available;
0227     u32 temp_dword;
0228     u32 rc;
0229     u8 loop;
0230     u8 numCtrl = 0;
0231     struct controller *ctrl;
0232     struct pci_resource *resNode;
0233     struct ev_hrt_header *p_EV_header;
0234     struct ev_hrt_ctrl *p_ev_ctrl;
0235 
0236     available = 1024;
0237 
0238     if (!check_for_compaq_ROM(rom_start))
0239         return(1);
0240 
0241     buffer = (u32 *) evbuffer;
0242 
0243     if (!buffer)
0244         return(1);
0245 
0246     pFill = buffer;
0247     usedbytes = 0;
0248 
0249     p_EV_header = (struct ev_hrt_header *) pFill;
0250 
0251     ctrl = cpqhp_ctrl_list;
0252 
0253     /* The revision of this structure */
0254     rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available);
0255     if (rc)
0256         return(rc);
0257 
0258     /* The number of controllers */
0259     rc = add_byte(&pFill, 1, &usedbytes, &available);
0260     if (rc)
0261         return(rc);
0262 
0263     while (ctrl) {
0264         p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
0265 
0266         numCtrl++;
0267 
0268         /* The bus number */
0269         rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available);
0270         if (rc)
0271             return(rc);
0272 
0273         /* The device Number */
0274         rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
0275         if (rc)
0276             return(rc);
0277 
0278         /* The function Number */
0279         rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
0280         if (rc)
0281             return(rc);
0282 
0283         /* Skip the number of available entries */
0284         rc = add_dword(&pFill, 0, &usedbytes, &available);
0285         if (rc)
0286             return(rc);
0287 
0288         /* Figure out memory Available */
0289 
0290         resNode = ctrl->mem_head;
0291 
0292         loop = 0;
0293 
0294         while (resNode) {
0295             loop++;
0296 
0297             /* base */
0298             rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
0299             if (rc)
0300                 return(rc);
0301 
0302             /* length */
0303             rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
0304             if (rc)
0305                 return(rc);
0306 
0307             resNode = resNode->next;
0308         }
0309 
0310         /* Fill in the number of entries */
0311         p_ev_ctrl->mem_avail = loop;
0312 
0313         /* Figure out prefetchable memory Available */
0314 
0315         resNode = ctrl->p_mem_head;
0316 
0317         loop = 0;
0318 
0319         while (resNode) {
0320             loop++;
0321 
0322             /* base */
0323             rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
0324             if (rc)
0325                 return(rc);
0326 
0327             /* length */
0328             rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
0329             if (rc)
0330                 return(rc);
0331 
0332             resNode = resNode->next;
0333         }
0334 
0335         /* Fill in the number of entries */
0336         p_ev_ctrl->p_mem_avail = loop;
0337 
0338         /* Figure out IO Available */
0339 
0340         resNode = ctrl->io_head;
0341 
0342         loop = 0;
0343 
0344         while (resNode) {
0345             loop++;
0346 
0347             /* base */
0348             rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
0349             if (rc)
0350                 return(rc);
0351 
0352             /* length */
0353             rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
0354             if (rc)
0355                 return(rc);
0356 
0357             resNode = resNode->next;
0358         }
0359 
0360         /* Fill in the number of entries */
0361         p_ev_ctrl->io_avail = loop;
0362 
0363         /* Figure out bus Available */
0364 
0365         resNode = ctrl->bus_head;
0366 
0367         loop = 0;
0368 
0369         while (resNode) {
0370             loop++;
0371 
0372             /* base */
0373             rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
0374             if (rc)
0375                 return(rc);
0376 
0377             /* length */
0378             rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
0379             if (rc)
0380                 return(rc);
0381 
0382             resNode = resNode->next;
0383         }
0384 
0385         /* Fill in the number of entries */
0386         p_ev_ctrl->bus_avail = loop;
0387 
0388         ctrl = ctrl->next;
0389     }
0390 
0391     p_EV_header->num_of_ctrl = numCtrl;
0392 
0393     /* Now store the EV */
0394 
0395     temp_dword = usedbytes;
0396 
0397     rc = access_EV(WRITE_EV, "CQTHPS", (u8 *) buffer, &temp_dword);
0398 
0399     dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
0400 
0401     evbuffer_length = temp_dword;
0402 
0403     if (rc) {
0404         err(msg_unable_to_save);
0405         return(1);
0406     }
0407 
0408     return(0);
0409 }
0410 
0411 
0412 void compaq_nvram_init(void __iomem *rom_start)
0413 {
0414     if (rom_start)
0415         compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
0416 
0417     dbg("int15 entry  = %p\n", compaq_int15_entry_point);
0418 }
0419 
0420 
0421 int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
0422 {
0423     u8 bus, device, function;
0424     u8 nummem, numpmem, numio, numbus;
0425     u32 rc;
0426     u8 *p_byte;
0427     struct pci_resource *mem_node;
0428     struct pci_resource *p_mem_node;
0429     struct pci_resource *io_node;
0430     struct pci_resource *bus_node;
0431     struct ev_hrt_ctrl *p_ev_ctrl;
0432     struct ev_hrt_header *p_EV_header;
0433 
0434     if (!evbuffer_init) {
0435         /* Read the resource list information in from NVRAM */
0436         if (load_HRT(rom_start))
0437             memset(evbuffer, 0, 1024);
0438 
0439         evbuffer_init = 1;
0440     }
0441 
0442     /* If we saved information in NVRAM, use it now */
0443     p_EV_header = (struct ev_hrt_header *) evbuffer;
0444 
0445     /* The following code is for systems where version 1.0 of this
0446      * driver has been loaded, but doesn't support the hardware.
0447      * In that case, the driver would incorrectly store something
0448      * in NVRAM.
0449      */
0450     if ((p_EV_header->Version == 2) ||
0451         ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
0452         p_byte = &(p_EV_header->next);
0453 
0454         p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
0455 
0456         p_byte += 3;
0457 
0458         if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
0459             return 2;
0460 
0461         bus = p_ev_ctrl->bus;
0462         device = p_ev_ctrl->device;
0463         function = p_ev_ctrl->function;
0464 
0465         while ((bus != ctrl->bus) ||
0466                (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
0467                (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
0468             nummem = p_ev_ctrl->mem_avail;
0469             numpmem = p_ev_ctrl->p_mem_avail;
0470             numio = p_ev_ctrl->io_avail;
0471             numbus = p_ev_ctrl->bus_avail;
0472 
0473             p_byte += 4;
0474 
0475             if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
0476                 return 2;
0477 
0478             /* Skip forward to the next entry */
0479             p_byte += (nummem + numpmem + numio + numbus) * 8;
0480 
0481             if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
0482                 return 2;
0483 
0484             p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
0485 
0486             p_byte += 3;
0487 
0488             if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
0489                 return 2;
0490 
0491             bus = p_ev_ctrl->bus;
0492             device = p_ev_ctrl->device;
0493             function = p_ev_ctrl->function;
0494         }
0495 
0496         nummem = p_ev_ctrl->mem_avail;
0497         numpmem = p_ev_ctrl->p_mem_avail;
0498         numio = p_ev_ctrl->io_avail;
0499         numbus = p_ev_ctrl->bus_avail;
0500 
0501         p_byte += 4;
0502 
0503         if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
0504             return 2;
0505 
0506         while (nummem--) {
0507             mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
0508 
0509             if (!mem_node)
0510                 break;
0511 
0512             mem_node->base = *(u32 *)p_byte;
0513             dbg("mem base = %8.8x\n", mem_node->base);
0514             p_byte += 4;
0515 
0516             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0517                 kfree(mem_node);
0518                 return 2;
0519             }
0520 
0521             mem_node->length = *(u32 *)p_byte;
0522             dbg("mem length = %8.8x\n", mem_node->length);
0523             p_byte += 4;
0524 
0525             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0526                 kfree(mem_node);
0527                 return 2;
0528             }
0529 
0530             mem_node->next = ctrl->mem_head;
0531             ctrl->mem_head = mem_node;
0532         }
0533 
0534         while (numpmem--) {
0535             p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
0536 
0537             if (!p_mem_node)
0538                 break;
0539 
0540             p_mem_node->base = *(u32 *)p_byte;
0541             dbg("pre-mem base = %8.8x\n", p_mem_node->base);
0542             p_byte += 4;
0543 
0544             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0545                 kfree(p_mem_node);
0546                 return 2;
0547             }
0548 
0549             p_mem_node->length = *(u32 *)p_byte;
0550             dbg("pre-mem length = %8.8x\n", p_mem_node->length);
0551             p_byte += 4;
0552 
0553             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0554                 kfree(p_mem_node);
0555                 return 2;
0556             }
0557 
0558             p_mem_node->next = ctrl->p_mem_head;
0559             ctrl->p_mem_head = p_mem_node;
0560         }
0561 
0562         while (numio--) {
0563             io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
0564 
0565             if (!io_node)
0566                 break;
0567 
0568             io_node->base = *(u32 *)p_byte;
0569             dbg("io base = %8.8x\n", io_node->base);
0570             p_byte += 4;
0571 
0572             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0573                 kfree(io_node);
0574                 return 2;
0575             }
0576 
0577             io_node->length = *(u32 *)p_byte;
0578             dbg("io length = %8.8x\n", io_node->length);
0579             p_byte += 4;
0580 
0581             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0582                 kfree(io_node);
0583                 return 2;
0584             }
0585 
0586             io_node->next = ctrl->io_head;
0587             ctrl->io_head = io_node;
0588         }
0589 
0590         while (numbus--) {
0591             bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
0592 
0593             if (!bus_node)
0594                 break;
0595 
0596             bus_node->base = *(u32 *)p_byte;
0597             p_byte += 4;
0598 
0599             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0600                 kfree(bus_node);
0601                 return 2;
0602             }
0603 
0604             bus_node->length = *(u32 *)p_byte;
0605             p_byte += 4;
0606 
0607             if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
0608                 kfree(bus_node);
0609                 return 2;
0610             }
0611 
0612             bus_node->next = ctrl->bus_head;
0613             ctrl->bus_head = bus_node;
0614         }
0615 
0616         /* If all of the following fail, we don't have any resources for
0617          * hot plug add
0618          */
0619         rc = 1;
0620         rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
0621         rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
0622         rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
0623         rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
0624 
0625         if (rc)
0626             return(rc);
0627     } else {
0628         if ((evbuffer[0] != 0) && (!ctrl->push_flag))
0629             return 1;
0630     }
0631 
0632     return 0;
0633 }
0634 
0635 
0636 int compaq_nvram_store(void __iomem *rom_start)
0637 {
0638     int rc = 1;
0639 
0640     if (rom_start == NULL)
0641         return -ENODEV;
0642 
0643     if (evbuffer_init) {
0644         rc = store_HRT(rom_start);
0645         if (rc)
0646             err(msg_unable_to_save);
0647     }
0648     return rc;
0649 }
0650