acpi_pcihp.c 14.2 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * Common ACPI functions for hot plug platforms
L
Linus Torvalds 已提交
3
 *
4
 * Copyright (C) 2006 Intel Corporation
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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.
 *
23
 * Send feedback to <kristen.c.accardi@intel.com>
L
Linus Torvalds 已提交
24 25 26 27
 *
 */

#include <linux/module.h>
28
#include <linux/moduleparam.h>
L
Linus Torvalds 已提交
29 30 31
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
32
#include <linux/pci_hotplug.h>
33
#include <linux/pci-acpi.h>
34
#include <acpi/acpi.h>
L
Linus Torvalds 已提交
35 36 37
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>

38 39
#define MY_NAME	"acpi_pcihp"

40
#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## arg); } while (0)
41 42 43 44
#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)

L
Linus Torvalds 已提交
45 46 47 48
#define	METHOD_NAME__SUN	"_SUN"
#define	METHOD_NAME__HPP	"_HPP"
#define	METHOD_NAME_OSHP	"OSHP"

49 50
static int debug_acpi;

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
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",
75
		       __func__, revision);
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
		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",
104
		       __func__, revision);
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
		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",
146
		       __func__, revision);
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
		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",
207
			       __func__, type);
208 209 210 211 212 213 214 215
			status = AE_ERROR;
			goto exit;
		}
	}
 exit:
	kfree(buffer.pointer);
	return status;
}
L
Linus Torvalds 已提交
216

217 218
static acpi_status
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
L
Linus Torvalds 已提交
219 220 221 222
{
	acpi_status		status;
	u8			nui[4];
	struct acpi_buffer	ret_buf = { 0, NULL};
223
	struct acpi_buffer	string = { ACPI_ALLOCATE_BUFFER, NULL };
L
Linus Torvalds 已提交
224 225 226
	union acpi_object	*ext_obj, *package;
	int			i, len = 0;

227 228
	acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);

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

L
Linus Torvalds 已提交
232
	/* get _hpp */
233
	status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
L
Linus Torvalds 已提交
234 235 236 237
	switch (status) {
	case AE_BUFFER_OVERFLOW:
		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
		if (!ret_buf.pointer) {
238
			printk(KERN_ERR "%s:%s alloc for _HPP fail\n",
239
				__func__, (char *)string.pointer);
240
			kfree(string.pointer);
241
			return AE_NO_MEMORY;
L
Linus Torvalds 已提交
242
		}
243 244
		status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
				NULL, &ret_buf);
L
Linus Torvalds 已提交
245 246 247 248
		if (ACPI_SUCCESS(status))
			break;
	default:
		if (ACPI_FAILURE(status)) {
249
			pr_debug("%s:%s _HPP fail=0x%x\n", __func__,
250
				(char *)string.pointer, status);
251
			kfree(string.pointer);
252
			return status;
L
Linus Torvalds 已提交
253 254 255 256 257
		}
	}

	ext_obj = (union acpi_object *) ret_buf.pointer;
	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
258
		printk(KERN_ERR "%s:%s _HPP obj not a package\n", __func__,
259
				(char *)string.pointer);
260
		status = AE_ERROR;
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269 270 271 272
		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:
273
			printk(KERN_ERR "%s:%s _HPP obj type incorrect\n",
274
				__func__, (char *)string.pointer);
275
			status = AE_ERROR;
L
Linus Torvalds 已提交
276 277 278 279
			goto free_and_return;
		}
	}

280 281 282 283 284
	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];
L
Linus Torvalds 已提交
285

286 287 288 289
	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);
L
Linus Torvalds 已提交
290 291

free_and_return:
292 293
	kfree(string.pointer);
	kfree(ret_buf.pointer);
294
	return status;
L
Linus Torvalds 已提交
295 296
}

297 298 299 300 301 302


/* acpi_run_oshp - get control of hotplug from the firmware
 *
 * @handle - the handle of the hotplug controller.
 */
303
static acpi_status acpi_run_oshp(acpi_handle handle)
L
Linus Torvalds 已提交
304 305
{
	acpi_status		status;
306 307 308
	struct acpi_buffer	string = { ACPI_ALLOCATE_BUFFER, NULL };

	acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
L
Linus Torvalds 已提交
309 310

	/* run OSHP */
311
	status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
312
	if (ACPI_FAILURE(status))
313 314
		if (status != AE_NOT_FOUND)
			printk(KERN_ERR "%s:%s OSHP fails=0x%x\n",
315
			       __func__, (char *)string.pointer, status);
316 317
		else
			dbg("%s:%s OSHP not found\n",
318
			    __func__, (char *)string.pointer);
319
	else
320
		pr_debug("%s:%s OSHP passes\n", __func__,
321 322
			(char *)string.pointer);

323
	kfree(string.pointer);
324 325 326 327 328
	return status;
}

/* acpi_get_hp_params_from_firmware
 *
329
 * @bus - the pci_bus of the bus on which the device is newly added
330 331
 * @hpp - allocated by the caller
 */
