⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpqphp_nvram.c

📁 优龙2410linux2.6.8内核源代码
💻 C
字号:
/* * Compaq Hot Plug Controller Driver * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 IBM Corp. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to <greg@kroah.com> * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <linux/slab.h>#include <linux/workqueue.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/uaccess.h>#include "cpqphp.h"#include "cpqphp_nvram.h"#define ROM_INT15_PHY_ADDR		0x0FF859#define READ_EV				0xD8A4#define WRITE_EV			0xD8A5struct register_foo {	union {		unsigned long lword;		/* eax */		unsigned short word;		/* ax */		struct {			unsigned char low;	/* al */			unsigned char high;	/* ah */		} byte;	} data;	unsigned char opcode;	/* see below */	unsigned long length;	/* if the reg. is a pointer, how much data */} __attribute__ ((packed));struct all_reg {	struct register_foo eax_reg;	struct register_foo ebx_reg;	struct register_foo ecx_reg;	struct register_foo edx_reg;	struct register_foo edi_reg;	struct register_foo esi_reg;	struct register_foo eflags_reg;} __attribute__ ((packed));struct ev_hrt_header {	u8 Version;	u8 num_of_ctrl;	u8 next;};struct ev_hrt_ctrl {	u8 bus;	u8 device;	u8 function;	u8 mem_avail;	u8 p_mem_avail;	u8 io_avail;	u8 bus_avail;	u8 next;};static u8 evbuffer_init;static u8 evbuffer_length;static u8 evbuffer[1024];static void *compaq_int15_entry_point;static spinlock_t int15_lock;		/* lock for ordering int15_bios_call() *//* This is a series of function that deals with   setting & getting the hotplug resource table in some environment variable.*//* * We really shouldn't be doing this unless there is a _very_ good reason to!!! * greg k-h */static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail){	u8 **tByte;	if ((*used + 1) > *avail)		return(1);		*((u8*)*p_buffer) = value;	tByte = (u8**)p_buffer;	(*tByte)++;	*used+=1;	return(0);}static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail){	if ((*used + 4) > *avail)		return(1);	**p_buffer = value;	(*p_buffer)++;	*used+=4;	return(0);}/* * check_for_compaq_ROM * * this routine verifies that the ROM OEM string is 'COMPAQ' * * returns 0 for non-Compaq ROM, 1 for Compaq ROM */static int check_for_compaq_ROM (void *rom_start){	u8 temp1, temp2, temp3, temp4, temp5, temp6;	int result = 0;	temp1 = readb(rom_start + 0xffea + 0);	temp2 = readb(rom_start + 0xffea + 1);	temp3 = readb(rom_start + 0xffea + 2);	temp4 = readb(rom_start + 0xffea + 3);	temp5 = readb(rom_start + 0xffea + 4);	temp6 = readb(rom_start + 0xffea + 5);	if ((temp1 == 'C') &&	    (temp2 == 'O') &&	    (temp3 == 'M') &&	    (temp4 == 'P') &&	    (temp5 == 'A') &&	    (temp6 == 'Q')) {		result = 1;	}	dbg ("%s - returned %d\n", __FUNCTION__, result);	return result;}static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size){	unsigned long flags;	int op = operation;	int ret_val;		if (!compaq_int15_entry_point)		return -ENODEV;		spin_lock_irqsave(&int15_lock, flags);	__asm__ (		"xorl   %%ebx,%%ebx\n" \		"xorl    %%edx,%%edx\n" \		"pushf\n" \		"push %%cs\n" \		"cli\n" \		"call *%6\n"		: "=c" (*buf_size), "=a" (ret_val)		: "a" (op), "c" (*buf_size), "S" (ev_name),		"D" (buffer), "m" (compaq_int15_entry_point)		: "%ebx", "%edx");	spin_unlock_irqrestore(&int15_lock, flags);		return((ret_val & 0xFF00) >> 8);}/* * load_HRT * * Read the hot plug Resource Table from NVRAM */static int load_HRT (void *rom_start){	u32 available;	u32 temp_dword;	u8 temp_byte = 0xFF;	u32 rc;	if (!check_for_compaq_ROM(rom_start)) {		return -ENODEV;	}	available = 1024;	// Now load the EV	temp_dword = available;	rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);	evbuffer_length = temp_dword;	// We're maintaining the resource lists so write FF to invalidate old info	temp_dword = 1;	rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);	return rc;}/* * store_HRT * * Save the hot plug Resource Table in NVRAM */static u32 store_HRT (void *rom_start){	u32 *buffer;	u32 *pFill;	u32 usedbytes;	u32 available;	u32 temp_dword;	u32 rc;	u8 loop;	u8 numCtrl = 0;	struct controller *ctrl;	struct pci_resource *resNode;	struct ev_hrt_header *p_EV_header;	struct ev_hrt_ctrl *p_ev_ctrl;	available = 1024;	if (!check_for_compaq_ROM(rom_start)) {		return(1);	}	buffer = (u32*) evbuffer;	if (!buffer)		return(1);	pFill = buffer;	usedbytes = 0;	p_EV_header = (struct ev_hrt_header *) pFill;	ctrl = cpqhp_ctrl_list;		// The revision of this structure	rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);	if (rc)		return(rc);	// The number of controllers	rc = add_byte( &pFill, 1, &usedbytes, &available);	if (rc)		return(rc);	while (ctrl) {		p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;		numCtrl++;		// The bus number		rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);		if (rc)			return(rc);		// The device Number		rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);		if (rc)			return(rc);		// The function Number		rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);		if (rc)			return(rc);		// Skip the number of available entries		rc = add_dword( &pFill, 0, &usedbytes, &available);		if (rc)			return(rc);		// Figure out memory Available		resNode = ctrl->mem_head;		loop = 0;		while (resNode) {			loop ++;			// base			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);			if (rc)				return(rc);			// length			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);			if (rc)				return(rc);			resNode = resNode->next;		}		// Fill in the number of entries		p_ev_ctrl->mem_avail = loop;		// Figure out prefetchable memory Available		resNode = ctrl->p_mem_head;		loop = 0;		while (resNode) {			loop ++;			// base			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);			if (rc)				return(rc);			// length			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);			if (rc)				return(rc);			resNode = resNode->next;		}		// Fill in the number of entries		p_ev_ctrl->p_mem_avail = loop;		// Figure out IO Available		resNode = ctrl->io_head;		loop = 0;		while (resNode) {			loop ++;			// base			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);			if (rc)				return(rc);			// length			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);			if (rc)				return(rc);			resNode = resNode->next;		}		// Fill in the number of entries		p_ev_ctrl->io_avail = loop;		// Figure out bus Available		resNode = ctrl->bus_head;		loop = 0;		while (resNode) {			loop ++;			// base			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);			if (rc)				return(rc);			// length			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);			if (rc)				return(rc);			resNode = resNode->next;		}		// Fill in the number of entries		p_ev_ctrl->bus_avail = loop;		ctrl = ctrl->next;	}		p_EV_header->num_of_ctrl = numCtrl;	// Now store the EV	temp_dword = usedbytes;	rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword);	dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);	evbuffer_length = temp_dword;	if (rc) {		err(msg_unable_to_save);		return(1);	}	return(0);}void compaq_nvram_init (void *rom_start){	if (rom_start) {		compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);	}	dbg("int15 entry  = %p\n", compaq_int15_entry_point);	/* initialize our int15 lock */	spin_lock_init(&int15_lock);}int compaq_nvram_load (void *rom_start, struct controller *ctrl){	u8 bus, device, function;	u8 nummem, numpmem, numio, numbus;	u32 rc;	u8 *p_byte;	struct pci_resource *mem_node;	struct pci_resource *p_mem_node;	struct pci_resource *io_node;	struct pci_resource *bus_node;	struct ev_hrt_ctrl *p_ev_ctrl;	struct ev_hrt_header *p_EV_header;	if (!evbuffer_init) {		// Read the resource list information in from NVRAM		if (load_HRT(rom_start))			memset (evbuffer, 0, 1024);		evbuffer_init = 1;	}	// If we saved information in NVRAM, use it now	p_EV_header = (struct ev_hrt_header *) evbuffer;	// The following code is for systems where version 1.0 of this	// driver has been loaded, but doesn't support the hardware.	// In that case, the driver would incorrectly store something	// in NVRAM.	if ((p_EV_header->Version == 2) ||	    ((p_EV_header->Version == 1) && !ctrl->push_flag)) {		p_byte = &(p_EV_header->next);		p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);		p_byte += 3;		if (p_byte > ((u8*)p_EV_header + evbuffer_length))			return 2;		bus = p_ev_ctrl->bus;		device = p_ev_ctrl->device;		function = p_ev_ctrl->function;		while ((bus != ctrl->bus) ||		       (device != PCI_SLOT(ctrl->pci_dev->devfn)) || 		       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {			nummem = p_ev_ctrl->mem_avail;			numpmem = p_ev_ctrl->p_mem_avail;			numio = p_ev_ctrl->io_avail;			numbus = p_ev_ctrl->bus_avail;			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length))				return 2;			// Skip forward to the next entry			p_byte += (nummem + numpmem + numio + numbus) * 8;			if (p_byte > ((u8*)p_EV_header + evbuffer_length))				return 2;			p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;			p_byte += 3;			if (p_byte > ((u8*)p_EV_header + evbuffer_length))				return 2;			bus = p_ev_ctrl->bus;			device = p_ev_ctrl->device;			function = p_ev_ctrl->function;		}		nummem = p_ev_ctrl->mem_avail;		numpmem = p_ev_ctrl->p_mem_avail;		numio = p_ev_ctrl->io_avail;		numbus = p_ev_ctrl->bus_avail;		p_byte += 4;		if (p_byte > ((u8*)p_EV_header + evbuffer_length))			return 2;		while (nummem--) {			mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!mem_node)				break;			mem_node->base = *(u32*)p_byte;			dbg("mem base = %8.8x\n",mem_node->base);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(mem_node);				return 2;			}			mem_node->length = *(u32*)p_byte;			dbg("mem length = %8.8x\n",mem_node->length);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(mem_node);				return 2;			}			mem_node->next = ctrl->mem_head;			ctrl->mem_head = mem_node;		}		while (numpmem--) {			p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!p_mem_node)				break;			p_mem_node->base = *(u32*)p_byte;			dbg("pre-mem base = %8.8x\n",p_mem_node->base);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(p_mem_node);				return 2;			}			p_mem_node->length = *(u32*)p_byte;			dbg("pre-mem length = %8.8x\n",p_mem_node->length);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(p_mem_node);				return 2;			}			p_mem_node->next = ctrl->p_mem_head;			ctrl->p_mem_head = p_mem_node;		}		while (numio--) {			io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!io_node)				break;			io_node->base = *(u32*)p_byte;			dbg("io base = %8.8x\n",io_node->base);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(io_node);				return 2;			}			io_node->length = *(u32*)p_byte;			dbg("io length = %8.8x\n",io_node->length);			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(io_node);				return 2;			}			io_node->next = ctrl->io_head;			ctrl->io_head = io_node;		}		while (numbus--) {			bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!bus_node)				break;			bus_node->base = *(u32*)p_byte;			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(bus_node);				return 2;			}			bus_node->length = *(u32*)p_byte;			p_byte += 4;			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {				kfree(bus_node);				return 2;			}			bus_node->next = ctrl->bus_head;			ctrl->bus_head = bus_node;		}		// If all of the following fail, we don't have any resources for		// hot plug add		rc = 1;		rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));		rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));		rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));		rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));		if (rc)			return(rc);	} else {		if ((evbuffer[0] != 0) && (!ctrl->push_flag)) 			return 1;	}	return 0;}	int compaq_nvram_store (void *rom_start){	int rc = 1;	if (rom_start == NULL)		return -ENODEV;	if (evbuffer_init) {		rc = store_HRT(rom_start);		if (rc) {			err(msg_unable_to_save);		}	}	return rc;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -