rsparser.c 25.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * pnpacpi -- PnP ACPI driver
 *
 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 7
 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
B
Bob Moore 已提交
8
 *
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * 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, 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.  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
26
#include <linux/pnp.h>
27
#include <linux/slab.h>
28
#include "../base.h"
L
Linus Torvalds 已提交
29 30
#include "pnpacpi.h"

B
Bjorn Helgaas 已提交
31
static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
32
			     int *polarity, int *shareable)
L
Linus Torvalds 已提交
33
{
B
Bjorn Helgaas 已提交
34 35
	switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
			 IORESOURCE_IRQ_LOWEDGE  | IORESOURCE_IRQ_HIGHEDGE)) {
L
Linus Torvalds 已提交
36
	case IORESOURCE_IRQ_LOWLEVEL:
B
Bob Moore 已提交
37 38
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
39
		break;
B
Bjorn Helgaas 已提交
40
	case IORESOURCE_IRQ_HIGHLEVEL:
B
Bob Moore 已提交
41 42
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
43 44
		break;
	case IORESOURCE_IRQ_LOWEDGE:
B
Bob Moore 已提交
45 46
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
47 48
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
B
Bob Moore 已提交
49 50
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
51
		break;
B
Bjorn Helgaas 已提交
52 53 54 55 56 57
	default:
		dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n",
			flags);
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
		break;
L
Linus Torvalds 已提交
58
	}
59 60 61 62 63

	if (flags & IORESOURCE_IRQ_SHAREABLE)
		*shareable = ACPI_SHARED;
	else
		*shareable = ACPI_EXCLUSIVE;
L
Linus Torvalds 已提交
64 65
}

66 67
static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
		     int transfer)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
	int flags = 0;

	if (bus_master)
		flags |= IORESOURCE_DMA_MASTER;
	switch (type) {
	case ACPI_COMPATIBILITY:
		flags |= IORESOURCE_DMA_COMPATIBLE;
		break;
	case ACPI_TYPE_A:
		flags |= IORESOURCE_DMA_TYPEA;
		break;
	case ACPI_TYPE_B:
		flags |= IORESOURCE_DMA_TYPEB;
		break;
	case ACPI_TYPE_F:
		flags |= IORESOURCE_DMA_TYPEF;
		break;
	default:
		/* Set a default value ? */
		flags |= IORESOURCE_DMA_COMPATIBLE;
89
		dev_err(&dev->dev, "invalid DMA type %d\n", type);
90 91 92 93 94 95 96 97 98 99 100 101 102 103
	}
	switch (transfer) {
	case ACPI_TRANSFER_8:
		flags |= IORESOURCE_DMA_8BIT;
		break;
	case ACPI_TRANSFER_8_16:
		flags |= IORESOURCE_DMA_8AND16BIT;
		break;
	case ACPI_TRANSFER_16:
		flags |= IORESOURCE_DMA_16BIT;
		break;
	default:
		/* Set a default value ? */
		flags |= IORESOURCE_DMA_8AND16BIT;
104
		dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
105 106 107 108 109
	}

	return flags;
}

110 111 112
/*
 * Allocated Resources
 */
B
Bjorn Helgaas 已提交
113

114 115 116 117
static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
{
	if (!(r->flags & IORESOURCE_DISABLED))
		pcibios_penalize_isa_irq(r->start, 1);
118

119
	pnp_add_resource(dev, r);
L
Linus Torvalds 已提交
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 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
/*
 * Device CSRs that do not appear in PCI config space should be described
 * via ACPI.  This would normally be done with Address Space Descriptors
 * marked as "consumer-only," but old versions of Windows and Linux ignore
 * the producer/consumer flag, so HP invented a vendor-defined resource to
 * describe the location and size of CSR space.
 */
static struct acpi_vendor_uuid hp_ccsr_uuid = {
	.subtype = 2,
	.data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a,
	    0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad },
};

