rsparser.c 32.6 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 31 32 33 34 35 36 37 38 39
#include "pnpacpi.h"

#ifdef CONFIG_IA64
#define valid_IRQ(i) (1)
#else
#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
#endif

/*
 * Allocated Resources
 */
40
static int irq_flags(int triggering, int polarity, int shareable)
L
Linus Torvalds 已提交
41
{
42 43
	int flags;

B
Bob Moore 已提交
44
	if (triggering == ACPI_LEVEL_SENSITIVE) {
B
Bjorn Helgaas 已提交
45
		if (polarity == ACPI_ACTIVE_LOW)
46
			flags = IORESOURCE_IRQ_LOWLEVEL;
L
Linus Torvalds 已提交
47
		else
48
			flags = IORESOURCE_IRQ_HIGHLEVEL;
B
Bjorn Helgaas 已提交
49
	} else {
B
Bjorn Helgaas 已提交
50
		if (polarity == ACPI_ACTIVE_LOW)
51
			flags = IORESOURCE_IRQ_LOWEDGE;
L
Linus Torvalds 已提交
52
		else
53
			flags = IORESOURCE_IRQ_HIGHEDGE;
L
Linus Torvalds 已提交
54
	}
55

56
	if (shareable == ACPI_SHARED)
57 58 59
		flags |= IORESOURCE_IRQ_SHAREABLE;

	return flags;
L
Linus Torvalds 已提交
60 61
}

B
Bjorn Helgaas 已提交
62
static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
63
			     int *polarity, int *shareable)
L
Linus Torvalds 已提交
64
{
B
Bjorn Helgaas 已提交
65 66
	switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
			 IORESOURCE_IRQ_LOWEDGE  | IORESOURCE_IRQ_HIGHEDGE)) {
L
Linus Torvalds 已提交
67
	case IORESOURCE_IRQ_LOWLEVEL:
B
Bob Moore 已提交
68 69
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
70
		break;
B
Bjorn Helgaas 已提交
71
	case IORESOURCE_IRQ_HIGHLEVEL:
B
Bob Moore 已提交
72 73
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
74 75
		break;
	case IORESOURCE_IRQ_LOWEDGE:
B
Bob Moore 已提交
76 77
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
78 79
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
B
Bob Moore 已提交
80 81
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
82
		break;
B
Bjorn Helgaas 已提交
83 84 85 86 87 88
	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 已提交
89
	}
90 91 92 93 94

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

97
static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
98 99
						u32 gsi, int triggering,
						int polarity, int shareable)
L
Linus Torvalds 已提交
100
{
101
	int irq, flags;
102
	int p, t;
103

104 105
	if (!valid_IRQ(gsi)) {
		pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED);
106
		return;
107
	}
108

109 110 111 112 113 114 115 116 117 118
	/*
	 * in IO-APIC mode, use overrided attribute. Two reasons:
	 * 1. BIOS bug in DSDT
	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
	 */
	if (!acpi_get_override_irq(gsi, &t, &p)) {
		t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
		p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;

		if (triggering != t || polarity != p) {
119
			dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
120 121 122 123 124 125
				gsi, t ? "edge":"level", p ? "low":"high");
			triggering = t;
			polarity = p;
		}
	}

126
	flags = irq_flags(triggering, polarity, shareable);
127
	irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
128 129 130 131
	if (irq >= 0)
		pcibios_penalize_isa_irq(irq, 1);
	else
		flags |= IORESOURCE_DISABLED;
132

133
	pnp_add_irq_resource(dev, irq, flags);
L
Linus Torvalds 已提交
134 135
}

136 137
static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
		     int transfer)
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
	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;
159
		dev_err(&dev->dev, "invalid DMA type %d\n", type);
160 161 162 163 164 165 166 167 168 169 170 171 172 173
	}
	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;
174
		dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
175 176 177 178 179
	}

	return flags;
}

180
static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
B
Bjorn Helgaas 已提交
181 182
					       u64 len, int io_decode,
					       int window)
