Blame view

drivers/acpi/resource.c 22.8 KB
1802d0bee   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
2
3
4
5
6
7
8
9
  /*
   * drivers/acpi/resource.c - ACPI device resources interpretation.
   *
   * Copyright (C) 2012, Intel Corp.
   * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
10
11
12
13
14
15
16
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   */
  
  #include <linux/acpi.h>
  #include <linux/device.h>
  #include <linux/export.h>
  #include <linux/ioport.h>
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
17
  #include <linux/slab.h>
55a93417c   Christophe RICARD   ACPI: Rename acpi...
18
  #include <linux/irq.h>
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
19
20
21
  
  #ifdef CONFIG_X86
  #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
4a2e7aab4   Lorenzo Pieralisi   PCI: ACPI: IA64: ...
22
23
24
25
26
  static inline bool acpi_iospace_resource_valid(struct resource *res)
  {
  	/* On X86 IO space is limited to the [0 - 64K] IO port range */
  	return res->end < 0x10003;
  }
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
27
28
  #else
  #define valid_IRQ(i) (true)
4a2e7aab4   Lorenzo Pieralisi   PCI: ACPI: IA64: ...
29
30
31
32
33
34
35
  /*
   * ACPI IO descriptors on arches other than X86 contain MMIO CPU physical
   * addresses mapping IO space in CPU physical address space, IO space
   * resources can be placed anywhere in the 64-bit physical address space.
   */
  static inline bool
  acpi_iospace_resource_valid(struct resource *res) { return true; }
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
36
  #endif
fa20b176f   Agustin Vega-Frias   ACPI: Generic GSI...
37
38
39
40
41
42
43
44
45
46
47
48
  #if IS_ENABLED(CONFIG_ACPI_GENERIC_GSI)
  static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq)
  {
  	return ext_irq->resource_source.string_length == 0 &&
  	       ext_irq->producer_consumer == ACPI_CONSUMER;
  }
  #else
  static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq)
  {
  	return true;
  }
  #endif
c420dbd13   Thomas Gleixner   ACPI: Implement p...
49
  static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
50
  {
c420dbd13   Thomas Gleixner   ACPI: Implement p...
51
  	u64 reslen = end - start + 1;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
52

c420dbd13   Thomas Gleixner   ACPI: Implement p...
53
54
55
56
  	/*
  	 * CHECKME: len might be required to check versus a minimum
  	 * length as well. 1 for io is fine, but for memory it does
  	 * not make any sense at all.
aa714d286   Jiang Liu   x86/PCI/ACPI: Rel...
57
58
  	 * Note: some BIOSes report incorrect length for ACPI address space
  	 * descriptor, so remove check of 'reslen == len' to avoid regression.
c420dbd13   Thomas Gleixner   ACPI: Implement p...
59
  	 */
aa714d286   Jiang Liu   x86/PCI/ACPI: Rel...
60
  	if (len && reslen && start <= end)
c420dbd13   Thomas Gleixner   ACPI: Implement p...
61
  		return true;
6a239af2a   Rafael J. Wysocki   ACPI / resources:...
62
63
  	pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]
  ",
c420dbd13   Thomas Gleixner   ACPI: Implement p...
64
65
66
67
68
69
  		io ? "io" : "mem", start, end, len);
  
  	return false;
  }
  
  static void acpi_dev_memresource_flags(struct resource *res, u64 len,
72e26b0d4   Thomas Gleixner   ACPI: Move the wi...
70
  				       u8 write_protect)
