1736759efSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Compaq Hot Plug Controller Driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1995,2001 Compaq Computer Corporation
61da177e4SLinus Torvalds * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
71da177e4SLinus Torvalds * Copyright (C) 2001 IBM Corp.
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * All rights reserved.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * Send feedback to <greg@kroah.com>
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds #include <linux/module.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/types.h>
181da177e4SLinus Torvalds #include <linux/proc_fs.h>
191da177e4SLinus Torvalds #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/workqueue.h>
211da177e4SLinus Torvalds #include <linux/pci.h>
227a54f25cSGreg Kroah-Hartman #include <linux/pci_hotplug.h>
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
241da177e4SLinus Torvalds #include "cpqphp.h"
251da177e4SLinus Torvalds #include "cpqphp_nvram.h"
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #define ROM_INT15_PHY_ADDR 0x0FF859
291da177e4SLinus Torvalds #define READ_EV 0xD8A4
301da177e4SLinus Torvalds #define WRITE_EV 0xD8A5
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds struct register_foo {
331da177e4SLinus Torvalds union {
341da177e4SLinus Torvalds unsigned long lword; /* eax */
351da177e4SLinus Torvalds unsigned short word; /* ax */
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds struct {
381da177e4SLinus Torvalds unsigned char low; /* al */
391da177e4SLinus Torvalds unsigned char high; /* ah */
401da177e4SLinus Torvalds } byte;
411da177e4SLinus Torvalds } data;
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds unsigned char opcode; /* see below */
441da177e4SLinus Torvalds unsigned long length; /* if the reg. is a pointer, how much data */
451da177e4SLinus Torvalds } __attribute__ ((packed));
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds struct all_reg {
481da177e4SLinus Torvalds struct register_foo eax_reg;
491da177e4SLinus Torvalds struct register_foo ebx_reg;
501da177e4SLinus Torvalds struct register_foo ecx_reg;
511da177e4SLinus Torvalds struct register_foo edx_reg;
521da177e4SLinus Torvalds struct register_foo edi_reg;
531da177e4SLinus Torvalds struct register_foo esi_reg;
541da177e4SLinus Torvalds struct register_foo eflags_reg;
551da177e4SLinus Torvalds } __attribute__ ((packed));
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds struct ev_hrt_header {
591da177e4SLinus Torvalds u8 Version;
601da177e4SLinus Torvalds u8 num_of_ctrl;
611da177e4SLinus Torvalds u8 next;
621da177e4SLinus Torvalds };
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds struct ev_hrt_ctrl {
651da177e4SLinus Torvalds u8 bus;
661da177e4SLinus Torvalds u8 device;
671da177e4SLinus Torvalds u8 function;
681da177e4SLinus Torvalds u8 mem_avail;
691da177e4SLinus Torvalds u8 p_mem_avail;
701da177e4SLinus Torvalds u8 io_avail;
711da177e4SLinus Torvalds u8 bus_avail;
721da177e4SLinus Torvalds u8 next;
731da177e4SLinus Torvalds };
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds static u8 evbuffer_init;
771da177e4SLinus Torvalds static u8 evbuffer_length;
781da177e4SLinus Torvalds static u8 evbuffer[1024];
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds static void __iomem *compaq_int15_entry_point;
811da177e4SLinus Torvalds
82427438c6SAlex Chiang /* lock for ordering int15_bios_call() */
83*3a306a5bSGuobin Huang static DEFINE_SPINLOCK(int15_lock);
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds /* This is a series of function that deals with
87427438c6SAlex Chiang * setting & getting the hotplug resource table in some environment variable.
881da177e4SLinus Torvalds */
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds * We really shouldn't be doing this unless there is a _very_ good reason to!!!
921da177e4SLinus Torvalds * greg k-h
931da177e4SLinus Torvalds */
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds
add_byte(u32 ** p_buffer,u8 value,u32 * used,u32 * avail)961da177e4SLinus Torvalds static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds u8 **tByte;
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds if ((*used + 1) > *avail)
1011da177e4SLinus Torvalds return(1);
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds *((u8 *)*p_buffer) = value;
1041da177e4SLinus Torvalds tByte = (u8 **)p_buffer;
1051da177e4SLinus Torvalds (*tByte)++;
1061da177e4SLinus Torvalds *used += 1;
1071da177e4SLinus Torvalds return(0);
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds
add_dword(u32 ** p_buffer,u32 value,u32 * used,u32 * avail)1111da177e4SLinus Torvalds static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds if ((*used + 4) > *avail)
1141da177e4SLinus Torvalds return(1);
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds **p_buffer = value;
1171da177e4SLinus Torvalds (*p_buffer)++;
1181da177e4SLinus Torvalds *used += 4;
1191da177e4SLinus Torvalds return(0);
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds /*
1241da177e4SLinus Torvalds * check_for_compaq_ROM
1251da177e4SLinus Torvalds *
1261da177e4SLinus Torvalds * this routine verifies that the ROM OEM string is 'COMPAQ'
1271da177e4SLinus Torvalds *
1281da177e4SLinus Torvalds * returns 0 for non-Compaq ROM, 1 for Compaq ROM
1291da177e4SLinus Torvalds */
check_for_compaq_ROM(void __iomem * rom_start)1301da177e4SLinus Torvalds static int check_for_compaq_ROM(void __iomem *rom_start)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds u8 temp1, temp2, temp3, temp4, temp5, temp6;
1331da177e4SLinus Torvalds int result = 0;
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds temp1 = readb(rom_start + 0xffea + 0);
1361da177e4SLinus Torvalds temp2 = readb(rom_start + 0xffea + 1);
1371da177e4SLinus Torvalds temp3 = readb(rom_start + 0xffea + 2);
1381da177e4SLinus Torvalds temp4 = readb(rom_start + 0xffea + 3);
1391da177e4SLinus Torvalds temp5 = readb(rom_start + 0xffea + 4);
1401da177e4SLinus Torvalds temp6 = readb(rom_start + 0xffea + 5);
1411da177e4SLinus Torvalds if ((temp1 == 'C') &&
1421da177e4SLinus Torvalds (temp2 == 'O') &&
1431da177e4SLinus Torvalds (temp3 == 'M') &&
1441da177e4SLinus Torvalds (temp4 == 'P') &&
1451da177e4SLinus Torvalds (temp5 == 'A') &&
1461da177e4SLinus Torvalds (temp6 == 'Q')) {
1471da177e4SLinus Torvalds result = 1;
1481da177e4SLinus Torvalds }
14966bef8c0SHarvey Harrison dbg("%s - returned %d\n", __func__, result);
1501da177e4SLinus Torvalds return result;
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds
access_EV(u16 operation,u8 * ev_name,u8 * buffer,u32 * buf_size)1541da177e4SLinus Torvalds static u32 access_EV(u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds unsigned long flags;
1571da177e4SLinus Torvalds int op = operation;
1581da177e4SLinus Torvalds int ret_val;
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds if (!compaq_int15_entry_point)
1611da177e4SLinus Torvalds return -ENODEV;
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds spin_lock_irqsave(&int15_lock, flags);
1641da177e4SLinus Torvalds __asm__ (
1651da177e4SLinus Torvalds "xorl %%ebx,%%ebx\n" \
1661da177e4SLinus Torvalds "xorl %%edx,%%edx\n" \
1671da177e4SLinus Torvalds "pushf\n" \
1681da177e4SLinus Torvalds "push %%cs\n" \
1691da177e4SLinus Torvalds "cli\n" \
1701da177e4SLinus Torvalds "call *%6\n"
1711da177e4SLinus Torvalds : "=c" (*buf_size), "=a" (ret_val)
1721da177e4SLinus Torvalds : "a" (op), "c" (*buf_size), "S" (ev_name),
1731da177e4SLinus Torvalds "D" (buffer), "m" (compaq_int15_entry_point)
1741da177e4SLinus Torvalds : "%ebx", "%edx");
1751da177e4SLinus Torvalds spin_unlock_irqrestore(&int15_lock, flags);
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds return((ret_val & 0xFF00) >> 8);
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds /*
1821da177e4SLinus Torvalds * load_HRT
1831da177e4SLinus Torvalds *
1841da177e4SLinus Torvalds * Read the hot plug Resource Table from NVRAM
1851da177e4SLinus Torvalds */
load_HRT(void __iomem * rom_start)1861da177e4SLinus Torvalds static int load_HRT(void __iomem *rom_start)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds u32 available;
1891da177e4SLinus Torvalds u32 temp_dword;
1901da177e4SLinus Torvalds u8 temp_byte = 0xFF;
1911da177e4SLinus Torvalds u32 rc;
1921da177e4SLinus Torvalds
193656f978fSQuentin Lambert if (!check_for_compaq_ROM(rom_start))
1941da177e4SLinus Torvalds return -ENODEV;
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds available = 1024;
1971da177e4SLinus Torvalds
198427438c6SAlex Chiang /* Now load the EV */
1991da177e4SLinus Torvalds temp_dword = available;
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
2021da177e4SLinus Torvalds
2031da177e4SLinus Torvalds evbuffer_length = temp_dword;
2041da177e4SLinus Torvalds
205427438c6SAlex Chiang /* We're maintaining the resource lists so write FF to invalidate old
206427438c6SAlex Chiang * info
207427438c6SAlex Chiang */
2081da177e4SLinus Torvalds temp_dword = 1;
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds return rc;
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds
2151da177e4SLinus Torvalds
2161da177e4SLinus Torvalds /*
2171da177e4SLinus Torvalds * store_HRT
2181da177e4SLinus Torvalds *
2191da177e4SLinus Torvalds * Save the hot plug Resource Table in NVRAM
2201da177e4SLinus Torvalds */
store_HRT(void __iomem * rom_start)2211da177e4SLinus Torvalds static u32 store_HRT(void __iomem *rom_start)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds u32 *buffer;
2241da177e4SLinus Torvalds u32 *pFill;
2251da177e4SLinus Torvalds u32 usedbytes;
2261da177e4SLinus Torvalds u32 available;
2271da177e4SLinus Torvalds u32 temp_dword;
2281da177e4SLinus Torvalds u32 rc;
2291da177e4SLinus Torvalds u8 loop;
2301da177e4SLinus Torvalds u8 numCtrl = 0;
2311da177e4SLinus Torvalds struct controller *ctrl;
2321da177e4SLinus Torvalds struct pci_resource *resNode;
2331da177e4SLinus Torvalds struct ev_hrt_header *p_EV_header;
2341da177e4SLinus Torvalds struct ev_hrt_ctrl *p_ev_ctrl;
2351da177e4SLinus Torvalds
2361da177e4SLinus Torvalds available = 1024;
2371da177e4SLinus Torvalds
238656f978fSQuentin Lambert if (!check_for_compaq_ROM(rom_start))
2391da177e4SLinus Torvalds return(1);
2401da177e4SLinus Torvalds
2411da177e4SLinus Torvalds buffer = (u32 *) evbuffer;
2421da177e4SLinus Torvalds
2431da177e4SLinus Torvalds if (!buffer)
2441da177e4SLinus Torvalds return(1);
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds pFill = buffer;
2471da177e4SLinus Torvalds usedbytes = 0;
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds p_EV_header = (struct ev_hrt_header *) pFill;
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds ctrl = cpqhp_ctrl_list;
2521da177e4SLinus Torvalds
253427438c6SAlex Chiang /* The revision of this structure */
2541da177e4SLinus Torvalds rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available);
2551da177e4SLinus Torvalds if (rc)
2561da177e4SLinus Torvalds return(rc);
2571da177e4SLinus Torvalds
258427438c6SAlex Chiang /* The number of controllers */
2591da177e4SLinus Torvalds rc = add_byte(&pFill, 1, &usedbytes, &available);
2601da177e4SLinus Torvalds if (rc)
2611da177e4SLinus Torvalds return(rc);
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds while (ctrl) {
2641da177e4SLinus Torvalds p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds numCtrl++;
2671da177e4SLinus Torvalds
268427438c6SAlex Chiang /* The bus number */
2691da177e4SLinus Torvalds rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available);
2701da177e4SLinus Torvalds if (rc)
2711da177e4SLinus Torvalds return(rc);
2721da177e4SLinus Torvalds
273427438c6SAlex Chiang /* The device Number */
2741da177e4SLinus Torvalds rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
2751da177e4SLinus Torvalds if (rc)
2761da177e4SLinus Torvalds return(rc);
2771da177e4SLinus Torvalds
278427438c6SAlex Chiang /* The function Number */
2791da177e4SLinus Torvalds rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
2801da177e4SLinus Torvalds if (rc)
2811da177e4SLinus Torvalds return(rc);
2821da177e4SLinus Torvalds
283427438c6SAlex Chiang /* Skip the number of available entries */
2841da177e4SLinus Torvalds rc = add_dword(&pFill, 0, &usedbytes, &available);
2851da177e4SLinus Torvalds if (rc)
2861da177e4SLinus Torvalds return(rc);
2871da177e4SLinus Torvalds
288427438c6SAlex Chiang /* Figure out memory Available */
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvalds resNode = ctrl->mem_head;
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds loop = 0;
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds while (resNode) {
2951da177e4SLinus Torvalds loop++;
2961da177e4SLinus Torvalds
297427438c6SAlex Chiang /* base */
2981da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
2991da177e4SLinus Torvalds if (rc)
3001da177e4SLinus Torvalds return(rc);
3011da177e4SLinus Torvalds
302427438c6SAlex Chiang /* length */
3031da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
3041da177e4SLinus Torvalds if (rc)
3051da177e4SLinus Torvalds return(rc);
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds resNode = resNode->next;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds
310427438c6SAlex Chiang /* Fill in the number of entries */
3111da177e4SLinus Torvalds p_ev_ctrl->mem_avail = loop;
3121da177e4SLinus Torvalds
313427438c6SAlex Chiang /* Figure out prefetchable memory Available */
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds resNode = ctrl->p_mem_head;
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds loop = 0;
3181da177e4SLinus Torvalds
3191da177e4SLinus Torvalds while (resNode) {
3201da177e4SLinus Torvalds loop++;
3211da177e4SLinus Torvalds
322427438c6SAlex Chiang /* base */
3231da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
3241da177e4SLinus Torvalds if (rc)
3251da177e4SLinus Torvalds return(rc);
3261da177e4SLinus Torvalds
327427438c6SAlex Chiang /* length */
3281da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
3291da177e4SLinus Torvalds if (rc)
3301da177e4SLinus Torvalds return(rc);
3311da177e4SLinus Torvalds
3321da177e4SLinus Torvalds resNode = resNode->next;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds
335427438c6SAlex Chiang /* Fill in the number of entries */
3361da177e4SLinus Torvalds p_ev_ctrl->p_mem_avail = loop;
3371da177e4SLinus Torvalds
338427438c6SAlex Chiang /* Figure out IO Available */
3391da177e4SLinus Torvalds
3401da177e4SLinus Torvalds resNode = ctrl->io_head;
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds loop = 0;
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds while (resNode) {
3451da177e4SLinus Torvalds loop++;
3461da177e4SLinus Torvalds
347427438c6SAlex Chiang /* base */
3481da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
3491da177e4SLinus Torvalds if (rc)
3501da177e4SLinus Torvalds return(rc);
3511da177e4SLinus Torvalds
352427438c6SAlex Chiang /* length */
3531da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
3541da177e4SLinus Torvalds if (rc)
3551da177e4SLinus Torvalds return(rc);
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds resNode = resNode->next;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds
360427438c6SAlex Chiang /* Fill in the number of entries */
3611da177e4SLinus Torvalds p_ev_ctrl->io_avail = loop;
3621da177e4SLinus Torvalds
363427438c6SAlex Chiang /* Figure out bus Available */
3641da177e4SLinus Torvalds
3651da177e4SLinus Torvalds resNode = ctrl->bus_head;
3661da177e4SLinus Torvalds
3671da177e4SLinus Torvalds loop = 0;
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvalds while (resNode) {
3701da177e4SLinus Torvalds loop++;
3711da177e4SLinus Torvalds
372427438c6SAlex Chiang /* base */
3731da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
3741da177e4SLinus Torvalds if (rc)
3751da177e4SLinus Torvalds return(rc);
3761da177e4SLinus Torvalds
377427438c6SAlex Chiang /* length */
3781da177e4SLinus Torvalds rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
3791da177e4SLinus Torvalds if (rc)
3801da177e4SLinus Torvalds return(rc);
3811da177e4SLinus Torvalds
3821da177e4SLinus Torvalds resNode = resNode->next;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds
385427438c6SAlex Chiang /* Fill in the number of entries */
3861da177e4SLinus Torvalds p_ev_ctrl->bus_avail = loop;
3871da177e4SLinus Torvalds
3881da177e4SLinus Torvalds ctrl = ctrl->next;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds p_EV_header->num_of_ctrl = numCtrl;
3921da177e4SLinus Torvalds
393427438c6SAlex Chiang /* Now store the EV */
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds temp_dword = usedbytes;
3961da177e4SLinus Torvalds
3971da177e4SLinus Torvalds rc = access_EV(WRITE_EV, "CQTHPS", (u8 *) buffer, &temp_dword);
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds evbuffer_length = temp_dword;
4021da177e4SLinus Torvalds
4031da177e4SLinus Torvalds if (rc) {
4041da177e4SLinus Torvalds err(msg_unable_to_save);
4051da177e4SLinus Torvalds return(1);
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds return(0);
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds
compaq_nvram_init(void __iomem * rom_start)4121da177e4SLinus Torvalds void compaq_nvram_init(void __iomem *rom_start)
4131da177e4SLinus Torvalds {
414656f978fSQuentin Lambert if (rom_start)
4151da177e4SLinus Torvalds compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
416656f978fSQuentin Lambert
4171da177e4SLinus Torvalds dbg("int15 entry = %p\n", compaq_int15_entry_point);
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds
4201da177e4SLinus Torvalds
compaq_nvram_load(void __iomem * rom_start,struct controller * ctrl)4211da177e4SLinus Torvalds int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds u8 bus, device, function;
4241da177e4SLinus Torvalds u8 nummem, numpmem, numio, numbus;
4251da177e4SLinus Torvalds u32 rc;
4261da177e4SLinus Torvalds u8 *p_byte;
4271da177e4SLinus Torvalds struct pci_resource *mem_node;
4281da177e4SLinus Torvalds struct pci_resource *p_mem_node;
4291da177e4SLinus Torvalds struct pci_resource *io_node;
4301da177e4SLinus Torvalds struct pci_resource *bus_node;
4311da177e4SLinus Torvalds struct ev_hrt_ctrl *p_ev_ctrl;
4321da177e4SLinus Torvalds struct ev_hrt_header *p_EV_header;
4331da177e4SLinus Torvalds
4341da177e4SLinus Torvalds if (!evbuffer_init) {
435427438c6SAlex Chiang /* Read the resource list information in from NVRAM */
4361da177e4SLinus Torvalds if (load_HRT(rom_start))
4371da177e4SLinus Torvalds memset(evbuffer, 0, 1024);
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds evbuffer_init = 1;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds
442427438c6SAlex Chiang /* If we saved information in NVRAM, use it now */
4431da177e4SLinus Torvalds p_EV_header = (struct ev_hrt_header *) evbuffer;
4441da177e4SLinus Torvalds
445427438c6SAlex Chiang /* The following code is for systems where version 1.0 of this
446427438c6SAlex Chiang * driver has been loaded, but doesn't support the hardware.
447427438c6SAlex Chiang * In that case, the driver would incorrectly store something
448427438c6SAlex Chiang * in NVRAM.
449427438c6SAlex Chiang */
4501da177e4SLinus Torvalds if ((p_EV_header->Version == 2) ||
4511da177e4SLinus Torvalds ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
4521da177e4SLinus Torvalds p_byte = &(p_EV_header->next);
4531da177e4SLinus Torvalds
4541da177e4SLinus Torvalds p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
4551da177e4SLinus Torvalds
4561da177e4SLinus Torvalds p_byte += 3;
4571da177e4SLinus Torvalds
4581da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
4591da177e4SLinus Torvalds return 2;
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds bus = p_ev_ctrl->bus;
4621da177e4SLinus Torvalds device = p_ev_ctrl->device;
4631da177e4SLinus Torvalds function = p_ev_ctrl->function;
4641da177e4SLinus Torvalds
4651da177e4SLinus Torvalds while ((bus != ctrl->bus) ||
4661da177e4SLinus Torvalds (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
4671da177e4SLinus Torvalds (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
4681da177e4SLinus Torvalds nummem = p_ev_ctrl->mem_avail;
4691da177e4SLinus Torvalds numpmem = p_ev_ctrl->p_mem_avail;
4701da177e4SLinus Torvalds numio = p_ev_ctrl->io_avail;
4711da177e4SLinus Torvalds numbus = p_ev_ctrl->bus_avail;
4721da177e4SLinus Torvalds
4731da177e4SLinus Torvalds p_byte += 4;
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
4761da177e4SLinus Torvalds return 2;
4771da177e4SLinus Torvalds
478427438c6SAlex Chiang /* Skip forward to the next entry */
4791da177e4SLinus Torvalds p_byte += (nummem + numpmem + numio + numbus) * 8;
4801da177e4SLinus Torvalds
4811da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
4821da177e4SLinus Torvalds return 2;
4831da177e4SLinus Torvalds
4841da177e4SLinus Torvalds p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
4851da177e4SLinus Torvalds
4861da177e4SLinus Torvalds p_byte += 3;
4871da177e4SLinus Torvalds
4881da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
4891da177e4SLinus Torvalds return 2;
4901da177e4SLinus Torvalds
4911da177e4SLinus Torvalds bus = p_ev_ctrl->bus;
4921da177e4SLinus Torvalds device = p_ev_ctrl->device;
4931da177e4SLinus Torvalds function = p_ev_ctrl->function;
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds
4961da177e4SLinus Torvalds nummem = p_ev_ctrl->mem_avail;
4971da177e4SLinus Torvalds numpmem = p_ev_ctrl->p_mem_avail;
4981da177e4SLinus Torvalds numio = p_ev_ctrl->io_avail;
4991da177e4SLinus Torvalds numbus = p_ev_ctrl->bus_avail;
5001da177e4SLinus Torvalds
5011da177e4SLinus Torvalds p_byte += 4;
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
5041da177e4SLinus Torvalds return 2;
5051da177e4SLinus Torvalds
5061da177e4SLinus Torvalds while (nummem--) {
5075cbded58SRobert P. J. Day mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
5081da177e4SLinus Torvalds
5091da177e4SLinus Torvalds if (!mem_node)
5101da177e4SLinus Torvalds break;
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds mem_node->base = *(u32 *)p_byte;
5131da177e4SLinus Torvalds dbg("mem base = %8.8x\n", mem_node->base);
5141da177e4SLinus Torvalds p_byte += 4;
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5171da177e4SLinus Torvalds kfree(mem_node);
5181da177e4SLinus Torvalds return 2;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds mem_node->length = *(u32 *)p_byte;
5221da177e4SLinus Torvalds dbg("mem length = %8.8x\n", mem_node->length);
5231da177e4SLinus Torvalds p_byte += 4;
5241da177e4SLinus Torvalds
5251da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5261da177e4SLinus Torvalds kfree(mem_node);
5271da177e4SLinus Torvalds return 2;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds
5301da177e4SLinus Torvalds mem_node->next = ctrl->mem_head;
5311da177e4SLinus Torvalds ctrl->mem_head = mem_node;
5321da177e4SLinus Torvalds }
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds while (numpmem--) {
5355cbded58SRobert P. J. Day p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
5361da177e4SLinus Torvalds
5371da177e4SLinus Torvalds if (!p_mem_node)
5381da177e4SLinus Torvalds break;
5391da177e4SLinus Torvalds
5401da177e4SLinus Torvalds p_mem_node->base = *(u32 *)p_byte;
5411da177e4SLinus Torvalds dbg("pre-mem base = %8.8x\n", p_mem_node->base);
5421da177e4SLinus Torvalds p_byte += 4;
5431da177e4SLinus Torvalds
5441da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5451da177e4SLinus Torvalds kfree(p_mem_node);
5461da177e4SLinus Torvalds return 2;
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds
5491da177e4SLinus Torvalds p_mem_node->length = *(u32 *)p_byte;
5501da177e4SLinus Torvalds dbg("pre-mem length = %8.8x\n", p_mem_node->length);
5511da177e4SLinus Torvalds p_byte += 4;
5521da177e4SLinus Torvalds
5531da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5541da177e4SLinus Torvalds kfree(p_mem_node);
5551da177e4SLinus Torvalds return 2;
5561da177e4SLinus Torvalds }
5571da177e4SLinus Torvalds
5581da177e4SLinus Torvalds p_mem_node->next = ctrl->p_mem_head;
5591da177e4SLinus Torvalds ctrl->p_mem_head = p_mem_node;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds
5621da177e4SLinus Torvalds while (numio--) {
5635cbded58SRobert P. J. Day io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds if (!io_node)
5661da177e4SLinus Torvalds break;
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds io_node->base = *(u32 *)p_byte;
5691da177e4SLinus Torvalds dbg("io base = %8.8x\n", io_node->base);
5701da177e4SLinus Torvalds p_byte += 4;
5711da177e4SLinus Torvalds
5721da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5731da177e4SLinus Torvalds kfree(io_node);
5741da177e4SLinus Torvalds return 2;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds
5771da177e4SLinus Torvalds io_node->length = *(u32 *)p_byte;
5781da177e4SLinus Torvalds dbg("io length = %8.8x\n", io_node->length);
5791da177e4SLinus Torvalds p_byte += 4;
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
5821da177e4SLinus Torvalds kfree(io_node);
5831da177e4SLinus Torvalds return 2;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds
5861da177e4SLinus Torvalds io_node->next = ctrl->io_head;
5871da177e4SLinus Torvalds ctrl->io_head = io_node;
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds
5901da177e4SLinus Torvalds while (numbus--) {
5915cbded58SRobert P. J. Day bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
5921da177e4SLinus Torvalds
5931da177e4SLinus Torvalds if (!bus_node)
5941da177e4SLinus Torvalds break;
5951da177e4SLinus Torvalds
5961da177e4SLinus Torvalds bus_node->base = *(u32 *)p_byte;
5971da177e4SLinus Torvalds p_byte += 4;
5981da177e4SLinus Torvalds
5991da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
6001da177e4SLinus Torvalds kfree(bus_node);
6011da177e4SLinus Torvalds return 2;
6021da177e4SLinus Torvalds }
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds bus_node->length = *(u32 *)p_byte;
6051da177e4SLinus Torvalds p_byte += 4;
6061da177e4SLinus Torvalds
6071da177e4SLinus Torvalds if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
6081da177e4SLinus Torvalds kfree(bus_node);
6091da177e4SLinus Torvalds return 2;
6101da177e4SLinus Torvalds }
6111da177e4SLinus Torvalds
6121da177e4SLinus Torvalds bus_node->next = ctrl->bus_head;
6131da177e4SLinus Torvalds ctrl->bus_head = bus_node;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds
616427438c6SAlex Chiang /* If all of the following fail, we don't have any resources for
617427438c6SAlex Chiang * hot plug add
618427438c6SAlex Chiang */
6191da177e4SLinus Torvalds rc = 1;
6201da177e4SLinus Torvalds rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
6211da177e4SLinus Torvalds rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
6221da177e4SLinus Torvalds rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
6231da177e4SLinus Torvalds rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
6241da177e4SLinus Torvalds
6251da177e4SLinus Torvalds if (rc)
6261da177e4SLinus Torvalds return(rc);
6271da177e4SLinus Torvalds } else {
6281da177e4SLinus Torvalds if ((evbuffer[0] != 0) && (!ctrl->push_flag))
6291da177e4SLinus Torvalds return 1;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds
6321da177e4SLinus Torvalds return 0;
6331da177e4SLinus Torvalds }
6341da177e4SLinus Torvalds
6351da177e4SLinus Torvalds
compaq_nvram_store(void __iomem * rom_start)6361da177e4SLinus Torvalds int compaq_nvram_store(void __iomem *rom_start)
6371da177e4SLinus Torvalds {
6381da177e4SLinus Torvalds int rc = 1;
6391da177e4SLinus Torvalds
6401da177e4SLinus Torvalds if (rom_start == NULL)
6411da177e4SLinus Torvalds return -ENODEV;
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds if (evbuffer_init) {
6441da177e4SLinus Torvalds rc = store_HRT(rom_start);
645656f978fSQuentin Lambert if (rc)
6461da177e4SLinus Torvalds err(msg_unable_to_save);
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds return rc;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds
651