Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 789e7dc8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (30 commits)
  [PATCH] PCI Hotplug: Fix recovery path from errors during pcie_init()
  [PATCH] PCI Hotplug: fake NULL pointer dereferences in IBM Hot Plug Controller Driver
  [PATCH] shpchp: Cleanup improper info messages
  [PATCH] shpchp: Remove Unused hpc_evelnt_lock
  [PATCH] shpchp: Cleanup interrupt polling timer
  [PATCH] shpchp: Cleanup SHPC commands
  [PATCH] shpchp: Cleanup interrupt handler
  [PATCH] shpchp: Remove unnecessary hpc_ctlr_handle check
  [PATCH] pciehp: Implement get_address callback
  [PATCH] pciehp: Add missing pci_dev_put
  [PATCH] pciehp: Replace pci_find_slot() with pci_get_slot()
  [PATCH] SGI Hotplug: Incorrect power status
  [PATCH] shpchp: Create shpchpd at controller probe time
  [PATCH] shpchp: Mask Global SERR and Intr at controller release time
  [PATCH] SHPC: Fix SHPC Contoller SERR-INT Register bits access
  [PATCH] SHPC: Fix SHPC Logical Slot Register bits access
  [PATCH] SHPC: Cleanup SHPC Logical Slot Register bits access
  [PATCH] SHPC: Cleanup SHPC Logical Slot Register access
  [PATCH] SHPC: Cleanup SHPC register access
  [PATCH] pciehp: Fix programming hotplug parameters
  ...
parents 28e4b224 9c64f977
Loading
Loading
Loading
Loading
+230 −27
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
@@ -33,10 +34,184 @@
#include <acpi/actypes.h>
#include "pci_hotplug.h"

#define MY_NAME	"acpi_pcihp"

#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)

#define	METHOD_NAME__SUN	"_SUN"
#define	METHOD_NAME__HPP	"_HPP"
#define	METHOD_NAME_OSHP	"OSHP"

static int debug_acpi;

static acpi_status
decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
	int i;
	union acpi_object *fields = record->package.elements;
	u32 revision = fields[1].integer.value;

	switch (revision) {
	case 1:
		if (record->package.count != 6)
			return AE_ERROR;
		for (i = 2; i < 6; i++)
			if (fields[i].type != ACPI_TYPE_INTEGER)
				return AE_ERROR;
		hpx->t0 = &hpx->type0_data;
		hpx->t0->revision        = revision;
		hpx->t0->cache_line_size = fields[2].integer.value;
		hpx->t0->latency_timer   = fields[3].integer.value;
		hpx->t0->enable_serr     = fields[4].integer.value;
		hpx->t0->enable_perr     = fields[5].integer.value;
		break;
	default:
		printk(KERN_WARNING
		       "%s: Type 0 Revision %d record not supported\n",
		       __FUNCTION__, revision);
		return AE_ERROR;
	}
	return AE_OK;
}

static acpi_status
decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
	int i;
	union acpi_object *fields = record->package.elements;
	u32 revision = fields[1].integer.value;

	switch (revision) {
	case 1:
		if (record->package.count != 5)
			return AE_ERROR;
		for (i = 2; i < 5; i++)
			if (fields[i].type != ACPI_TYPE_INTEGER)
				return AE_ERROR;
		hpx->t1 = &hpx->type1_data;
		hpx->t1->revision      = revision;
		hpx->t1->max_mem_read  = fields[2].integer.value;
		hpx->t1->avg_max_split = fields[3].integer.value;
		hpx->t1->tot_max_split = fields[4].integer.value;
		break;
	default:
		printk(KERN_WARNING
		       "%s: Type 1 Revision %d record not supported\n",
		       __FUNCTION__, revision);
		return AE_ERROR;
	}
	return AE_OK;
}

