rsparser.c 25.8 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 = {0};
184
	int i, flags;
L
Linus Torvalds 已提交
185

186
	if (acpi_dev_resource_address_space(res, &r)
187 188 189 190 191 192 193 194 195 196
	    || 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);
197

198
		if (i > 1) {
199 200 201 202 203
			/*
			 * 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.
			 */
204
			if (pnp_can_write(dev)) {
205 206 207 208 209
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
L
Linus Torvalds 已提交
210
		}
211 212 213 214 215
		return AE_OK;
	} else if (r.flags & IORESOURCE_DISABLED) {
		pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		return AE_OK;
	}
L
Linus Torvalds 已提交
216

217
	switch (res->type) {
218 219 220 221 222 223 224 225 226 227 228
	case ACPI_RESOURCE_TYPE_MEMORY24:
	case ACPI_RESOURCE_TYPE_MEMORY32:
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
		if (acpi_dev_resource_memory(res, &r))
			pnp_add_resource(dev, &r);
		break;
	case ACPI_RESOURCE_TYPE_IO:
	case ACPI_RESOURCE_TYPE_FIXED_IO:
		if (acpi_dev_resource_io(res, &r))
			pnp_add_resource(dev, &r);
		break;
B
Bob Moore 已提交
229
	case ACPI_RESOURCE_TYPE_DMA:
230
		dma = &res->data.dma;
231
		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
232
			flags = dma_flags(dev, dma->type, dma->bus_master,
233
					  dma->transfer);
234 235 236
		else
			flags = IORESOURCE_DISABLED;
		pnp_add_dma_resource(dev, dma->channels[0], flags);
L
Linus Torvalds 已提交
237
		break;
238 239 240 241 242 243

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

	case ACPI_RESOURCE_TYPE_VENDOR:
244 245
		vendor_typed = &res->data.vendor_typed;
		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
246 247 248 249 250 251
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
L
Linus Torvalds 已提交
252
		break;
253

L
Linus Torvalds 已提交
254
	default:
255 256
		dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
			 res->type);
L
Linus Torvalds 已提交
257 258
		return AE_ERROR;
	}
B
Bjorn Helgaas 已提交
259

L
Linus Torvalds 已提交
260 261 262
	return AE_OK;
}

263
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
L
Linus Torvalds 已提交
264
{
265 266
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
267
	acpi_status status;
268

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

271
	pnp_init_resources(dev);
L
Linus Torvalds 已提交
272

273 274 275 276 277 278 279 280 281
	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 已提交
282 283
}

284
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
285
					    unsigned int option_flags,
286
					    struct acpi_resource_dma *p)
L
Linus Torvalds 已提交
287 288
{
	int i;
289
	unsigned char map = 0, flags;
L
Linus Torvalds 已提交
290

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

294
	flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
295
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
296 297
}

298
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
299
					    unsigned int option_flags,
300
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
301 302
{
	int i;
303
	pnp_irq_mask_t map;
304
	unsigned char flags;
L
Linus Torvalds 已提交
305

306
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
307
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
308
		if (p->interrupts[i])
309
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
310

311
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
312
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
313 314
}

315
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
316
					unsigned int option_flags,
317
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
318 319
{
	int i;
320
	pnp_irq_mask_t map;
321
	unsigned char flags;
L
Linus Torvalds 已提交
322

323
	bitmap_zero(map.bits, PNP_IRQ_NR);
324 325 326 327 328 329 330 331 332 333
	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 已提交
334

335
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
336
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
337 338
}

339
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
340
					     unsigned int option_flags,
341
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
342
{
343
	unsigned char flags = 0;
L
Linus Torvalds 已提交
344

345
	if (io->io_decode == ACPI_DECODE_16)
346
		flags = IORESOURCE_IO_16BIT_ADDR;
347
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
348
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
349 350
}

351
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
352
					unsigned int option_flags,
353
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
354
{
355
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
356
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
357 358
}

359
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
360
					      unsigned int option_flags,
