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