L
Linus Torvalds 已提交
183
{
184 185
	int flags = 0;
	u64 end = start + len - 1;
B
Bjorn Helgaas 已提交
186

187
	if (io_decode == ACPI_DECODE_16)
188
		flags |= IORESOURCE_IO_16BIT_ADDR;
189 190
	if (len == 0 || end >= 0x10003)
		flags |= IORESOURCE_DISABLED;
B
Bjorn Helgaas 已提交
191 192
	if (window)
		flags |= IORESOURCE_WINDOW;
193 194

	pnp_add_io_resource(dev, start, end, flags);
L
Linus Torvalds 已提交
195 196
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*
 * 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);
	}
}

252
static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
253
						u64 start, u64 len,
B
Bjorn Helgaas 已提交
254
						int write_protect, int window)
L
Linus Torvalds 已提交
255
{
256 257 258 259 260 261 262
	int flags = 0;
	u64 end = start + len - 1;

	if (len == 0)
		flags |= IORESOURCE_DISABLED;
	if (write_protect == ACPI_READ_WRITE_MEMORY)
		flags |= IORESOURCE_MEM_WRITEABLE;
B
Bjorn Helgaas 已提交
263 264
	if (window)
		flags |= IORESOURCE_WINDOW;
265 266

	pnp_add_mem_resource(dev, start, end, flags);
L
Linus Torvalds 已提交
267 268
}

B
Bjorn Helgaas 已提交
269 270 271 272 273 274 275 276
static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
						u64 start, u64 len)
{
	u64 end = start + len - 1;

	pnp_add_bus_resource(dev, start, end);
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len)
{
	u64 max_len;

	max_len = max - min + 1;
	if (len <= max_len)
		return len;

	/*
	 * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes
	 * don't do this correctly, e.g.,
	 * https://bugzilla.kernel.org/show_bug.cgi?id=15480
	 */
	dev_info(&dev->dev,
	         "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n",
		 (unsigned long long) len, (unsigned long long) min,
		 (unsigned long long) max);
	return max_len;
}

297
static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
298
						  struct acpi_resource *res)
299 300 301
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
B
Bjorn Helgaas 已提交
302
	int window;
303
	u64 len;
304 305 306

	status = acpi_resource_to_address64(res, p);
	if (!ACPI_SUCCESS(status)) {
307
		dev_warn(&dev->dev, "failed to convert resource type %d\n",
B
Bjorn Helgaas 已提交
308
			 res->type);
309 310 311
		return;
	}

312
	len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
B
Bjorn Helgaas 已提交
313
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
314

315
	if (p->resource_type == ACPI_MEMORY_RANGE)
316
		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
317
			p->info.mem.write_protect, window);
318
	else if (p->resource_type == ACPI_IO_RANGE)
319
		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
320
			p->granularity == 0xfff ? ACPI_DECODE_10 :
B
Bjorn Helgaas 已提交
321
				ACPI_DECODE_16, window);
B
Bjorn Helgaas 已提交
322
	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
323
		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
324
}
L
Linus Torvalds 已提交
325

326 327 328 329
static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
						      struct acpi_resource *res)
{
	struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
B
Bjorn Helgaas 已提交
330
	int window;
331
	u64 len;
332

333
	len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
B
Bjorn Helgaas 已提交
334
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
335 336

	if (p->resource_type == ACPI_MEMORY_RANGE)
337
		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
338
			p->info.mem.write_protect, window);
339
	else if (p->resource_type == ACPI_IO_RANGE)
340
		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
341
			p->granularity == 0xfff ? ACPI_DECODE_10 :
B
Bjorn Helgaas 已提交
342
				ACPI_DECODE_16, window);
B
Bjorn Helgaas 已提交
343
	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
344
		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
345 346
}

L
Linus Torvalds 已提交
347
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
348
					      void *data)
