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

📄 acpiphp_glue.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
		return;	}	bridge->pci_bus = bridge->pci_dev->subordinate;	if (!bridge->pci_bus) {		err("This is not a PCI-to-PCI bridge!\n");		kfree(bridge);		return;	}	spin_lock_init(&bridge->res_lock);	bridge->bus = bridge->pci_bus->number;	bridge->sub = bridge->pci_bus->subordinate;	/*	 * decode resources under this P2P bridge	 */	/* I/O resources */	pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);	base = tmp8;	pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);	limit = tmp8;	switch (base & PCI_IO_RANGE_TYPE_MASK) {	case PCI_IO_RANGE_TYPE_16:		base = (base << 8) & 0xf000;		limit = ((limit << 8) & 0xf000) + 0xfff;		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);		if (!bridge->io_head) {			err("out of memory\n");			kfree(bridge);			return;		}		dbg("16bit I/O range: %04x-%04x\n",		    (u32)bridge->io_head->base,		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));		break;	case PCI_IO_RANGE_TYPE_32:		pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);		base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);		pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);		if (!bridge->io_head) {			err("out of memory\n");			kfree(bridge);			return;		}		dbg("32bit I/O range: %08x-%08x\n",		    (u32)bridge->io_head->base,		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));		break;	case 0x0f:		dbg("I/O space unsupported\n");		break;	default:		warn("Unknown I/O range type\n");	}	/* Memory resources (mandatory for P2P bridge) */	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);	base = (tmp16 & 0xfff0) << 16;	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);	if (!bridge->mem_head) {		err("out of memory\n");		kfree(bridge);		return;	}	dbg("32bit Memory range: %08x-%08x\n",	    (u32)bridge->mem_head->base,	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));	/* Prefetchable Memory resources (optional) */	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);	base = tmp16;	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);	limit = tmp16;	switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {	case PCI_PREF_RANGE_TYPE_32:		base = (base & 0xfff0) << 16;		limit = ((limit & 0xfff0) << 16) | 0xfffff;		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);		if (!bridge->p_mem_head) {			err("out of memory\n");			kfree(bridge);			return;		}		dbg("32bit Prefetchable memory range: %08x-%08x\n",		    (u32)bridge->p_mem_head->base,		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));		break;	case PCI_PREF_RANGE_TYPE_64:		pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);		pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);		base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);		limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);		if (!bridge->p_mem_head) {			err("out of memory\n");			kfree(bridge);			return;		}		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",		    (u32)(bridge->p_mem_head->base >> 32),		    (u32)(bridge->p_mem_head->base & 0xffffffff),		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));		break;	case 0x0f:		break;	default:		warn("Unknown prefetchale memory type\n");	}	init_bridge_misc(bridge);}/* callback routine to find P2P bridges */static acpi_statusfind_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv){	acpi_status status;	acpi_handle dummy_handle;	unsigned long *segbus = context;	unsigned long tmp;	int seg, bus, device, function;	struct pci_dev *dev;	/* get PCI address */	seg = (*segbus >> 8) & 0xff;	bus = *segbus & 0xff;	status = acpi_get_handle(handle, "_ADR", &dummy_handle);	if (ACPI_FAILURE(status))		return AE_OK;		/* continue */	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);	if (ACPI_FAILURE(status)) {		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);		return AE_OK;	}	device = (tmp >> 16) & 0xffff;	function = tmp & 0xffff;	dev = pci_find_slot(bus, PCI_DEVFN(device, function));	if (!dev)		return AE_OK;	if (!dev->subordinate)		return AE_OK;	/* check if this bridge has ejectable slots */	if (detect_ejectable_slots(handle) > 0) {		dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));		add_p2p_bridge(handle, seg, bus, device, function);	}	return AE_OK;}/* find hot-pluggable slots, and then find P2P bridge */static int add_bridge(acpi_handle handle){	acpi_status status;	unsigned long tmp;	int seg, bus;	acpi_handle dummy_handle;	/* if the bridge doesn't have _STA, we assume it is always there */	status = acpi_get_handle(handle, "_STA", &dummy_handle);	if (ACPI_SUCCESS(status)) {		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);		if (ACPI_FAILURE(status)) {			dbg("%s: _STA evaluation failure\n", __FUNCTION__);			return 0;		}		if ((tmp & ACPI_STA_FUNCTIONING) == 0)			/* don't register this object */			return 0;	}	/* get PCI segment number */	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);	seg = ACPI_SUCCESS(status) ? tmp : 0;	/* get PCI bus number */	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);	if (ACPI_SUCCESS(status)) {		bus = tmp;	} else {		warn("can't get bus number, assuming 0\n");		bus = 0;	}	/* check if this bridge has ejectable slots */	if (detect_ejectable_slots(handle) > 0) {		dbg("found PCI host-bus bridge with hot-pluggable slots\n");		add_host_bridge(handle, seg, bus);		return 0;	}	tmp = seg << 8 | bus;	/* search P2P bridges under this host bridge */	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,				     find_p2p_bridge, &tmp, NULL);	if (ACPI_FAILURE(status))		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);	return 0;}static void remove_bridge(acpi_handle handle){	/* No-op for now .. */}static int power_on_slot(struct acpiphp_slot *slot){	acpi_status status;	struct acpiphp_func *func;	struct list_head *l;	int retval = 0;	/* if already enabled, just skip */	if (slot->flags & SLOT_POWEREDON)		goto err_exit;	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		if (func->flags & FUNC_HAS_PS0) {			dbg("%s: executing _PS0\n", __FUNCTION__);			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);			if (ACPI_FAILURE(status)) {				warn("%s: _PS0 failed\n", __FUNCTION__);				retval = -1;				goto err_exit;			} else				break;		}	}	/* TBD: evaluate _STA to check if the slot is enabled */	slot->flags |= SLOT_POWEREDON; err_exit:	return retval;}static int power_off_slot(struct acpiphp_slot *slot){	acpi_status status;	struct acpiphp_func *func;	struct list_head *l;	struct acpi_object_list arg_list;	union acpi_object arg;	int retval = 0;	/* if already disabled, just skip */	if ((slot->flags & SLOT_POWEREDON) == 0)		goto err_exit;	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);			if (ACPI_FAILURE(status)) {				warn("%s: _PS3 failed\n", __FUNCTION__);				retval = -1;				goto err_exit;			} else				break;		}	}	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		/* We don't want to call _EJ0 on non-existing functions. */		if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {			/* _EJ0 method take one argument */			arg_list.count = 1;			arg_list.pointer = &arg;			arg.type = ACPI_TYPE_INTEGER;			arg.integer.value = 1;			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);			if (ACPI_FAILURE(status)) {				warn("%s: _EJ0 failed\n", __FUNCTION__);				retval = -1;				goto err_exit;			} else				break;		}	}	/* TBD: evaluate _STA to check if the slot is disabled */	slot->flags &= (~SLOT_POWEREDON); err_exit:	return retval;}/** * enable_device - enable, configure a slot * @slot: slot to be enabled * * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. * */static int enable_device(struct acpiphp_slot *slot){	u8 bus;	struct pci_dev *dev;	struct pci_bus *child;	struct list_head *l;	struct acpiphp_func *func;	int retval = 0;	int num;	if (slot->flags & SLOT_ENABLED)		goto err_exit;	/* sanity check: dev should be NULL when hot-plugged in */	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));	if (dev) {		/* This case shouldn't happen */		err("pci_dev structure already exists.\n");		retval = -1;		goto err_exit;	}	/* allocate resources to device */	retval = acpiphp_configure_slot(slot);	if (retval)		goto err_exit;	/* returned `dev' is the *first function* only! */	num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));	if (num)		pci_bus_add_devices(slot->bridge->pci_bus);	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));	if (!dev) {		err("No new device found\n");		retval = -1;		goto err_exit;	}	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);		child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);		pci_do_scan_bus(child);	}	/* associate pci_dev to our representation */	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		func->pci_dev = pci_find_slot(slot->bridge->bus,					      PCI_DEVFN(slot->device,							func->function));		if (!func->pci_dev)			continue;		/* configure device */		retval = acpiphp_configure_function(func);		if (retval)			goto err_exit;	}	slot->flags |= SLOT_ENABLED;	dbg("Available resources:\n");	acpiphp_dump_resource(slot->bridge); err_exit:	return retval;}/** * disable_device - disable a slot */static int disable_device(struct acpiphp_slot *slot){	int retval = 0;	struct acpiphp_func *func;	struct list_head *l;	/* is this slot already disabled? */	if (!(slot->flags & SLOT_ENABLED))		goto err_exit;	list_for_each (l, &slot->funcs) {		func = list_entry(l, struct acpiphp_func, sibling);		if (func->pci_dev)			acpiphp_unconfigure_function(func);	}	slot->flags &= (~SLOT_ENABLED); err_exit:	return retval;}/** * get_slot_status - get ACPI slot status * * if a slot has _STA for each function and if any one of them * returned non-zero status, return it * * if a slot doesn't have _STA and if any one of its functions' * configuration space is configured, return 0x0f as a _STA * * otherwise return 0 */static unsigned int get_slot_status(struct acpiphp_slot *slot){	acpi_status status;	unsigned long sta = 0;	u32 dvid;	struct list_head *l;	struct acpiphp_func *func;

⌨️ 快捷键说明

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