static acpi_status
decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
	int i;
	union acpi_object *fields = record->package.elements;
	u32 revision = fields[1].integer.value;

	switch (revision) {
	case 1:
		if (record->package.count != 18)
			return AE_ERROR;
		for (i = 2; i < 18; i++)
			if (fields[i].type != ACPI_TYPE_INTEGER)
				return AE_ERROR;
		hpx->t2 = &hpx->type2_data;
		hpx->t2->revision      = revision;
		hpx->t2->unc_err_mask_and      = fields[2].integer.value;
		hpx->t2->unc_err_mask_or       = fields[3].integer.value;
		hpx->t2->unc_err_sever_and     = fields[4].integer.value;
		hpx->t2->unc_err_sever_or      = fields[5].integer.value;
		hpx->t2->cor_err_mask_and      = fields[6].integer.value;
		hpx->t2->cor_err_mask_or       = fields[7].integer.value;
		hpx->t2->adv_err_cap_and       = fields[8].integer.value;
		hpx->t2->adv_err_cap_or        = fields[9].integer.value;
		hpx->t2->pci_exp_devctl_and    = fields[10].integer.value;
		hpx->t2->pci_exp_devctl_or     = fields[11].integer.value;
		hpx->t2->pci_exp_lnkctl_and    = fields[12].integer.value;
		hpx->t2->pci_exp_lnkctl_or     = fields[13].integer.value;
		hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
		hpx->t2->sec_unc_err_sever_or  = fields[15].integer.value;
		hpx->t2->sec_unc_err_mask_and  = fields[16].integer.value;
		hpx->t2->sec_unc_err_mask_or   = fields[17].integer.value;
		break;
	default:
		printk(KERN_WARNING
		       "%s: Type 2 Revision %d record not supported\n",
		       __FUNCTION__, revision);
		return AE_ERROR;
	}
	return AE_OK;
}

static acpi_status
acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
{
	acpi_status status;
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
	union acpi_object *package, *record, *fields;
	u32 type;
	int i;

	/* Clear the return buffer with zeros */
	memset(hpx, 0, sizeof(struct hotplug_params));

	status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
	if (ACPI_FAILURE(status))
		return status;

	package = (union acpi_object *)buffer.pointer;
	if (package->type != ACPI_TYPE_PACKAGE) {
		status = AE_ERROR;
		goto exit;
	}

	for (i = 0; i < package->package.count; i++) {
		record = &package->package.elements[i];
		if (record->type != ACPI_TYPE_PACKAGE) {
			status = AE_ERROR;
			goto exit;
		}

		fields = record->package.elements;
		if (fields[0].type != ACPI_TYPE_INTEGER ||
		    fields[1].type != ACPI_TYPE_INTEGER) {
			status = AE_ERROR;
			goto exit;
		}

		type = fields[0].integer.value;
		switch (type) {
		case 0:
			status = decode_type0_hpx_record(record, hpx);
			if (ACPI_FAILURE(status))
				goto exit;
			break;
		case 1:
			status = decode_type1_hpx_record(record, hpx);
			if (ACPI_FAILURE(status))
				goto exit;
			break;
		case 2:
			status = decode_type2_hpx_record(record, hpx);
			if (ACPI_FAILURE(status))
				goto exit;
			break;
		default:
			printk(KERN_ERR "%s: Type %d record not supported\n",
			       __FUNCTION__, type);
			status = AE_ERROR;
			goto exit;
		}
	}
 exit:
	kfree(buffer.pointer);
	return status;
}

static acpi_status
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
@@ -50,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)

	acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);

	/* Clear the return buffer with zeros */
	memset(hpp, 0, sizeof(struct hotplug_params));

	/* get _hpp */
	status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
	switch (status) {
@@ -58,7 +236,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
		if (!ret_buf.pointer) {
			printk(KERN_ERR "%s:%s alloc for _HPP fail\n",
				__FUNCTION__, (char *)string.pointer);
			acpi_os_free(string.pointer);
			kfree(string.pointer);
			return AE_NO_MEMORY;
		}
		status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
@@ -69,7 +247,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
		if (ACPI_FAILURE(status)) {
			pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__,
				(char *)string.pointer, status);
			acpi_os_free(string.pointer);
			kfree(string.pointer);
			return status;
		}
	}