static int vendor_resource_matches(struct pnp_dev *dev,
				   struct acpi_resource_vendor_typed *vendor,
				   struct acpi_vendor_uuid *match,
				   int expected_len)
{
	int uuid_len = sizeof(vendor->uuid);
	u8 uuid_subtype = vendor->uuid_subtype;
	u8 *uuid = vendor->uuid;
	int actual_len;

	/* byte_length includes uuid_subtype and uuid */
	actual_len = vendor->byte_length - uuid_len - 1;

	if (uuid_subtype == match->subtype &&
	    uuid_len == sizeof(match->data) &&
	    memcmp(uuid, match->data, uuid_len) == 0) {
		if (expected_len && expected_len != actual_len) {
			dev_err(&dev->dev, "wrong vendor descriptor size; "
				"expected %d, found %d bytes\n",
				expected_len, actual_len);
			return 0;
		}

		return 1;
	}

	return 0;
}

static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
				    struct acpi_resource_vendor_typed *vendor)
{
	if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) {
		u64 start, length;

		memcpy(&start, vendor->byte_data, sizeof(start));
		memcpy(&length, vendor->byte_data + 8, sizeof(length));

		pnp_add_mem_resource(dev, start, start + length - 1, 0);
	}
}

L
Linus Torvalds 已提交
177
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
178
					      void *data)
L
Linus Torvalds 已提交
179
{
180
	struct pnp_dev *dev = data;
181
	struct acpi_resource_dma *dma;
182
	struct acpi_resource_vendor_typed *vendor_typed;
183
	struct resource r;
184
	int i, flags;
L
Linus Torvalds 已提交
185

186 187 188 189 190 191 192 193 194 195 196 197 198
	if (acpi_dev_resource_memory(res, &r)
	    || acpi_dev_resource_io(res, &r)
	    || acpi_dev_resource_address_space(res, &r)
	    || acpi_dev_resource_ext_address_space(res, &r)) {
		pnp_add_resource(dev, &r);
		return AE_OK;
	}

	r.flags = 0;
	if (acpi_dev_resource_interrupt(res, 0, &r)) {
		pnpacpi_add_irqresource(dev, &r);
		for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++)
			pnpacpi_add_irqresource(dev, &r);
199

200
		if (i > 1) {
201 202 203 204 205
			/*
			 * The IRQ encoder puts a single interrupt in each
			 * descriptor, so if a _CRS descriptor has more than
			 * one interrupt, we won't be able to re-encode it.
			 */
206
			if (pnp_can_write(dev)) {
207 208 209 210 211
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
L
Linus Torvalds 已提交
212
		}
213 214 215 216 217
		return AE_OK;
	} else if (r.flags & IORESOURCE_DISABLED) {
		pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		return AE_OK;
	}
L
Linus Torvalds 已提交
218

219
	switch (res->type) {
B
Bob Moore 已提交
220
	case ACPI_RESOURCE_TYPE_DMA:
221
		dma = &res->data.dma;
222
		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
223
			flags = dma_flags(dev, dma->type, dma->bus_master,
224
					  dma->transfer);
225 226 227
		else
			flags = IORESOURCE_DISABLED;
		pnp_add_dma_resource(dev, dma->channels[0], flags);
L
Linus Torvalds 已提交
228
		break;
229 230 231 232 233 234

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

	case ACPI_RESOURCE_TYPE_VENDOR:
235 236
		vendor_typed = &res->data.vendor_typed;
		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
237 238 239 240 241 242
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
L
Linus Torvalds 已提交
243
		break;
244

L
Linus Torvalds 已提交
245
	default:
246 247
		dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
			 res->type);
L
Linus Torvalds 已提交
248 249
		return AE_ERROR;
	}
B
Bjorn Helgaas 已提交
250

L
Linus Torvalds 已提交
251 252 253
	return AE_OK;
}

254
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
L
Linus Torvalds 已提交
255
{
256 257
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
258
	acpi_status status;
259

B
Bjorn Helgaas 已提交
260
	pnp_dbg(&dev->dev, "parse allocated resources\n");
261

262
	pnp_init_resources(dev);
L
Linus Torvalds 已提交
263

264 265 266 267 268 269 270 271 272
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
				     pnpacpi_allocated_resource, dev);

	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND)
			dev_err(&dev->dev, "can't evaluate _CRS: %d", status);
		return -EPERM;
	}
	return 0;