L
Linus Torvalds 已提交
349
{
350
	struct pnp_dev *dev = data;
351 352 353 354
	struct acpi_resource_irq *irq;
	struct acpi_resource_dma *dma;
	struct acpi_resource_io *io;
	struct acpi_resource_fixed_io *fixed_io;
355
	struct acpi_resource_vendor_typed *vendor_typed;
356 357 358 359
	struct acpi_resource_memory24 *memory24;
	struct acpi_resource_memory32 *memory32;
	struct acpi_resource_fixed_memory32 *fixed_memory32;
	struct acpi_resource_extended_irq *extended_irq;
360
	int i, flags;
L
Linus Torvalds 已提交
361

362
	switch (res->type) {
B
Bob Moore 已提交
363
	case ACPI_RESOURCE_TYPE_IRQ:
364 365 366 367
		/*
		 * Per spec, only one interrupt per descriptor is allowed in
		 * _CRS, but some firmware violates this, so parse them all.
		 */
368
		irq = &res->data.irq;
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
		if (irq->interrupt_count == 0)
			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		else {
			for (i = 0; i < irq->interrupt_count; i++) {
				pnpacpi_parse_allocated_irqresource(dev,
					irq->interrupts[i],
					irq->triggering,
					irq->polarity,
				    irq->sharable);
			}

			/*
			 * 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.
			 */
			if (pnp_can_write(dev) && irq->interrupt_count > 1) {
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
L
Linus Torvalds 已提交
391 392 393
		}
		break;

B
Bob Moore 已提交
394
	case ACPI_RESOURCE_TYPE_DMA:
395
		dma = &res->data.dma;
396
		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
397
			flags = dma_flags(dev, dma->type, dma->bus_master,
398
					  dma->transfer);
399 400 401
		else
			flags = IORESOURCE_DISABLED;
		pnp_add_dma_resource(dev, dma->channels[0], flags);
L
Linus Torvalds 已提交
402
		break;
403

B
Bob Moore 已提交
404
	case ACPI_RESOURCE_TYPE_IO:
405
		io = &res->data.io;
406
		pnpacpi_parse_allocated_ioresource(dev,
407 408
			io->minimum,
			io->address_length,
B
Bjorn Helgaas 已提交
409
			io->io_decode, 0);
L
Linus Torvalds 已提交
410
		break;
411 412 413 414 415

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

B
Bob Moore 已提交
416
	case ACPI_RESOURCE_TYPE_FIXED_IO:
417
		fixed_io = &res->data.fixed_io;
418
		pnpacpi_parse_allocated_ioresource(dev,
419 420
			fixed_io->address,
			fixed_io->address_length,
B
Bjorn Helgaas 已提交
421
			ACPI_DECODE_10, 0);
L
Linus Torvalds 已提交
422
		break;
423 424

	case ACPI_RESOURCE_TYPE_VENDOR:
425 426
		vendor_typed = &res->data.vendor_typed;
		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
427 428 429 430 431
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

B
Bob Moore 已提交
432
	case ACPI_RESOURCE_TYPE_MEMORY24:
433
		memory24 = &res->data.memory24;
434
		pnpacpi_parse_allocated_memresource(dev,
435 436
			memory24->minimum,
			memory24->address_length,
B
Bjorn Helgaas 已提交
437
			memory24->write_protect, 0);
L
Linus Torvalds 已提交
438
		break;
B
Bob Moore 已提交
439
	case ACPI_RESOURCE_TYPE_MEMORY32:
440
		memory32 = &res->data.memory32;
441
		pnpacpi_parse_allocated_memresource(dev,
442 443
			memory32->minimum,
			memory32->address_length,
B
Bjorn Helgaas 已提交
444
			memory32->write_protect, 0);
L
Linus Torvalds 已提交
445
		break;
B
Bob Moore 已提交
446
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
447
		fixed_memory32 = &res->data.fixed_memory32;
448
		pnpacpi_parse_allocated_memresource(dev,
449 450
			fixed_memory32->address,
			fixed_memory32->address_length,
B
Bjorn Helgaas 已提交
451
			fixed_memory32->write_protect, 0);
L
Linus Torvalds 已提交
452
		break;
B
Bob Moore 已提交
453 454 455
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
456
		pnpacpi_parse_allocated_address_space(dev, res);
L
Linus Torvalds 已提交
457
		break;
458 459

	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
460
		pnpacpi_parse_allocated_ext_address_space(dev, res);
461 462 463
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
464
		extended_irq = &res->data.extended_irq;
465

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
		if (extended_irq->interrupt_count == 0)
			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		else {
			for (i = 0; i < extended_irq->interrupt_count; i++) {
				pnpacpi_parse_allocated_irqresource(dev,
					extended_irq->interrupts[i],
					extended_irq->triggering,
					extended_irq->polarity,
					extended_irq->sharable);
			}

			/*
			 * 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.
			 */
			if (pnp_can_write(dev) &&
			    extended_irq->interrupt_count > 1) {
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
489 490 491 492
		}
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
L
Linus Torvalds 已提交
493
		break;
494

L
Linus Torvalds 已提交
495
	default:
496 497
		dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
			 res->type);
L
Linus Torvalds 已提交
498 499
		return AE_ERROR;
	}
B
Bjorn Helgaas 已提交
500

L
Linus Torvalds 已提交
501 502 503
	return AE_OK;
}

504
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
L
Linus Torvalds 已提交
505
{
506 507
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
508
	acpi_status status;
509

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

512
	pnp_init_resources(dev);
L
Linus Torvalds 已提交
513

514 515 516 517 518 519 520 521 522
	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 已提交
523 524
}

525
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
526
					    unsigned int option_flags,
527
					    struct acpi_resource_dma *p)
L
Linus Torvalds 已提交
528 529
{
	int i;
530
	unsigned char map = 0, flags;
L
Linus Torvalds 已提交
531

B
Bob Moore 已提交
532
	if (p->channel_count == 0)
L
Linus Torvalds 已提交
533 534
		return;

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

538
	flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
539
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
540 541
}

542
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
543
					    unsigned int option_flags,
544
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
545 546
{
	int i;
547 548
	pnp_irq_mask_t map;
	unsigned char flags;
B
Bjorn Helgaas 已提交
549

B
Bob Moore 已提交
550
	if (p->interrupt_count == 0)
L
Linus Torvalds 已提交
551 552
		return;

553
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
554
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
555
		if (p->interrupts[i])
556
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
557

558
	flags = irq_flags(p->triggering, p->polarity, p->sharable);
559
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
560 561
}

562
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
563
					unsigned int option_flags,
564
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
565 566
{
	int i;
567 568
	pnp_irq_mask_t map;
	unsigned char flags;
L
Linus Torvalds 已提交
569

B
Bob Moore 已提交
570
	if (p->interrupt_count == 0)
L
Linus Torvalds 已提交
571 572
		return;

573
	bitmap_zero(map.bits, PNP_IRQ_NR);
574 575 576 577 578 579 580 581 582 583
	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 已提交
584

585
	flags = irq_flags(p->triggering, p->polarity, p->sharable);
586
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
587 588
}

589
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
590
					     unsigned int option_flags,
591
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
592
{
593
	unsigned char flags = 0;
L
Linus Torvalds 已提交
594

B
Bob Moore 已提交
595
	if (io->address_length == 0)
L
Linus Torvalds 已提交
596
		return;
597 598 599

	if (io->io_decode == ACPI_DECODE_16)
		flags = IORESOURCE_IO_16BIT_ADDR;
600
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
601
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
602 603
}

604
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
605
					unsigned int option_flags,
606
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
607
{
B
Bob Moore 已提交
608
	if (io->address_length == 0)
L
Linus Torvalds 已提交
609
		return;
610

611 612
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
613 614
}

615
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
616
					      unsigned int option_flags,
617
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
618
{
619
	unsigned char flags = 0;
L
Linus Torvalds 已提交
620

B
Bob Moore 已提交
621
	if (p->address_length == 0)
L
Linus Torvalds 已提交
622 623
		return;

624 625
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
		flags = IORESOURCE_MEM_WRITEABLE;
626
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
627
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
628 629
}