@@ -98,19 +276,20 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
		}
	}

	hpp->cache_line_size = nui[0];
	hpp->latency_timer = nui[1];
	hpp->enable_serr = nui[2];
	hpp->enable_perr = nui[3];
	hpp->t0 = &hpp->type0_data;
	hpp->t0->cache_line_size = nui[0];
	hpp->t0->latency_timer = nui[1];
	hpp->t0->enable_serr = nui[2];
	hpp->t0->enable_perr = nui[3];

	pr_debug("  _HPP: cache_line_size=0x%x\n", hpp->cache_line_size);
	pr_debug("  _HPP: latency timer  =0x%x\n", hpp->latency_timer);
	pr_debug("  _HPP: enable SERR    =0x%x\n", hpp->enable_serr);
	pr_debug("  _HPP: enable PERR    =0x%x\n", hpp->enable_perr);
	pr_debug("  _HPP: cache_line_size=0x%x\n", hpp->t0->cache_line_size);
	pr_debug("  _HPP: latency timer  =0x%x\n", hpp->t0->latency_timer);
	pr_debug("  _HPP: enable SERR    =0x%x\n", hpp->t0->enable_serr);
	pr_debug("  _HPP: enable PERR    =0x%x\n", hpp->t0->enable_perr);

free_and_return:
	acpi_os_free(string.pointer);
	acpi_os_free(ret_buf.pointer);
	kfree(string.pointer);
	kfree(ret_buf.pointer);
	return status;
}

@@ -130,13 +309,17 @@ acpi_status acpi_run_oshp(acpi_handle handle)
	/* run OSHP */
	status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
	if (ACPI_FAILURE(status))
		printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__,
			(char *)string.pointer, status);
		if (status != AE_NOT_FOUND)
			printk(KERN_ERR "%s:%s OSHP fails=0x%x\n",
			       __FUNCTION__, (char *)string.pointer, status);
		else
			dbg("%s:%s OSHP not found\n",
			    __FUNCTION__, (char *)string.pointer);
	else
		pr_debug("%s:%s OSHP passes\n", __FUNCTION__,
			(char *)string.pointer);

	acpi_os_free(string.pointer);
	kfree(string.pointer);
	return status;
}
EXPORT_SYMBOL_GPL(acpi_run_oshp);
@@ -145,14 +328,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp);

/* acpi_get_hp_params_from_firmware
 *
 * @dev - the pci_dev of the newly added device
 * @bus - the pci_bus of the bus on which the device is newly added
 * @hpp - allocated by the caller
 */
acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
		struct hotplug_params *hpp)
{
	acpi_status status = AE_NOT_FOUND;
	struct pci_dev *pdev = dev;
	acpi_handle handle, phandle;
	struct pci_bus *pbus = bus;
	struct pci_dev *pdev;

	do {
		pdev = pbus->self;
		if (!pdev) {
			handle = acpi_get_pci_rootbridge_handle(
				pci_domain_nr(pbus), pbus->number);
			break;
		}
		handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
		pbus = pbus->parent;
	} while (!handle);

	/*
	 * _HPP settings apply to all child buses, until another _HPP is
@@ -160,15 +356,19 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
	 * look for it in the parent device scope since that would apply to
	 * this pci dev. If we don't find any _HPP, use hardcoded defaults
	 */
	while (pdev && (ACPI_FAILURE(status))) {
		acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
		if (!handle)
	while (handle) {
		status = acpi_run_hpx(handle, hpp);
		if (ACPI_SUCCESS(status))
			break;
		status = acpi_run_hpp(handle, hpp);
		if (!(pdev->bus->parent))
		if (ACPI_SUCCESS(status))
			break;
		/* Check if a parent object supports _HPP */
		pdev = pdev->bus->parent->self;
		if (acpi_root_bridge(handle))
			break;
		status = acpi_get_parent(handle, &phandle);
		if (ACPI_FAILURE(status))
			break;
		handle = phandle;
	}
	return status;
}
@@ -192,20 +392,23 @@ int acpi_root_bridge(acpi_handle handle)
		if ((info->valid & ACPI_VALID_HID) &&
			!strcmp(PCI_ROOT_HID_STRING,
					info->hardware_id.value)) {
			acpi_os_free(buffer.pointer);
			kfree(buffer.pointer);
			return 1;
		}
		if (info->valid & ACPI_VALID_CID) {
			for (i=0; i < info->compatibility_id.count; i++) {
				if (!strcmp(PCI_ROOT_HID_STRING,
					info->compatibility_id.id[i].value)) {
					acpi_os_free(buffer.pointer);
					kfree(buffer.pointer);
					return 1;
				}
			}
		}
		acpi_os_free(buffer.pointer);
		kfree(buffer.pointer);
	}
	return 0;
}
EXPORT_SYMBOL_GPL(acpi_root_bridge);