L
Linus Torvalds 已提交
273 274
}

275
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
276
					    unsigned int option_flags,
277
					    struct acpi_resource_dma *p)
L
Linus Torvalds 已提交
278 279
{
	int i;
280
	unsigned char map = 0, flags;
L
Linus Torvalds 已提交
281

B
Bjorn Helgaas 已提交
282
	for (i = 0; i < p->channel_count; i++)
283
		map |= 1 << p->channels[i];
L
Linus Torvalds 已提交
284

285
	flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
286
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
287 288
}

289
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
290
					    unsigned int option_flags,
291
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
292 293
{
	int i;
294
	pnp_irq_mask_t map;
295
	unsigned char flags;
L
Linus Torvalds 已提交
296

297
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
298
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
299
		if (p->interrupts[i])
300
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
301

302
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
303
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
304 305
}

306
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
307
					unsigned int option_flags,
308
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
309 310
{
	int i;
311
	pnp_irq_mask_t map;
312
	unsigned char flags;
L
Linus Torvalds 已提交
313

314
	bitmap_zero(map.bits, PNP_IRQ_NR);
315 316 317 318 319 320 321 322 323 324
	for (i = 0; i < p->interrupt_count; i++) {
		if (p->interrupts[i]) {
			if (p->interrupts[i] < PNP_IRQ_NR)
				__set_bit(p->interrupts[i], map.bits);
			else
				dev_err(&dev->dev, "ignoring IRQ %d option "
					"(too large for %d entry bitmap)\n",
					p->interrupts[i], PNP_IRQ_NR);
		}
	}
L
Linus Torvalds 已提交
325

326
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
327
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
328 329
}

330
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
331
					     unsigned int option_flags,
332
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
333
{
334
	unsigned char flags = 0;
L
Linus Torvalds 已提交
335

336
	if (io->io_decode == ACPI_DECODE_16)
337
		flags = IORESOURCE_IO_16BIT_ADDR;
338
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
339
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
340 341
}

342
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
343
					unsigned int option_flags,
344
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
345
{
346
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
347
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
348 349
}

350
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
351
					      unsigned int option_flags,
352
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
353
{
354
	unsigned char flags = 0;
L
Linus Torvalds 已提交
355

356
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
357
		flags = IORESOURCE_MEM_WRITEABLE;
358
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
359
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
360 361
}

362
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
363
					      unsigned int option_flags,
364
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
365
{
366
	unsigned char flags = 0;
L
Linus Torvalds 已提交
367

368
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
369
		flags = IORESOURCE_MEM_WRITEABLE;
370
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
371
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
372 373
}

374
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
375
					unsigned int option_flags,
376
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
377
{
378
	unsigned char flags = 0;
L
Linus Torvalds 已提交
379

380
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
381
		flags = IORESOURCE_MEM_WRITEABLE;
382
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
383
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
384 385
}

386
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
387
						unsigned int option_flags,
388
						struct acpi_resource *r)
389 390 391
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
392
	unsigned char flags = 0;
393 394

	status = acpi_resource_to_address64(r, p);
395 396
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
397
			 r->type);
398 399 400 401
		return;
	}

	if (p->resource_type == ACPI_MEMORY_RANGE) {
402
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
403
			flags = IORESOURCE_MEM_WRITEABLE;
404 405 406
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
407
	} else if (p->resource_type == ACPI_IO_RANGE)
408 409
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
410
					   IORESOURCE_IO_FIXED);
411 412
}

413 414 415 416 417 418 419 420 421
static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev,
						    unsigned int option_flags,
						    struct acpi_resource *r)
{
	struct acpi_resource_extended_address64 *p = &r->data.ext_address64;
	unsigned char flags = 0;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
422
			flags = IORESOURCE_MEM_WRITEABLE;
423 424 425 426 427 428
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
	} else if (p->resource_type == ACPI_IO_RANGE)
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
429
					   IORESOURCE_IO_FIXED);