361
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
362
{
363
	unsigned char flags = 0;
L
Linus Torvalds 已提交
364

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

371
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
372
					      unsigned int option_flags,
373
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
374
{
375
	unsigned char flags = 0;
L
Linus Torvalds 已提交
376

377
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
378
		flags = IORESOURCE_MEM_WRITEABLE;
379
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
380
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
381 382
}

383
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
384
					unsigned int option_flags,
385
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
386
{
387
	unsigned char flags = 0;
L
Linus Torvalds 已提交
388

389
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
390
		flags = IORESOURCE_MEM_WRITEABLE;
391
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
392
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
393 394
}

395
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
396
						unsigned int option_flags,
397
						struct acpi_resource *r)
398 399 400
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
401
	unsigned char flags = 0;
402 403

	status = acpi_resource_to_address64(r, p);
404 405
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
406
			 r->type);
407 408 409 410
		return;
	}

	if (p->resource_type == ACPI_MEMORY_RANGE) {
411
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
412
			flags = IORESOURCE_MEM_WRITEABLE;
413 414
		pnp_register_mem_resource(dev, option_flags, p->address.minimum,
					  p->address.minimum, 0, p->address.address_length,
415
					  flags);
416
	} else if (p->resource_type == ACPI_IO_RANGE)
417 418
		pnp_register_port_resource(dev, option_flags, p->address.minimum,
					   p->address.minimum, 0, p->address.address_length,
419
					   IORESOURCE_IO_FIXED);
420 421
}

422 423 424 425 426 427 428 429 430
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)
431
			flags = IORESOURCE_MEM_WRITEABLE;
432 433
		pnp_register_mem_resource(dev, option_flags, p->address.minimum,
					  p->address.minimum, 0, p->address.address_length,
434 435
					  flags);
	} else if (p->resource_type == ACPI_IO_RANGE)
436 437
		pnp_register_port_resource(dev, option_flags, p->address.minimum,
					   p->address.minimum, 0, p->address.address_length,
438
					   IORESOURCE_IO_FIXED);
439 440
}

L
Linus Torvalds 已提交
441 442
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
443
	unsigned int option_flags;
L
Linus Torvalds 已提交
444 445
};

446 447
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
448
{
449
	int priority;
450
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
451
	struct pnp_dev *dev = parse_data->dev;
452
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
453

454
	switch (res->type) {
B
Bjorn Helgaas 已提交
455
	case ACPI_RESOURCE_TYPE_IRQ:
456
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
457
		break;
458

B
Bjorn Helgaas 已提交
459
	case ACPI_RESOURCE_TYPE_DMA:
460
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
461
		break;
462

B
Bjorn Helgaas 已提交
463 464 465 466
	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 已提交
467
			break;
468

B
Bjorn Helgaas 已提交
469 470
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
471
			break;
472

B
Bjorn Helgaas 已提交
473 474
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
475
			break;
B
Bjorn Helgaas 已提交
476 477
		default:
			priority = PNP_RES_PRIORITY_INVALID;
478
			break;
B
Bjorn Helgaas 已提交
479
		}
480
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
481
		break;
482

B
Bjorn Helgaas 已提交
483
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
484
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
485
		break;
486

B
Bjorn Helgaas 已提交
487
	case ACPI_RESOURCE_TYPE_IO:
488
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
489
		break;
490

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

B
Bjorn Helgaas 已提交
496 497 498
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
499

B
Bjorn Helgaas 已提交
500
	case ACPI_RESOURCE_TYPE_MEMORY24:
501 502
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
503
		break;
504

B
Bjorn Helgaas 已提交
505
	case ACPI_RESOURCE_TYPE_MEMORY32:
506 507
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
508
		break;
509

B
Bjorn Helgaas 已提交
510
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
511
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
512 513
						 &res->data.fixed_memory32);
		break;
514

B
Bjorn Helgaas 已提交
515 516 517
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
518
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
519
		break;
520

