acpi_pcihp.c 11.4 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 <acpi/acpi.h>
L
Linus Torvalds 已提交
34 35 36
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>

37 38
#define MY_NAME	"acpi_pcihp"

39
#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## arg); } while (0)
40 41 42 43
#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 已提交
44 45 46 47
#define	METHOD_NAME__SUN	"_SUN"
#define	METHOD_NAME__HPP	"_HPP"
#define	METHOD_NAME_OSHP	"OSHP"

48 49
static int debug_acpi;

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
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",
74
		       __func__, revision);
75 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
		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",
103
		       __func__, revision);
104 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
		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",
145
		       __func__, revision);
146 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
		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",
206
			       __func__, type);
207 208 209 210 211 212 213 214
			status = AE_ERROR;
			goto exit;
		}
	}
 exit:
	kfree(buffer.pointer);
	return status;
}
L
Linus Torvalds 已提交
215

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

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

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

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

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

279 280 281 282 283
	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 已提交
284

285 286 287 288
	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 已提交
289 290

free_and_return:
291 292
	kfree(string.pointer);
	kfree(ret_buf.pointer);
293
	return status;
L
Linus Torvalds 已提交
294 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.
 */
acpi_status acpi_run_oshp(acpi_handle handle)
L
Linus Torvalds 已提交
303 304
{
	acpi_status		status;
305 306 307
	struct acpi_buffer	string = { ACPI_ALLOCATE_BUFFER, NULL };

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

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

322
	kfree(string.pointer);
323 324 325 326 327 328 329 330
	return status;
}
EXPORT_SYMBOL_GPL(acpi_run_oshp);



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

	/*
	 * _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
	 */
359
	while (handle) {
360 361 362
		status = acpi_run_hpx(handle, hpp);
		if (ACPI_SUCCESS(status))
			break;
363
		status = acpi_run_hpp(handle, hpp);
364 365 366 367 368 369
		if (ACPI_SUCCESS(status))
			break;
		if (acpi_root_bridge(handle))
			break;
		status = acpi_get_parent(handle, &phandle);
		if (ACPI_FAILURE(status))
370
			break;
371
		handle = phandle;
L
Linus Torvalds 已提交
372
	}
373
	return status;
L
Linus Torvalds 已提交
374
}
375 376
EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);

L
Linus Torvalds 已提交
377

378 379 380 381 382
/* 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)
383 384 385 386 387 388 389 390 391 392 393 394
{
	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)) {
395
			kfree(buffer.pointer);
396 397 398 399 400 401
			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)) {
402
					kfree(buffer.pointer);
403 404 405 406
					return 1;
				}
			}
		}
407
		kfree(buffer.pointer);
408 409 410
	}
	return 0;
}
411
EXPORT_SYMBOL_GPL(acpi_root_bridge);
412 413 414

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