c420dbd13   Thomas Gleixner   ACPI: Implement p...
71
72
73
74
  {
  	res->flags = IORESOURCE_MEM;
  
  	if (!acpi_dev_resource_len_valid(res->start, res->end, len, false))
c78b68856   Jiang Liu   ACPI: Set flag IO...
75
  		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
76
77
  
  	if (write_protect == ACPI_READ_WRITE_MEMORY)
c420dbd13   Thomas Gleixner   ACPI: Implement p...
78
  		res->flags |= IORESOURCE_MEM_WRITEABLE;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
79
80
81
82
83
84
85
  }
  
  static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
  				     u8 write_protect)
  {
  	res->start = start;
  	res->end = start + len - 1;
72e26b0d4   Thomas Gleixner   ACPI: Move the wi...
86
  	acpi_dev_memresource_flags(res, len, write_protect);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
87
88
89
90
91
92
93
94
95
96
  }
  
  /**
   * acpi_dev_resource_memory - Extract ACPI memory resource information.
   * @ares: Input ACPI resource object.
   * @res: Output generic resource object.
   *
   * Check if the given ACPI resource object represents a memory resource and
   * if that's the case, use the information in it to populate the generic
   * resource object pointed to by @res.
581c19f3a   Jiang Liu   ACPI: Normalize r...
97
98
99
100
101
   *
   * Return:
   * 1) false with res->flags setting to zero: not the expected resource type
   * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
   * 3) true: valid assigned resource
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
102
103
104
105
106
107
108
109
110
111
   */
  bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
  {
  	struct acpi_resource_memory24 *memory24;
  	struct acpi_resource_memory32 *memory32;
  	struct acpi_resource_fixed_memory32 *fixed_memory32;
  
  	switch (ares->type) {
  	case ACPI_RESOURCE_TYPE_MEMORY24:
  		memory24 = &ares->data.memory24;
8515f9368   Jiang Liu   ACPI: Fix a bug i...
112
113
  		acpi_dev_get_memresource(res, memory24->minimum << 8,
  					 memory24->address_length << 8,
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  					 memory24->write_protect);
  		break;
  	case ACPI_RESOURCE_TYPE_MEMORY32:
  		memory32 = &ares->data.memory32;
  		acpi_dev_get_memresource(res, memory32->minimum,
  					 memory32->address_length,
  					 memory32->write_protect);
  		break;
  	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  		fixed_memory32 = &ares->data.fixed_memory32;
  		acpi_dev_get_memresource(res, fixed_memory32->address,
  					 fixed_memory32->address_length,
  					 fixed_memory32->write_protect);
  		break;
  	default:
581c19f3a   Jiang Liu   ACPI: Normalize r...
129
  		res->flags = 0;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
130
131
  		return false;
  	}
c420dbd13   Thomas Gleixner   ACPI: Implement p...
132
133
  
  	return !(res->flags & IORESOURCE_DISABLED);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
134
135
  }
  EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
1d0420f1c   Thomas Gleixner   ACPI: Use the len...
136
  static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
91236ecc7   Jiang Liu   ACPI/PCI: Enhance...
137
  				      u8 io_decode, u8 translation_type)
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
138
  {
1d0420f1c   Thomas Gleixner   ACPI: Use the len...
139
  	res->flags = IORESOURCE_IO;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
140

1d0420f1c   Thomas Gleixner   ACPI: Use the len...
141
  	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
c78b68856   Jiang Liu   ACPI: Set flag IO...
142
  		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
1d0420f1c   Thomas Gleixner   ACPI: Use the len...
143

4a2e7aab4   Lorenzo Pieralisi   PCI: ACPI: IA64: ...
144
  	if (!acpi_iospace_resource_valid(res))
c78b68856   Jiang Liu   ACPI: Set flag IO...
145
  		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
146

1d0420f1c   Thomas Gleixner   ACPI: Use the len...
147
148
  	if (io_decode == ACPI_DECODE_16)
  		res->flags |= IORESOURCE_IO_16BIT_ADDR;
91236ecc7   Jiang Liu   ACPI/PCI: Enhance...
149
150
  	if (translation_type == ACPI_SPARSE_TRANSLATION)
  		res->flags |= IORESOURCE_IO_SPARSE;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
151
152
153
154
155
  }
  
  static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
  				    u8 io_decode)
  {
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
156
  	res->start = start;
1d0420f1c   Thomas Gleixner   ACPI: Use the len...
157
  	res->end = start + len - 1;
91236ecc7   Jiang Liu   ACPI/PCI: Enhance...
158
  	acpi_dev_ioresource_flags(res, len, io_decode, 0);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
159
160
161
162
163
164
165
166
167
168
  }
  
  /**
   * acpi_dev_resource_io - Extract ACPI I/O resource information.
   * @ares: Input ACPI resource object.
   * @res: Output generic resource object.
   *
   * Check if the given ACPI resource object represents an I/O resource and
   * if that's the case, use the information in it to populate the generic
   * resource object pointed to by @res.
581c19f3a   Jiang Liu   ACPI: Normalize r...
169
170
171
172
173
   *
   * Return:
   * 1) false with res->flags setting to zero: not the expected resource type
   * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
   * 3) true: valid assigned resource
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
   */
  bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
  {
  	struct acpi_resource_io *io;
  	struct acpi_resource_fixed_io *fixed_io;
  
  	switch (ares->type) {
  	case ACPI_RESOURCE_TYPE_IO:
  		io = &ares->data.io;
  		acpi_dev_get_ioresource(res, io->minimum,
  					io->address_length,
  					io->io_decode);
  		break;
  	case ACPI_RESOURCE_TYPE_FIXED_IO:
  		fixed_io = &ares->data.fixed_io;
  		acpi_dev_get_ioresource(res, fixed_io->address,
  					fixed_io->address_length,
  					ACPI_DECODE_10);
  		break;
  	default:
581c19f3a   Jiang Liu   ACPI: Normalize r...
194
  		res->flags = 0;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
195
196
  		return false;
  	}
1d0420f1c   Thomas Gleixner   ACPI: Use the len...
197
198
  
  	return !(res->flags & IORESOURCE_DISABLED);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
199
200
  }
  EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