B
Bjorn Helgaas 已提交
521
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
522
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
523 524 525
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
526
		pnpacpi_parse_ext_irq_option(dev, option_flags,
527
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
528 529 530 531 532 533
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
534 535
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
536
		return AE_ERROR;
L
Linus Torvalds 已提交
537
	}
B
Bjorn Helgaas 已提交
538

L
Linus Torvalds 已提交
539 540 541
	return AE_OK;
}

542
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
543
{
544 545
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
546 547 548
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

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

L
Linus Torvalds 已提交
551
	parse_data.dev = dev;
552 553
	parse_data.option_flags = 0;

B
Bob Moore 已提交
554
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
555
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
556

557 558 559 560 561 562
	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 已提交
563 564
}

565
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
566
{
567
	switch (res->type) {
B
Bob Moore 已提交
568 569 570 571 572 573 574 575 576 577
	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:
578
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
579
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
580
		return 1;
L
Linus Torvalds 已提交
581
	}
582 583 584 585 586 587 588
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
589
					   void *data)
590
{
591
	int *res_cnt = data;
592 593 594

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
595 596 597
	return AE_OK;
}

B
Bjorn Helgaas 已提交
598
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
599
{
600
	struct acpi_resource **resource = data;
601 602

	if (pnpacpi_supported_resource(res)) {
603
		(*resource)->type = res->type;
604
		(*resource)->length = sizeof(struct acpi_resource);
605 606 607
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
608 609 610 611 612 613
		(*resource)++;
	}

	return AE_OK;
}

614
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
615
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
616
{
617 618
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
619 620 621 622
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
623
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
624
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
625
	if (ACPI_FAILURE(status)) {
626
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
627 628 629 630 631
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
632
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
633 634
	if (!buffer->pointer)
		return -ENOMEM;
635

L
Linus Torvalds 已提交
636
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
637
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
638
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
639 640
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
641
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
642 643 644
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
645
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
646
	resource->length = sizeof(struct acpi_resource);
L
Linus Torvalds 已提交
647 648 649 650

	return 0;
}

651 652
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
653
			       struct resource *p)
L
Linus Torvalds 已提交
654
{
655
	struct acpi_resource_irq *irq = &resource->data.irq;
656
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
657

658 659
	if (!pnp_resource_enabled(p)) {
		irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
660
		pnp_dbg(&dev->dev, "  encode irq (%s)\n",
661 662 663 664
			p ? "disabled" : "missing");
		return;
	}

665
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
666 667
	irq->triggering = triggering;
	irq->polarity = polarity;
668
	irq->sharable = shareable;
669 670
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
671

B
Bjorn Helgaas 已提交
672
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s (%d-byte descriptor)\n",
673
		(int) p->start,
674 675
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
676 677
		irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
		irq->descriptor_length);
L
Linus Torvalds 已提交
678 679
}

680 681
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
682
				   struct resource *p)
L
Linus Torvalds 已提交
683
{
684
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
685
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
686

687 688
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
689
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
690 691 692 693
			p ? "disabled" : "missing");
		return;
	}

694
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
695 696 697
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
698
	extended_irq->sharable = shareable;
699 700
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
701

B
Bjorn Helgaas 已提交
702
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
703 704 705
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
706 707
}

708 709
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
710
			       struct resource *p)
L
Linus Torvalds 已提交
711
{
712 713
	struct acpi_resource_dma *dma = &resource->data.dma;

714 715
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
716
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
717 718 719 720
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
721
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
722
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
723
	case IORESOURCE_DMA_TYPEA:
724
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
725 726
		break;
	case IORESOURCE_DMA_TYPEB:
727
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
728 729
		break;
	case IORESOURCE_DMA_TYPEF:
730
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
731 732
		break;
	default:
733
		dma->type = ACPI_COMPATIBILITY;
734 735 736
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
737
	case IORESOURCE_DMA_8BIT:
738
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
739 740
		break;
	case IORESOURCE_DMA_8AND16BIT:
741
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
742 743
		break;
	default:
744
		dma->transfer = ACPI_TRANSFER_16;
745 746
	}