332
acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
333 334 335
		struct hotplug_params *hpp)
{
	acpi_status status = AE_NOT_FOUND;
336 337 338 339 340 341 342 343 344 345 346 347 348 349
	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);
350 351 352 353 354 355 356

	/*
	 * _HPP settings apply to all child buses, until another _HPP is
	 * encountered. If we don't find an _HPP for the input pci 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
	 */
357
	while (handle) {
358 359 360
		status = acpi_run_hpx(handle, hpp);
		if (ACPI_SUCCESS(status))
			break;
361
		status = acpi_run_hpp(handle, hpp);
362 363 364 365 366 367
		if (ACPI_SUCCESS(status))
			break;
		if (acpi_root_bridge(handle))
			break;
		status = acpi_get_parent(handle, &phandle);
		if (ACPI_FAILURE(status))
368
			break;
369
		handle = phandle;
L
Linus Torvalds 已提交
370
	}
371
	return status;
L
Linus Torvalds 已提交
372
}
373 374
EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);

375 376 377 378 379 380 381 382 383 384
/**
 * acpi_get_hp_hw_control_from_firmware
 * @dev: the pci_dev of the bridge that has a hotplug controller
 * @flags: requested control bits for _OSC
 *
 * Attempt to take hotplug control from firmware.
 */
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
{
	acpi_status status;
385
	acpi_handle chandle, handle;
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
	struct pci_dev *pdev = dev;
	struct pci_bus *parent;
	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };

	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
		  OSC_SHPC_NATIVE_HP_CONTROL |
		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
	if (!flags) {
		err("Invalid flags %u specified!\n", flags);
		return -EINVAL;
	}

	/*
	 * Per PCI firmware specification, we should run the ACPI _OSC
	 * method to get control of hotplug hardware before using it. If
	 * an _OSC is missing, we look for an OSHP to do the same thing.
402 403 404
	 * To handle different BIOS behavior, we look for _OSC on a root
	 * bridge preferentially (according to PCI fw spec). Later for
	 * OSHP within the scope of the hotplug controller and its parents,
405 406
	 * upto the host bridge under which this controller exists.
	 */
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
	while (pdev->bus->self)
		pdev = pdev->bus->self;
	handle = acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus),
			pdev->bus->number);
	if (handle) {
		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
		dbg("Trying to get hotplug control for %s\n",
				(char *)string.pointer);
		status = pci_osc_control_set(handle, flags);
		if (ACPI_SUCCESS(status))
			goto got_one;
		kfree(string.pointer);
		string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
	}

	pdev = dev;
	handle = DEVICE_ACPI_HANDLE(&dev->dev);
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	while (!handle) {
		/*
		 * This hotplug controller was not listed in the ACPI name
		 * space at all. Try to get acpi handle of parent pci bus.
		 */
		if (!pdev || !pdev->bus->parent)
			break;
		parent = pdev->bus->parent;
		dbg("Could not find %s in acpi namespace, trying parent\n",
		    pci_name(pdev));
		if (!parent->self)
			/* Parent must be a host bridge */
			handle = acpi_get_pci_rootbridge_handle(
					pci_domain_nr(parent),
					parent->number);
		else
			handle = DEVICE_ACPI_HANDLE(&(parent->self->dev));
		pdev = parent->self;
	}

	while (handle) {
		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
		dbg("Trying to get hotplug control for %s \n",
		    (char *)string.pointer);
448 449 450
		status = acpi_run_oshp(handle);
		if (ACPI_SUCCESS(status))
			goto got_one;
451 452 453 454 455 456 457 458 459 460 461 462 463
		if (acpi_root_bridge(handle))
			break;
		chandle = handle;
		status = acpi_get_parent(chandle, &handle);
		if (ACPI_FAILURE(status))
			break;
	}

	dbg("Cannot get control of hotplug hardware for pci %s\n",
	    pci_name(dev));

	kfree(string.pointer);
	return -ENODEV;
464 465 466 467 468
got_one:
	dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev),
			(char *)string.pointer);
	kfree(string.pointer);
	return 0;
469 470
}
EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware);
L
Linus Torvalds 已提交
471

472 473 474 475 476
/* acpi_root_bridge - check to see if this acpi object is a root bridge
 *
 * @handle - the acpi object in question.
 */
int acpi_root_bridge(acpi_handle handle)
477 478 479 480 481 482 483 484 485 486 487 488
{
	acpi_status status;
	struct acpi_device_info *info;
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
	int i;

	status = acpi_get_object_info(handle, &buffer);
	if (ACPI_SUCCESS(status)) {
		info = buffer.pointer;
		if ((info->valid & ACPI_VALID_HID) &&
			!strcmp(PCI_ROOT_HID_STRING,
					info->hardware_id.value)) {
489
			kfree(buffer.pointer);
490 491 492 493 494 495
			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)) {
496
					kfree(buffer.pointer);
497 498 499 500
					return 1;
				}
			}
		}
501
		kfree(buffer.pointer);
502 503 504
	}
	return 0;
}
505
EXPORT_SYMBOL_GPL(acpi_root_bridge);
506 507 508

module_param(debug_acpi, bool, 0644);
MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");