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

📄 shpchprm_acpi.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform * * Copyright (C) 2003-2004 Intel Corporation * * 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 <dely.l.sy@intel.com> * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/acpi.h>#include <linux/efi.h>#include <asm/uaccess.h>#include <asm/system.h>#ifdef	CONFIG_IA64#include <asm/iosapic.h>#endif#include <acpi/acpi.h>#include <acpi/acpi_bus.h>#include <acpi/actypes.h>#include "shpchp.h"#include "shpchprm.h"#define	PCI_MAX_BUS		0x100#define	ACPI_STA_DEVICE_PRESENT	0x01#define	METHOD_NAME__SUN	"_SUN"#define	METHOD_NAME__HPP	"_HPP"#define	METHOD_NAME_OSHP	"OSHP"#define	PHP_RES_BUS		0xA0#define	PHP_RES_IO		0xA1#define	PHP_RES_MEM		0xA2#define	PHP_RES_PMEM		0xA3#define	BRIDGE_TYPE_P2P		0x00#define	BRIDGE_TYPE_HOST	0x01/* this should go to drivers/acpi/include/ */struct acpi__hpp {	u8	cache_line_size;	u8	latency_timer;	u8	enable_serr;	u8	enable_perr;};struct acpi_php_slot {	struct acpi_php_slot	*next;	struct acpi_bridge	*bridge;	acpi_handle		handle;	int	seg;	int	bus;	int	dev;	int	fun;	u32	sun;	struct pci_resource *mem_head;	struct pci_resource *p_mem_head;	struct pci_resource *io_head;	struct pci_resource *bus_head;	void	*slot_ops;	/* _STA, _EJx, etc */	struct slot *slot;};		/* per func */struct acpi_bridge {	struct acpi_bridge	*parent;	struct acpi_bridge	*next;	struct acpi_bridge	*child;	acpi_handle	handle;	int seg;	int pbus;				/* pdev->bus->number		*/	int pdevice;				/* PCI_SLOT(pdev->devfn)	*/	int pfunction;				/* PCI_DEVFN(pdev->devfn)	*/	int bus;				/* pdev->subordinate->number	*/	struct acpi__hpp		*_hpp;	struct acpi_php_slot	*slots;	struct pci_resource 	*tmem_head;	/* total from crs	*/	struct pci_resource 	*tp_mem_head;	/* total from crs	*/	struct pci_resource 	*tio_head;	/* total from crs	*/	struct pci_resource 	*tbus_head;	/* total from crs	*/	struct pci_resource 	*mem_head;	/* available	*/	struct pci_resource 	*p_mem_head;	/* available	*/	struct pci_resource 	*io_head;	/* available	*/	struct pci_resource 	*bus_head;	/* available	*/	int scanned;	int type;};static struct acpi_bridge *acpi_bridges_head;static u8 * acpi_path_name( acpi_handle	handle){	acpi_status		status;	static u8	path_name[ACPI_PATHNAME_MAX];	struct acpi_buffer		ret_buf = { ACPI_PATHNAME_MAX, path_name };	memset(path_name, 0, sizeof (path_name));	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);	if (ACPI_FAILURE(status))		return NULL;	else		return path_name;	}static void acpi_get__hpp ( struct acpi_bridge	*ab);static void acpi_run_oshp ( struct acpi_bridge	*ab);static int acpi_add_slot_to_php_slots(	struct acpi_bridge	*ab,	int				bus_num,	acpi_handle		handle,	u32				adr,	u32				sun	){	struct acpi_php_slot	*aps;	static long	samesun = -1;	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);	if (!aps) {		err ("acpi_shpchprm: alloc for aps fail\n");		return -1;	}	memset(aps, 0, sizeof(struct acpi_php_slot));	aps->handle = handle;	aps->bus = bus_num;	aps->dev = (adr >> 16) & 0xffff;	aps->fun = adr & 0xffff;	aps->sun = sun;	aps->next = ab->slots;	/* cling to the bridge */	aps->bridge = ab;	ab->slots = aps;	ab->scanned += 1;	if (!ab->_hpp)		acpi_get__hpp(ab);	acpi_run_oshp(ab);	if (sun != samesun) {		info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, 			aps->bus, aps->dev, aps->fun);		samesun = sun;	}	return 0;}static void acpi_get__hpp ( struct acpi_bridge	*ab){	acpi_status		status;	u8			nui[4];	struct acpi_buffer	ret_buf = { 0, NULL};	union acpi_object	*ext_obj, *package;	u8			*path_name = acpi_path_name(ab->handle);	int			i, len = 0;	/* get _hpp */	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);	switch (status) {	case AE_BUFFER_OVERFLOW:		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);		if (!ret_buf.pointer) {			err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name);			return;		}		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);		if (ACPI_SUCCESS(status))			break;	default:		if (ACPI_FAILURE(status)) {			err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status);			return;		}	}	ext_obj = (union acpi_object *) ret_buf.pointer;	if (ext_obj->type != ACPI_TYPE_PACKAGE) {		err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name);		goto free_and_return;	}	len = ext_obj->package.count;	package = (union acpi_object *) ret_buf.pointer;	for ( i = 0; (i < len) || (i < 4); i++) {		ext_obj = (union acpi_object *) &package->package.elements[i];		switch (ext_obj->type) {		case ACPI_TYPE_INTEGER:			nui[i] = (u8)ext_obj->integer.value;			break;		default:			err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name);			goto free_and_return;		}	}	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);	if (!ab->_hpp) {		err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);		goto free_and_return;	}	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));	ab->_hpp->cache_line_size	= nui[0];	ab->_hpp->latency_timer		= nui[1];	ab->_hpp->enable_serr		= nui[2];	ab->_hpp->enable_perr		= nui[3];	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);free_and_return:	kfree(ret_buf.pointer);}static void acpi_run_oshp ( struct acpi_bridge	*ab){	acpi_status		status;	u8			*path_name = acpi_path_name(ab->handle);	struct acpi_buffer	ret_buf = { 0, NULL};	/* run OSHP */	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);	if (ACPI_FAILURE(status)) {		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);	} else		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);	return;}static acpi_status acpi_evaluate_crs(	acpi_handle		handle,	struct acpi_resource	**retbuf	){	acpi_status		status;	struct acpi_buffer		crsbuf;	u8			*path_name = acpi_path_name(handle);	crsbuf.length  = 0;	crsbuf.pointer = NULL;	status = acpi_get_current_resources (handle, &crsbuf);	switch (status) {	case AE_BUFFER_OVERFLOW:		break;		/* found */	case AE_NOT_FOUND:		dbg("acpi_shpchprm:%s _CRS not found\n", path_name);		return status;	default:		err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status);		return status;	}	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);	if (!crsbuf.pointer) {		err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);		return AE_NO_MEMORY;	}	status = acpi_get_current_resources (handle, &crsbuf);	if (ACPI_FAILURE(status)) {		err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status);		kfree(crsbuf.pointer);		return status;	}	*retbuf = crsbuf.pointer;	return status;}static void free_pci_resource ( struct pci_resource	*aprh){	struct pci_resource	*res, *next;	for (res = aprh; res; res = next) {		next = res->next;		kfree(res);	}}static void print_pci_resource ( struct pci_resource	*aprh){	struct pci_resource	*res;	for (res = aprh; res; res = res->next)		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);}static void print_slot_resources( struct acpi_php_slot	*aps){	if (aps->bus_head) {		dbg("    BUS Resources:\n");		print_pci_resource (aps->bus_head);	}	if (aps->io_head) {		dbg("    IO Resources:\n");		print_pci_resource (aps->io_head);	}	if (aps->mem_head) {		dbg("    MEM Resources:\n");		print_pci_resource (aps->mem_head);	}	if (aps->p_mem_head) {		dbg("    PMEM Resources:\n");		print_pci_resource (aps->p_mem_head);	}}static void print_pci_resources( struct acpi_bridge	*ab){	if (ab->tbus_head) {		dbg("    Total BUS Resources:\n");		print_pci_resource (ab->tbus_head);	}	if (ab->bus_head) {		dbg("    BUS Resources:\n");		print_pci_resource (ab->bus_head);	}	if (ab->tio_head) {		dbg("    Total IO Resources:\n");		print_pci_resource (ab->tio_head);	}	if (ab->io_head) {		dbg("    IO Resources:\n");		print_pci_resource (ab->io_head);	}	if (ab->tmem_head) {		dbg("    Total MEM Resources:\n");		print_pci_resource (ab->tmem_head);	}	if (ab->mem_head) {		dbg("    MEM Resources:\n");		print_pci_resource (ab->mem_head);	}	if (ab->tp_mem_head) {		dbg("    Total PMEM Resources:\n");		print_pci_resource (ab->tp_mem_head);	}	if (ab->p_mem_head) {		dbg("    PMEM Resources:\n");		print_pci_resource (ab->p_mem_head);	}	if (ab->_hpp) {		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);	}}static int shpchprm_delete_resource(	struct pci_resource **aprh,	ulong base,	ulong size){	struct pci_resource *res;	struct pci_resource *prevnode;	struct pci_resource *split_node;	ulong tbase;	shpchp_resource_sort_and_combine(aprh);	for (res = *aprh; res; res = res->next) {		if (res->base > base)			continue;		if ((res->base + res->length) < (base + size))			continue;		if (res->base < base) {			tbase = base;			if ((res->length - (tbase - res->base)) < size)				continue;			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!split_node)				return -ENOMEM;			split_node->base = res->base;			split_node->length = tbase - res->base;			res->base = tbase;			res->length -= split_node->length;			split_node->next = res->next;			res->next = split_node;		}		if (res->length >= size) {			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);			if (!split_node)				return -ENOMEM;			split_node->base = res->base + size;			split_node->length = res->length - size;			res->length = size;			split_node->next = res->next;			res->next = split_node;		}		if (*aprh == res) {			*aprh = res->next;		} else {			prevnode = *aprh;			while (prevnode->next != res)				prevnode = prevnode->next;			prevnode->next = res->next;		}		res->next = NULL;		kfree(res);		break;	}	return 0;}static int shpchprm_delete_resources(	struct pci_resource **aprh,	struct pci_resource *this	){	struct pci_resource *res;	for (res = this; res; res = res->next)		shpchprm_delete_resource(aprh, res->base, res->length);	return 0;}static int shpchprm_add_resource(	struct pci_resource **aprh,	ulong base,	ulong size){	struct pci_resource *res;	for (res = *aprh; res; res = res->next) {		if ((res->base + res->length) == base) {			res->length += size;			size = 0L;			break;		}		if (res->next == *aprh)			break;	}	if (size) {		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);		if (!res) {			err ("acpi_shpchprm: alloc for res fail\n");			return -ENOMEM;		}		memset(res, 0, sizeof (struct pci_resource));		res->base = base;		res->length = size;		res->next = *aprh;		*aprh = res;	}	return 0;}static int shpchprm_add_resources(	struct pci_resource **aprh,	struct pci_resource *this	){	struct pci_resource *res;	int	rc = 0;	for (res = this; res && !rc; res = res->next)		rc = shpchprm_add_resource(aprh, res->base, res->length);	return rc;}static void acpi_parse_io (	struct acpi_bridge		*ab,	union acpi_resource_data	*data	){	struct acpi_resource_io	*dataio;	dataio = (struct acpi_resource_io *) data;	dbg("Io Resource\n");	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);	dbg("  Range minimum base: %08X\n", dataio->min_base_address);	dbg("  Range maximum base: %08X\n", dataio->max_base_address);	dbg("  Alignment: %08X\n", dataio->alignment);	dbg("  Range Length: %08X\n", dataio->range_length);}static void acpi_parse_fixed_io (	struct acpi_bridge		*ab,	union acpi_resource_data	*data	){	struct acpi_resource_fixed_io  *datafio;	datafio = (struct acpi_resource_fixed_io *) data;	dbg("Fixed Io Resource\n");	dbg("  Range base address: %08X", datafio->base_address);	dbg("  Range length: %08X", datafio->range_length);}static void acpi_parse_address16_32 (	struct acpi_bridge		*ab,	union acpi_resource_data	*data,	acpi_resource_type		id	){	/* 	 * acpi_resource_address16 == acpi_resource_address32	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;	 */	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;	struct pci_resource **aprh, **tprh;	if (id == ACPI_RSTYPE_ADDRESS16)		dbg("acpi_shpchprm:16-Bit Address Space Resource\n");	else		dbg("acpi_shpchprm:32-Bit Address Space Resource\n");	switch (data32->resource_type) {	case ACPI_MEMORY_RANGE: 		dbg("  Resource Type: Memory Range\n");		aprh = &ab->mem_head;		tprh = &ab->tmem_head;		switch (data32->attribute.memory.cache_attribute) {		case ACPI_NON_CACHEABLE_MEMORY:			dbg("  Type Specific: Noncacheable memory\n");			break; 		case ACPI_CACHABLE_MEMORY:			dbg("  Type Specific: Cacheable memory\n");

⌨️ 快捷键说明

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