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

📄 acpiphp_pci.c

📁 h内核
💻 C
字号:
/* * ACPI PCI HotPlug PCI configuration space management * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2002 IBM Corp. * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002 NEC 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 <t-kochi@bq.jp.nec.com> * */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/acpi.h>#include "../pci.h"#include "pci_hotplug.h"#include "acpiphp.h"#define MY_NAME "acpiphp_pci"/* allocate mem/pmem/io resource to a new function */static int init_config_space (struct acpiphp_func *func){	u32 bar, len;	u32 address[] = {		PCI_BASE_ADDRESS_0,		PCI_BASE_ADDRESS_1,		PCI_BASE_ADDRESS_2,		PCI_BASE_ADDRESS_3,		PCI_BASE_ADDRESS_4,		PCI_BASE_ADDRESS_5,		0	};	int count;	struct acpiphp_bridge *bridge;	struct pci_resource *res;	struct pci_bus *pbus;	int bus, device, function;	unsigned int devfn;	u16 tmp;	bridge = func->slot->bridge;	pbus = bridge->pci_bus;	bus = bridge->bus;	device = func->slot->device;	function = func->function;	devfn = PCI_DEVFN(device, function);	for (count = 0; address[count]; count++) {	/* for 6 BARs */		pci_bus_write_config_dword(pbus, devfn,					   address[count], 0xFFFFFFFF);		pci_bus_read_config_dword(pbus, devfn, address[count], &bar);		if (!bar)	/* This BAR is not implemented */			continue;		dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {			/* This is IO */			len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);			len = len & ~(len - 1);			dbg("len in IO %x, BAR %d\n", len, count);			spin_lock(&bridge->res_lock);			res = acpiphp_get_io_resource(&bridge->io_head, len);			spin_unlock(&bridge->res_lock);			if (!res) {				err("cannot allocate requested io for %02x:%02x.%d len %x\n",				    bus, device, function, len);				return -1;			}			pci_bus_write_config_dword(pbus, devfn,						   address[count],						   (u32)res->base);			res->next = func->io_head;			func->io_head = res;		} else {			/* This is Memory */			if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {				/* pfmem */				len = bar & 0xFFFFFFF0;				len = ~len + 1;				dbg("len in PFMEM %x, BAR %d\n", len, count);				spin_lock(&bridge->res_lock);				res = acpiphp_get_resource(&bridge->p_mem_head, len);				spin_unlock(&bridge->res_lock);				if (!res) {					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",					    bus, device, function, len);					return -1;				}				pci_bus_write_config_dword(pbus, devfn,							   address[count],							   (u32)res->base);				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */					dbg("inside the pfmem 64 case, count %d\n", count);					count += 1;					pci_bus_write_config_dword(pbus, devfn,								   address[count],								   (u32)(res->base >> 32));				}				res->next = func->p_mem_head;				func->p_mem_head = res;			} else {				/* regular memory */				len = bar & 0xFFFFFFF0;				len = ~len + 1;				dbg("len in MEM %x, BAR %d\n", len, count);				spin_lock(&bridge->res_lock);				res = acpiphp_get_resource(&bridge->mem_head, len);				spin_unlock(&bridge->res_lock);				if (!res) {					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",					    bus, device, function, len);					return -1;				}				pci_bus_write_config_dword(pbus, devfn,							   address[count],							   (u32)res->base);				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {					/* takes up another dword */					dbg("inside mem 64 case, reg. mem, count %d\n", count);					count += 1;					pci_bus_write_config_dword(pbus, devfn,								   address[count],								   (u32)(res->base >> 32));				}				res->next = func->mem_head;				func->mem_head = res;			}		}	}	/* disable expansion rom */	pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000);	/* set PCI parameters from _HPP */	pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE,				  bridge->hpp.cache_line_size);	pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER,				  bridge->hpp.latency_timer);	pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp);	if (bridge->hpp.enable_SERR)		tmp |= PCI_COMMAND_SERR;	if (bridge->hpp.enable_PERR)		tmp |= PCI_COMMAND_PARITY;	pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp);	return 0;}/* detect_used_resource - subtract resource under dev from bridge */static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev){	int count;	dbg("Device %s\n", pci_name(dev));	for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) {		struct pci_resource *res;		struct pci_resource **head;		unsigned long base = dev->resource[count].start;		unsigned long len = dev->resource[count].end - base + 1;		unsigned long flags = dev->resource[count].flags;		if (!flags)			continue;		dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base,				base + len - 1, flags);		if (flags & IORESOURCE_IO) {			head = &bridge->io_head;		} else if (flags & IORESOURCE_PREFETCH) {			head = &bridge->p_mem_head;		} else {			head = &bridge->mem_head;		}		spin_lock(&bridge->res_lock);		res = acpiphp_get_resource_with_base(head, base, len);		spin_unlock(&bridge->res_lock);		if (res)			kfree(res);	}	return 0;}/** * acpiphp_detect_pci_resource - detect resources under bridge * @bridge: detect all resources already used under this bridge * * collect all resources already allocated for all devices under a bridge. */int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge){	struct list_head *l;	struct pci_dev *dev;	list_for_each (l, &bridge->pci_bus->devices) {		dev = pci_dev_b(l);		detect_used_resource(bridge, dev);	}	return 0;}/** * acpiphp_init_slot_resource - gather resource usage information of a slot * @slot: ACPI slot object to be checked, should have valid pci_dev member * * TBD: PCI-to-PCI bridge case *      use pci_dev->resource[] */int acpiphp_init_func_resource (struct acpiphp_func *func){	u64 base;	u32 bar, len;	u32 address[] = {		PCI_BASE_ADDRESS_0,		PCI_BASE_ADDRESS_1,		PCI_BASE_ADDRESS_2,		PCI_BASE_ADDRESS_3,		PCI_BASE_ADDRESS_4,		PCI_BASE_ADDRESS_5,		0	};	int count;	struct pci_resource *res;	struct pci_dev *dev;	dev = func->pci_dev;	dbg("Hot-pluggable device %s\n", pci_name(dev));	for (count = 0; address[count]; count++) {	/* for 6 BARs */		pci_read_config_dword(dev, address[count], &bar);		if (!bar)	/* This BAR is not implemented */			continue;		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);		pci_read_config_dword(dev, address[count], &len);		if (len & PCI_BASE_ADDRESS_SPACE_IO) {			/* This is IO */			base = bar & 0xFFFFFFFC;			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);			len = len & ~(len - 1);			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);			res = acpiphp_make_resource(base, len);			if (!res)				goto no_memory;			res->next = func->io_head;			func->io_head = res;		} else {			/* This is Memory */			base = bar & 0xFFFFFFF0;			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {				/* pfmem */				len &= 0xFFFFFFF0;				len = ~len + 1;				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */					dbg("prefetch mem 64\n");					count += 1;				}				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);				res = acpiphp_make_resource(base, len);				if (!res)					goto no_memory;				res->next = func->p_mem_head;				func->p_mem_head = res;			} else {				/* regular memory */				len &= 0xFFFFFFF0;				len = ~len + 1;				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {					/* takes up another dword */					dbg("mem 64\n");					count += 1;				}				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);				res = acpiphp_make_resource(base, len);				if (!res)					goto no_memory;				res->next = func->mem_head;				func->mem_head = res;			}		}		pci_write_config_dword(dev, address[count], bar);	}#if 1	acpiphp_dump_func_resource(func);#endif	return 0; no_memory:	err("out of memory\n");	acpiphp_free_resource(&func->io_head);	acpiphp_free_resource(&func->mem_head);	acpiphp_free_resource(&func->p_mem_head);	return -1;}/** * acpiphp_configure_slot - allocate PCI resources * @slot: slot to be configured * * initializes a PCI functions on a device inserted * into the slot * */int acpiphp_configure_slot (struct acpiphp_slot *slot){	struct acpiphp_func *func;	struct list_head *l;	u8 hdr;	u32 dvid;	int retval = 0;	int is_multi = 0;	pci_bus_read_config_byte(slot->bridge->pci_bus,				 PCI_DEVFN(slot->device, 0),				 PCI_HEADER_TYPE, &hdr);	if (hdr & 0x80)		is_multi = 1;	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		if (is_multi || func->function == 0) {			pci_bus_read_config_dword(slot->bridge->pci_bus,						  PCI_DEVFN(slot->device,							    func->function),						  PCI_VENDOR_ID, &dvid);			if (dvid != 0xffffffff) {				retval = init_config_space(func);				if (retval)					break;			}		}	}	return retval;}/** * acpiphp_configure_function - configure PCI function * @func: function to be configured * * initializes a PCI functions on a device inserted * into the slot * */int acpiphp_configure_function (struct acpiphp_func *func){	/* all handled by the pci core now */	return 0;}/** * acpiphp_unconfigure_function - unconfigure PCI function * @func: function to be unconfigured * */void acpiphp_unconfigure_function (struct acpiphp_func *func){	struct acpiphp_bridge *bridge;	/* if pci_dev is NULL, ignore it */	if (!func->pci_dev)		return;	pci_remove_bus_device(func->pci_dev);	/* free all resources */	bridge = func->slot->bridge;	spin_lock(&bridge->res_lock);	acpiphp_move_resource(&func->io_head, &bridge->io_head);	acpiphp_move_resource(&func->mem_head, &bridge->mem_head);	acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);	acpiphp_move_resource(&func->bus_head, &bridge->bus_head);	spin_unlock(&bridge->res_lock);}

⌨️ 快捷键说明

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