430 431
}

L
Linus Torvalds 已提交
432 433
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
434
	unsigned int option_flags;
L
Linus Torvalds 已提交
435 436
};

437 438
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
439
{
440
	int priority;
441
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
442
	struct pnp_dev *dev = parse_data->dev;
443
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
444

445
	switch (res->type) {
B
Bjorn Helgaas 已提交
446
	case ACPI_RESOURCE_TYPE_IRQ:
447
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
448
		break;
449

B
Bjorn Helgaas 已提交
450
	case ACPI_RESOURCE_TYPE_DMA:
451
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
452
		break;
453

B
Bjorn Helgaas 已提交
454 455 456 457
	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
		switch (res->data.start_dpf.compatibility_priority) {
		case ACPI_GOOD_CONFIGURATION:
			priority = PNP_RES_PRIORITY_PREFERRED;
L
Linus Torvalds 已提交
458
			break;
459

B
Bjorn Helgaas 已提交
460 461
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
462
			break;
463

B
Bjorn Helgaas 已提交
464 465
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
466
			break;
B
Bjorn Helgaas 已提交
467 468
		default:
			priority = PNP_RES_PRIORITY_INVALID;
469
			break;
B
Bjorn Helgaas 已提交
470
		}
471
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
472
		break;
473

B
Bjorn Helgaas 已提交
474
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
475
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
476
		break;
477

B
Bjorn Helgaas 已提交
478
	case ACPI_RESOURCE_TYPE_IO:
479
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
480
		break;
481

B
Bjorn Helgaas 已提交
482
	case ACPI_RESOURCE_TYPE_FIXED_IO:
483
		pnpacpi_parse_fixed_port_option(dev, option_flags,
484
					        &res->data.fixed_io);
B
Bjorn Helgaas 已提交
485
		break;
486

B
Bjorn Helgaas 已提交
487 488 489
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
490

B
Bjorn Helgaas 已提交
491
	case ACPI_RESOURCE_TYPE_MEMORY24:
492 493
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
494
		break;
495

B
Bjorn Helgaas 已提交
496
	case ACPI_RESOURCE_TYPE_MEMORY32:
497 498
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
499
		break;
500

B
Bjorn Helgaas 已提交
501
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
502
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
503 504
						 &res->data.fixed_memory32);
		break;
505

B
Bjorn Helgaas 已提交
506 507 508
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
509
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
510
		break;
511

B
Bjorn Helgaas 已提交
512
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
513
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
514 515 516
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
517
		pnpacpi_parse_ext_irq_option(dev, option_flags,
518
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
519 520 521 522 523 524
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
525 526
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
527
		return AE_ERROR;
L
Linus Torvalds 已提交
528
	}
B
Bjorn Helgaas 已提交
529

L
Linus Torvalds 已提交
530 531 532
	return AE_OK;
}

533
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
534
{
535 536
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
537 538 539
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

B
Bjorn Helgaas 已提交
540
	pnp_dbg(&dev->dev, "parse resource options\n");
541

L
Linus Torvalds 已提交
542
	parse_data.dev = dev;
543 544
	parse_data.option_flags = 0;

B
Bob Moore 已提交
545
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
546
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
547

548 549 550 551 552 553
	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND)
			dev_err(&dev->dev, "can't evaluate _PRS: %d", status);
		return -EPERM;
	}
	return 0;
L
Linus Torvalds 已提交
554 555
}

556
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
557
{
558
	switch (res->type) {
B
Bob Moore 已提交
559 560 561 562 563 564 565 566 567 568
	case ACPI_RESOURCE_TYPE_IRQ:
	case ACPI_RESOURCE_TYPE_DMA:
	case ACPI_RESOURCE_TYPE_IO:
	case ACPI_RESOURCE_TYPE_FIXED_IO:
	case ACPI_RESOURCE_TYPE_MEMORY24:
	case ACPI_RESOURCE_TYPE_MEMORY32:
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
569
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
570
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
571
		return 1;
L
Linus Torvalds 已提交
572
	}
573 574 575 576 577 578 579
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
580
					   void *data)