747 748 749
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
750

B
Bjorn Helgaas 已提交
751
	pnp_dbg(&dev->dev, "  encode dma %d "
752 753
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
754 755
}

756 757
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
758
			      struct resource *p)
L
Linus Torvalds 已提交
759
{
760 761
	struct acpi_resource_io *io = &resource->data.io;

762 763
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
764
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
765 766 767 768
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
769
		io->address_length = resource_size(p);
770 771 772 773
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
774

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

779 780
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
781
				    struct resource *p)
L
Linus Torvalds 已提交
782
{
783 784
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

785 786
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
787
		fixed_io->address_length = resource_size(p);
788 789 790 791
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
792

B
Bjorn Helgaas 已提交
793
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
794
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
795 796
}

797 798
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
799
				 struct resource *p)
L
Linus Torvalds 已提交
800
{
801 802
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

803 804 805 806 807 808 809
	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;
810
		memory24->address_length = resource_size(p);
811 812 813 814 815
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
816
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
817 818
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
819
		memory24->write_protect);
L
Linus Torvalds 已提交
820 821
}

822 823
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
824
				 struct resource *p)
L
Linus Torvalds 已提交
825
{
826 827
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

828 829 830 831 832 833
	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;
834
		memory32->address_length = resource_size(p);
835 836 837 838
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
839

B
Bjorn Helgaas 已提交
840
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
841 842
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
843
		memory32->write_protect);
L
Linus Torvalds 已提交
844 845
}

846 847
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
848
				       struct resource *p)
L
Linus Torvalds 已提交
849
{
850 851
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

852 853 854 855 856
	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;
857
		fixed_memory32->address_length = resource_size(p);
858 859 860 861
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
862

B
Bjorn Helgaas 已提交
863
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
864 865
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
866
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
867 868
}

869
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
870 871 872
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
873
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
874
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
875 876
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
877
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
878
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
879
		switch (resource->type) {
B
Bob Moore 已提交
880
		case ACPI_RESOURCE_TYPE_IRQ:
881
			pnpacpi_encode_irq(dev, resource,
882
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
883 884 885
			irq++;
			break;

B
Bob Moore 已提交
886
		case ACPI_RESOURCE_TYPE_DMA:
887
			pnpacpi_encode_dma(dev, resource,
888
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
889
			dma++;
L
Linus Torvalds 已提交
890
			break;
B
Bob Moore 已提交
891
		case ACPI_RESOURCE_TYPE_IO:
892
			pnpacpi_encode_io(dev, resource,
893
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
894
			port++;
L
Linus Torvalds 已提交
895
			break;
B
Bob Moore 已提交
896
		case ACPI_RESOURCE_TYPE_FIXED_IO:
897
			pnpacpi_encode_fixed_io(dev, resource,
898
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
899
			port++;
L
Linus Torvalds 已提交
900
			break;
B
Bob Moore 已提交
901
		case ACPI_RESOURCE_TYPE_MEMORY24:
902
			pnpacpi_encode_mem24(dev, resource,
903
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
904
			mem++;
L
Linus Torvalds 已提交
905
			break;
B
Bob Moore 已提交
906
		case ACPI_RESOURCE_TYPE_MEMORY32:
907
			pnpacpi_encode_mem32(dev, resource,
908
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
909
			mem++;
L
Linus Torvalds 已提交
910
			break;
B
Bob Moore 已提交
911
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
912
			pnpacpi_encode_fixed_mem32(dev, resource,
913
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
914
			mem++;
L
Linus Torvalds 已提交
915
			break;
916
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
917
			pnpacpi_encode_ext_irq(dev, resource,
918
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
919 920 921 922 923 924 925 926 927 928 929
			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 已提交
930
		default:	/* other type */
931 932
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
933 934
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
935 936
		resource++;
		i++;
L
Linus Torvalds 已提交
937 938 939
	}
	return 0;
}