18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Compaq Hot Plug Controller Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995,2001 Compaq Computer Corporation 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 78c2ecf20Sopenharmony_ci * Copyright (C) 2001 IBM Corp. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * All rights reserved. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Send feedback to <greg@kroah.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 218c2ecf20Sopenharmony_ci#include <linux/pci.h> 228c2ecf20Sopenharmony_ci#include <linux/pci_hotplug.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include "cpqphp.h" 258c2ecf20Sopenharmony_ci#include "cpqphp_nvram.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define ROM_INT15_PHY_ADDR 0x0FF859 298c2ecf20Sopenharmony_ci#define READ_EV 0xD8A4 308c2ecf20Sopenharmony_ci#define WRITE_EV 0xD8A5 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct register_foo { 338c2ecf20Sopenharmony_ci union { 348c2ecf20Sopenharmony_ci unsigned long lword; /* eax */ 358c2ecf20Sopenharmony_ci unsigned short word; /* ax */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci struct { 388c2ecf20Sopenharmony_ci unsigned char low; /* al */ 398c2ecf20Sopenharmony_ci unsigned char high; /* ah */ 408c2ecf20Sopenharmony_ci } byte; 418c2ecf20Sopenharmony_ci } data; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci unsigned char opcode; /* see below */ 448c2ecf20Sopenharmony_ci unsigned long length; /* if the reg. is a pointer, how much data */ 458c2ecf20Sopenharmony_ci} __attribute__ ((packed)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct all_reg { 488c2ecf20Sopenharmony_ci struct register_foo eax_reg; 498c2ecf20Sopenharmony_ci struct register_foo ebx_reg; 508c2ecf20Sopenharmony_ci struct register_foo ecx_reg; 518c2ecf20Sopenharmony_ci struct register_foo edx_reg; 528c2ecf20Sopenharmony_ci struct register_foo edi_reg; 538c2ecf20Sopenharmony_ci struct register_foo esi_reg; 548c2ecf20Sopenharmony_ci struct register_foo eflags_reg; 558c2ecf20Sopenharmony_ci} __attribute__ ((packed)); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistruct ev_hrt_header { 598c2ecf20Sopenharmony_ci u8 Version; 608c2ecf20Sopenharmony_ci u8 num_of_ctrl; 618c2ecf20Sopenharmony_ci u8 next; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct ev_hrt_ctrl { 658c2ecf20Sopenharmony_ci u8 bus; 668c2ecf20Sopenharmony_ci u8 device; 678c2ecf20Sopenharmony_ci u8 function; 688c2ecf20Sopenharmony_ci u8 mem_avail; 698c2ecf20Sopenharmony_ci u8 p_mem_avail; 708c2ecf20Sopenharmony_ci u8 io_avail; 718c2ecf20Sopenharmony_ci u8 bus_avail; 728c2ecf20Sopenharmony_ci u8 next; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic u8 evbuffer_init; 778c2ecf20Sopenharmony_cistatic u8 evbuffer_length; 788c2ecf20Sopenharmony_cistatic u8 evbuffer[1024]; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void __iomem *compaq_int15_entry_point; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* lock for ordering int15_bios_call() */ 838c2ecf20Sopenharmony_cistatic spinlock_t int15_lock; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* This is a series of function that deals with 878c2ecf20Sopenharmony_ci * setting & getting the hotplug resource table in some environment variable. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * We really shouldn't be doing this unless there is a _very_ good reason to!!! 928c2ecf20Sopenharmony_ci * greg k-h 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u8 **tByte; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if ((*used + 1) > *avail) 1018c2ecf20Sopenharmony_ci return(1); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci *((u8 *)*p_buffer) = value; 1048c2ecf20Sopenharmony_ci tByte = (u8 **)p_buffer; 1058c2ecf20Sopenharmony_ci (*tByte)++; 1068c2ecf20Sopenharmony_ci *used += 1; 1078c2ecf20Sopenharmony_ci return(0); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci if ((*used + 4) > *avail) 1148c2ecf20Sopenharmony_ci return(1); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci **p_buffer = value; 1178c2ecf20Sopenharmony_ci (*p_buffer)++; 1188c2ecf20Sopenharmony_ci *used += 4; 1198c2ecf20Sopenharmony_ci return(0); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * check_for_compaq_ROM 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * this routine verifies that the ROM OEM string is 'COMPAQ' 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * returns 0 for non-Compaq ROM, 1 for Compaq ROM 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic int check_for_compaq_ROM(void __iomem *rom_start) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci u8 temp1, temp2, temp3, temp4, temp5, temp6; 1338c2ecf20Sopenharmony_ci int result = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci temp1 = readb(rom_start + 0xffea + 0); 1368c2ecf20Sopenharmony_ci temp2 = readb(rom_start + 0xffea + 1); 1378c2ecf20Sopenharmony_ci temp3 = readb(rom_start + 0xffea + 2); 1388c2ecf20Sopenharmony_ci temp4 = readb(rom_start + 0xffea + 3); 1398c2ecf20Sopenharmony_ci temp5 = readb(rom_start + 0xffea + 4); 1408c2ecf20Sopenharmony_ci temp6 = readb(rom_start + 0xffea + 5); 1418c2ecf20Sopenharmony_ci if ((temp1 == 'C') && 1428c2ecf20Sopenharmony_ci (temp2 == 'O') && 1438c2ecf20Sopenharmony_ci (temp3 == 'M') && 1448c2ecf20Sopenharmony_ci (temp4 == 'P') && 1458c2ecf20Sopenharmony_ci (temp5 == 'A') && 1468c2ecf20Sopenharmony_ci (temp6 == 'Q')) { 1478c2ecf20Sopenharmony_ci result = 1; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci dbg("%s - returned %d\n", __func__, result); 1508c2ecf20Sopenharmony_ci return result; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic u32 access_EV(u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci unsigned long flags; 1578c2ecf20Sopenharmony_ci int op = operation; 1588c2ecf20Sopenharmony_ci int ret_val; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (!compaq_int15_entry_point) 1618c2ecf20Sopenharmony_ci return -ENODEV; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci spin_lock_irqsave(&int15_lock, flags); 1648c2ecf20Sopenharmony_ci __asm__ ( 1658c2ecf20Sopenharmony_ci "xorl %%ebx,%%ebx\n" \ 1668c2ecf20Sopenharmony_ci "xorl %%edx,%%edx\n" \ 1678c2ecf20Sopenharmony_ci "pushf\n" \ 1688c2ecf20Sopenharmony_ci "push %%cs\n" \ 1698c2ecf20Sopenharmony_ci "cli\n" \ 1708c2ecf20Sopenharmony_ci "call *%6\n" 1718c2ecf20Sopenharmony_ci : "=c" (*buf_size), "=a" (ret_val) 1728c2ecf20Sopenharmony_ci : "a" (op), "c" (*buf_size), "S" (ev_name), 1738c2ecf20Sopenharmony_ci "D" (buffer), "m" (compaq_int15_entry_point) 1748c2ecf20Sopenharmony_ci : "%ebx", "%edx"); 1758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&int15_lock, flags); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return((ret_val & 0xFF00) >> 8); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * load_HRT 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * Read the hot plug Resource Table from NVRAM 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic int load_HRT(void __iomem *rom_start) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u32 available; 1898c2ecf20Sopenharmony_ci u32 temp_dword; 1908c2ecf20Sopenharmony_ci u8 temp_byte = 0xFF; 1918c2ecf20Sopenharmony_ci u32 rc; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (!check_for_compaq_ROM(rom_start)) 1948c2ecf20Sopenharmony_ci return -ENODEV; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci available = 1024; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Now load the EV */ 1998c2ecf20Sopenharmony_ci temp_dword = available; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci evbuffer_length = temp_dword; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* We're maintaining the resource lists so write FF to invalidate old 2068c2ecf20Sopenharmony_ci * info 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci temp_dword = 1; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return rc; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * store_HRT 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * Save the hot plug Resource Table in NVRAM 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_cistatic u32 store_HRT(void __iomem *rom_start) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci u32 *buffer; 2248c2ecf20Sopenharmony_ci u32 *pFill; 2258c2ecf20Sopenharmony_ci u32 usedbytes; 2268c2ecf20Sopenharmony_ci u32 available; 2278c2ecf20Sopenharmony_ci u32 temp_dword; 2288c2ecf20Sopenharmony_ci u32 rc; 2298c2ecf20Sopenharmony_ci u8 loop; 2308c2ecf20Sopenharmony_ci u8 numCtrl = 0; 2318c2ecf20Sopenharmony_ci struct controller *ctrl; 2328c2ecf20Sopenharmony_ci struct pci_resource *resNode; 2338c2ecf20Sopenharmony_ci struct ev_hrt_header *p_EV_header; 2348c2ecf20Sopenharmony_ci struct ev_hrt_ctrl *p_ev_ctrl; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci available = 1024; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!check_for_compaq_ROM(rom_start)) 2398c2ecf20Sopenharmony_ci return(1); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci buffer = (u32 *) evbuffer; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!buffer) 2448c2ecf20Sopenharmony_ci return(1); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci pFill = buffer; 2478c2ecf20Sopenharmony_ci usedbytes = 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci p_EV_header = (struct ev_hrt_header *) pFill; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ctrl = cpqhp_ctrl_list; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* The revision of this structure */ 2548c2ecf20Sopenharmony_ci rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available); 2558c2ecf20Sopenharmony_ci if (rc) 2568c2ecf20Sopenharmony_ci return(rc); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* The number of controllers */ 2598c2ecf20Sopenharmony_ci rc = add_byte(&pFill, 1, &usedbytes, &available); 2608c2ecf20Sopenharmony_ci if (rc) 2618c2ecf20Sopenharmony_ci return(rc); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci while (ctrl) { 2648c2ecf20Sopenharmony_ci p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci numCtrl++; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* The bus number */ 2698c2ecf20Sopenharmony_ci rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available); 2708c2ecf20Sopenharmony_ci if (rc) 2718c2ecf20Sopenharmony_ci return(rc); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* The device Number */ 2748c2ecf20Sopenharmony_ci rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); 2758c2ecf20Sopenharmony_ci if (rc) 2768c2ecf20Sopenharmony_ci return(rc); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* The function Number */ 2798c2ecf20Sopenharmony_ci rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); 2808c2ecf20Sopenharmony_ci if (rc) 2818c2ecf20Sopenharmony_ci return(rc); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Skip the number of available entries */ 2848c2ecf20Sopenharmony_ci rc = add_dword(&pFill, 0, &usedbytes, &available); 2858c2ecf20Sopenharmony_ci if (rc) 2868c2ecf20Sopenharmony_ci return(rc); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Figure out memory Available */ 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci resNode = ctrl->mem_head; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci loop = 0; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci while (resNode) { 2958c2ecf20Sopenharmony_ci loop++; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* base */ 2988c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->base, &usedbytes, &available); 2998c2ecf20Sopenharmony_ci if (rc) 3008c2ecf20Sopenharmony_ci return(rc); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* length */ 3038c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->length, &usedbytes, &available); 3048c2ecf20Sopenharmony_ci if (rc) 3058c2ecf20Sopenharmony_ci return(rc); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci resNode = resNode->next; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Fill in the number of entries */ 3118c2ecf20Sopenharmony_ci p_ev_ctrl->mem_avail = loop; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Figure out prefetchable memory Available */ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci resNode = ctrl->p_mem_head; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci loop = 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci while (resNode) { 3208c2ecf20Sopenharmony_ci loop++; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* base */ 3238c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->base, &usedbytes, &available); 3248c2ecf20Sopenharmony_ci if (rc) 3258c2ecf20Sopenharmony_ci return(rc); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* length */ 3288c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->length, &usedbytes, &available); 3298c2ecf20Sopenharmony_ci if (rc) 3308c2ecf20Sopenharmony_ci return(rc); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci resNode = resNode->next; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Fill in the number of entries */ 3368c2ecf20Sopenharmony_ci p_ev_ctrl->p_mem_avail = loop; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Figure out IO Available */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci resNode = ctrl->io_head; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci loop = 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci while (resNode) { 3458c2ecf20Sopenharmony_ci loop++; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* base */ 3488c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->base, &usedbytes, &available); 3498c2ecf20Sopenharmony_ci if (rc) 3508c2ecf20Sopenharmony_ci return(rc); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* length */ 3538c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->length, &usedbytes, &available); 3548c2ecf20Sopenharmony_ci if (rc) 3558c2ecf20Sopenharmony_ci return(rc); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci resNode = resNode->next; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Fill in the number of entries */ 3618c2ecf20Sopenharmony_ci p_ev_ctrl->io_avail = loop; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Figure out bus Available */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci resNode = ctrl->bus_head; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci loop = 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci while (resNode) { 3708c2ecf20Sopenharmony_ci loop++; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* base */ 3738c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->base, &usedbytes, &available); 3748c2ecf20Sopenharmony_ci if (rc) 3758c2ecf20Sopenharmony_ci return(rc); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* length */ 3788c2ecf20Sopenharmony_ci rc = add_dword(&pFill, resNode->length, &usedbytes, &available); 3798c2ecf20Sopenharmony_ci if (rc) 3808c2ecf20Sopenharmony_ci return(rc); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci resNode = resNode->next; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Fill in the number of entries */ 3868c2ecf20Sopenharmony_ci p_ev_ctrl->bus_avail = loop; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ctrl = ctrl->next; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci p_EV_header->num_of_ctrl = numCtrl; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Now store the EV */ 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci temp_dword = usedbytes; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rc = access_EV(WRITE_EV, "CQTHPS", (u8 *) buffer, &temp_dword); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci evbuffer_length = temp_dword; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (rc) { 4048c2ecf20Sopenharmony_ci err(msg_unable_to_save); 4058c2ecf20Sopenharmony_ci return(1); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return(0); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_civoid compaq_nvram_init(void __iomem *rom_start) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci if (rom_start) 4158c2ecf20Sopenharmony_ci compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dbg("int15 entry = %p\n", compaq_int15_entry_point); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* initialize our int15 lock */ 4208c2ecf20Sopenharmony_ci spin_lock_init(&int15_lock); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciint compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci u8 bus, device, function; 4278c2ecf20Sopenharmony_ci u8 nummem, numpmem, numio, numbus; 4288c2ecf20Sopenharmony_ci u32 rc; 4298c2ecf20Sopenharmony_ci u8 *p_byte; 4308c2ecf20Sopenharmony_ci struct pci_resource *mem_node; 4318c2ecf20Sopenharmony_ci struct pci_resource *p_mem_node; 4328c2ecf20Sopenharmony_ci struct pci_resource *io_node; 4338c2ecf20Sopenharmony_ci struct pci_resource *bus_node; 4348c2ecf20Sopenharmony_ci struct ev_hrt_ctrl *p_ev_ctrl; 4358c2ecf20Sopenharmony_ci struct ev_hrt_header *p_EV_header; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!evbuffer_init) { 4388c2ecf20Sopenharmony_ci /* Read the resource list information in from NVRAM */ 4398c2ecf20Sopenharmony_ci if (load_HRT(rom_start)) 4408c2ecf20Sopenharmony_ci memset(evbuffer, 0, 1024); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci evbuffer_init = 1; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* If we saved information in NVRAM, use it now */ 4468c2ecf20Sopenharmony_ci p_EV_header = (struct ev_hrt_header *) evbuffer; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* The following code is for systems where version 1.0 of this 4498c2ecf20Sopenharmony_ci * driver has been loaded, but doesn't support the hardware. 4508c2ecf20Sopenharmony_ci * In that case, the driver would incorrectly store something 4518c2ecf20Sopenharmony_ci * in NVRAM. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if ((p_EV_header->Version == 2) || 4548c2ecf20Sopenharmony_ci ((p_EV_header->Version == 1) && !ctrl->push_flag)) { 4558c2ecf20Sopenharmony_ci p_byte = &(p_EV_header->next); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci p_byte += 3; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) 4628c2ecf20Sopenharmony_ci return 2; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci bus = p_ev_ctrl->bus; 4658c2ecf20Sopenharmony_ci device = p_ev_ctrl->device; 4668c2ecf20Sopenharmony_ci function = p_ev_ctrl->function; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci while ((bus != ctrl->bus) || 4698c2ecf20Sopenharmony_ci (device != PCI_SLOT(ctrl->pci_dev->devfn)) || 4708c2ecf20Sopenharmony_ci (function != PCI_FUNC(ctrl->pci_dev->devfn))) { 4718c2ecf20Sopenharmony_ci nummem = p_ev_ctrl->mem_avail; 4728c2ecf20Sopenharmony_ci numpmem = p_ev_ctrl->p_mem_avail; 4738c2ecf20Sopenharmony_ci numio = p_ev_ctrl->io_avail; 4748c2ecf20Sopenharmony_ci numbus = p_ev_ctrl->bus_avail; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci p_byte += 4; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) 4798c2ecf20Sopenharmony_ci return 2; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Skip forward to the next entry */ 4828c2ecf20Sopenharmony_ci p_byte += (nummem + numpmem + numio + numbus) * 8; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) 4858c2ecf20Sopenharmony_ci return 2; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci p_byte += 3; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) 4928c2ecf20Sopenharmony_ci return 2; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci bus = p_ev_ctrl->bus; 4958c2ecf20Sopenharmony_ci device = p_ev_ctrl->device; 4968c2ecf20Sopenharmony_ci function = p_ev_ctrl->function; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci nummem = p_ev_ctrl->mem_avail; 5008c2ecf20Sopenharmony_ci numpmem = p_ev_ctrl->p_mem_avail; 5018c2ecf20Sopenharmony_ci numio = p_ev_ctrl->io_avail; 5028c2ecf20Sopenharmony_ci numbus = p_ev_ctrl->bus_avail; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci p_byte += 4; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) 5078c2ecf20Sopenharmony_ci return 2; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci while (nummem--) { 5108c2ecf20Sopenharmony_ci mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (!mem_node) 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci mem_node->base = *(u32 *)p_byte; 5168c2ecf20Sopenharmony_ci dbg("mem base = %8.8x\n", mem_node->base); 5178c2ecf20Sopenharmony_ci p_byte += 4; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5208c2ecf20Sopenharmony_ci kfree(mem_node); 5218c2ecf20Sopenharmony_ci return 2; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci mem_node->length = *(u32 *)p_byte; 5258c2ecf20Sopenharmony_ci dbg("mem length = %8.8x\n", mem_node->length); 5268c2ecf20Sopenharmony_ci p_byte += 4; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5298c2ecf20Sopenharmony_ci kfree(mem_node); 5308c2ecf20Sopenharmony_ci return 2; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci mem_node->next = ctrl->mem_head; 5348c2ecf20Sopenharmony_ci ctrl->mem_head = mem_node; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci while (numpmem--) { 5388c2ecf20Sopenharmony_ci p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!p_mem_node) 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci p_mem_node->base = *(u32 *)p_byte; 5448c2ecf20Sopenharmony_ci dbg("pre-mem base = %8.8x\n", p_mem_node->base); 5458c2ecf20Sopenharmony_ci p_byte += 4; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5488c2ecf20Sopenharmony_ci kfree(p_mem_node); 5498c2ecf20Sopenharmony_ci return 2; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci p_mem_node->length = *(u32 *)p_byte; 5538c2ecf20Sopenharmony_ci dbg("pre-mem length = %8.8x\n", p_mem_node->length); 5548c2ecf20Sopenharmony_ci p_byte += 4; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5578c2ecf20Sopenharmony_ci kfree(p_mem_node); 5588c2ecf20Sopenharmony_ci return 2; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci p_mem_node->next = ctrl->p_mem_head; 5628c2ecf20Sopenharmony_ci ctrl->p_mem_head = p_mem_node; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci while (numio--) { 5668c2ecf20Sopenharmony_ci io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (!io_node) 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci io_node->base = *(u32 *)p_byte; 5728c2ecf20Sopenharmony_ci dbg("io base = %8.8x\n", io_node->base); 5738c2ecf20Sopenharmony_ci p_byte += 4; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5768c2ecf20Sopenharmony_ci kfree(io_node); 5778c2ecf20Sopenharmony_ci return 2; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci io_node->length = *(u32 *)p_byte; 5818c2ecf20Sopenharmony_ci dbg("io length = %8.8x\n", io_node->length); 5828c2ecf20Sopenharmony_ci p_byte += 4; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 5858c2ecf20Sopenharmony_ci kfree(io_node); 5868c2ecf20Sopenharmony_ci return 2; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci io_node->next = ctrl->io_head; 5908c2ecf20Sopenharmony_ci ctrl->io_head = io_node; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci while (numbus--) { 5948c2ecf20Sopenharmony_ci bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!bus_node) 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci bus_node->base = *(u32 *)p_byte; 6008c2ecf20Sopenharmony_ci p_byte += 4; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 6038c2ecf20Sopenharmony_ci kfree(bus_node); 6048c2ecf20Sopenharmony_ci return 2; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci bus_node->length = *(u32 *)p_byte; 6088c2ecf20Sopenharmony_ci p_byte += 4; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) { 6118c2ecf20Sopenharmony_ci kfree(bus_node); 6128c2ecf20Sopenharmony_ci return 2; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci bus_node->next = ctrl->bus_head; 6168c2ecf20Sopenharmony_ci ctrl->bus_head = bus_node; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* If all of the following fail, we don't have any resources for 6208c2ecf20Sopenharmony_ci * hot plug add 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci rc = 1; 6238c2ecf20Sopenharmony_ci rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); 6248c2ecf20Sopenharmony_ci rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); 6258c2ecf20Sopenharmony_ci rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); 6268c2ecf20Sopenharmony_ci rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (rc) 6298c2ecf20Sopenharmony_ci return(rc); 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci if ((evbuffer[0] != 0) && (!ctrl->push_flag)) 6328c2ecf20Sopenharmony_ci return 1; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ciint compaq_nvram_store(void __iomem *rom_start) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci int rc = 1; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (rom_start == NULL) 6448c2ecf20Sopenharmony_ci return -ENODEV; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (evbuffer_init) { 6478c2ecf20Sopenharmony_ci rc = store_HRT(rom_start); 6488c2ecf20Sopenharmony_ci if (rc) 6498c2ecf20Sopenharmony_ci err(msg_unable_to_save); 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci return rc; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 654