a49170b55   Jiang Liu   ACPI: Return tran...
201
  static bool acpi_decode_space(struct resource_win *win,
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
202
203
204
205
  			      struct acpi_resource_address *addr,
  			      struct acpi_address64_attribute *attr)
  {
  	u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16;
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
206
207
  	bool wp = addr->info.mem.write_protect;
  	u64 len = attr->address_length;
1fb01ca93   Jiang Liu   ACPI / PCI: Fix r...
208
  	u64 start, end, offset = 0;
a49170b55   Jiang Liu   ACPI: Return tran...
209
  	struct resource *res = &win->res;
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
210

a274019fc   Jiang Liu   ACPI: Enforce str...
211
212
213
214
215
216
217
218
219
  	/*
  	 * Filter out invalid descriptor according to ACPI Spec 5.0, section
  	 * 6.4.3.5 Address Space Resource Descriptors.
  	 */
  	if ((addr->min_address_fixed != addr->max_address_fixed && len) ||
  	    (addr->min_address_fixed && addr->max_address_fixed && !len))
  		pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx
  ",
  			 addr->min_address_fixed, addr->max_address_fixed, len);
2ea3d266b   Jiang Liu   ACPI: Translate r...
220
221
222
223
224
225
226
  	/*
  	 * For bridges that translate addresses across the bridge,
  	 * translation_offset is the offset that must be added to the
  	 * address on the secondary side to obtain the address on the
  	 * primary side. Non-bridge devices must list 0 for all Address
  	 * Translation offset bits.
  	 */
1fb01ca93   Jiang Liu   ACPI / PCI: Fix r...
227
228
229
  	if (addr->producer_consumer == ACPI_PRODUCER)
  		offset = attr->translation_offset;
  	else if (attr->translation_offset)
2ea3d266b   Jiang Liu   ACPI: Translate r...
230
231
232
  		pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.
  ",
  			 attr->translation_offset);
1fb01ca93   Jiang Liu   ACPI / PCI: Fix r...
233
234
235
236
237
238
239
240
241
242
243
244
  	start = attr->minimum + offset;
  	end = attr->maximum + offset;
  
  	win->offset = offset;
  	res->start = start;
  	res->end = end;
  	if (sizeof(resource_size_t) < sizeof(u64) &&
  	    (offset != win->offset || start != res->start || end != res->end)) {
  		pr_warn("acpi resource window ([%#llx-%#llx] ignored, not CPU addressable)
  ",
  			attr->minimum, attr->maximum);
  		return false;
2ea3d266b   Jiang Liu   ACPI: Translate r...
245
  	}
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
246
247
  	switch (addr->resource_type) {
  	case ACPI_MEMORY_RANGE:
72e26b0d4   Thomas Gleixner   ACPI: Move the wi...
248
  		acpi_dev_memresource_flags(res, len, wp);
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
249
250
  		break;
  	case ACPI_IO_RANGE:
91236ecc7   Jiang Liu   ACPI/PCI: Enhance...
251
252
  		acpi_dev_ioresource_flags(res, len, iodec,
  					  addr->info.io.translation_type);
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
253
254
255
256
257
258
259
  		break;
  	case ACPI_BUS_NUMBER_RANGE:
  		res->flags = IORESOURCE_BUS;
  		break;
  	default:
  		return false;
  	}
72e26b0d4   Thomas Gleixner   ACPI: Move the wi...
260
261
  	if (addr->producer_consumer == ACPI_PRODUCER)
  		res->flags |= IORESOURCE_WINDOW;
fcb29bbcd   Thomas Gleixner   ACPI: Add prefetc...
262
263
264
  
  	if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
  		res->flags |= IORESOURCE_PREFETCH;
72e26b0d4   Thomas Gleixner   ACPI: Move the wi...
265

eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
266
267
  	return !(res->flags & IORESOURCE_DISABLED);
  }
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
268
269
270
  /**
   * acpi_dev_resource_address_space - Extract ACPI address space information.
   * @ares: Input ACPI resource object.
a49170b55   Jiang Liu   ACPI: Return tran...
271
   * @win: Output generic resource object.
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
272
273
274
   *
   * Check if the given ACPI resource object represents an address space resource
   * and if that's the case, use the information in it to populate the generic
a49170b55   Jiang Liu   ACPI: Return tran...
275
   * resource object pointed to by @win.
581c19f3a   Jiang Liu   ACPI: Normalize r...
276
277
   *
   * Return:
a49170b55   Jiang Liu   ACPI: Return tran...
278
279
280
   * 1) false with win->res.flags setting to zero: not the expected resource type
   * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned
   *    resource
581c19f3a   Jiang Liu   ACPI: Normalize r...
281
   * 3) true: valid assigned resource
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
282
283
   */
  bool acpi_dev_resource_address_space(struct acpi_resource *ares,
a49170b55   Jiang Liu   ACPI: Return tran...
284
  				     struct resource_win *win)
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
285
  {
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
286
  	struct acpi_resource_address64 addr;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
287

a49170b55   Jiang Liu   ACPI: Return tran...
288
  	win->res.flags = 0;
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
289
  	if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr)))
6658c7394   Jiang Liu   ACPI: Correct ret...
290
  		return false;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
291

a49170b55   Jiang Liu   ACPI: Return tran...
292
  	return acpi_decode_space(win, (struct acpi_resource_address *)&addr,
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
293
  				 &addr.address);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
294
295
296
297
298
299
  }
  EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
  
  /**
   * acpi_dev_resource_ext_address_space - Extract ACPI address space information.
   * @ares: Input ACPI resource object.
a49170b55   Jiang Liu   ACPI: Return tran...
300
   * @win: Output generic resource object.
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
301
302
303
   *
   * Check if the given ACPI resource object represents an extended address space
   * resource and if that's the case, use the information in it to populate the
a49170b55   Jiang Liu   ACPI: Return tran...
304
   * generic resource object pointed to by @win.
581c19f3a   Jiang Liu   ACPI: Normalize r...
305
306
   *
   * Return:
a49170b55   Jiang Liu   ACPI: Return tran...
307
308
309
   * 1) false with win->res.flags setting to zero: not the expected resource type
   * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned
   *    resource
581c19f3a   Jiang Liu   ACPI: Normalize r...
310
   * 3) true: valid assigned resource
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
311
312
   */
  bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
a49170b55   Jiang Liu   ACPI: Return tran...
313
  					 struct resource_win *win)
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
314
315
  {
  	struct acpi_resource_extended_address64 *ext_addr;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
316

a49170b55   Jiang Liu   ACPI: Return tran...
317
  	win->res.flags = 0;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
318
319
320
321
  	if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
  		return false;
  
  	ext_addr = &ares->data.ext_address64;
a49170b55   Jiang Liu   ACPI: Return tran...
322
  	return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr,
eb76d55e6   Thomas Gleixner   ACPI: Unify the p...
323
  				 &ext_addr->address);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  }
  EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
  
  /**
   * acpi_dev_irq_flags - Determine IRQ resource flags.
   * @triggering: Triggering type as provided by ACPI.
   * @polarity: Interrupt polarity as provided by ACPI.
   * @shareable: Whether or not the interrupt is shareable.
   */
  unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable)
  {
  	unsigned long flags;
  
  	if (triggering == ACPI_LEVEL_SENSITIVE)
  		flags = polarity == ACPI_ACTIVE_LOW ?
  			IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL;
  	else
  		flags = polarity == ACPI_ACTIVE_LOW ?
  			IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE;
  
  	if (shareable == ACPI_SHARED)
  		flags |= IORESOURCE_IRQ_SHAREABLE;
  
  	return flags | IORESOURCE_IRQ;
  }
  EXPORT_SYMBOL_GPL(acpi_dev_irq_flags);
