Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4b49b9fe
Commit
4b49b9fe
authored
Feb 12, 2014
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge back earlier 'acpi-pci-hotplug' material.
Conflicts: drivers/pci/hotplug/acpiphp_glue.c
parents
72820594
21369c77
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
332 additions
and
402 deletions
+332
-402
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfeval.c
+30
-3
drivers/acpi/bus.c
drivers/acpi/bus.c
+39
-22
drivers/acpi/internal.h
drivers/acpi/internal.h
+1
-0
drivers/acpi/pci_root.c
drivers/acpi/pci_root.c
+1
-1
drivers/acpi/scan.c
drivers/acpi/scan.c
+93
-88
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp.h
+12
-4
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/acpiphp_glue.c
+124
-281
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+26
-1
include/acpi/acpixf.h
include/acpi/acpixf.h
+4
-0
include/linux/pci-acpi.h
include/linux/pci-acpi.h
+2
-2
No files found.
drivers/acpi/acpica/nsxfeval.c
View file @
4b49b9fe
...
...
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data)
/*******************************************************************************
*
* FUNCTION: acpi_get_data
* FUNCTION: acpi_get_data
_full
*
* PARAMETERS: obj_handle - Namespace node
* handler - Handler used in call to attach_data
* data - Where the data is returned
* callback - function to execute before returning
*
* RETURN: Status
*
* DESCRIPTION: Retrieve data that was previously attached to a namespace node.
* DESCRIPTION: Retrieve data that was previously attached to a namespace node
* and execute a callback before returning.
*
******************************************************************************/
acpi_status
acpi_get_data
(
acpi_handle
obj_handle
,
acpi_object_handler
handler
,
void
**
data
)
acpi_get_data_full
(
acpi_handle
obj_handle
,
acpi_object_handler
handler
,
void
**
data
,
void
(
*
callback
)(
void
*
))
{
struct
acpi_namespace_node
*
node
;
acpi_status
status
;
...
...
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
}
status
=
acpi_ns_get_attached_data
(
node
,
handler
,
data
);
if
(
ACPI_SUCCESS
(
status
)
&&
callback
)
{
callback
(
*
data
);
}
unlock_and_exit:
(
void
)
acpi_ut_release_mutex
(
ACPI_MTX_NAMESPACE
);
return
(
status
);
}
ACPI_EXPORT_SYMBOL
(
acpi_get_data_full
)
/*******************************************************************************
*
* FUNCTION: acpi_get_data
*
* PARAMETERS: obj_handle - Namespace node
* handler - Handler used in call to attach_data
* data - Where the data is returned
*
* RETURN: Status
*
* DESCRIPTION: Retrieve data that was previously attached to a namespace node.
*
******************************************************************************/
acpi_status
acpi_get_data
(
acpi_handle
obj_handle
,
acpi_object_handler
handler
,
void
**
data
)
{
return
acpi_get_data_full
(
obj_handle
,
handler
,
data
,
NULL
);
}
ACPI_EXPORT_SYMBOL
(
acpi_get_data
)
drivers/acpi/bus.c
View file @
4b49b9fe
...
...
@@ -340,60 +340,77 @@ static void acpi_bus_osc_support(void)
*/
static
void
acpi_bus_notify
(
acpi_handle
handle
,
u32
type
,
void
*
data
)
{
struct
acpi_device
*
device
=
NULL
;
struct
acpi_device
*
adev
;
struct
acpi_driver
*
driver
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Notification %#02x to handle %p
\n
"
,
type
,
handle
));
acpi_status
status
;
u32
ost_code
=
ACPI_OST_SC_NON_SPECIFIC_FAILURE
;
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
/* TBD */
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_BUS_CHECK event
\n
"
);
break
;
case
ACPI_NOTIFY_DEVICE_CHECK
:
/* TBD */
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_DEVICE_CHECK event
\n
"
);
break
;
case
ACPI_NOTIFY_DEVICE_WAKE
:
/* TBD */
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_DEVICE_WAKE event
\n
"
);
break
;
case
ACPI_NOTIFY_EJECT_REQUEST
:
/* TBD */
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_EJECT_REQUEST event
\n
"
);
break
;
case
ACPI_NOTIFY_DEVICE_CHECK_LIGHT
:
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_DEVICE_CHECK_LIGHT event
\n
"
);
/* TBD: Exactly what does 'light' mean? */
break
;
case
ACPI_NOTIFY_FREQUENCY_MISMATCH
:
/* TBD */
acpi_handle_err
(
handle
,
"Device cannot be configured due "
"to a frequency mismatch
\n
"
);
break
;
case
ACPI_NOTIFY_BUS_MODE_MISMATCH
:
/* TBD */
acpi_handle_err
(
handle
,
"Device cannot be configured due "
"to a bus mode mismatch
\n
"
);
break
;
case
ACPI_NOTIFY_POWER_FAULT
:
/* TBD */
acpi_handle_err
(
handle
,
"Device has suffered a power fault
\n
"
);
break
;
default:
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Received unknown/unsupported notification [%08x]
\n
"
,
type
));
break
;
acpi_handle_warn
(
handle
,
"Unsupported event type 0x%x
\n
"
,
type
);
ost_code
=
ACPI_OST_SC_UNRECOGNIZED_NOTIFY
;
goto
err
;
}
acpi_bus_get_device
(
handle
,
&
device
);
if
(
device
)
{
driver
=
device
->
driver
;
if
(
driver
&&
driver
->
ops
.
notify
&&
(
driver
->
flags
&
ACPI_DRIVER_ALL_NOTIFY_EVENTS
))
driver
->
ops
.
notify
(
device
,
type
);
adev
=
acpi_bus_get_acpi_device
(
handle
);
if
(
!
adev
)
goto
err
;
driver
=
adev
->
driver
;
if
(
driver
&&
driver
->
ops
.
notify
&&
(
driver
->
flags
&
ACPI_DRIVER_ALL_NOTIFY_EVENTS
))
driver
->
ops
.
notify
(
adev
,
type
);
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
case
ACPI_NOTIFY_DEVICE_CHECK
:
case
ACPI_NOTIFY_EJECT_REQUEST
:
status
=
acpi_hotplug_execute
(
acpi_device_hotplug
,
adev
,
type
);
if
(
ACPI_SUCCESS
(
status
))
return
;
default:
break
;
}
acpi_bus_put_acpi_device
(
adev
);
return
;
err:
acpi_evaluate_hotplug_ost
(
handle
,
type
,
ost_code
,
NULL
);
}
/* --------------------------------------------------------------------------
...
...
drivers/acpi/internal.h
View file @
4b49b9fe
...
...
@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {}
#endif
bool
acpi_queue_hotplug_work
(
struct
work_struct
*
work
);
void
acpi_device_hotplug
(
void
*
data
,
u32
src
);
bool
acpi_scan_is_offline
(
struct
acpi_device
*
adev
,
bool
uevent
);
/* --------------------------------------------------------------------------
...
...
drivers/acpi/pci_root.c
View file @
4b49b9fe
...
...
@@ -51,7 +51,7 @@ static void acpi_pci_root_remove(struct acpi_device *device);
static
int
acpi_pci_root_scan_dependent
(
struct
acpi_device
*
adev
)
{
acpiphp_check_host_bridge
(
adev
->
handle
);
acpiphp_check_host_bridge
(
adev
);
return
0
;
}
...
...
drivers/acpi/scan.c
View file @
4b49b9fe
...
...
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock);
static
LIST_HEAD
(
acpi_scan_handlers_list
);
DEFINE_MUTEX
(
acpi_device_lock
);
LIST_HEAD
(
acpi_wakeup_device_list
);
static
DEFINE_MUTEX
(
acpi_hp_context_lock
);
struct
acpi_device_bus_id
{
char
bus_id
[
15
];
...
...
@@ -60,6 +61,16 @@ void acpi_scan_lock_release(void)
}
EXPORT_SYMBOL_GPL
(
acpi_scan_lock_release
);
void
acpi_lock_hp_context
(
void
)
{
mutex_lock
(
&
acpi_hp_context_lock
);
}
void
acpi_unlock_hp_context
(
void
)
{
mutex_unlock
(
&
acpi_hp_context_lock
);
}
int
acpi_scan_add_handler
(
struct
acpi_scan_handler
*
handler
)
{
if
(
!
handler
||
!
handler
->
attach
)
...
...
@@ -439,90 +450,74 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
return
0
;
}
static
void
acpi_device_hotplug
(
void
*
data
,
u32
src
)
static
int
acpi_generic_hotplug_event
(
struct
acpi_device
*
adev
,
u32
type
)
{
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
return
acpi_scan_bus_check
(
adev
);
case
ACPI_NOTIFY_DEVICE_CHECK
:
return
acpi_scan_device_check
(
adev
);
case
ACPI_NOTIFY_EJECT_REQUEST
:
case
ACPI_OST_EC_OSPM_EJECT
:
if
(
adev
->
handler
&&
!
adev
->
handler
->
hotplug
.
enabled
)
{
dev_info
(
&
adev
->
dev
,
"Eject disabled
\n
"
);
return
-
EPERM
;
}
acpi_evaluate_hotplug_ost
(
adev
->
handle
,
ACPI_NOTIFY_EJECT_REQUEST
,
ACPI_OST_SC_EJECT_IN_PROGRESS
,
NULL
);
return
acpi_scan_hot_remove
(
adev
);
}
return
-
EINVAL
;
}
void
acpi_device_hotplug
(
void
*
data
,
u32
src
)
{
u32
ost_code
=
ACPI_OST_SC_NON_SPECIFIC_FAILURE
;
struct
acpi_device
*
adev
=
data
;
int
error
;
int
error
=
-
ENODEV
;
lock_device_hotplug
();
mutex_lock
(
&
acpi_scan_lock
);
/*
* The device object's ACPI handle cannot become invalid as long as we
* are holding acpi_scan_lock, but it m
ay
have become invalid before
* are holding acpi_scan_lock, but it m
ight
have become invalid before
* that lock was acquired.
*/
if
(
adev
->
handle
==
INVALID_ACPI_HANDLE
)
goto
out
;
switch
(
src
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
error
=
acpi_scan_bus_check
(
adev
);
break
;
case
ACPI_NOTIFY_DEVICE_CHECK
:
error
=
acpi_scan_device_check
(
adev
);
break
;
case
ACPI_NOTIFY_EJECT_REQUEST
:
case
ACPI_OST_EC_OSPM_EJECT
:
error
=
acpi_scan_hot_remove
(
adev
);
break
;
default:
error
=
-
EINVAL
;
break
;
}
if
(
!
error
)
ost_code
=
ACPI_OST_SC_SUCCESS
;
out:
acpi_evaluate_hotplug_ost
(
adev
->
handle
,
src
,
ost_code
,
NULL
);
put_device
(
&
adev
->
dev
);
mutex_unlock
(
&
acpi_scan_lock
);
unlock_device_hotplug
();
}
static
void
acpi_hotplug_notify_cb
(
acpi_handle
handle
,
u32
type
,
void
*
data
)
{
u32
ost_code
=
ACPI_OST_SC_NON_SPECIFIC_FAILURE
;
struct
acpi_device
*
adev
;
acpi_status
status
;
if
(
acpi_bus_get_device
(
handle
,
&
adev
))
goto
err_out
;
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_BUS_CHECK event
\n
"
);
break
;
case
ACPI_NOTIFY_DEVICE_CHECK
:
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_DEVICE_CHECK event
\n
"
);
break
;
case
ACPI_NOTIFY_EJECT_REQUEST
:
acpi_handle_debug
(
handle
,
"ACPI_NOTIFY_EJECT_REQUEST event
\n
"
);
if
(
!
adev
->
handler
)
goto
err_out
;
if
(
!
adev
->
handler
->
hotplug
.
enabled
)
{
acpi_handle_err
(
handle
,
"Eject disabled
\n
"
);
if
(
adev
->
flags
.
hotplug_notify
)
{
error
=
acpi_generic_hotplug_event
(
adev
,
src
);
if
(
error
==
-
EPERM
)
{
ost_code
=
ACPI_OST_SC_EJECT_NOT_SUPPORTED
;
goto
err_out
;
}
acpi_evaluate_hotplug_ost
(
handle
,
ACPI_NOTIFY_EJECT_REQUEST
,
ACPI_OST_SC_EJECT_IN_PROGRESS
,
NULL
);
break
;
default:
/* non-hotplug event; possibly handled by other handler */
return
;
}
get_device
(
&
adev
->
dev
);
status
=
acpi_hotplug_execute
(
acpi_device_hotplug
,
adev
,
type
);
if
(
ACPI_SUCCESS
(
status
))
return
;
}
else
{
int
(
*
event
)(
struct
acpi_device
*
,
u32
);
put_device
(
&
adev
->
dev
);
acpi_lock_hp_context
();
event
=
adev
->
hp
?
adev
->
hp
->
event
:
NULL
;
acpi_unlock_hp_context
();
/*
* There may be additional notify handlers for device objects
* without the .event() callback, so ignore them here.
*/
if
(
event
)
error
=
event
(
adev
,
src
);
else
goto
out
;
}
if
(
!
error
)
ost_code
=
ACPI_OST_SC_SUCCESS
;
err_out:
acpi_evaluate_hotplug_ost
(
handle
,
type
,
ost_code
,
NULL
);
acpi_evaluate_hotplug_ost
(
adev
->
handle
,
src
,
ost_code
,
NULL
);
out:
acpi_bus_put_acpi_device
(
adev
);
mutex_unlock
(
&
acpi_scan_lock
);
unlock_device_hotplug
();
}
static
ssize_t
real_power_state_show
(
struct
device
*
dev
,
...
...
@@ -570,8 +565,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if
(
ACPI_FAILURE
(
status
)
||
!
acpi_device
->
flags
.
ejectable
)
return
-
ENODEV
;
acpi_evaluate_hotplug_ost
(
acpi_device
->
handle
,
ACPI_OST_EC_OSPM_EJECT
,
ACPI_OST_SC_EJECT_IN_PROGRESS
,
NULL
);
get_device
(
&
acpi_device
->
dev
);
status
=
acpi_hotplug_execute
(
acpi_device_hotplug
,
acpi_device
,
ACPI_OST_EC_OSPM_EJECT
);
...
...
@@ -1114,14 +1107,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
mutex_unlock
(
&
acpi_device_del_lock
);
}
int
acpi_bus_get_device
(
acpi_handle
handle
,
struct
acpi_device
**
device
)
static
int
acpi_get_device_data
(
acpi_handle
handle
,
struct
acpi_device
**
device
,
void
(
*
callback
)(
void
*
))
{
acpi_status
status
;
if
(
!
device
)
return
-
EINVAL
;
status
=
acpi_get_data
(
handle
,
acpi_scan_drop_device
,
(
void
**
)
device
);
status
=
acpi_get_data_full
(
handle
,
acpi_scan_drop_device
,
(
void
**
)
device
,
callback
);
if
(
ACPI_FAILURE
(
status
)
||
!*
device
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"No context for object [%p]
\n
"
,
handle
));
...
...
@@ -1129,8 +1124,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
}
return
0
;
}
int
acpi_bus_get_device
(
acpi_handle
handle
,
struct
acpi_device
**
device
)
{
return
acpi_get_device_data
(
handle
,
device
,
NULL
);
}
EXPORT_SYMBOL
(
acpi_bus_get_device
);
static
void
get_acpi_device
(
void
*
dev
)
{
if
(
dev
)
get_device
(
&
((
struct
acpi_device
*
)
dev
)
->
dev
);
}
struct
acpi_device
*
acpi_bus_get_acpi_device
(
acpi_handle
handle
)
{
struct
acpi_device
*
adev
=
NULL
;
acpi_get_device_data
(
handle
,
&
adev
,
get_acpi_device
);
return
adev
;
}
void
acpi_bus_put_acpi_device
(
struct
acpi_device
*
adev
)
{
put_device
(
&
adev
->
dev
);
}
int
acpi_device_add
(
struct
acpi_device
*
device
,
void
(
*
release
)(
struct
device
*
))
{
...
...
@@ -1941,33 +1960,19 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
mutex_unlock
(
&
acpi_scan_lock
);
}
static
void
acpi_scan_init_hotplug
(
acpi_handle
handle
,
int
type
)
static
void
acpi_scan_init_hotplug
(
struct
acpi_device
*
adev
)
{
struct
acpi_device_pnp
pnp
=
{};
struct
acpi_hardware_id
*
hwid
;
struct
acpi_scan_handler
*
handler
;
INIT_LIST_HEAD
(
&
pnp
.
ids
);
acpi_set_pnp_ids
(
handle
,
&
pnp
,
type
);
if
(
!
pnp
.
type
.
hardware_id
)
goto
out
;
list_for_each_entry
(
hwid
,
&
adev
->
pnp
.
ids
,
list
)
{
struct
acpi_scan_handler
*
handler
;
/*
* This relies on the fact that acpi_install_notify_handler() will not
* install the same notify handler routine twice for the same handle.
*/
list_for_each_entry
(
hwid
,
&
pnp
.
ids
,
list
)
{
handler
=
acpi_scan_match_handler
(
hwid
->
id
,
NULL
);
if
(
handler
)
{
acpi_install_notify_handler
(
handle
,
ACPI_SYSTEM_NOTIFY
,
acpi_hotplug_notify_cb
,
handler
);
adev
->
flags
.
hotplug_notify
=
true
;
break
;
}
}
out:
acpi_free_pnp_ids
(
&
pnp
);
}
static
acpi_status
acpi_bus_check_add
(
acpi_handle
handle
,
u32
lvl_not_used
,
...
...
@@ -1991,12 +1996,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return
AE_OK
;
}
acpi_scan_init_hotplug
(
handle
,
type
);
acpi_add_single_object
(
&
device
,
handle
,
type
,
sta
);
if
(
!
device
)
return
AE_CTRL_DEPTH
;
acpi_scan_init_hotplug
(
device
);
out:
if
(
!*
return_value
)
*
return_value
=
device
;
...
...
drivers/pci/hotplug/acpiphp.h
View file @
4b49b9fe
...
...
@@ -93,7 +93,6 @@ struct acpiphp_slot {
struct
list_head
funcs
;
/* one slot may have different
objects (i.e. for each function) */
struct
slot
*
slot
;
struct
mutex
crit_sect
;
u8
device
;
/* pci device# */
u32
flags
;
/* see below */
...
...
@@ -117,20 +116,30 @@ struct acpiphp_func {
};
struct
acpiphp_context
{
acpi_handle
handle
;
struct
acpi_hotplug_context
hp
;
struct
acpiphp_func
func
;
struct
acpiphp_bridge
*
bridge
;
unsigned
int
refcount
;
};
static
inline
struct
acpiphp_context
*
to_acpiphp_context
(
struct
acpi_hotplug_context
*
hp
)
{
return
container_of
(
hp
,
struct
acpiphp_context
,
hp
);
}
static
inline
struct
acpiphp_context
*
func_to_context
(
struct
acpiphp_func
*
func
)
{
return
container_of
(
func
,
struct
acpiphp_context
,
func
);
}
static
inline
struct
acpi_device
*
func_to_acpi_device
(
struct
acpiphp_func
*
func
)
{
return
func_to_context
(
func
)
->
hp
.
self
;
}
static
inline
acpi_handle
func_to_handle
(
struct
acpiphp_func
*
func
)
{
return
func_to_
context
(
func
)
->
handle
;
return
func_to_
acpi_device
(
func
)
->
handle
;
}
/*
...
...
@@ -158,7 +167,6 @@ struct acpiphp_attention_info
#define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002)
#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */
...
...
drivers/pci/hotplug/acpiphp_glue.c
View file @
4b49b9fe
...
...
@@ -58,71 +58,57 @@
static
LIST_HEAD
(
bridge_list
);
static
DEFINE_MUTEX
(
bridge_mutex
);
static
DEFINE_MUTEX
(
acpiphp_context_lock
);
static
void
handle_hotplug_event
(
acpi_handle
handle
,
u32
type
,
void
*
data
);
static
int
acpiphp_hotplug_event
(
struct
acpi_device
*
adev
,
u32
type
);
static
void
acpiphp_sanitize_bus
(
struct
pci_bus
*
bus
);
static
void
acpiphp_set_hpp_values
(
struct
pci_bus
*
bus
);
static
void
hotplug_event
(
acpi_handle
handle
,
u32
type
,
void
*
data
);
static
void
hotplug_event
(
u32
type
,
struct
acpiphp_context
*
context
);
static
void
free_bridge
(
struct
kref
*
kref
);
static
void
acpiphp_context_handler
(
acpi_handle
handle
,
void
*
context
)
{
/* Intentionally empty. */
}
/**
* acpiphp_init_context - Create hotplug context and grab a reference to it.
* @
handle: ACPI object handle
to create the context for.
* @
adev: ACPI device object
to create the context for.
*
* Call under acpi
p
hp_context_lock.
* Call under acpi
_
hp_context_lock.
*/
static
struct
acpiphp_context
*
acpiphp_init_context
(
acpi_handle
handle
)
static
struct
acpiphp_context
*
acpiphp_init_context
(
struct
acpi_device
*
adev
)
{
struct
acpiphp_context
*
context
;
acpi_status
status
;
context
=
kzalloc
(
sizeof
(
*
context
),
GFP_KERNEL
);
if
(
!
context
)
return
NULL
;
context
->
handle
=
handle
;
context
->
refcount
=
1
;
status
=
acpi_attach_data
(
handle
,
acpiphp_context_handler
,
context
);
if
(
ACPI_FAILURE
(
status
))
{
kfree
(
context
);
return
NULL
;
}
acpi_set_hp_context
(
adev
,
&
context
->
hp
,
acpiphp_hotplug_event
);
return
context
;
}
/**
* acpiphp_get_context - Get hotplug context and grab a reference to it.
* @
handle: ACPI object handle
to get the context for.
* @
adev: ACPI device object
to get the context for.
*
* Call under acpi
p
hp_context_lock.
* Call under acpi
_
hp_context_lock.
*/
static
struct
acpiphp_context
*
acpiphp_get_context
(
acpi_handle
handle
)
static
struct
acpiphp_context
*
acpiphp_get_context
(
struct
acpi_device
*
adev
)
{
struct
acpiphp_context
*
context
=
NULL
;
acpi_status
status
;
void
*
data
;
struct
acpiphp_context
*
context
;
status
=
acpi_get_data
(
handle
,
acpiphp_context_handler
,
&
data
);
if
(
ACPI_SUCCESS
(
status
))
{
context
=
data
;
context
->
refcount
++
;
}
if
(
!
adev
->
hp
)
return
NULL
;
context
=
to_acpiphp_context
(
adev
->
hp
)
;
context
->
refcount
++
;
return
context
;
}
/**
* acpiphp_put_context - Drop a reference to ACPI hotplug context.
* @
handle: ACPI object handle to put the context for
.
* @
context: ACPI hotplug context to drop a reference to
.
*
* The context object is removed if there are no more references to it.
*
* Call under acpi
p
hp_context_lock.
* Call under acpi
_
hp_context_lock.
*/
static
void
acpiphp_put_context
(
struct
acpiphp_context
*
context
)
{
...
...
@@ -130,7 +116,7 @@ static void acpiphp_put_context(struct acpiphp_context *context)
return
;
WARN_ON
(
context
->
bridge
);
acpi_detach_data
(
context
->
handle
,
acpiphp_context_handler
)
;
context
->
hp
.
self
->
hp
=
NULL
;
kfree
(
context
);
}
...
...
@@ -151,7 +137,7 @@ static void free_bridge(struct kref *kref)
struct
acpiphp_slot
*
slot
,
*
next
;
struct
acpiphp_func
*
func
,
*
tmp
;
mutex_lock
(
&
acpiphp_context_lock
);
acpi_lock_hp_context
(
);
bridge
=
container_of
(
kref
,
struct
acpiphp_bridge
,
ref
);
...
...
@@ -175,7 +161,7 @@ static void free_bridge(struct kref *kref)
pci_dev_put
(
bridge
->
pci_dev
);
kfree
(
bridge
);
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
}
/*
...
...
@@ -212,22 +198,13 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
static
void
dock_event
(
acpi_handle
handle
,
u32
type
,
void
*
data
)
{
struct
acpi
php_context
*
context
;
struct
acpi
_device
*
adev
;
mutex_lock
(
&
acpiphp_context_lock
);
context
=
acpiphp_get_context
(
handle
);
if
(
!
context
||
WARN_ON
(
context
->
handle
!=
handle
)
||
context
->
func
.
parent
->
is_going_away
)
{
mutex_unlock
(
&
acpiphp_context_lock
);
return
;
adev
=
acpi_bus_get_acpi_device
(
handle
);
if
(
adev
)
{
acpiphp_hotplug_event
(
adev
,
type
);
acpi_bus_put_acpi_device
(
adev
);
}
get_bridge
(
context
->
func
.
parent
);
acpiphp_put_context
(
context
);
mutex_unlock
(
&
acpiphp_context_lock
);
hotplug_event
(
handle
,
type
,
data
);
put_bridge
(
context
->
func
.
parent
);
}
static
const
struct
acpi_dock_ops
acpiphp_dock_ops
=
{
...
...
@@ -284,6 +261,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
{
struct
acpiphp_bridge
*
bridge
=
data
;
struct
acpiphp_context
*
context
;
struct
acpi_device
*
adev
;
struct
acpiphp_slot
*
slot
;
struct
acpiphp_func
*
newfunc
;
acpi_status
status
=
AE_OK
;
...
...
@@ -303,21 +281,22 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
"can't evaluate _ADR (%#x)
\n
"
,
status
);
return
AE_OK
;
}
if
(
acpi_bus_get_device
(
handle
,
&
adev
))
return
AE_OK
;
device
=
(
adr
>>
16
)
&
0xffff
;
function
=
adr
&
0xffff
;
mutex_lock
(
&
acpiphp_context_lock
);
context
=
acpiphp_init_context
(
handle
);
acpi_lock_hp_context
(
);
context
=
acpiphp_init_context
(
adev
);
if
(
!
context
)
{
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
acpi_handle_err
(
handle
,
"No hotplug context
\n
"
);
return
AE_NOT_EXIST
;
}
newfunc
=
&
context
->
func
;
newfunc
->
function
=
function
;
newfunc
->
parent
=
bridge
;
mutex_unlock
(
&
acpiphp_context_lock
);
if
(
acpi_has_method
(
handle
,
"_EJ0"
))
newfunc
->
flags
=
FUNC_HAS_EJ0
;
...
...
@@ -325,8 +304,14 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
if
(
acpi_has_method
(
handle
,
"_STA"
))
newfunc
->
flags
|=
FUNC_HAS_STA
;
/*
* Dock stations' notify handler should be used for dock devices instead
* of the common one, so clear hp.event in their contexts.
*/
if
(
acpi_has_method
(
handle
,
"_DCK"
))
newfunc
->
flags
|=
FUNC_HAS_DCK
;
context
->
hp
.
event
=
NULL
;
acpi_unlock_hp_context
();
/* search for objects that share the same slot */
list_for_each_entry
(
slot
,
&
bridge
->
slots
,
node
)
...
...
@@ -335,14 +320,15 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
slot
=
kzalloc
(
sizeof
(
struct
acpiphp_slot
),
GFP_KERNEL
);
if
(
!
slot
)
{
status
=
AE_NO_MEMORY
;
goto
err
;
acpi_lock_hp_context
();
acpiphp_put_context
(
context
);
acpi_unlock_hp_context
();
return
AE_NO_MEMORY
;
}
slot
->
bus
=
bridge
->
pci_bus
;
slot
->
device
=
device
;
INIT_LIST_HEAD
(
&
slot
->
funcs
);
mutex_init
(
&
slot
->
crit_sect
);
list_add_tail
(
&
slot
->
node
,
&
bridge
->
slots
);
...
...
@@ -393,32 +379,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
pr_debug
(
"failed to register dock device
\n
"
);
}
/* install notify handler */
if
(
!
(
newfunc
->
flags
&
FUNC_HAS_DCK
))
{
status
=
acpi_install_notify_handler
(
handle
,
ACPI_SYSTEM_NOTIFY
,
handle_hotplug_event
,
context
);
if
(
ACPI_FAILURE
(
status
))
acpi_handle_err
(
handle
,
"failed to install notify handler
\n
"
);
}
return
AE_OK
;
err:
mutex_lock
(
&
acpiphp_context_lock
);
acpiphp_put_context
(
context
);
mutex_unlock
(
&
acpiphp_context_lock
);
return
status
;
}
static
struct
acpiphp_bridge
*
acpiphp_
handle_to_bridge
(
acpi_handle
handle
)
static
struct
acpiphp_bridge
*
acpiphp_
dev_to_bridge
(
struct
acpi_device
*
adev
)
{
struct
acpiphp_context
*
context
;
struct
acpiphp_bridge
*
bridge
=
NULL
;
mutex_lock
(
&
acpiphp_context_lock
);
context
=
acpiphp_get_context
(
handle
);
acpi_lock_hp_context
(
);
context
=
acpiphp_get_context
(
adev
);
if
(
context
)
{
bridge
=
context
->
bridge
;
if
(
bridge
)
...
...
@@ -426,7 +396,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
acpiphp_put_context
(
context
);
}
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
return
bridge
;
}
...
...
@@ -434,22 +404,17 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
{
struct
acpiphp_slot
*
slot
;
struct
acpiphp_func
*
func
;
acpi_status
status
;
list_for_each_entry
(
slot
,
&
bridge
->
slots
,
node
)
{
list_for_each_entry
(
func
,
&
slot
->
funcs
,
sibling
)
{
acpi_handle
handle
=
func_to_handl
e
(
func
);
struct
acpi_device
*
adev
=
func_to_acpi_devic
e
(
func
);
if
(
is_dock_device
(
handle
))
unregister_hotplug_dock_device
(
handle
);
if
(
is_dock_device
(
adev
->
handle
))
unregister_hotplug_dock_device
(
adev
->
handle
);
if
(
!
(
func
->
flags
&
FUNC_HAS_DCK
))
{
status
=
acpi_remove_notify_handler
(
handle
,
ACPI_SYSTEM_NOTIFY
,
handle_hotplug_event
);
if
(
ACPI_FAILURE
(
status
))
pr_err
(
"failed to remove notify handler
\n
"
);
}
acpi_lock_hp_context
();
adev
->
hp
->
event
=
NULL
;
acpi_unlock_hp_context
();
}
slot
->
flags
|=
SLOT_IS_GOING_AWAY
;
if
(
slot
->
slot
)
...
...
@@ -460,9 +425,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_del
(
&
bridge
->
list
);
mutex_unlock
(
&
bridge_mutex
);
mutex_lock
(
&
acpiphp_context_lock
);
acpi_lock_hp_context
(
);
bridge
->
is_going_away
=
true
;
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
}
/**
...
...
@@ -492,33 +457,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
return
max
;
}
/**
* acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
* @handle: ACPI device object handle to start from.
*/
static
void
acpiphp_bus_trim
(
acpi_handle
handle
)
{
struct
acpi_device
*
adev
=
NULL
;
acpi_bus_get_device
(
handle
,
&
adev
);
if
(
adev
)
acpi_bus_trim
(
adev
);
}
/**
* acpiphp_bus_add - Scan ACPI namespace subtree.
* @handle: ACPI object handle to start the scan from.
*/
static
void
acpiphp_bus_add
(
acpi_handle
handle
)
{
struct
acpi_device
*
adev
=
NULL
;
acpi_bus_scan
(
handle
);
acpi_bus_get_device
(
handle
,
&
adev
);
if
(
acpi_device_enumerated
(
adev
))
acpi_device_set_power
(
adev
,
ACPI_STATE_D0
);
}
static
void
acpiphp_set_acpi_region
(
struct
acpiphp_slot
*
slot
)
{
struct
acpiphp_func
*
func
;
...
...
@@ -558,9 +496,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
{
struct
acpiphp_func
*
func
;
list_for_each_entry
(
func
,
&
slot
->
funcs
,
sibling
)
acpiphp_bus_add
(
func_to_handle
(
func
)
);
list_for_each_entry
(
func
,
&
slot
->
funcs
,
sibling
)
{
struct
acpi_device
*
adev
=
func_to_acpi_device
(
func
);
acpi_bus_scan
(
adev
->
handle
);
if
(
acpi_device_enumerated
(
adev
))
acpi_device_set_power
(
adev
,
ACPI_STATE_D0
);
}
return
pci_scan_slot
(
slot
->
bus
,
PCI_DEVFN
(
slot
->
device
,
0
));
}
...
...
@@ -625,32 +567,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
}
}
/* return first device in slot, acquiring a reference on it */
static
struct
pci_dev
*
dev_in_slot
(
struct
acpiphp_slot
*
slot
)
{
struct
pci_bus
*
bus
=
slot
->
bus
;
struct
pci_dev
*
dev
;
struct
pci_dev
*
ret
=
NULL
;
down_read
(
&
pci_bus_sem
);
list_for_each_entry
(
dev
,
&
bus
->
devices
,
bus_list
)
if
(
PCI_SLOT
(
dev
->
devfn
)
==
slot
->
device
)
{
ret
=
pci_dev_get
(
dev
);
break
;
}
up_read
(
&
pci_bus_sem
);
return
ret
;
}
/**
* disable_slot - disable a slot
* @slot: ACPI PHP slot
*/
static
void
disable_slot
(
struct
acpiphp_slot
*
slot
)
{
struct
pci_bus
*
bus
=
slot
->
bus
;
struct
pci_dev
*
dev
,
*
prev
;
struct
acpiphp_func
*
func
;
struct
pci_dev
*
pdev
;
/*
* enable_slot() enumerates all functions in this device via
...
...
@@ -658,22 +583,18 @@ static void disable_slot(struct acpiphp_slot *slot)
* methods (_EJ0, etc.) or not. Therefore, we remove all functions
* here.
*/
while
((
pdev
=
dev_in_slot
(
slot
)))
{
pci_stop_and_remove_bus_device
(
pdev
);
pci_dev_put
(
pdev
);
}
list_for_each_entry_safe_reverse
(
dev
,
prev
,
&
bus
->
devices
,
bus_list
)
if
(
PCI_SLOT
(
dev
->
devfn
)
==
slot
->
device
)
pci_stop_and_remove_bus_device
(
dev
);
list_for_each_entry
(
func
,
&
slot
->
funcs
,
sibling
)
acpi
php_bus_trim
(
func_to_handl
e
(
func
));
acpi
_bus_trim
(
func_to_acpi_devic
e
(
func
));
slot
->
flags
&=
(
~
SLOT_ENABLED
);
}
static
bool
acpiphp_no_hotplug
(
acpi_handle
handle
)
static
bool
acpiphp_no_hotplug
(
struct
acpi_device
*
adev
)
{
struct
acpi_device
*
adev
=
NULL
;
acpi_bus_get_device
(
handle
,
&
adev
);
return
adev
&&
adev
->
flags
.
no_hotplug
;
}
...
...
@@ -682,7 +603,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot)
struct
acpiphp_func
*
func
;
list_for_each_entry
(
func
,
&
slot
->
funcs
,
sibling
)
if
(
acpiphp_no_hotplug
(
func_to_
handl
e
(
func
)))
if
(
acpiphp_no_hotplug
(
func_to_
acpi_devic
e
(
func
)))
return
true
;
return
false
;
...
...
@@ -747,17 +668,17 @@ static inline bool device_status_valid(unsigned int sta)
*/
static
void
trim_stale_devices
(
struct
pci_dev
*
dev
)
{
acpi_handle
handle
=
ACPI_HANDLE
(
&
dev
->
dev
);
struct
acpi_device
*
adev
=
ACPI_COMPANION
(
&
dev
->
dev
);
struct
pci_bus
*
bus
=
dev
->
subordinate
;
bool
alive
=
false
;
if
(
handle
)
{
if
(
adev
)
{
acpi_status
status
;
unsigned
long
long
sta
;
status
=
acpi_evaluate_integer
(
handle
,
"_STA"
,
NULL
,
&
sta
);
status
=
acpi_evaluate_integer
(
adev
->
handle
,
"_STA"
,
NULL
,
&
sta
);
alive
=
(
ACPI_SUCCESS
(
status
)
&&
device_status_valid
(
sta
))
||
acpiphp_no_hotplug
(
handle
);
||
acpiphp_no_hotplug
(
adev
);
}
if
(
!
alive
)
{
u32
v
;
...
...
@@ -767,8 +688,8 @@ static void trim_stale_devices(struct pci_dev *dev)
}
if
(
!
alive
)
{
pci_stop_and_remove_bus_device
(
dev
);
if
(
handle
)
acpi
php_bus_trim
(
handle
);
if
(
adev
)
acpi
_bus_trim
(
adev
);
}
else
if
(
bus
)
{
struct
pci_dev
*
child
,
*
tmp
;
...
...
@@ -800,7 +721,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
struct
pci_bus
*
bus
=
slot
->
bus
;
struct
pci_dev
*
dev
,
*
tmp
;
mutex_lock
(
&
slot
->
crit_sect
);
if
(
slot_no_hotplug
(
slot
))
{
;
/* do nothing */
}
else
if
(
device_status_valid
(
get_slot_status
(
slot
)))
{
...
...
@@ -815,7 +735,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
}
else
{
disable_slot
(
slot
);
}
mutex_unlock
(
&
slot
->
crit_sect
);
}
}
...
...
@@ -855,11 +774,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
* ACPI event handlers
*/
void
acpiphp_check_host_bridge
(
acpi_handle
handle
)
void
acpiphp_check_host_bridge
(
struct
acpi_device
*
adev
)
{
struct
acpiphp_bridge
*
bridge
;
bridge
=
acpiphp_
handle_to_bridge
(
handle
);
bridge
=
acpiphp_
dev_to_bridge
(
adev
);
if
(
bridge
)
{
pci_lock_rescan_remove
();
...
...
@@ -872,73 +791,52 @@ void acpiphp_check_host_bridge(acpi_handle handle)
static
int
acpiphp_disable_and_eject_slot
(
struct
acpiphp_slot
*
slot
);
static
void
hotplug_event
(
acpi_handle
handle
,
u32
type
,
void
*
data
)
static
void
hotplug_event
(
u32
type
,
struct
acpiphp_context
*
context
)
{
struct
acpiphp_context
*
context
=
data
;
acpi_handle
handle
=
context
->
hp
.
self
->
handle
;
struct
acpiphp_func
*
func
=
&
context
->
func
;
struct
acpiphp_slot
*
slot
=
func
->
slot
;
struct
acpiphp_bridge
*
bridge
;
char
objname
[
64
];
struct
acpi_buffer
buffer
=
{
.
length
=
sizeof
(
objname
),
.
pointer
=
objname
};
mutex_lock
(
&
acpiphp_context_lock
);
acpi_lock_hp_context
(
);
bridge
=
context
->
bridge
;
if
(
bridge
)
get_bridge
(
bridge
);
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
pci_lock_rescan_remove
();
acpi_get_name
(
handle
,
ACPI_FULL_PATHNAME
,
&
buffer
);
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
/* bus re-enumerate */
pr_debug
(
"%s: Bus check notify on %s
\n
"
,
__func__
,
objname
);
pr_debug
(
"%s: re-enumerating slots under %s
\n
"
,
__func__
,
objname
);
if
(
bridge
)
{
acpi_handle_debug
(
handle
,
"Bus check in %s()
\n
"
,
__func__
);
if
(
bridge
)
acpiphp_check_bridge
(
bridge
);
}
else
{
struct
acpiphp_slot
*
slot
=
func
->
slot
;
if
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
)
break
;
mutex_lock
(
&
slot
->
crit_sect
);
else
if
(
!
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
))
enable_slot
(
slot
);
mutex_unlock
(
&
slot
->
crit_sect
);
}
break
;
case
ACPI_NOTIFY_DEVICE_CHECK
:
/* device check */
pr_debug
(
"%s: Device check notify on %s
\n
"
,
__func__
,
objname
);
acpi_handle_debug
(
handle
,
"Device check in %s()
\n
"
,
__func__
);
if
(
bridge
)
{
acpiphp_check_bridge
(
bridge
);
}
else
{
struct
acpiphp_slot
*
slot
=
func
->
slot
;
int
ret
;
if
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
)
break
;
}
else
if
(
!
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
))
{
/*
* Check if anything has changed in the slot and rescan
* from the parent if that's the case.
*/
mutex_lock
(
&
slot
->
crit_sect
);
ret
=
acpiphp_rescan_slot
(
slot
);
mutex_unlock
(
&
slot
->
crit_sect
);
if
(
ret
)
if
(
acpiphp_rescan_slot
(
slot
))
acpiphp_check_bridge
(
func
->
parent
);
}
break
;
case
ACPI_NOTIFY_EJECT_REQUEST
:
/* request device eject */
pr_debug
(
"%s: Device eject notify on %s
\n
"
,
__func__
,
objname
);
acpiphp_disable_and_eject_slot
(
func
->
slot
);
acpi_handle_debug
(
handle
,
"Eject request in %s()
\n
"
,
__func__
);
acpiphp_disable_and_eject_slot
(
slot
);
break
;
}
...
...
@@ -947,106 +845,48 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
put_bridge
(
bridge
);
}
static
void
hotplug_event_work
(
void
*
data
,
u32
type
)
{
struct
acpiphp_context
*
context
=
data
;
acpi_handle
handle
=
context
->
handle
;
acpi_scan_lock_acquire
();
hotplug_event
(
handle
,
type
,
context
);
acpi_scan_lock_release
();
acpi_evaluate_hotplug_ost
(
handle
,
type
,
ACPI_OST_SC_SUCCESS
,
NULL
);
put_bridge
(
context
->
func
.
parent
);
}
/**
* handle_hotplug_event - handle ACPI hotplug event
* @handle: Notify()'ed acpi_handle
* @type: Notify code
* @data: pointer to acpiphp_context structure
*
* Handles ACPI event notification on slots.
*/
static
void
handle_hotplug_event
(
acpi_handle
handle
,
u32
type
,
void
*
data
)
static
int
acpiphp_hotplug_event
(
struct
acpi_device
*
adev
,
u32
type
)
{
struct
acpiphp_context
*
context
;
u32
ost_code
=
ACPI_OST_SC_SUCCESS
;
acpi_status
status
;
switch
(
type
)
{
case
ACPI_NOTIFY_BUS_CHECK
:
case
ACPI_NOTIFY_DEVICE_CHECK
:
break
;
case
ACPI_NOTIFY_EJECT_REQUEST
:
ost_code
=
ACPI_OST_SC_EJECT_IN_PROGRESS
;
acpi_evaluate_hotplug_ost
(
handle
,
type
,
ost_code
,
NULL
);
break
;
case
ACPI_NOTIFY_DEVICE_WAKE
:
return
;
case
ACPI_NOTIFY_FREQUENCY_MISMATCH
:
acpi_handle_err
(
handle
,
"Device cannot be configured due "
"to a frequency mismatch
\n
"
);
goto
out
;
case
ACPI_NOTIFY_BUS_MODE_MISMATCH
:
acpi_handle_err
(
handle
,
"Device cannot be configured due "
"to a bus mode mismatch
\n
"
);
goto
out
;
case
ACPI_NOTIFY_POWER_FAULT
:
acpi_handle_err
(
handle
,
"Device has suffered a power fault
\n
"
);
goto
out
;
default:
acpi_handle_warn
(
handle
,
"Unsupported event type 0x%x
\n
"
,
type
);
ost_code
=
ACPI_OST_SC_UNRECOGNIZED_NOTIFY
;
goto
out
;
acpi_lock_hp_context
();
context
=
acpiphp_get_context
(
adev
);
if
(
!
context
||
context
->
func
.
parent
->
is_going_away
)
{
acpi_unlock_hp_context
();
return
-
ENODATA
;
}
mutex_lock
(
&
acpiphp_context_lock
);
context
=
acpiphp_get_context
(
handle
);
if
(
!
context
||
WARN_ON
(
context
->
handle
!=
handle
)
||
context
->
func
.
parent
->
is_going_away
)
goto
err_out
;
get_bridge
(
context
->
func
.
parent
);
acpiphp_put_context
(
context
);
status
=
acpi_hotplug_execute
(
hotplug_event_work
,
context
,
type
);
if
(
ACPI_SUCCESS
(
status
))
{
mutex_unlock
(
&
acpiphp_context_lock
);
return
;
}
put_bridge
(
context
->
func
.
parent
);
acpi_unlock_hp_context
();
err_out:
mutex_unlock
(
&
acpiphp_context_lock
);
ost_code
=
ACPI_OST_SC_NON_SPECIFIC_FAILURE
;
hotplug_event
(
type
,
context
);
out:
acpi_evaluate_hotplug_ost
(
handle
,
type
,
ost_code
,
NULL
)
;
put_bridge
(
context
->
func
.
parent
);
return
0
;
}
/*
* Create hotplug slots for the PCI bus.
* It should always return 0 to avoid skipping following notifiers.
/**
* acpiphp_enumerate_slots - Enumerate PCI slots for a given bus.
* @bus: PCI bus to enumerate the slots for.
*
* A "slot" is an object associated with a PCI device number. All functions
* (PCI devices) with the same bus and device number belong to the same slot.
*/
void
acpiphp_enumerate_slots
(
struct
pci_bus
*
bus
)
{
struct
acpiphp_bridge
*
bridge
;
struct
acpi_device
*
adev
;
acpi_handle
handle
;
acpi_status
status
;
if
(
acpiphp_disabled
)
return
;
handle
=
ACPI_HANDLE
(
bus
->
bridge
);
if
(
!
handle
)
adev
=
ACPI_COMPANION
(
bus
->
bridge
);
if
(
!
adev
)
return
;
handle
=
adev
->
handle
;
bridge
=
kzalloc
(
sizeof
(
struct
acpiphp_bridge
),
GFP_KERNEL
);
if
(
!
bridge
)
{
acpi_handle_err
(
handle
,
"No memory for bridge object
\n
"
);
...
...
@@ -1074,10 +914,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
* parent is going to be handled by pciehp, in which case this
* bridge is not interesting to us either.
*/
mutex_lock
(
&
acpiphp_context_lock
);
context
=
acpiphp_get_context
(
handle
);
acpi_lock_hp_context
(
);
context
=
acpiphp_get_context
(
adev
);
if
(
!
context
)
{
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
put_device
(
&
bus
->
dev
);
pci_dev_put
(
bridge
->
pci_dev
);
kfree
(
bridge
);
...
...
@@ -1087,7 +927,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
context
->
bridge
=
bridge
;
/* Get a reference to the parent bridge. */
get_bridge
(
context
->
func
.
parent
);
mutex_unlock
(
&
acpiphp_context_lock
);
acpi_unlock_hp_context
(
);
}
/* must be added to the list prior to calling register_slot */
...
...
@@ -1105,7 +945,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
}
}
/* Destroy hotplug slots associated with the PCI bus */
/**
* acpiphp_remove_slots - Remove slot objects associated with a given bus.
* @bus: PCI bus to remove the slot objects for.
*/
void
acpiphp_remove_slots
(
struct
pci_bus
*
bus
)
{
struct
acpiphp_bridge
*
bridge
;
...
...
@@ -1136,13 +979,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
if
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
)
return
-
ENODEV
;
mutex_lock
(
&
slot
->
crit_sect
);
/* configure all functions */
if
(
!
(
slot
->
flags
&
SLOT_ENABLED
))
enable_slot
(
slot
);
mutex_unlock
(
&
slot
->
crit_sect
);
pci_unlock_rescan_remove
();
return
0
;
}
...
...
@@ -1158,8 +998,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
if
(
slot
->
flags
&
SLOT_IS_GOING_AWAY
)
return
-
ENODEV
;
mutex_lock
(
&
slot
->
crit_sect
);
/* unconfigure all functions */
disable_slot
(
slot
);
...
...
@@ -1173,7 +1011,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
break
;
}
mutex_unlock
(
&
slot
->
crit_sect
);
return
0
;
}
...
...
@@ -1181,9 +1018,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
{
int
ret
;
/*
* Acquire acpi_scan_lock to ensure that the execution of _EJ0 in
* acpiphp_disable_and_eject_slot() will be synchronized properly.
*/
acpi_scan_lock_acquire
();
pci_lock_rescan_remove
();
ret
=
acpiphp_disable_and_eject_slot
(
slot
);
pci_unlock_rescan_remove
();
acpi_scan_lock_release
();
return
ret
;
}
...
...
include/acpi/acpi_bus.h
View file @
4b49b9fe
...
...
@@ -136,6 +136,16 @@ struct acpi_scan_handler {
struct
acpi_hotplug_profile
hotplug
;
};
/*
* ACPI Hotplug Context
* --------------------
*/
struct
acpi_hotplug_context
{
struct
acpi_device
*
self
;
int
(
*
event
)(
struct
acpi_device
*
,
u32
);
};
/*
* ACPI Driver
* -----------
...
...
@@ -190,7 +200,8 @@ struct acpi_device_flags {
u32
initialized
:
1
;
u32
visited
:
1
;
u32
no_hotplug
:
1
;
u32
reserved
:
24
;
u32
hotplug_notify
:
1
;
u32
reserved
:
23
;
};
/* File System */
...
...
@@ -329,6 +340,7 @@ struct acpi_device {
struct
acpi_device_perf
performance
;
struct
acpi_device_dir
dir
;
struct
acpi_scan_handler
*
handler
;
struct
acpi_hotplug_context
*
hp
;
struct
acpi_driver
*
driver
;
void
*
driver_data
;
struct
device
dev
;
...
...
@@ -351,6 +363,15 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta)
*
((
u32
*
)
&
adev
->
status
)
=
sta
;
}
static
inline
void
acpi_set_hp_context
(
struct
acpi_device
*
adev
,
struct
acpi_hotplug_context
*
hp
,
int
(
*
event
)(
struct
acpi_device
*
,
u32
))
{
hp
->
self
=
adev
;
hp
->
event
=
event
;
adev
->
hp
=
hp
;
}
/* acpi_device.dev.bus == &acpi_bus_type */
extern
struct
bus_type
acpi_bus_type
;
...
...
@@ -381,6 +402,8 @@ extern int unregister_acpi_notifier(struct notifier_block *);
*/
int
acpi_bus_get_device
(
acpi_handle
handle
,
struct
acpi_device
**
device
);
struct
acpi_device
*
acpi_bus_get_acpi_device
(
acpi_handle
handle
);
void
acpi_bus_put_acpi_device
(
struct
acpi_device
*
adev
);
acpi_status
acpi_bus_get_status_handle
(
acpi_handle
handle
,
unsigned
long
long
*
sta
);
int
acpi_bus_get_status
(
struct
acpi_device
*
device
);
...
...
@@ -402,6 +425,8 @@ static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
void
acpi_scan_lock_acquire
(
void
);
void
acpi_scan_lock_release
(
void
);
void
acpi_lock_hp_context
(
void
);
void
acpi_unlock_hp_context
(
void
);
int
acpi_scan_add_handler
(
struct
acpi_scan_handler
*
handler
);
int
acpi_bus_register_driver
(
struct
acpi_driver
*
driver
);
void
acpi_bus_unregister_driver
(
struct
acpi_driver
*
driver
);
...
...
include/acpi/acpixf.h
View file @
4b49b9fe
...
...
@@ -229,6 +229,10 @@ acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data);
acpi_status
acpi_detach_data
(
acpi_handle
object
,
acpi_object_handler
handler
);
acpi_status
acpi_get_data_full
(
acpi_handle
object
,
acpi_object_handler
handler
,
void
**
data
,
void
(
*
callback
)(
void
*
));
acpi_status
acpi_get_data
(
acpi_handle
object
,
acpi_object_handler
handler
,
void
**
data
);
...
...
include/linux/pci-acpi.h
View file @
4b49b9fe
...
...
@@ -59,12 +59,12 @@ static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
void
acpiphp_init
(
void
);
void
acpiphp_enumerate_slots
(
struct
pci_bus
*
bus
);
void
acpiphp_remove_slots
(
struct
pci_bus
*
bus
);
void
acpiphp_check_host_bridge
(
acpi_handle
handle
);
void
acpiphp_check_host_bridge
(
struct
acpi_device
*
adev
);
#else
static
inline
void
acpiphp_init
(
void
)
{
}
static
inline
void
acpiphp_enumerate_slots
(
struct
pci_bus
*
bus
)
{
}
static
inline
void
acpiphp_remove_slots
(
struct
pci_bus
*
bus
)
{
}
static
inline
void
acpiphp_check_host_bridge
(
acpi_handle
handle
)
{
}
static
inline
void
acpiphp_check_host_bridge
(
struct
acpi_device
*
adev
)
{
}
#endif
#else
/* CONFIG_ACPI */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment