1/******************************************************************************
2 *
3 * Module Name: evgpeblk - GPE block creation and initialization.
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45#include "accommon.h"
46#include "acevents.h"
47#include "acnamesp.h"
48
49#define _COMPONENT          ACPI_EVENTS
50ACPI_MODULE_NAME("evgpeblk")
51#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
52/* Local prototypes */
53static acpi_status
54acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
55			  u32 interrupt_number);
56
57static acpi_status
58acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
59
60/*******************************************************************************
61 *
62 * FUNCTION:    acpi_ev_install_gpe_block
63 *
64 * PARAMETERS:  gpe_block               - New GPE block
65 *              interrupt_number        - Xrupt to be associated with this
66 *                                        GPE block
67 *
68 * RETURN:      Status
69 *
70 * DESCRIPTION: Install new GPE block with mutex support
71 *
72 ******************************************************************************/
73
74static acpi_status
75acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
76			  u32 interrupt_number)
77{
78	struct acpi_gpe_block_info *next_gpe_block;
79	struct acpi_gpe_xrupt_info *gpe_xrupt_block;
80	acpi_status status;
81	acpi_cpu_flags flags;
82
83	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
84
85	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
86	if (ACPI_FAILURE(status)) {
87		return_ACPI_STATUS(status);
88	}
89
90	status =
91	    acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
92	if (ACPI_FAILURE(status)) {
93		goto unlock_and_exit;
94	}
95
96	/* Install the new block at the end of the list with lock */
97
98	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
99	if (gpe_xrupt_block->gpe_block_list_head) {
100		next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
101		while (next_gpe_block->next) {
102			next_gpe_block = next_gpe_block->next;
103		}
104
105		next_gpe_block->next = gpe_block;
106		gpe_block->previous = next_gpe_block;
107	} else {
108		gpe_xrupt_block->gpe_block_list_head = gpe_block;
109	}
110
111	gpe_block->xrupt_block = gpe_xrupt_block;
112	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
113
114unlock_and_exit:
115	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
116	return_ACPI_STATUS(status);
117}
118
119/*******************************************************************************
120 *
121 * FUNCTION:    acpi_ev_delete_gpe_block
122 *
123 * PARAMETERS:  gpe_block           - Existing GPE block
124 *
125 * RETURN:      Status
126 *
127 * DESCRIPTION: Remove a GPE block
128 *
129 ******************************************************************************/
130
131acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
132{
133	acpi_status status;
134	acpi_cpu_flags flags;
135
136	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
137
138	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
139	if (ACPI_FAILURE(status)) {
140		return_ACPI_STATUS(status);
141	}
142
143	/* Disable all GPEs in this block */
144
145	status =
146	    acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
147
148	if (!gpe_block->previous && !gpe_block->next) {
149
150		/* This is the last gpe_block on this interrupt */
151
152		status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
153		if (ACPI_FAILURE(status)) {
154			goto unlock_and_exit;
155		}
156	} else {
157		/* Remove the block on this interrupt with lock */
158
159		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
160		if (gpe_block->previous) {
161			gpe_block->previous->next = gpe_block->next;
162		} else {
163			gpe_block->xrupt_block->gpe_block_list_head =
164			    gpe_block->next;
165		}
166
167		if (gpe_block->next) {
168			gpe_block->next->previous = gpe_block->previous;
169		}
170		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
171	}
172
173	acpi_current_gpe_count -= gpe_block->gpe_count;
174
175	/* Free the gpe_block */
176
177	ACPI_FREE(gpe_block->register_info);
178	ACPI_FREE(gpe_block->event_info);
179	ACPI_FREE(gpe_block);
180
181unlock_and_exit:
182	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
183	return_ACPI_STATUS(status);
184}
185
186/*******************************************************************************
187 *
188 * FUNCTION:    acpi_ev_create_gpe_info_blocks
189 *
190 * PARAMETERS:  gpe_block   - New GPE block
191 *
192 * RETURN:      Status
193 *
194 * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
195 *
196 ******************************************************************************/
197
198static acpi_status
199acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
200{
201	struct acpi_gpe_register_info *gpe_register_info = NULL;
202	struct acpi_gpe_event_info *gpe_event_info = NULL;
203	struct acpi_gpe_event_info *this_event;
204	struct acpi_gpe_register_info *this_register;
205	u32 i;
206	u32 j;
207	acpi_status status;
208
209	ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
210
211	/* Allocate the GPE register information block */
212
213	gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->
214						 register_count *
215						 sizeof(struct
216							acpi_gpe_register_info));
217	if (!gpe_register_info) {
218		ACPI_ERROR((AE_INFO,
219			    "Could not allocate the GpeRegisterInfo table"));
220		return_ACPI_STATUS(AE_NO_MEMORY);
221	}
222
223	/*
224	 * Allocate the GPE event_info block. There are eight distinct GPEs
225	 * per register. Initialization to zeros is sufficient.
226	 */
227	gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count *
228					      sizeof(struct
229						     acpi_gpe_event_info));
230	if (!gpe_event_info) {
231		ACPI_ERROR((AE_INFO,
232			    "Could not allocate the GpeEventInfo table"));
233		status = AE_NO_MEMORY;
234		goto error_exit;
235	}
236
237	/* Save the new Info arrays in the GPE block */
238
239	gpe_block->register_info = gpe_register_info;
240	gpe_block->event_info = gpe_event_info;
241
242	/*
243	 * Initialize the GPE Register and Event structures. A goal of these
244	 * tables is to hide the fact that there are two separate GPE register
245	 * sets in a given GPE hardware block, the status registers occupy the
246	 * first half, and the enable registers occupy the second half.
247	 */
248	this_register = gpe_register_info;
249	this_event = gpe_event_info;
250
251	for (i = 0; i < gpe_block->register_count; i++) {
252
253		/* Init the register_info for this GPE register (8 GPEs) */
254
255		this_register->base_gpe_number = (u16)
256		    (gpe_block->block_base_number +
257		     (i * ACPI_GPE_REGISTER_WIDTH));
258
259		this_register->status_address.address = gpe_block->address + i;
260
261		this_register->enable_address.address =
262		    gpe_block->address + i + gpe_block->register_count;
263
264		this_register->status_address.space_id = gpe_block->space_id;
265		this_register->enable_address.space_id = gpe_block->space_id;
266		this_register->status_address.bit_width =
267		    ACPI_GPE_REGISTER_WIDTH;
268		this_register->enable_address.bit_width =
269		    ACPI_GPE_REGISTER_WIDTH;
270		this_register->status_address.bit_offset = 0;
271		this_register->enable_address.bit_offset = 0;
272
273		/* Init the event_info for each GPE within this register */
274
275		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
276			this_event->gpe_number =
277			    (u8) (this_register->base_gpe_number + j);
278			this_event->register_info = this_register;
279			this_event++;
280		}
281
282		/* Disable all GPEs within this register */
283
284		status = acpi_hw_write(0x00, &this_register->enable_address);
285		if (ACPI_FAILURE(status)) {
286			goto error_exit;
287		}
288
289		/* Clear any pending GPE events within this register */
290
291		status = acpi_hw_write(0xFF, &this_register->status_address);
292		if (ACPI_FAILURE(status)) {
293			goto error_exit;
294		}
295
296		this_register++;
297	}
298
299	return_ACPI_STATUS(AE_OK);
300
301error_exit:
302	if (gpe_register_info) {
303		ACPI_FREE(gpe_register_info);
304	}
305	if (gpe_event_info) {
306		ACPI_FREE(gpe_event_info);
307	}
308
309	return_ACPI_STATUS(status);
310}
311
312/*******************************************************************************
313 *
314 * FUNCTION:    acpi_ev_create_gpe_block
315 *
316 * PARAMETERS:  gpe_device          - Handle to the parent GPE block
317 *              gpe_block_address   - Address and space_ID
318 *              register_count      - Number of GPE register pairs in the block
319 *              gpe_block_base_number - Starting GPE number for the block
320 *              interrupt_number    - H/W interrupt for the block
321 *              return_gpe_block    - Where the new block descriptor is returned
322 *
323 * RETURN:      Status
324 *
325 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
326 *              the block are disabled at exit.
327 *              Note: Assumes namespace is locked.
328 *
329 ******************************************************************************/
330
331acpi_status
332acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
333			 u64 address,
334			 u8 space_id,
335			 u32 register_count,
336			 u16 gpe_block_base_number,
337			 u32 interrupt_number,
338			 struct acpi_gpe_block_info **return_gpe_block)
339{
340	acpi_status status;
341	struct acpi_gpe_block_info *gpe_block;
342	struct acpi_gpe_walk_info walk_info;
343
344	ACPI_FUNCTION_TRACE(ev_create_gpe_block);
345
346	if (!register_count) {
347		return_ACPI_STATUS(AE_OK);
348	}
349
350	/* Allocate a new GPE block */
351
352	gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
353	if (!gpe_block) {
354		return_ACPI_STATUS(AE_NO_MEMORY);
355	}
356
357	/* Initialize the new GPE block */
358
359	gpe_block->address = address;
360	gpe_block->space_id = space_id;
361	gpe_block->node = gpe_device;
362	gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
363	gpe_block->initialized = FALSE;
364	gpe_block->register_count = register_count;
365	gpe_block->block_base_number = gpe_block_base_number;
366
367	/*
368	 * Create the register_info and event_info sub-structures
369	 * Note: disables and clears all GPEs in the block
370	 */
371	status = acpi_ev_create_gpe_info_blocks(gpe_block);
372	if (ACPI_FAILURE(status)) {
373		ACPI_FREE(gpe_block);
374		return_ACPI_STATUS(status);
375	}
376
377	/* Install the new block in the global lists */
378
379	status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
380	if (ACPI_FAILURE(status)) {
381		ACPI_FREE(gpe_block->register_info);
382		ACPI_FREE(gpe_block->event_info);
383		ACPI_FREE(gpe_block);
384		return_ACPI_STATUS(status);
385	}
386
387	acpi_gbl_all_gpes_initialized = FALSE;
388
389	/* Find all GPE methods (_Lxx or_Exx) for this block */
390
391	walk_info.gpe_block = gpe_block;
392	walk_info.gpe_device = gpe_device;
393	walk_info.execute_by_owner_id = FALSE;
394
395	status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
396					ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
397					acpi_ev_match_gpe_method, NULL,
398					&walk_info, NULL);
399
400	/* Return the new block */
401
402	if (return_gpe_block) {
403		(*return_gpe_block) = gpe_block;
404	}
405
406	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
407			      "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
408			      (u32)gpe_block->block_base_number,
409			      (u32)(gpe_block->block_base_number +
410				    (gpe_block->gpe_count - 1)),
411			      gpe_device->name.ascii, gpe_block->register_count,
412			      interrupt_number,
413			      interrupt_number ==
414			      acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
415
416	/* Update global count of currently available GPEs */
417
418	acpi_current_gpe_count += gpe_block->gpe_count;
419	return_ACPI_STATUS(AE_OK);
420}
421
422/*******************************************************************************
423 *
424 * FUNCTION:    acpi_ev_initialize_gpe_block
425 *
426 * PARAMETERS:  acpi_gpe_callback
427 *
428 * RETURN:      Status
429 *
430 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
431 *              associated methods.
432 *              Note: Assumes namespace is locked.
433 *
434 ******************************************************************************/
435
436acpi_status
437acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
438			     struct acpi_gpe_block_info *gpe_block,
439			     void *ignored)
440{
441	acpi_status status;
442	struct acpi_gpe_event_info *gpe_event_info;
443	u32 gpe_enabled_count;
444	u32 gpe_index;
445	u32 i;
446	u32 j;
447
448	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
449
450	/*
451	 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
452	 * any GPE blocks that have been initialized already.
453	 */
454	if (!gpe_block || gpe_block->initialized) {
455		return_ACPI_STATUS(AE_OK);
456	}
457
458	/*
459	 * Enable all GPEs that have a corresponding method and have the
460	 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
461	 * must be enabled via the acpi_enable_gpe() interface.
462	 */
463	gpe_enabled_count = 0;
464
465	for (i = 0; i < gpe_block->register_count; i++) {
466		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
467
468			/* Get the info block for this particular GPE */
469
470			gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
471			gpe_event_info = &gpe_block->event_info[gpe_index];
472
473			/*
474			 * Ignore GPEs that have no corresponding _Lxx/_Exx method
475			 * and GPEs that are used to wake the system
476			 */
477			if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
478			     ACPI_GPE_DISPATCH_NONE)
479			    || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
480				== ACPI_GPE_DISPATCH_HANDLER)
481			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
482				continue;
483			}
484
485			status = acpi_ev_add_gpe_reference(gpe_event_info);
486			if (ACPI_FAILURE(status)) {
487				ACPI_EXCEPTION((AE_INFO, status,
488					"Could not enable GPE 0x%02X",
489					gpe_index +
490					gpe_block->block_base_number));
491				continue;
492			}
493
494			gpe_enabled_count++;
495		}
496	}
497
498	if (gpe_enabled_count) {
499		ACPI_INFO((AE_INFO,
500			   "Enabled %u GPEs in block %02X to %02X",
501			   gpe_enabled_count, (u32)gpe_block->block_base_number,
502			   (u32)(gpe_block->block_base_number +
503				 (gpe_block->gpe_count - 1))));
504	}
505
506	gpe_block->initialized = TRUE;
507
508	return_ACPI_STATUS(AE_OK);
509}
510
511#endif				/* !ACPI_REDUCED_HARDWARE */
512