55a93417c   Christophe RICARD   ACPI: Rename acpi...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  /**
   * acpi_dev_get_irq_type - Determine irq type.
   * @triggering: Triggering type as provided by ACPI.
   * @polarity: Interrupt polarity as provided by ACPI.
   */
  unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
  {
  	switch (polarity) {
  	case ACPI_ACTIVE_LOW:
  		return triggering == ACPI_EDGE_SENSITIVE ?
  		       IRQ_TYPE_EDGE_FALLING :
  		       IRQ_TYPE_LEVEL_LOW;
  	case ACPI_ACTIVE_HIGH:
  		return triggering == ACPI_EDGE_SENSITIVE ?
  		       IRQ_TYPE_EDGE_RISING :
  		       IRQ_TYPE_LEVEL_HIGH;
  	case ACPI_ACTIVE_BOTH:
  		if (triggering == ACPI_EDGE_SENSITIVE)
  			return IRQ_TYPE_EDGE_BOTH;
57d2dd4bd   Gustavo A. R. Silva   ACPI: Use fallthr...
369
  		fallthrough;
55a93417c   Christophe RICARD   ACPI: Rename acpi...
370
371
372
373
374
  	default:
  		return IRQ_TYPE_NONE;
  	}
  }
  EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
375
376
377
378
  static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
  {
  	res->start = gsi;
  	res->end = gsi;
c78b68856   Jiang Liu   ACPI: Set flag IO...
379
  	res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
380
381
382
  }
  
  static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
204ebc0aa   Mika Westerberg   ACPI / resources:...
383
384
  				     u8 triggering, u8 polarity, u8 shareable,
  				     bool legacy)
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
385
386
387
388
389
390
391
392
393
  {
  	int irq, p, t;
  
  	if (!valid_IRQ(gsi)) {
  		acpi_dev_irqresource_disabled(res, gsi);
  		return;
  	}
  
  	/*
03671057c   Masahiro Yamada   scripts/spelling....
394
  	 * In IO-APIC mode, use overridden attribute. Two reasons:
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
395
396
  	 * 1. BIOS bug in DSDT
  	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
204ebc0aa   Mika Westerberg   ACPI / resources:...
397
398
399
400
401
  	 *
  	 * We do this only if we are dealing with IRQ() or IRQNoFlags()
  	 * resource (the legacy ISA resources). With modern ACPI 5 devices
  	 * using extended IRQ descriptors we take the IRQ configuration
  	 * from _CRS directly.
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
402
  	 */
204ebc0aa   Mika Westerberg   ACPI / resources:...
403
  	if (legacy && !acpi_get_override_irq(gsi, &t, &p)) {
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
404
405
406
407
  		u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
  		u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
  
  		if (triggering != trig || polarity != pol) {
933ca4e32   Kefeng Wang   acpi: Use pr_warn...
408
409
410
  			pr_warn("ACPI: IRQ %d override to %s, %s
  ", gsi,
  				t ? "level" : "edge", p ? "low" : "high");
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  			triggering = trig;
  			polarity = pol;
  		}
  	}
  
  	res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
  	irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
  	if (irq >= 0) {
  		res->start = irq;
  		res->end = irq;
  	} else {
  		acpi_dev_irqresource_disabled(res, gsi);
  	}
  }
  
  /**
   * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
   * @ares: Input ACPI resource object.
   * @index: Index into the array of GSIs represented by the resource.
   * @res: Output generic resource object.
   *
   * Check if the given ACPI resource object represents an interrupt resource
   * and @index does not exceed the resource's interrupt count (true is returned
   * in that case regardless of the results of the other checks)).  If that's the
   * case, register the GSI corresponding to @index from the array of interrupts
   * represented by the resource and populate the generic resource object pointed
   * to by @res accordingly.  If the registration of the GSI is not successful,
   * IORESOURCE_DISABLED will be set it that object's flags.
581c19f3a   Jiang Liu   ACPI: Normalize r...
439
440
441
442
443
   *
   * Return:
   * 1) false with res->flags setting to zero: not the expected resource type
   * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
   * 3) true: valid assigned resource
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
   */
  bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
  				 struct resource *res)
  {
  	struct acpi_resource_irq *irq;
  	struct acpi_resource_extended_irq *ext_irq;
  
  	switch (ares->type) {
  	case ACPI_RESOURCE_TYPE_IRQ:
  		/*
  		 * Per spec, only one interrupt per descriptor is allowed in
  		 * _CRS, but some firmware violates this, so parse them all.
  		 */
  		irq = &ares->data.irq;
  		if (index >= irq->interrupt_count) {
  			acpi_dev_irqresource_disabled(res, 0);
  			return false;
  		}
  		acpi_dev_get_irqresource(res, irq->interrupts[index],
  					 irq->triggering, irq->polarity,
c163f90cc   Erik Schmauss   ACPI/ACPICA: Triv...
464
  					 irq->shareable, true);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
465
466
467
468
469
470
471
  		break;
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  		ext_irq = &ares->data.extended_irq;
  		if (index >= ext_irq->interrupt_count) {
  			acpi_dev_irqresource_disabled(res, 0);
  			return false;
  		}
fa20b176f   Agustin Vega-Frias   ACPI: Generic GSI...
472
473
  		if (is_gsi(ext_irq))
  			acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
474
  					 ext_irq->triggering, ext_irq->polarity,
c163f90cc   Erik Schmauss   ACPI/ACPICA: Triv...
475
  					 ext_irq->shareable, false);
fa20b176f   Agustin Vega-Frias   ACPI: Generic GSI...
476
477
  		else
  			acpi_dev_irqresource_disabled(res, 0);
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
478
479
  		break;
  	default:
581c19f3a   Jiang Liu   ACPI: Normalize r...
480
  		res->flags = 0;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
481
482
483
484
485
486
  		return false;
  	}
  
  	return true;
  }
  EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