630
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
631
					      unsigned int option_flags,
632
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
633
{
634
	unsigned char flags = 0;
L
Linus Torvalds 已提交
635

B
Bob Moore 已提交
636
	if (p->address_length == 0)
L
Linus Torvalds 已提交
637 638
		return;

639 640
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
		flags = IORESOURCE_MEM_WRITEABLE;
641
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
642
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
643 644
}

645
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
646
					unsigned int option_flags,
647
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
648
{
649
	unsigned char flags = 0;
L
Linus Torvalds 已提交
650

B
Bob Moore 已提交
651
	if (p->address_length == 0)
L
Linus Torvalds 已提交
652 653
		return;

654 655
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
		flags = IORESOURCE_MEM_WRITEABLE;
656
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
657
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
658 659
}

660
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
661
						unsigned int option_flags,
662
						struct acpi_resource *r)
663 664 665
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
666
	unsigned char flags = 0;
667 668

	status = acpi_resource_to_address64(r, p);
669 670
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
671
			 r->type);
672 673 674 675 676 677 678
		return;
	}

	if (p->address_length == 0)
		return;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
679 680
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
			flags = IORESOURCE_MEM_WRITEABLE;
681 682 683
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
684
	} else if (p->resource_type == ACPI_IO_RANGE)
685 686
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
687
					   IORESOURCE_IO_FIXED);
688 689
}

690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
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->address_length == 0)
		return;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
			flags = IORESOURCE_MEM_WRITEABLE;
		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,
					   IORESOURCE_IO_FIXED);
}

L
Linus Torvalds 已提交
712 713
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
714
	unsigned int option_flags;
L
Linus Torvalds 已提交
715 716
};

717 718
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
719
{
720
	int priority;
721
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
722
	struct pnp_dev *dev = parse_data->dev;
723
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
724

725
	switch (res->type) {
B
Bjorn Helgaas 已提交
726
	case ACPI_RESOURCE_TYPE_IRQ:
727
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
728
		break;
729

B
Bjorn Helgaas 已提交
730
	case ACPI_RESOURCE_TYPE_DMA:
731
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
732
		break;
733

B
Bjorn Helgaas 已提交
734 735 736 737
	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 已提交
738
			break;
739

B
Bjorn Helgaas 已提交
740 741
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
742
			break;
743

B
Bjorn Helgaas 已提交
744 745
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
746
			break;
B
Bjorn Helgaas 已提交
747 748
		default:
			priority = PNP_RES_PRIORITY_INVALID;
749
			break;
B
Bjorn Helgaas 已提交
750
		}
751
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
752
		break;
753

B
Bjorn Helgaas 已提交
754
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
755
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
756
		break;
757

B
Bjorn Helgaas 已提交
758
	case ACPI_RESOURCE_TYPE_IO:
759
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
760
		break;
761

B
Bjorn Helgaas 已提交
762
	case ACPI_RESOURCE_TYPE_FIXED_IO:
763
		pnpacpi_parse_fixed_port_option(dev, option_flags,
764
					        &res->data.fixed_io);
B
Bjorn Helgaas 已提交
765
		break;
766

B
Bjorn Helgaas 已提交
767 768 769
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
770

B
Bjorn Helgaas 已提交
771
	case ACPI_RESOURCE_TYPE_MEMORY24:
772 773
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
774
		break;
775

B
Bjorn Helgaas 已提交
776
	case ACPI_RESOURCE_TYPE_MEMORY32:
777 778
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
779
		break;
780

B
Bjorn Helgaas 已提交
781
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
782
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
783 784
						 &res->data.fixed_memory32);
		break;
785

B
Bjorn Helgaas 已提交
786 787 788
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
789
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
790
		break;
791