module_param(debug_acpi, bool, 0644);
MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");
+5 −0
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@ struct acpiphp_bridge {
	struct list_head list;
	acpi_handle handle;
	struct acpiphp_slot *slots;

	/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
	struct acpiphp_func *func;

	int type;
	int nr_slots;

@@ -122,6 +126,7 @@ struct acpiphp_slot {
 */
struct acpiphp_func {
	struct acpiphp_slot *slot;	/* parent */
	struct acpiphp_bridge *bridge;	/* Ejectable PCI-to-PCI bridge */

	struct list_head sibling;
	struct pci_dev *pci_dev;
+179 −63
Original line number Diff line number Diff line
@@ -286,13 +286,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
{
	acpi_status status;

	status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp);
	if (ACPI_FAILURE(status)) {
	status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp);
	if (ACPI_FAILURE(status) ||
	    !bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) {
		/* use default numbers */
		bridge->hpp.cache_line_size = 0x10;
		bridge->hpp.latency_timer = 0x40;
		bridge->hpp.enable_serr = 0;
		bridge->hpp.enable_perr = 0;
		printk(KERN_WARNING
		       "%s: Could not get hotplug parameters. Use defaults\n",
		       __FUNCTION__);
		bridge->hpp.t0 = &bridge->hpp.type0_data;
		bridge->hpp.t0->revision = 0;
		bridge->hpp.t0->cache_line_size = 0x10;
		bridge->hpp.t0->latency_timer = 0x40;
		bridge->hpp.t0->enable_serr = 0;
		bridge->hpp.t0->enable_perr = 0;
	}
}

@@ -319,6 +325,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)

	/* install notify handler */
	if (bridge->type != BRIDGE_TYPE_HOST) {
		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
			status = acpi_remove_notify_handler(bridge->func->handle,
						ACPI_SYSTEM_NOTIFY,
						handle_hotplug_event_func);
			if (ACPI_FAILURE(status))
				err("failed to remove notify handler\n");
		}
		status = acpi_install_notify_handler(bridge->handle,
					     ACPI_SYSTEM_NOTIFY,
					     handle_hotplug_event_bridge,
@@ -331,6 +344,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
}


/* find acpiphp_func from acpiphp_bridge */
static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
{
	struct list_head *node, *l;
	struct acpiphp_bridge *bridge;
	struct acpiphp_slot *slot;
	struct acpiphp_func *func;

	list_for_each(node, &bridge_list) {
		bridge = list_entry(node, struct acpiphp_bridge, list);
		for (slot = bridge->slots; slot; slot = slot->next) {
			list_for_each(l, &slot->funcs) {
				func = list_entry(l, struct acpiphp_func,
							sibling);
				if (func->handle == handle)
					return func;
			}
		}
	}

	return NULL;
}


static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
{
	acpi_handle dummy_handle;

	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
					"_STA", &dummy_handle)))
		bridge->flags |= BRIDGE_HAS_STA;

	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
					"_EJ0", &dummy_handle)))
		bridge->flags |= BRIDGE_HAS_EJ0;

	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
					"_PS0", &dummy_handle)))
		bridge->flags |= BRIDGE_HAS_PS0;

	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
					"_PS3", &dummy_handle)))
		bridge->flags |= BRIDGE_HAS_PS3;

	/* is this ejectable p2p bridge? */
	if (bridge->flags & BRIDGE_HAS_EJ0) {
		struct acpiphp_func *func;

		dbg("found ejectable p2p bridge\n");

		/* make link between PCI bridge and PCI function */
		func = acpiphp_bridge_handle_to_function(bridge->handle);
		if (!func)
			return;
		bridge->func = func;
		func->bridge = bridge;
	}
}