581
{
582
	int *res_cnt = data;
583 584 585

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
586 587 588
	return AE_OK;
}

B
Bjorn Helgaas 已提交
589
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
590
{
591
	struct acpi_resource **resource = data;
592 593

	if (pnpacpi_supported_resource(res)) {
594
		(*resource)->type = res->type;
595
		(*resource)->length = sizeof(struct acpi_resource);
596 597 598
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
599 600 601 602 603 604
		(*resource)++;
	}

	return AE_OK;
}

605
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
606
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
607
{
608 609
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
610 611 612 613
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
614
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
615
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
616
	if (ACPI_FAILURE(status)) {
617
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
618 619 620 621 622
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
623
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
624 625
	if (!buffer->pointer)
		return -ENOMEM;
626

L
Linus Torvalds 已提交
627
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
628
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
629
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
630 631
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
632
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
633 634 635
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
636
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
L
Linus Torvalds 已提交
637 638 639 640

	return 0;
}

641 642
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
643
			       struct resource *p)
L
Linus Torvalds 已提交
644
{
645
	struct acpi_resource_irq *irq = &resource->data.irq;
646
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
647

648 649
	if (!pnp_resource_enabled(p)) {
		irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
650
		pnp_dbg(&dev->dev, "  encode irq (%s)\n",
651 652 653 654
			p ? "disabled" : "missing");
		return;
	}

655
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
656 657
	irq->triggering = triggering;
	irq->polarity = polarity;
658
	irq->sharable = shareable;
659 660
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
661

B
Bjorn Helgaas 已提交
662
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s (%d-byte descriptor)\n",
663
		(int) p->start,
664 665
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
666 667
		irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
		irq->descriptor_length);
L
Linus Torvalds 已提交
668 669
}

670 671
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
672
				   struct resource *p)
L
Linus Torvalds 已提交
673
{
674
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
675
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
676

677 678
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
679
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
680 681 682 683
			p ? "disabled" : "missing");
		return;
	}

684
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
685 686 687
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
688
	extended_irq->sharable = shareable;
689 690
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
691

B
Bjorn Helgaas 已提交
692
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
693 694 695
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
696 697
}

698 699
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
700
			       struct resource *p)
L
Linus Torvalds 已提交
701
{
702 703
	struct acpi_resource_dma *dma = &resource->data.dma;

704 705
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
706
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
707 708 709 710
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
711
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
712
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
713
	case IORESOURCE_DMA_TYPEA:
714
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
715 716
		break;
	case IORESOURCE_DMA_TYPEB:
717
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
718 719
		break;
	case IORESOURCE_DMA_TYPEF:
720
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
721 722
		break;
	default:
723
		dma->type = ACPI_COMPATIBILITY;
724 725 726
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
727
	case IORESOURCE_DMA_8BIT:
728
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
729 730
		break;
	case IORESOURCE_DMA_8AND16BIT:
731
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
732 733
		break;
	default:
734
		dma->transfer = ACPI_TRANSFER_16;
735 736
	}

737 738 739
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
740

B
Bjorn Helgaas 已提交
741
	pnp_dbg(&dev->dev, "  encode dma %d "
742 743
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
744 745
}

746 747
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
748
			      struct resource *p)
L
Linus Torvalds 已提交
749
{
750 751
	struct acpi_resource_io *io = &resource->data.io;

752 753
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
754
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
755 756 757 758
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
759
		io->address_length = resource_size(p);
760 761 762 763
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
764

B
Bjorn Helgaas 已提交
765
	pnp_dbg(&dev->dev, "  encode io %#x-%#x decode %#x\n", io->minimum,
766
		io->minimum + io->address_length - 1, io->io_decode);
L
Linus Torvalds 已提交
767 768
}

769 770
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
771
				    struct resource *p)
L
Linus Torvalds 已提交
772
{
773 774
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

775 776
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
777
		fixed_io->address_length = resource_size(p);
778 779 780 781
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
782

B
Bjorn Helgaas 已提交
783
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
784
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
785 786
}