487
488
489
490
491
492
493
  
  /**
   * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
   * @list: The head of the resource list to free.
   */
  void acpi_dev_free_resource_list(struct list_head *list)
  {
90e978206   Jiang Liu   resources: Move s...
494
  	resource_list_free(list);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
495
496
497
498
499
500
501
502
503
504
  }
  EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
  
  struct res_proc_context {
  	struct list_head *list;
  	int (*preproc)(struct acpi_resource *, void *);
  	void *preproc_data;
  	int count;
  	int error;
  };
a49170b55   Jiang Liu   ACPI: Return tran...
505
  static acpi_status acpi_dev_new_resource_entry(struct resource_win *win,
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
506
507
  					       struct res_proc_context *c)
  {
90e978206   Jiang Liu   resources: Move s...
508
  	struct resource_entry *rentry;
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
509

90e978206   Jiang Liu   resources: Move s...
510
  	rentry = resource_list_create_entry(NULL, 0);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
511
512
513
514
  	if (!rentry) {
  		c->error = -ENOMEM;
  		return AE_NO_MEMORY;
  	}
90e978206   Jiang Liu   resources: Move s...
515
  	*rentry->res = win->res;
93286f479   Jiang Liu   ACPI: Add field o...
516
  	rentry->offset = win->offset;
90e978206   Jiang Liu   resources: Move s...
517
  	resource_list_add_tail(rentry, c->list);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
518
519
520
521
522
523
524
525
  	c->count++;
  	return AE_OK;
  }
  
  static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
  					     void *context)
  {
  	struct res_proc_context *c = context;
a49170b55   Jiang Liu   ACPI: Return tran...
526
527
  	struct resource_win win;
  	struct resource *res = &win.res;
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
528
529
530
531
532
533
534
535
  	int i;
  
  	if (c->preproc) {
  		int ret;
  
  		ret = c->preproc(ares, c->preproc_data);
  		if (ret < 0) {
  			c->error = ret;
c5f7d6244   Daniel Scally   Revert "ACPI / re...
536
  			return AE_ABORT_METHOD;
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
537
538
539
540
  		} else if (ret > 0) {
  			return AE_OK;
  		}
  	}
a49170b55   Jiang Liu   ACPI: Return tran...
541
  	memset(&win, 0, sizeof(win));
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
542

a49170b55   Jiang Liu   ACPI: Return tran...
543
544
545
546
547
  	if (acpi_dev_resource_memory(ares, res)
  	    || acpi_dev_resource_io(ares, res)
  	    || acpi_dev_resource_address_space(ares, &win)
  	    || acpi_dev_resource_ext_address_space(ares, &win))
  		return acpi_dev_new_resource_entry(&win, c);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
548

a49170b55   Jiang Liu   ACPI: Return tran...
549
  	for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) {
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
550
  		acpi_status status;
a49170b55   Jiang Liu   ACPI: Return tran...
551
  		status = acpi_dev_new_resource_entry(&win, c);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
552
553
554
555
556
557
  		if (ACPI_FAILURE(status))
  			return status;
  	}
  
  	return AE_OK;
  }