/* allocate and initialize host bridge data structure */
static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
{
@@ -364,6 +437,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)

	bridge->type = BRIDGE_TYPE_P2P;
	bridge->handle = handle;
	config_p2p_bridge_flags(bridge);

	bridge->pci_dev = pci_dev_get(pci_dev);
	bridge->pci_bus = pci_dev->subordinate;
@@ -423,7 +497,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
				     find_p2p_bridge, dev->subordinate, NULL);
	if (ACPI_FAILURE(status))
		warn("find_p2p_bridge faied (error code = 0x%x)\n", status);
		warn("find_p2p_bridge failed (error code = 0x%x)\n", status);

 out:
	pci_dev_put(dev);
@@ -478,7 +552,6 @@ static int add_bridge(acpi_handle handle)
	if (detect_ejectable_slots(handle) > 0) {
		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
		add_host_bridge(handle, pci_bus);
		return 0;
	}

	/* search P2P bridges under this host bridge */
@@ -486,7 +559,7 @@ static int add_bridge(acpi_handle handle)
				     find_p2p_bridge, pci_bus, NULL);

	if (ACPI_FAILURE(status))
		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
		warn("find_p2p_bridge failed (error code = 0x%x)\n", status);

	return 0;
}
@@ -516,6 +589,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
	if (ACPI_FAILURE(status))
		err("failed to remove notify handler\n");

	if ((bridge->type != BRIDGE_TYPE_HOST) &&
	    ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
		status = acpi_install_notify_handler(bridge->func->handle,
						ACPI_SYSTEM_NOTIFY,
						handle_hotplug_event_func,
						bridge->func);
		if (ACPI_FAILURE(status))
			err("failed to install interrupt notify handler\n");
	}

	slot = bridge->slots;
	while (slot) {
		struct acpiphp_slot *next = slot->next;
@@ -549,6 +632,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
	struct acpiphp_bridge *bridge;

	/* cleanup p2p bridges under this P2P bridge
	   in a depth-first manner */
	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
				cleanup_p2p_bridge, NULL, NULL);

	if (!(bridge = acpiphp_handle_to_bridge(handle)))
		return AE_OK;
	cleanup_bridge(bridge);
@@ -559,15 +647,14 @@ static void remove_bridge(acpi_handle handle)
{
	struct acpiphp_bridge *bridge;

	/* cleanup p2p bridges under this host bridge
	   in a depth-first manner */
	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
				(u32)1, cleanup_p2p_bridge, NULL, NULL);

	bridge = acpiphp_handle_to_bridge(handle);
	if (bridge) {
	if (bridge)
		cleanup_bridge(bridge);
	} else {
		/* clean-up p2p bridges under this host bridge */
		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
				    ACPI_UINT32_MAX, cleanup_p2p_bridge,
				    NULL, NULL);
	}
}

static struct pci_dev * get_apic_pci_info(acpi_handle handle)
@@ -634,7 +721,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
		break;
	}
 out:
	acpi_os_free(buffer.pointer);
	kfree(buffer.pointer);
	return result;
}

@@ -797,36 +884,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
}



/**
 *  get_func - get a pointer to acpiphp_func given a slot, device
 *  @slot: slot to search
 *  @dev:  pci_dev struct to match.
 *
 *  This function will increase the reference count of pci_dev,
 *  so callers should call pci_dev_put when complete.
 *
 */
static struct acpiphp_func *
get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
{
	struct acpiphp_func *func = NULL;
	struct pci_bus *bus = slot->bridge->pci_bus;
	struct pci_dev *pdev;

	list_for_each_entry(func, &slot->funcs, sibling) {
		pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
					func->function));
		if (pdev) {
			if (pdev == dev)
				break;
			pci_dev_put(pdev);
		}
	}
	return func;
}


/**
 * acpiphp_bus_add - add a new bus to acpi subsystem
 * @func: acpiphp_func of the bridge
@@ -872,6 +929,28 @@ acpiphp_bus_add_out:
}


/**
 * acpiphp_bus_trim - trim a bus from acpi subsystem
 * @handle: handle to acpi namespace
 *
 */