787 788
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
789
				 struct resource *p)
L
Linus Torvalds 已提交
790
{
791 792
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

793 794 795 796 797 798 799
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */
		memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		memory24->minimum = p->start;
		memory24->maximum = p->end;
		memory24->alignment = 0;
800
		memory24->address_length = resource_size(p);
801 802 803 804 805
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
806
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
807 808
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
809
		memory24->write_protect);
L
Linus Torvalds 已提交
810 811
}

812 813
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
814
				 struct resource *p)
L
Linus Torvalds 已提交
815
{
816 817
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

818 819 820 821 822 823
	if (pnp_resource_enabled(p)) {
		memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		memory32->minimum = p->start;
		memory32->maximum = p->end;
		memory32->alignment = 0;
824
		memory32->address_length = resource_size(p);
825 826 827 828
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
829

B
Bjorn Helgaas 已提交
830
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
831 832
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
833
		memory32->write_protect);
L
Linus Torvalds 已提交
834 835
}

836 837
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
838
				       struct resource *p)
L
Linus Torvalds 已提交
839
{
840 841
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

842 843 844 845 846
	if (pnp_resource_enabled(p)) {
		fixed_memory32->write_protect =
		    p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		fixed_memory32->address = p->start;
847
		fixed_memory32->address_length = resource_size(p);
848 849 850 851
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
852

B
Bjorn Helgaas 已提交
853
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
854 855
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
856
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
857 858
}

859
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
860 861 862
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
863
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
864
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
865 866
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
867
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
868
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
869
		switch (resource->type) {
B
Bob Moore 已提交
870
		case ACPI_RESOURCE_TYPE_IRQ:
871
			pnpacpi_encode_irq(dev, resource,
872
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
873 874 875
			irq++;
			break;

B
Bob Moore 已提交
876
		case ACPI_RESOURCE_TYPE_DMA:
877
			pnpacpi_encode_dma(dev, resource,
878
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
879
			dma++;
L
Linus Torvalds 已提交
880
			break;
B
Bob Moore 已提交
881
		case ACPI_RESOURCE_TYPE_IO:
882
			pnpacpi_encode_io(dev, resource,
883
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
884
			port++;
L
Linus Torvalds 已提交
885
			break;
B
Bob Moore 已提交
886
		case ACPI_RESOURCE_TYPE_FIXED_IO:
887
			pnpacpi_encode_fixed_io(dev, resource,
888
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
889
			port++;
L
Linus Torvalds 已提交
890
			break;
B
Bob Moore 已提交
891
		case ACPI_RESOURCE_TYPE_MEMORY24:
892
			pnpacpi_encode_mem24(dev, resource,
893
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
894
			mem++;
L
Linus Torvalds 已提交
895
			break;
B
Bob Moore 已提交
896
		case ACPI_RESOURCE_TYPE_MEMORY32:
897
			pnpacpi_encode_mem32(dev, resource,
898
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
899
			mem++;
L
Linus Torvalds 已提交
900
			break;
B
Bob Moore 已提交
901
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
902
			pnpacpi_encode_fixed_mem32(dev, resource,
903
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
904
			mem++;
L
Linus Torvalds 已提交
905
			break;
906
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
907
			pnpacpi_encode_ext_irq(dev, resource,
908
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
909 910 911 912 913 914 915 916 917 918 919
			irq++;
			break;
		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		case ACPI_RESOURCE_TYPE_VENDOR:
		case ACPI_RESOURCE_TYPE_END_TAG:
		case ACPI_RESOURCE_TYPE_ADDRESS16:
		case ACPI_RESOURCE_TYPE_ADDRESS32:
		case ACPI_RESOURCE_TYPE_ADDRESS64:
		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
B
Bjorn Helgaas 已提交
920
		default:	/* other type */
921 922
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
923 924
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
925 926
		resource++;
		i++;
L
Linus Torvalds 已提交
927 928 929
	}
	return 0;
}