4f0450af5   Lorenzo Pieralisi   ACPI: Make acpi_d...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  static int __acpi_dev_get_resources(struct acpi_device *adev,
  				    struct list_head *list,
  				    int (*preproc)(struct acpi_resource *, void *),
  				    void *preproc_data, char *method)
  {
  	struct res_proc_context c;
  	acpi_status status;
  
  	if (!adev || !adev->handle || !list_empty(list))
  		return -EINVAL;
  
  	if (!acpi_has_method(adev->handle, method))
  		return 0;
  
  	c.list = list;
  	c.preproc = preproc;
  	c.preproc_data = preproc_data;
  	c.count = 0;
  	c.error = 0;
  	status = acpi_walk_resources(adev->handle, method,
  				     acpi_dev_process_resource, &c);
  	if (ACPI_FAILURE(status)) {
  		acpi_dev_free_resource_list(list);
  		return c.error ? c.error : -EIO;
  	}
  
  	return c.count;
  }
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  /**
   * acpi_dev_get_resources - Get current resources of a device.
   * @adev: ACPI device node to get the resources for.
   * @list: Head of the resultant list of resources (must be empty).
   * @preproc: The caller's preprocessing routine.
   * @preproc_data: Pointer passed to the caller's preprocessing routine.
   *
   * Evaluate the _CRS method for the given device node and process its output by
   * (1) executing the @preproc() rountine provided by the caller, passing the
   * resource pointer and @preproc_data to it as arguments, for each ACPI resource
   * returned and (2) converting all of the returned ACPI resources into struct
   * resource objects if possible.  If the return value of @preproc() in step (1)
   * is different from 0, step (2) is not applied to the given ACPI resource and
   * if that value is negative, the whole processing is aborted and that value is
   * returned as the final error code.
   *
   * The resultant struct resource objects are put on the list pointed to by
90e978206   Jiang Liu   resources: Move s...
603
   * @list, that must be empty initially, as members of struct resource_entry
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
604
605
606
607
608
609
610
611
612
613
   * objects.  Callers of this routine should use %acpi_dev_free_resource_list() to
   * free that list.
   *
   * The number of resources in the output list is returned on success, an error
   * code reflecting the error condition is returned otherwise.
   */
  int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
  			   int (*preproc)(struct acpi_resource *, void *),
  			   void *preproc_data)
  {
4f0450af5   Lorenzo Pieralisi   ACPI: Make acpi_d...
614
615
  	return __acpi_dev_get_resources(adev, list, preproc, preproc_data,
  					METHOD_NAME__CRS);
8e345c991   Rafael J. Wysocki   ACPI: Centralized...
616
617
  }
  EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
62d1141ff   Jiang Liu   ACPI: Introduce h...
618

c04ac679c   Lorenzo Pieralisi   ACPI: Introduce D...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  static int is_memory(struct acpi_resource *ares, void *not_used)
  {
  	struct resource_win win;
  	struct resource *res = &win.res;
  
  	memset(&win, 0, sizeof(win));
  
  	return !(acpi_dev_resource_memory(ares, res)
  	       || acpi_dev_resource_address_space(ares, &win)
  	       || acpi_dev_resource_ext_address_space(ares, &win));
  }
  
  /**
   * acpi_dev_get_dma_resources - Get current DMA resources of a device.
   * @adev: ACPI device node to get the resources for.
   * @list: Head of the resultant list of resources (must be empty).
   *
   * Evaluate the _DMA method for the given device node and process its
   * output.
   *
   * The resultant struct resource objects are put on the list pointed to
   * by @list, that must be empty initially, as members of struct
   * resource_entry objects.  Callers of this routine should use
   * %acpi_dev_free_resource_list() to free that list.
   *
   * The number of resources in the output list is returned on success,
   * an error code reflecting the error condition is returned otherwise.
   */
  int acpi_dev_get_dma_resources(struct acpi_device *adev, struct list_head *list)
  {
  	return __acpi_dev_get_resources(adev, list, is_memory, NULL,
  					METHOD_NAME__DMA);
  }
  EXPORT_SYMBOL_GPL(acpi_dev_get_dma_resources);