int acpiphp_bus_trim(acpi_handle handle)
{
	struct acpi_device *device;
	int retval;

	retval = acpi_bus_get_device(handle, &device);
	if (retval) {
		dbg("acpi_device not found\n");
		return retval;
	}

	retval = acpi_bus_trim(device, 1);
	if (retval)
		err("cannot remove from acpi list\n");

	return retval;
}

/**
 * enable_device - enable, configure a slot
@@ -889,6 +968,7 @@ static int enable_device(struct acpiphp_slot *slot)
	struct acpiphp_func *func;
	int retval = 0;
	int num, max, pass;
	acpi_status status;

	if (slot->flags & SLOT_ENABLED)
		goto err_exit;
@@ -918,17 +998,15 @@ static int enable_device(struct acpiphp_slot *slot)
			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
				max = pci_scan_bridge(bus, dev, max, pass);
				if (pass && dev->subordinate) {
				if (pass && dev->subordinate)
					pci_bus_size_bridges(dev->subordinate);
					func = get_func(slot, dev);
					if (func) {
						acpiphp_bus_add(func);
						/* side effect of get_func */
						pci_dev_put(dev);
					}
			}
		}
	}

	list_for_each (l, &slot->funcs) {
		func = list_entry(l, struct acpiphp_func, sibling);
		acpiphp_bus_add(func);
	}

	pci_bus_assign_resources(bus);
@@ -943,6 +1021,17 @@ static int enable_device(struct acpiphp_slot *slot)
		func = list_entry(l, struct acpiphp_func, sibling);
		func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
							func->function));
		if (!func->pci_dev)
			continue;

		if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
		    func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
			continue;

		status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
		if (ACPI_FAILURE(status))
			warn("find_p2p_bridge failed (error code = 0x%x)\n",
				status);
	}

	slot->flags |= SLOT_ENABLED;
@@ -967,6 +1056,18 @@ static int disable_device(struct acpiphp_slot *slot)

	list_for_each (l, &slot->funcs) {
		func = list_entry(l, struct acpiphp_func, sibling);

		if (func->bridge) {
			/* cleanup p2p bridges under this P2P bridge */
			cleanup_p2p_bridge(func->bridge->handle,
						(u32)1, NULL, NULL);
			func->bridge = NULL;
		}

		acpiphp_bus_trim(func->handle);
		/* try to remove anyway.
		 * acpiphp_bus_add might have been failed */

		if (!func->pci_dev)
			continue;

@@ -1111,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
			(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
			(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
		return;

	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
			bridge->hpp.cache_line_size);
			bridge->hpp.t0->cache_line_size);
	pci_write_config_byte(dev, PCI_LATENCY_TIMER,
			bridge->hpp.latency_timer);
			bridge->hpp.t0->latency_timer);
	pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
	if (bridge->hpp.enable_serr)
	if (bridge->hpp.t0->enable_serr)
		pci_cmd |= PCI_COMMAND_SERR;
	else
		pci_cmd &= ~PCI_COMMAND_SERR;
	if (bridge->hpp.enable_perr)
	if (bridge->hpp.t0->enable_perr)
		pci_cmd |= PCI_COMMAND_PARITY;
	else
		pci_cmd &= ~PCI_COMMAND_PARITY;
@@ -1129,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
	/* Program bridge control value and child devices */
	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
				bridge->hpp.latency_timer);
				bridge->hpp.t0->latency_timer);
		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
		if (bridge->hpp.enable_serr)
		if (bridge->hpp.t0->enable_serr)
			pci_bctl |= PCI_BRIDGE_CTL_SERR;
		else
			pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
		if (bridge->hpp.enable_perr)
		if (bridge->hpp.t0->enable_perr)
			pci_bctl |= PCI_BRIDGE_CTL_PARITY;
		else
			pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
@@ -1155,6 +1257,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)

	memset(&bridge, 0, sizeof(bridge));
	bridge.handle = handle;
	bridge.pci_bus = bus;
	bridge.pci_dev = bus->self;
	decode_hpp(&bridge);
	list_for_each_entry(dev, &bus->devices, bus_list)