B
Bjorn Helgaas 已提交
792
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
793
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
794 795 796
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
797
		pnpacpi_parse_ext_irq_option(dev, option_flags,
798
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
799 800 801 802 803 804
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
805 806
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
807
		return AE_ERROR;
L
Linus Torvalds 已提交
808
	}
B
Bjorn Helgaas 已提交
809

L
Linus Torvalds 已提交
810 811 812
	return AE_OK;
}

813
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
814
{
815 816
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
817 818 819
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

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

L
Linus Torvalds 已提交
822
	parse_data.dev = dev;
823 824
	parse_data.option_flags = 0;

B
Bob Moore 已提交
825
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
826
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
827

828 829 830 831 832 833
	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 已提交
834 835
}

836
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
837
{
838
	switch (res->type) {
B
Bob Moore 已提交
839 840 841 842 843 844 845 846 847 848
	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:
849
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
850
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
851
		return 1;
L
Linus Torvalds 已提交
852
	}
853 854 855 856 857 858 859
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
860
					   void *data)
861
{
862
	int *res_cnt = data;
863 864 865

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
866 867 868
	return AE_OK;
}

B
Bjorn Helgaas 已提交
869
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
870
{
871
	struct acpi_resource **resource = data;
872 873

	if (pnpacpi_supported_resource(res)) {
874
		(*resource)->type = res->type;
875
		(*resource)->length = sizeof(struct acpi_resource);
876 877 878
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
879 880 881 882 883 884
		(*resource)++;
	}

	return AE_OK;
}

885
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
886
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
887
{
888 889
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
890 891 892 893
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
894
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
895
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
896
	if (ACPI_FAILURE(status)) {
897
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
898 899 900 901 902
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
903
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
904 905
	if (!buffer->pointer)
		return -ENOMEM;
906

L
Linus Torvalds 已提交
907
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
908
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
909
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
910 911
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
912
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
913 914 915
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
916
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
L
Linus Torvalds 已提交
917 918 919 920

	return 0;
}

921 922
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
923
			       struct resource *p)
L
Linus Torvalds 已提交
924
{
925
	struct acpi_resource_irq *irq = &resource->data.irq;
926
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
927

928 929
	if (!pnp_resource_enabled(p)) {
		irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
930
		pnp_dbg(&dev->dev, "  encode irq (%s)\n",
931 932 933 934
			p ? "disabled" : "missing");
		return;
	}

935
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
936 937
	irq->triggering = triggering;
	irq->polarity = polarity;
938
	irq->sharable = shareable;
939 940
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
941

B
Bjorn Helgaas 已提交
942
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s (%d-byte descriptor)\n",
943
		(int) p->start,
944 945
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
946 947
		irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
		irq->descriptor_length);
L
Linus Torvalds 已提交
948 949
}

950 951
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
952
				   struct resource *p)
L
Linus Torvalds 已提交
953
{
954
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
955
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
956

957 958
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
959
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
960 961 962 963
			p ? "disabled" : "missing");
		return;
	}

964
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
965 966 967
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
968
	extended_irq->sharable = shareable;
969 970
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
971

B
Bjorn Helgaas 已提交
972
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
973 974 975
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
976 977
}

978 979
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
980
			       struct resource *p)
L
Linus Torvalds 已提交
981
{
982 983
	struct acpi_resource_dma *dma = &resource->data.dma;

984 985
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
986
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
987 988 989 990
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
991
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
992
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
993
	case IORESOURCE_DMA_TYPEA:
994
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
995 996
		break;
	case IORESOURCE_DMA_TYPEB:
997
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
998 999
		break;
	case IORESOURCE_DMA_TYPEF:
1000
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
1001 1002
		break;
	default:
1003
		dma->type = ACPI_COMPATIBILITY;
1004 1005 1006
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
1007
	case IORESOURCE_DMA_8BIT:
1008
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
1009 1010
		break;
	case IORESOURCE_DMA_8AND16BIT:
1011
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
1012 1013
		break;
	default:
1014
		dma->transfer = ACPI_TRANSFER_16;
1015 1016
	}

1017 1018 1019
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
1020