62d1141ff   Jiang Liu   ACPI: Introduce h...
653
654
655
656
657
658
  /**
   * acpi_dev_filter_resource_type - Filter ACPI resource according to resource
   *				   types
   * @ares: Input ACPI resource object.
   * @types: Valid resource types of IORESOURCE_XXX
   *
2c62e8492   Jiang Liu   x86/PCI/ACPI: Mak...
659
   * This is a helper function to support acpi_dev_get_resources(), which filters
62d1141ff   Jiang Liu   ACPI: Introduce h...
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
   * ACPI resource objects according to resource types.
   */
  int acpi_dev_filter_resource_type(struct acpi_resource *ares,
  				  unsigned long types)
  {
  	unsigned long type = 0;
  
  	switch (ares->type) {
  	case ACPI_RESOURCE_TYPE_MEMORY24:
  	case ACPI_RESOURCE_TYPE_MEMORY32:
  	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  		type = IORESOURCE_MEM;
  		break;
  	case ACPI_RESOURCE_TYPE_IO:
  	case ACPI_RESOURCE_TYPE_FIXED_IO:
  		type = IORESOURCE_IO;
  		break;
  	case ACPI_RESOURCE_TYPE_IRQ:
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  		type = IORESOURCE_IRQ;
  		break;
  	case ACPI_RESOURCE_TYPE_DMA:
  	case ACPI_RESOURCE_TYPE_FIXED_DMA:
  		type = IORESOURCE_DMA;
  		break;
  	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
  		type = IORESOURCE_REG;
  		break;
  	case ACPI_RESOURCE_TYPE_ADDRESS16:
  	case ACPI_RESOURCE_TYPE_ADDRESS32:
  	case ACPI_RESOURCE_TYPE_ADDRESS64:
  	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
  		if (ares->data.address.resource_type == ACPI_MEMORY_RANGE)
  			type = IORESOURCE_MEM;
  		else if (ares->data.address.resource_type == ACPI_IO_RANGE)
  			type = IORESOURCE_IO;
  		else if (ares->data.address.resource_type ==
  			 ACPI_BUS_NUMBER_RANGE)
  			type = IORESOURCE_BUS;
  		break;
  	default:
  		break;
  	}
  
  	return (type & types) ? 0 : 1;
  }
  EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
00710984e   Bjorn Helgaas   ACPI: Add acpi_re...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  
  static int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res)
  {
  	struct list_head resource_list;
  	struct resource_entry *rentry;
  	int ret, found = 0;
  
  	INIT_LIST_HEAD(&resource_list);
  	ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
  	if (ret < 0)
  		return 0;
  
  	list_for_each_entry(rentry, &resource_list, node) {
  		if (resource_contains(rentry->res, res)) {
  			found = 1;
  			break;
  		}
  
  	}
  
  	acpi_dev_free_resource_list(&resource_list);
  	return found;
  }
  
  static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth,
  					 void *context, void **ret)
  {
  	struct resource *res = context;
  	struct acpi_device **consumer = (struct acpi_device **) ret;
  	struct acpi_device *adev;
  
  	if (acpi_bus_get_device(handle, &adev))
  		return AE_OK;
  
  	if (acpi_dev_consumes_res(adev, res)) {
  		*consumer = adev;
  		return AE_CTRL_TERMINATE;
  	}
  
  	return AE_OK;
  }
  
  /**
   * acpi_resource_consumer - Find the ACPI device that consumes @res.
   * @res: Resource to search for.
   *
   * Search the current resource settings (_CRS) of every ACPI device node
   * for @res.  If we find an ACPI device whose _CRS includes @res, return
   * it.  Otherwise, return NULL.
   */
  struct acpi_device *acpi_resource_consumer(struct resource *res)
  {
  	struct acpi_device *consumer = NULL;
  
  	acpi_get_devices(NULL, acpi_res_consumer_cb, res, (void **) &consumer);
  	return consumer;
  }