@@ -1297,6 +1400,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
	case ACPI_NOTIFY_EJECT_REQUEST:
		/* request device eject */
		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
		if ((bridge->type != BRIDGE_TYPE_HOST) &&
		    (bridge->flags & BRIDGE_HAS_EJ0)) {
			struct acpiphp_slot *slot;
			slot = bridge->func->slot;
			if (!acpiphp_disable_slot(slot))
				acpiphp_eject_slot(slot);
		}
		break;

	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1490,9 +1600,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
	if (retval)
		goto err_exit;

	if (get_slot_status(slot) == ACPI_STA_ALL)
	if (get_slot_status(slot) == ACPI_STA_ALL) {
		/* configure all functions */
		retval = enable_device(slot);
		if (retval)
			power_off_slot(slot);
	} else {
		dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__);
		power_off_slot(slot);
	}

 err_exit:
	mutex_unlock(&slot->crit_sect);
+6 −6
Original line number Diff line number Diff line
@@ -285,7 +285,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
					(ulong) hotplug_slot, (ulong) value);
        
	ibmphp_lock_operations();
	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			memcpy(&myslot, pslot, sizeof(struct slot));
@@ -315,7 +315,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
	debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
					(ulong) hotplug_slot, (ulong) value);
	ibmphp_lock_operations();
	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			memcpy(&myslot, pslot, sizeof(struct slot));
@@ -342,7 +342,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
	debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
					(ulong) hotplug_slot, (ulong) value);
	ibmphp_lock_operations();
	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			memcpy(&myslot, pslot, sizeof(struct slot));
@@ -369,7 +369,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value)
	debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
					(ulong) hotplug_slot, (ulong) value);
	ibmphp_lock_operations();
	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			memcpy(&myslot, pslot, sizeof(struct slot));
@@ -401,7 +401,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe

	ibmphp_lock_operations();

	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			rc = 0;
@@ -441,7 +441,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe

	ibmphp_lock_operations();

	if (hotplug_slot && value) {
	if (hotplug_slot) {
		pslot = hotplug_slot->private;
		if (pslot) {
			rc = get_cur_bus_info(&pslot);
+45 −5
Original line number Diff line number Diff line
@@ -176,19 +176,59 @@ extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
					 struct hotplug_slot_info *info);
extern struct subsystem pci_hotplug_slots_subsys;

struct hotplug_params {
/* PCI Setting Record (Type 0) */
struct hpp_type0 {
	u32 revision;
	u8  cache_line_size;
	u8  latency_timer;
	u8  enable_serr;
	u8  enable_perr;
};

/* PCI-X Setting Record (Type 1) */
struct hpp_type1 {
	u32 revision;
	u8  max_mem_read;
	u8  avg_max_split;
	u16 tot_max_split;
};

/* PCI Express Setting Record (Type 2) */
struct hpp_type2 {
	u32 revision;
	u32 unc_err_mask_and;
	u32 unc_err_mask_or;
	u32 unc_err_sever_and;
	u32 unc_err_sever_or;
	u32 cor_err_mask_and;
	u32 cor_err_mask_or;
	u32 adv_err_cap_and;
	u32 adv_err_cap_or;
	u16 pci_exp_devctl_and;
	u16 pci_exp_devctl_or;
	u16 pci_exp_lnkctl_and;
	u16 pci_exp_lnkctl_or;
	u32 sec_unc_err_sever_and;
	u32 sec_unc_err_sever_or;
	u32 sec_unc_err_mask_and;
	u32 sec_unc_err_mask_or;
};

struct hotplug_params {
	struct hpp_type0 *t0;		/* Type0: NULL if not available */
	struct hpp_type1 *t1;		/* Type1: NULL if not available */
	struct hpp_type2 *t2;		/* Type2: NULL if not available */
	struct hpp_type0 type0_data;
	struct hpp_type1 type1_data;
	struct hpp_type2 type2_data;
};

#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
extern acpi_status acpi_run_oshp(acpi_handle handle);
extern acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
				struct hotplug_params *hpp);
int acpi_root_bridge(acpi_handle handle);
#endif
Loading