B
Bjorn Helgaas 已提交
1021
	pnp_dbg(&dev->dev, "  encode dma %d "
1022 1023
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
1024 1025
}

1026 1027
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1028
			      struct resource *p)
L
Linus Torvalds 已提交
1029
{
1030 1031
	struct acpi_resource_io *io = &resource->data.io;

1032 1033
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
1034
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
1035 1036 1037 1038 1039 1040 1041 1042 1043
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
		io->address_length = p->end - p->start + 1;
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
1044

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

1049 1050
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1051
				    struct resource *p)
L
Linus Torvalds 已提交
1052
{
1053 1054
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

1055 1056 1057 1058 1059 1060 1061
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
		fixed_io->address_length = p->end - p->start + 1;
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
1062

B
Bjorn Helgaas 已提交
1063
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
1064
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
1065 1066
}

1067 1068
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1069
				 struct resource *p)
L
Linus Torvalds 已提交
1070
{
1071 1072
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
	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;
		memory24->address_length = p->end - p->start + 1;
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
1086
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
1087 1088
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
1089
		memory24->write_protect);
L
Linus Torvalds 已提交
1090 1091
}

1092 1093
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1094
				 struct resource *p)
L
Linus Torvalds 已提交
1095
{
1096 1097
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
	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;
		memory32->address_length = p->end - p->start + 1;
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
1109

B
Bjorn Helgaas 已提交
1110
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
1111 1112
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
1113
		memory32->write_protect);
L
Linus Torvalds 已提交
1114 1115
}

1116 1117
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1118
				       struct resource *p)
L
Linus Torvalds 已提交
1119
{
1120 1121
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
	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;
		fixed_memory32->address_length = p->end - p->start + 1;
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
1132

B
Bjorn Helgaas 已提交
1133
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
1134 1135
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
1136
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
1137 1138
}

1139
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
1140 1141 1142
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
1143
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
1144
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
1145 1146
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
1147
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
1148
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
1149
		switch (resource->type) {
B
Bob Moore 已提交
1150
		case ACPI_RESOURCE_TYPE_IRQ:
1151
			pnpacpi_encode_irq(dev, resource,
1152
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
1153 1154 1155
			irq++;
			break;

B
Bob Moore 已提交
1156
		case ACPI_RESOURCE_TYPE_DMA:
1157
			pnpacpi_encode_dma(dev, resource,
1158
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
1159
			dma++;
L
Linus Torvalds 已提交
1160
			break;
B
Bob Moore 已提交
1161
		case ACPI_RESOURCE_TYPE_IO:
1162
			pnpacpi_encode_io(dev, resource,
1163
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1164
			port++;
L
Linus Torvalds 已提交
1165
			break;
B
Bob Moore 已提交
1166
		case ACPI_RESOURCE_TYPE_FIXED_IO:
1167
			pnpacpi_encode_fixed_io(dev, resource,
1168
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1169
			port++;
L
Linus Torvalds 已提交
1170
			break;
B
Bob Moore 已提交
1171
		case ACPI_RESOURCE_TYPE_MEMORY24:
1172
			pnpacpi_encode_mem24(dev, resource,
1173
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1174
			mem++;
L
Linus Torvalds 已提交
1175
			break;
B
Bob Moore 已提交
1176
		case ACPI_RESOURCE_TYPE_MEMORY32:
1177
			pnpacpi_encode_mem32(dev, resource,
1178
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1179
			mem++;
L
Linus Torvalds 已提交
1180
			break;
B
Bob Moore 已提交
1181
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1182
			pnpacpi_encode_fixed_mem32(dev, resource,
1183
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1184
			mem++;
L
Linus Torvalds 已提交
1185
			break;
1186
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1187
			pnpacpi_encode_ext_irq(dev, resource,
1188
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
			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 已提交
1200
		default:	/* other type */
1201 1202
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
1203 1204
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
1205 1206
		resource++;
		i++;
L
Linus Torvalds 已提交
1207 1208 1209
	}
	return 0;
}