rsparser.c 25.5 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;
637
	resource->length = sizeof(struct acpi_resource);
L
Linus Torvalds 已提交
638 639 640 641

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

794 795 796 797 798 799 800
	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;
801
		memory24->address_length = resource_size(p);
802 803 804 805 806
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

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

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

819 820 821 822 823 824
	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;
825
		memory32->address_length = resource_size(p);
826 827 828 829
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
830

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

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

843 844 845 846 847
	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;
848
		fixed_memory32->address_length = resource_size(p);
849 850 851 852
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
853

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

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

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

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