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
4960aefd
Commit
4960aefd
authored
Mar 09, 2004
by
Linda Xie
Committed by
Greg Kroah-Hartman
Mar 09, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] PCI Hotplug: rpaphp/rpadlpar latest (support for vio and multifunction devices )
parent
3d3c5375
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1038 additions
and
761 deletions
+1038
-761
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/Makefile
+3
-1
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/hotplug/rpadlpar_core.c
+132
-54
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/rpaphp.h
+61
-29
drivers/pci/hotplug/rpaphp_core.c
drivers/pci/hotplug/rpaphp_core.c
+193
-660
drivers/pci/hotplug/rpaphp_pci.c
drivers/pci/hotplug/rpaphp_pci.c
+340
-17
drivers/pci/hotplug/rpaphp_slot.c
drivers/pci/hotplug/rpaphp_slot.c
+188
-0
drivers/pci/hotplug/rpaphp_vio.c
drivers/pci/hotplug/rpaphp_vio.c
+121
-0
No files found.
drivers/pci/hotplug/Makefile
View file @
4960aefd
...
@@ -40,7 +40,9 @@ acpiphp-objs := acpiphp_core.o \
...
@@ -40,7 +40,9 @@ acpiphp-objs := acpiphp_core.o \
acpiphp_res.o
acpiphp_res.o
rpaphp-objs
:=
rpaphp_core.o
\
rpaphp-objs
:=
rpaphp_core.o
\
rpaphp_pci.o
rpaphp_pci.o
\
rpaphp_slot.o
\
rpaphp_vio.o
rpadlpar_io-objs
:=
rpadlpar_core.o
\
rpadlpar_io-objs
:=
rpadlpar_core.o
\
rpadlpar_sysfs.o
rpadlpar_sysfs.o
...
...
drivers/pci/hotplug/rpadlpar_core.c
View file @
4960aefd
...
@@ -43,7 +43,28 @@ static char *get_node_drc_name(struct device_node *dn)
...
@@ -43,7 +43,28 @@ static char *get_node_drc_name(struct device_node *dn)
return
ptr
;
return
ptr
;
}
}
static
struct
device_node
*
find_php_slot_node
(
char
*
drc_name
)
static
struct
device_node
*
find_php_slot_vio_node
(
char
*
drc_name
)
{
struct
device_node
*
child
;
struct
device_node
*
parent
=
of_find_node_by_name
(
NULL
,
"vdevice"
);
if
(
!
parent
)
return
NULL
;
for
(
child
=
of_get_next_child
(
parent
,
NULL
);
child
;
child
=
of_get_next_child
(
parent
,
child
))
{
char
*
loc_code
;
loc_code
=
get_property
(
child
,
"ibm,loc-code"
,
NULL
);
if
(
loc_code
&&
!
strcmp
(
loc_code
,
drc_name
))
return
child
;
}
return
NULL
;
}
static
struct
device_node
*
find_php_slot_pci_node
(
char
*
drc_name
)
{
{
struct
device_node
*
np
=
NULL
;
struct
device_node
*
np
=
NULL
;
char
*
name
;
char
*
name
;
...
@@ -193,6 +214,20 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
...
@@ -193,6 +214,20 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
}
}
pci_remove_bus_device
(
bridge_dev
);
pci_remove_bus_device
(
bridge_dev
);
return
0
;
}
static
inline
int
dlpar_add_pci_slot
(
char
*
drc_name
,
struct
device_node
*
dn
)
{
struct
pci_dev
*
dev
;
/* Add pci bus */
dev
=
dlpar_pci_add_bus
(
dn
);
if
(
!
dev
)
{
printk
(
KERN_ERR
"%s: unable to add bus %s
\n
"
,
__FUNCTION__
,
drc_name
);
return
-
EIO
;
}
return
0
;
return
0
;
}
}
...
@@ -212,35 +247,31 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
...
@@ -212,35 +247,31 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
*/
*/
int
dlpar_add_slot
(
char
*
drc_name
)
int
dlpar_add_slot
(
char
*
drc_name
)
{
{
struct
device_node
*
dn
=
find_php_slot_node
(
drc_name
);
struct
device_node
*
dn
;
struct
pci_dev
*
dev
;
int
rc
=
0
;
int
rc
=
0
;
if
(
down_interruptible
(
&
rpadlpar_sem
))
if
(
down_interruptible
(
&
rpadlpar_sem
))
return
-
ERESTARTSYS
;
return
-
ERESTARTSYS
;
if
(
!
dn
)
{
rc
=
-
ENODEV
;
goto
exit
;
}
/* Check for existing hotplug slot */
/* Check for existing hotplug slot */
if
(
find_slot
(
drc_name
))
{
if
(
find_slot
(
drc_name
))
{
rc
=
-
EINVAL
;
rc
=
-
EINVAL
;
goto
exit
;
goto
exit
;
}
}
/* Add pci bus */
dn
=
find_php_slot_vio_node
(
drc_name
);
dev
=
dlpar_pci_add_bus
(
dn
);
if
(
!
dn
)
{
if
(
!
dev
)
{
dn
=
find_php_slot_pci_node
(
drc_name
);
printk
(
KERN_ERR
"%s: unable to add bus %s
\n
"
,
__FUNCTION__
,
if
(
dn
)
drc_name
);
rc
=
dlpar_add_pci_slot
(
drc_name
,
dn
);
rc
=
-
EIO
;
else
{
rc
=
-
ENODEV
;
goto
exit
;
goto
exit
;
}
}
}
/* Add hotplug slot for new
bus
*/
/* Add hotplug slot for new
VIOA or PCI
*/
if
(
rpaphp_add_slot
(
drc_name
))
{
if
(
!
rc
&&
rpaphp_add_slot
(
dn
))
{
printk
(
KERN_ERR
"%s: unable to add hotplug slot %s
\n
"
,
printk
(
KERN_ERR
"%s: unable to add hotplug slot %s
\n
"
,
__FUNCTION__
,
drc_name
);
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
rc
=
-
EIO
;
...
@@ -251,59 +282,106 @@ int dlpar_add_slot(char *drc_name)
...
@@ -251,59 +282,106 @@ int dlpar_add_slot(char *drc_name)
}
}
/**
/**
* dlpar_remove_
slot - DLPAR remove an
I/O Slot
* dlpar_remove_
vio_slot - DLPAR remove a virtual
I/O Slot
* @drc_name: drc-name of newly added slot
* @drc_name: drc-name of newly added slot
*
*
* Remove the kernel and hotplug representations
* Remove the kernel and hotplug representations
* of an I/O Slot.
* of an I/O Slot.
* Return Codes:
* Return Codes:
* 0 Success
* 0 Success
* -EIO Internal Error
*/
int
dlpar_remove_vio_slot
(
struct
slot
*
slot
,
char
*
drc_name
)
{
/* Remove hotplug slot */
if
(
rpaphp_remove_slot
(
slot
))
{
printk
(
KERN_ERR
"%s: unable to remove hotplug slot %s
\n
"
,
__FUNCTION__
,
drc_name
);
return
-
EIO
;
}
return
0
;
}
/**
* dlpar_remove_slot - DLPAR remove a PCI I/O Slot
* @drc_name: drc-name of newly added slot
*
* Remove the kernel and hotplug representations
* of a PCI I/O Slot.
* Return Codes:
* 0 Success
* -ENODEV Not a valid drc_name
* -ENODEV Not a valid drc_name
* -EINVAL Slot already removed
* -ERESTARTSYS Signalled before obtaining lock
* -EIO Internal PCI Error
* -EIO Internal PCI Error
*/
*/
int
dlpar_remove_
slot
(
char
*
drc_name
)
int
dlpar_remove_
pci_slot
(
struct
slot
*
slot
,
char
*
drc_name
)
{
{
struct
device_node
*
dn
=
find_php_slot_node
(
drc_name
);
struct
device_node
*
dn
=
find_php_slot_pci_node
(
drc_name
);
struct
slot
*
slot
;
struct
pci_dev
*
bridge_dev
;
struct
pci_dev
*
bridge_dev
;
int
rc
=
0
;
if
(
down_interruptible
(
&
rpadlpar_sem
))
return
-
ERESTARTSYS
;
if
(
!
dn
)
{
if
(
!
dn
)
rc
=
-
ENODEV
;
return
-
ENODEV
;
goto
exit
;
}
slot
=
find_slot
(
drc_name
);
if
(
!
slot
)
{
rc
=
-
EINVAL
;
goto
exit
;
}
bridge_dev
=
slot
->
bridge
;
bridge_dev
=
slot
->
bridge
;
if
(
!
bridge_dev
)
{
if
(
!
bridge_dev
)
{
printk
(
KERN_ERR
"%s: unexpected null bridge device
\n
"
,
printk
(
KERN_ERR
"%s: unexpected null bridge device
\n
"
,
__FUNCTION__
);
__FUNCTION__
);
rc
=
-
EIO
;
return
-
EIO
;
goto
exit
;
}
}
/* Remove hotplug slot */
/* Remove hotplug slot */
if
(
rpaphp_remove_slot
(
slot
))
{
if
(
rpaphp_remove_slot
(
slot
))
{
printk
(
KERN_ERR
"%s: unable to remove hotplug slot %s
\n
"
,
printk
(
KERN_ERR
"%s: unable to remove hotplug slot %s
\n
"
,
__FUNCTION__
,
drc_name
);
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
return
-
EIO
;
goto
exit
;
}
}
/* Remove pci bus */
/* Remove pci bus */
if
(
dlpar_pci_remove_bus
(
bridge_dev
))
{
if
(
dlpar_pci_remove_bus
(
bridge_dev
))
{
printk
(
KERN_ERR
"%s: unable to remove pci bus %s
\n
"
,
printk
(
KERN_ERR
"%s: unable to remove pci bus %s
\n
"
,
__FUNCTION__
,
drc_name
);
__FUNCTION__
,
drc_name
);
return
-
EIO
;
}
return
0
;
}
/**
* dlpar_remove_slot - DLPAR remove an I/O Slot
* @drc_name: drc-name of newly added slot
*
* Remove the kernel and hotplug representations
* of an I/O Slot.
* Return Codes:
* 0 Success
* -ENODEV Not a valid drc_name
* -EINVAL Slot already removed
* -ERESTARTSYS Signalled before obtaining lock
* -EIO Internal Error
*/
int
dlpar_remove_slot
(
char
*
drc_name
)
{
struct
slot
*
slot
;
int
rc
=
0
;
if
(
down_interruptible
(
&
rpadlpar_sem
))
return
-
ERESTARTSYS
;
slot
=
find_slot
(
drc_name
);
if
(
!
slot
)
{
rc
=
-
EINVAL
;
goto
exit
;
}
switch
(
slot
->
dev_type
)
{
case
PCI_DEV
:
rc
=
dlpar_remove_pci_slot
(
slot
,
drc_name
);
break
;
case
VIO_DEV
:
rc
=
dlpar_remove_vio_slot
(
slot
,
drc_name
);
break
;
default:
rc
=
-
EIO
;
rc
=
-
EIO
;
}
}
exit:
exit:
...
...
drivers/pci/hotplug/rpaphp.h
View file @
4960aefd
...
@@ -26,6 +26,8 @@
...
@@ -26,6 +26,8 @@
#ifndef _PPC64PHP_H
#ifndef _PPC64PHP_H
#define _PPC64PHP_H
#define _PPC64PHP_H
#include <linux/pci.h>
#include "pci_hotplug.h"
#include "pci_hotplug.h"
#define DR_INDICATOR 9002
#define DR_INDICATOR 9002
...
@@ -39,8 +41,6 @@
...
@@ -39,8 +41,6 @@
#define LED_ID 2
/* slow blinking */
#define LED_ID 2
/* slow blinking */
#define LED_ACTION 3
/* fast blinking */
#define LED_ACTION 3
/* fast blinking */
#define SLOT_NAME_SIZE 12
/* Error status from rtas_get-sensor */
/* Error status from rtas_get-sensor */
#define NEED_POWER -9000
/* slot must be power up and unisolated to get state */
#define NEED_POWER -9000
/* slot must be power up and unisolated to get state */
#define PWR_ONLY -9001
/* slot must be powerd up to get state, leave isolated */
#define PWR_ONLY -9001
/* slot must be powerd up to get state, leave isolated */
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
#define PRESENT 1
/* Card in slot */
#define PRESENT 1
/* Card in slot */
#define MY_NAME "rpaphp"
#define MY_NAME "rpaphp"
extern
int
debug
;
#define dbg(format, arg...) \
#define dbg(format, arg...) \
do { \
do { \
if (debug) \
if (debug) \
...
@@ -64,6 +64,10 @@
...
@@ -64,6 +64,10 @@
#define SLOT_MAGIC 0x67267322
#define SLOT_MAGIC 0x67267322
/* slot types */
#define VIO_DEV 1
#define PCI_DEV 2
/* slot states */
/* slot states */
#define NOT_VALID 3
#define NOT_VALID 3
...
@@ -81,21 +85,49 @@ struct slot {
...
@@ -81,21 +85,49 @@ struct slot {
u32
type
;
u32
type
;
u32
power_domain
;
u32
power_domain
;
char
*
name
;
char
*
name
;
struct
device_node
*
dn
;
/* slot's device_node in OFDT
*/
struct
device_node
*
dn
;
/* slot's device_node in OFDT
*/
/* dn has phb info */
/* dn has phb info */
struct
pci_dev
*
bridge
;
/* slot's pci_dev in pci_devices
*/
struct
pci_dev
*
bridge
;
/* slot's pci_dev in pci_devices
*/
union
{
struct
pci_dev
*
dev
;
/* pci_dev of device in this slot
*/
struct
pci_dev
*
pci_dev
;
/* pci_dev of device in this slot
*/
/* it will be used for unconfig */
/* it will be used for unconfig */
/* NULL if slot is empty */
/* NULL if slot is empty */
struct
vio_dev
*
vio_dev
;
/* vio_dev of the device in this slot */
}
dev
;
u8
dev_type
;
/* VIO or PCI */
struct
hotplug_slot
*
hotplug_slot
;
struct
hotplug_slot
*
hotplug_slot
;
struct
list_head
rpaphp_slot_list
;
struct
list_head
rpaphp_slot_list
;
};
};
extern
struct
hotplug_slot_ops
rpaphp_hotplug_slot_ops
;
extern
struct
list_head
rpaphp_slot_head
;
extern
int
num_slots
;
/* function prototypes */
/* rpaphp_pci.c */
extern
struct
pci_dev
*
rpaphp_find_pci_dev
(
struct
device_node
*
dn
);
extern
struct
pci_dev
*
rpaphp_find_pci_dev
(
struct
device_node
*
dn
);
extern
int
rpaphp_add_slot
(
char
*
slot_name
);
extern
int
rpaphp_remove_slot
(
struct
slot
*
slot
);
extern
int
rpaphp_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
);
extern
int
rpaphp_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
);
extern
int
rpaphp_enable_pci_slot
(
struct
slot
*
slot
);
extern
int
register_pci_slot
(
struct
slot
*
slot
);
extern
int
rpaphp_unconfig_pci_adapter
(
struct
slot
*
slot
);
extern
int
rpaphp_get_pci_adapter_status
(
struct
slot
*
slot
,
int
is_init
,
u8
*
value
);
/* rpaphp_core.c */
extern
int
rpaphp_add_slot
(
struct
device_node
*
dn
);
extern
int
rpaphp_remove_slot
(
struct
slot
*
slot
);
/* rpaphp_vio.c */
extern
int
rpaphp_get_vio_adapter_status
(
struct
slot
*
slot
,
int
is_init
,
u8
*
value
);
extern
int
rpaphp_unconfig_vio_adapter
(
struct
slot
*
slot
);
extern
int
register_vio_slot
(
struct
device_node
*
dn
);
extern
int
rpaphp_enable_vio_slot
(
struct
slot
*
slot
);
/* rpaphp_slot.c */
extern
void
dealloc_slot_struct
(
struct
slot
*
slot
);
extern
struct
slot
*
alloc_slot_struct
(
struct
device_node
*
dn
,
int
drc_index
,
char
*
drc_name
,
int
power_domain
);
extern
int
register_slot
(
struct
slot
*
slot
);
extern
int
rpaphp_get_power_status
(
struct
slot
*
slot
,
u8
*
value
);
extern
int
rpaphp_set_attention_status
(
struct
slot
*
slot
,
u8
status
);
#endif
/* _PPC64PHP_H */
#endif
/* _PPC64PHP_H */
drivers/pci/hotplug/rpaphp_core.c
View file @
4960aefd
...
@@ -33,16 +33,15 @@
...
@@ -33,16 +33,15 @@
#include <linux/init.h>
#include <linux/init.h>
#include <asm/rtas.h>
/* rtas_call */
#include <asm/rtas.h>
/* rtas_call */
#include <asm/pci-bridge.h>
/* for pci_controller */
#include <asm/pci-bridge.h>
/* for pci_controller */
#include "../pci.h"
/* for pci_add_new_bus*/
#include "../pci.h"
/* for pci_add_new_bus
*/
/* and pci_do_scan_bus*/
/* and pci_do_scan_bus
*/
#include "rpaphp.h"
#include "rpaphp.h"
#include "pci_hotplug.h"
#include "pci_hotplug.h"
int
debug
;
static
int
debug
;
static
struct
semaphore
rpaphp_sem
;
static
struct
semaphore
rpaphp_sem
;
static
LIST_HEAD
(
rpaphp_slot_head
);
LIST_HEAD
(
rpaphp_slot_head
);
static
int
num_slots
;
int
num_slots
;
#define DRIVER_VERSION "0.1"
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>"
#define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>"
...
@@ -59,13 +58,13 @@ module_param(debug, int, 0644);
...
@@ -59,13 +58,13 @@ module_param(debug, int, 0644);
static
int
enable_slot
(
struct
hotplug_slot
*
slot
);
static
int
enable_slot
(
struct
hotplug_slot
*
slot
);
static
int
disable_slot
(
struct
hotplug_slot
*
slot
);
static
int
disable_slot
(
struct
hotplug_slot
*
slot
);
static
int
set_attention_status
(
struct
hotplug_slot
*
slot
,
u8
value
);
static
int
set_attention_status
(
struct
hotplug_slot
*
slot
,
u8
value
);
static
int
get_power_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_power_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_attention_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_attention_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_adapter_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_adapter_status
(
struct
hotplug_slot
*
slot
,
u8
*
value
);
static
int
get_max_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
);
static
int
get_max_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
);
static
int
get_cur_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
);
static
int
get_cur_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
);
st
atic
st
ruct
hotplug_slot_ops
rpaphp_hotplug_slot_ops
=
{
struct
hotplug_slot_ops
rpaphp_hotplug_slot_ops
=
{
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
.
enable_slot
=
enable_slot
,
.
enable_slot
=
enable_slot
,
.
disable_slot
=
disable_slot
,
.
disable_slot
=
disable_slot
,
...
@@ -77,91 +76,17 @@ static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
...
@@ -77,91 +76,17 @@ static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.
get_cur_bus_speed
=
get_cur_bus_speed
,
.
get_cur_bus_speed
=
get_cur_bus_speed
,
};
};
static
in
t
rpaphp_get_sensor_state
(
int
index
,
int
*
state
)
static
in
line
struct
slot
*
get_slot
(
struct
hotplug_slot
*
hotplug_slot
,
const
char
*
function
)
{
{
int
rc
;
rc
=
rtas_get_sensor
(
DR_ENTITY_SENSE
,
index
,
state
);
if
(
rc
)
{
if
(
rc
==
NEED_POWER
||
rc
==
PWR_ONLY
)
{
dbg
(
"%s: slot must be power up to get sensor-state
\n
"
,
__FUNCTION__
);
}
else
if
(
rc
==
ERR_SENSE_USE
)
info
(
"%s: slot is unusable
\n
"
,
__FUNCTION__
);
else
err
(
"%s failed to get sensor state
\n
"
,
__FUNCTION__
);
}
return
rc
;
}
static
struct
pci_dev
*
rpaphp_find_bridge_pdev
(
struct
slot
*
slot
)
{
return
rpaphp_find_pci_dev
(
slot
->
dn
);
}
static
struct
pci_dev
*
rpaphp_find_adapter_pdev
(
struct
slot
*
slot
)
{
return
rpaphp_find_pci_dev
(
slot
->
dn
->
child
);
}
/* Inline functions to check the sanity of a pointer that is passed to us */
static
inline
int
slot_paranoia_check
(
struct
slot
*
slot
,
const
char
*
function
)
{
if
(
!
slot
)
{
dbg
(
"%s - slot == NULL
\n
"
,
function
);
return
-
1
;
}
if
(
!
slot
->
hotplug_slot
)
{
dbg
(
"%s - slot->hotplug_slot == NULL!
\n
"
,
function
);
return
-
1
;
}
return
0
;
}
static
inline
struct
slot
*
get_slot
(
struct
hotplug_slot
*
hotplug_slot
,
const
char
*
function
)
{
struct
slot
*
slot
;
if
(
!
hotplug_slot
)
{
if
(
!
hotplug_slot
)
{
dbg
(
"%s - hotplug_slot == NULL
\n
"
,
function
);
dbg
(
"%s - hotplug_slot == NULL
\n
"
,
function
);
return
NULL
;
return
NULL
;
}
}
return
(
struct
slot
*
)
hotplug_slot
->
private
;
slot
=
(
struct
slot
*
)
hotplug_slot
->
private
;
if
(
slot_paranoia_check
(
slot
,
function
))
return
NULL
;
return
slot
;
}
static
inline
int
rpaphp_set_attention_status
(
struct
slot
*
slot
,
u8
status
)
{
int
rc
;
/* status: LED_OFF or LED_ON */
rc
=
rtas_set_indicator
(
DR_INDICATOR
,
slot
->
index
,
status
);
if
(
rc
)
err
(
"slot(%s) set attention-status(%d) failed! rc=0x%x
\n
"
,
slot
->
name
,
status
,
rc
);
return
rc
;
}
static
int
rpaphp_get_power_status
(
struct
slot
*
slot
,
u8
*
value
)
{
int
rc
;
rc
=
rtas_get_power_level
(
slot
->
power_domain
,
(
int
*
)
value
);
if
(
rc
)
err
(
"failed to get power-level for slot(%s), rc=0x%x
\n
"
,
slot
->
name
,
rc
);
return
rc
;
}
}
static
int
rpaphp_get_attention_status
(
struct
slot
*
slot
)
static
int
rpaphp_get_attention_status
(
struct
slot
*
slot
)
{
{
return
slot
->
hotplug_slot
->
info
->
attention_status
;
return
slot
->
hotplug_slot
->
info
->
attention_status
;
}
}
...
@@ -172,7 +97,7 @@ static int rpaphp_get_attention_status(struct slot *slot)
...
@@ -172,7 +97,7 @@ static int rpaphp_get_attention_status(struct slot *slot)
* echo 2 > attention -- set LED ID(identify, light is blinking)
* echo 2 > attention -- set LED ID(identify, light is blinking)
*
*
*/
*/
static
int
set_attention_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
value
)
static
int
set_attention_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
value
)
{
{
int
retval
=
0
;
int
retval
=
0
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
@@ -186,21 +111,17 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
...
@@ -186,21 +111,17 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
retval
=
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
retval
=
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
hotplug_slot
->
info
->
attention_status
=
0
;
hotplug_slot
->
info
->
attention_status
=
0
;
break
;
break
;
case
1
:
case
1
:
default:
default:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ON
);
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ON
);
hotplug_slot
->
info
->
attention_status
=
1
;
hotplug_slot
->
info
->
attention_status
=
1
;
break
;
break
;
case
2
:
case
2
:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ID
);
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ID
);
hotplug_slot
->
info
->
attention_status
=
2
;
hotplug_slot
->
info
->
attention_status
=
2
;
break
;
break
;
}
}
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
return
retval
;
return
retval
;
}
}
...
@@ -211,7 +132,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
...
@@ -211,7 +132,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
*
*
*
*
*/
*/
static
int
get_power_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
static
int
get_power_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
{
{
int
retval
;
int
retval
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
@@ -222,7 +143,6 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
...
@@ -222,7 +143,6 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
down
(
&
rpaphp_sem
);
down
(
&
rpaphp_sem
);
retval
=
rpaphp_get_power_status
(
slot
,
value
);
retval
=
rpaphp_get_power_status
(
slot
,
value
);
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
return
retval
;
return
retval
;
}
}
...
@@ -231,7 +151,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
...
@@ -231,7 +151,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
*
*
*
*
*/
*/
static
int
get_attention_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
static
int
get_attention_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
{
{
int
retval
=
0
;
int
retval
=
0
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
@@ -239,81 +159,36 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
...
@@ -239,81 +159,36 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
if
(
slot
==
NULL
)
if
(
slot
==
NULL
)
return
-
ENODEV
;
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
down
(
&
rpaphp_sem
);
*
value
=
rpaphp_get_attention_status
(
slot
);
*
value
=
rpaphp_get_attention_status
(
slot
);
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
return
retval
;
return
retval
;
}
}
/*
static
int
get_adapter_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
* get_adapter_status - get the status of a slot
*
* 0-- slot is empty
* 1-- adapter is configured
* 2-- adapter is not configured
* 3-- not valid
*/
static
int
rpaphp_get_adapter_status
(
struct
slot
*
slot
,
int
is_init
,
u8
*
value
)
{
int
state
,
rc
;
*
value
=
NOT_VALID
;
rc
=
rpaphp_get_sensor_state
(
slot
->
index
,
&
state
);
if
(
rc
)
return
rc
;
if
(
state
==
PRESENT
)
{
dbg
(
"slot is occupied
\n
"
);
if
(
!
is_init
)
/* at run-time slot->state can be changed by */
/* config/unconfig adapter */
*
value
=
slot
->
state
;
else
{
if
(
!
slot
->
dn
->
child
)
dbg
(
"%s: %s is not valid OFDT node
\n
"
,
__FUNCTION__
,
slot
->
dn
->
full_name
);
else
if
(
rpaphp_find_pci_dev
(
slot
->
dn
->
child
))
*
value
=
CONFIGURED
;
else
{
dbg
(
"%s: can't find pdev of adapter in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
*
value
=
NOT_CONFIGURED
;
}
}
}
else
if
(
state
==
EMPTY
)
{
dbg
(
"slot is empty
\n
"
);
*
value
=
state
;
}
return
0
;
}
static
int
get_adapter_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
{
{
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
int
retval
=
0
;
int
retval
=
0
;
if
(
slot
==
NULL
)
if
(
slot
==
NULL
)
return
-
ENODEV
;
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
down
(
&
rpaphp_sem
);
/* have to go through this */
/* have to go through this */
retval
=
rpaphp_get_adapter_status
(
slot
,
0
,
value
);
switch
(
slot
->
dev_type
)
{
case
PCI_DEV
:
retval
=
rpaphp_get_pci_adapter_status
(
slot
,
0
,
value
);
break
;
case
VIO_DEV
:
retval
=
rpaphp_get_vio_adapter_status
(
slot
,
0
,
value
);
break
;
default:
retval
=
-
EINVAL
;
}
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
return
retval
;
return
retval
;
}
}
static
int
get_max_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
)
static
int
get_max_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
)
{
{
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
@@ -321,7 +196,6 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
...
@@ -321,7 +196,6 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
return
-
ENODEV
;
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
down
(
&
rpaphp_sem
);
switch
(
slot
->
type
)
{
switch
(
slot
->
type
)
{
case
1
:
case
1
:
case
2
:
case
2
:
...
@@ -352,15 +226,12 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
...
@@ -352,15 +226,12 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
break
;
break
;
}
}
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
return
0
;
return
0
;
}
}
/* return dummy value because not sure if PRA provides any method... */
/* return dummy value because not sure if PRA provides any method... */
static
int
get_cur_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
)
static
int
get_cur_bus_speed
(
struct
hotplug_slot
*
hotplug_slot
,
enum
pci_bus_speed
*
value
)
{
{
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
@@ -368,414 +239,104 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
...
@@ -368,414 +239,104 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
return
-
ENODEV
;
return
-
ENODEV
;
*
value
=
PCI_SPEED_UNKNOWN
;
*
value
=
PCI_SPEED_UNKNOWN
;
return
0
;
}
/*
* rpaphp_validate_slot - make sure the name of the slot matches
* the location code , if the slots is not
* empty.
*/
static
int
rpaphp_validate_slot
(
const
char
*
slot_name
,
const
int
slot_index
)
{
struct
device_node
*
dn
;
for
(
dn
=
find_all_nodes
();
dn
;
dn
=
dn
->
next
)
{
int
*
index
;
unsigned
char
*
loc_code
;
index
=
(
int
*
)
get_property
(
dn
,
"ibm,my-drc-index"
,
NULL
);
if
(
index
&&
*
index
==
slot_index
)
{
char
*
slash
,
*
tmp_str
;
loc_code
=
get_property
(
dn
,
"ibm,loc-code"
,
NULL
);
if
(
!
loc_code
)
{
return
-
1
;
}
tmp_str
=
kmalloc
(
MAX_LOC_CODE
,
GFP_KERNEL
);
if
(
!
tmp_str
)
{
err
(
"%s: out of memory
\n
"
,
__FUNCTION__
);
return
-
1
;
}
strcpy
(
tmp_str
,
loc_code
);
slash
=
strrchr
(
tmp_str
,
'/'
);
if
(
slash
)
*
slash
=
'\0'
;
if
(
strcmp
(
slot_name
,
tmp_str
))
{
kfree
(
tmp_str
);
return
-
1
;
}
kfree
(
tmp_str
);
break
;
}
}
return
0
;
}
/* Must be called before pci_bus_add_devices */
static
void
rpaphp_fixup_new_devices
(
struct
pci_bus
*
bus
)
{
struct
pci_dev
*
dev
;
list_for_each_entry
(
dev
,
&
bus
->
devices
,
bus_list
)
{
/*
* Skip already-present devices (which are on the
* global device list.)
*/
if
(
list_empty
(
&
dev
->
global_list
))
{
int
i
;
pcibios_fixup_device_resources
(
dev
,
bus
);
pci_read_irq_line
(
dev
);
for
(
i
=
0
;
i
<
PCI_NUM_RESOURCES
;
i
++
)
{
struct
resource
*
r
=
&
dev
->
resource
[
i
];
if
(
r
->
parent
||
!
r
->
start
||
!
r
->
flags
)
continue
;
rpaphp_claim_resource
(
dev
,
i
);
}
}
}
}
static
struct
pci_dev
*
rpaphp_config_adapter
(
struct
slot
*
slot
)
{
struct
pci_bus
*
pci_bus
;
struct
device_node
*
dn
;
int
num
;
struct
pci_dev
*
dev
=
NULL
;
if
(
slot
->
bridge
)
{
pci_bus
=
slot
->
bridge
->
subordinate
;
if
(
!
pci_bus
)
{
err
(
"%s: can't find bus structure
\n
"
,
__FUNCTION__
);
goto
exit
;
}
for
(
dn
=
slot
->
dn
->
child
;
dn
;
dn
=
dn
->
sibling
)
{
dbg
(
"child dn's devfn=[%x]
\n
"
,
dn
->
devfn
);
num
=
pci_scan_slot
(
pci_bus
,
PCI_DEVFN
(
PCI_SLOT
(
dn
->
devfn
),
0
));
dbg
(
"pci_scan_slot return num=%d
\n
"
,
num
);
if
(
num
)
{
rpaphp_fixup_new_devices
(
pci_bus
);
pci_bus_add_devices
(
pci_bus
);
}
}
dev
=
rpaphp_find_pci_dev
(
slot
->
dn
->
child
);
}
else
{
/* slot is not enabled */
err
(
"slot doesn't have pci_dev structure
\n
"
);
dev
=
NULL
;
goto
exit
;
}
exit:
dbg
(
"Exit %s: pci_dev %s
\n
"
,
__FUNCTION__
,
dev
?
"found"
:
"not found"
);
return
dev
;
}
static
int
rpaphp_unconfig_adapter
(
struct
slot
*
slot
)
{
if
(
!
slot
->
dev
)
{
info
(
"%s: no card in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
return
-
EINVAL
;
}
/* remove the device from the pci core */
pci_remove_bus_device
(
slot
->
dev
);
pci_dev_put
(
slot
->
dev
);
slot
->
state
=
NOT_CONFIGURED
;
dbg
(
"%s: adapter in slot[%s] unconfigured.
\n
"
,
__FUNCTION__
,
slot
->
name
);
return
0
;
return
0
;
}
}
/* free up the memory user be a slot */
static
void
rpaphp_release_slot
(
struct
hotplug_slot
*
hotplug_slot
)
{
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
if
(
slot
==
NULL
)
return
;
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
->
name
);
kfree
(
slot
->
hotplug_slot
);
pci_dev_put
(
slot
->
bridge
);
pci_dev_put
(
slot
->
dev
);
kfree
(
slot
);
}
int
rpaphp_remove_slot
(
struct
slot
*
slot
)
int
rpaphp_remove_slot
(
struct
slot
*
slot
)
{
{
int
retval
=
0
;
int
retval
=
0
;
char
*
rm_link
;
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
dbg
(
"%s - Entry: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
bridge
->
slot_name
);
if
(
slot
->
dev_type
==
PCI_DEV
)
rm_link
=
pci_name
(
slot
->
bridge
);
else
rm_link
=
strstr
(
slot
->
dn
->
full_name
,
"@"
);
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
rm_link
);
list_del
(
&
slot
->
rpaphp_slot_list
);
list_del
(
&
slot
->
rpaphp_slot_list
);
retval
=
pci_hp_deregister
(
slot
->
hotplug_slot
);
retval
=
pci_hp_deregister
(
slot
->
hotplug_slot
);
if
(
retval
)
if
(
retval
)
err
(
"Problem unregistering a slot %s
\n
"
,
slot
->
name
);
err
(
"Problem unregistering a slot %s
\n
"
,
slot
->
name
);
num_slots
--
;
num_slots
--
;
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
return
retval
;
}
}
static
int
is_php_dn
(
struct
device_node
*
dn
,
int
**
indexes
,
int
**
names
,
int
**
types
,
int
**
power_domains
)
static
int
is_php_dn
(
struct
device_node
*
dn
,
int
**
indexes
,
int
**
names
,
int
**
types
,
int
**
power_domains
)
{
{
*
indexes
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-indexes"
,
NULL
);
*
indexes
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-indexes"
,
NULL
);
if
(
!*
indexes
)
if
(
!*
indexes
)
return
(
0
);
return
(
0
);
/* &names[1] contains NULL terminated slot names */
/* &names[1] contains NULL terminated slot names */
*
names
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-names"
,
NULL
);
*
names
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-names"
,
NULL
);
if
(
!*
names
)
if
(
!*
names
)
return
(
0
);
return
(
0
);
/* &types[1] contains NULL terminated slot types */
/* &types[1] contains NULL terminated slot types */
*
types
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-types"
,
NULL
);
*
types
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-types"
,
NULL
);
if
(
!*
types
)
if
(
!*
types
)
return
(
0
);
return
(
0
);
/* power_domains[1...n] are the slot power domains */
/* power_domains[1...n] are the slot power domains */
*
power_domains
=
(
int
*
)
get_property
(
dn
,
*
power_domains
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-power-domains"
,
NULL
);
"ibm,drc-power-domains"
,
NULL
);
if
(
!*
power_domains
)
if
(
!*
power_domains
)
return
(
0
);
if
(
!
get_property
(
dn
,
"ibm,fw-pci-hot-plug-ctrl"
,
NULL
))
return
(
0
);
return
(
1
);
}
static
struct
slot
*
alloc_slot_struct
(
void
)
{
struct
slot
*
slot
;
slot
=
kmalloc
(
sizeof
(
struct
slot
),
GFP_KERNEL
);
if
(
!
slot
)
return
(
NULL
);
memset
(
slot
,
0
,
sizeof
(
struct
slot
));
slot
->
hotplug_slot
=
kmalloc
(
sizeof
(
struct
hotplug_slot
),
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
)
{
kfree
(
slot
);
return
(
NULL
);
}
memset
(
slot
->
hotplug_slot
,
0
,
sizeof
(
struct
hotplug_slot
));
slot
->
hotplug_slot
->
info
=
kmalloc
(
sizeof
(
struct
hotplug_slot_info
),
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
->
info
)
{
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
(
NULL
);
}
memset
(
slot
->
hotplug_slot
->
info
,
0
,
sizeof
(
struct
hotplug_slot_info
));
slot
->
hotplug_slot
->
name
=
kmalloc
(
SLOT_NAME_SIZE
,
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
->
name
)
{
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
(
NULL
);
}
return
(
slot
);
}
static
int
setup_hotplug_slot_info
(
struct
slot
*
slot
)
{
rpaphp_get_power_status
(
slot
,
&
slot
->
hotplug_slot
->
info
->
power_status
);
rpaphp_get_adapter_status
(
slot
,
1
,
&
slot
->
hotplug_slot
->
info
->
adapter_status
);
if
(
slot
->
hotplug_slot
->
info
->
adapter_status
==
NOT_VALID
)
{
dbg
(
"%s: NOT_VALID: skip dn->full_name=%s
\n
"
,
__FUNCTION__
,
slot
->
dn
->
full_name
);
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
->
name
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
(
-
1
);
}
return
(
0
);
return
(
0
);
if
(
strcmp
(
dn
->
name
,
"pci"
)
==
0
&&
!
get_property
(
dn
,
"ibm,fw-pci-hot-plug-ctrl"
,
NULL
))
return
(
0
);
return
(
1
);
}
}
static
in
t
register_slot
(
struct
slot
*
slot
)
static
in
line
int
is_vdevice_root
(
struct
device_node
*
dn
)
{
{
int
retval
;
return
!
strcmp
(
dn
->
name
,
"vdevice"
);
retval
=
pci_hp_register
(
slot
->
hotplug_slot
);
if
(
retval
)
{
err
(
"pci_hp_register failed with error %d
\n
"
,
retval
);
rpaphp_release_slot
(
slot
->
hotplug_slot
);
return
(
retval
);
}
/* create symlink between slot->name and it's bus_id */
dbg
(
"%s: sysfs_create_link: %s --> %s
\n
"
,
__FUNCTION__
,
slot
->
bridge
->
slot_name
,
slot
->
name
);
retval
=
sysfs_create_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
&
slot
->
hotplug_slot
->
kobj
,
slot
->
bridge
->
slot_name
);
if
(
retval
)
{
err
(
"sysfs_create_link failed with error %d
\n
"
,
retval
);
rpaphp_release_slot
(
slot
->
hotplug_slot
);
return
(
retval
);
}
/* add slot to our internal list */
dbg
(
"%s adding slot[%s] to rpaphp_slot_list
\n
"
,
__FUNCTION__
,
slot
->
name
);
list_add
(
&
slot
->
rpaphp_slot_list
,
&
rpaphp_slot_head
);
info
(
"Slot [%s] (bus_id=%s) registered
\n
"
,
slot
->
name
,
slot
->
bridge
->
slot_name
);
return
(
0
);
}
}
/*************************************
/*************************************
* Add Hot Plug slot(s) to sysfs
* Add Hot Plug slot(s) to sysfs
*
*
************************************/
************************************/
int
rpaphp_add_slot
(
char
*
slot_name
)
int
rpaphp_add_slot
(
struct
device_node
*
dn
)
{
{
struct
slot
*
slot
;
struct
slot
*
slot
;
int
retval
=
0
;
int
retval
=
0
;
int
i
;
int
i
;
struct
device_node
*
dn
;
int
*
indexes
,
*
names
,
*
types
,
*
power_domains
;
int
*
indexes
,
*
names
,
*
types
,
*
power_domains
;
char
*
name
,
*
type
;
char
*
name
,
*
type
;
for
(
dn
=
find_all_nodes
();
dn
;
dn
=
dn
->
next
)
{
dbg
(
"Entry %s: dn->full_name=%s
\n
"
,
__FUNCTION__
,
dn
->
full_name
);
if
(
dn
->
name
!=
0
&&
strcmp
(
dn
->
name
,
"pci"
)
==
0
)
{
if
(
!
is_php_dn
(
dn
,
&
indexes
,
&
names
,
&
types
,
&
power_domains
))
continue
;
dbg
(
"%s : found device_node in OFDT full_name=%s, name=%s
\n
"
,
if
(
dn
->
parent
&&
is_vdevice_root
(
dn
->
parent
))
{
__FUNCTION__
,
dn
->
full_name
,
dn
->
name
);
/* register a VIO device */
retval
=
register_vio_slot
(
dn
);
goto
exit
;
}
name
=
(
char
*
)
&
names
[
1
];
/* register PCI devices */
type
=
(
char
*
)
&
types
[
1
];
if
(
dn
->
name
!=
0
&&
strcmp
(
dn
->
name
,
"pci"
)
==
0
&&
is_php_dn
(
dn
,
&
indexes
,
&
names
,
&
types
,
&
power_domains
))
{
name
=
(
char
*
)
&
names
[
1
];
type
=
(
char
*
)
&
types
[
1
];
for
(
i
=
0
;
i
<
indexes
[
0
];
for
(
i
=
0
;
i
<
indexes
[
0
];
i
++
,
i
++
,
name
+=
(
strlen
(
name
)
+
1
),
name
+=
(
strlen
(
name
)
+
1
),
type
+=
(
strlen
(
type
)
+
1
))
{
type
+=
(
strlen
(
type
)
+
1
))
{
if
(
!
(
slot
=
alloc_slot_struct
(
dn
,
indexes
[
i
+
1
],
name
,
power_domains
[
i
+
1
])))
{
dbg
(
"%s: name[%s] index[%x]
\n
"
,
__FUNCTION__
,
name
,
indexes
[
i
+
1
]);
if
(
slot_name
&&
strcmp
(
slot_name
,
name
))
continue
;
if
(
rpaphp_validate_slot
(
name
,
indexes
[
i
+
1
]))
{
dbg
(
"%s: slot(%s, 0x%x) is invalid.
\n
"
,
__FUNCTION__
,
name
,
indexes
[
i
+
1
]);
continue
;
}
slot
=
alloc_slot_struct
();
if
(
!
slot
)
{
retval
=
-
ENOMEM
;
retval
=
-
ENOMEM
;
goto
exit
;
goto
exit
;
}
}
slot
->
name
=
slot
->
hotplug_slot
->
name
;
slot
->
index
=
indexes
[
i
+
1
];
strcpy
(
slot
->
name
,
name
);
slot
->
type
=
simple_strtoul
(
type
,
NULL
,
10
);
slot
->
type
=
simple_strtoul
(
type
,
NULL
,
10
);
if
(
slot
->
type
<
1
||
slot
->
type
>
16
)
if
(
slot
->
type
<
1
||
slot
->
type
>
16
)
slot
->
type
=
0
;
slot
->
type
=
0
;
retval
=
register_pci_slot
(
slot
);
slot
->
power_domain
=
power_domains
[
i
+
1
];
}
/* for indexes */
slot
->
magic
=
SLOT_MAGIC
;
}
/* end of PCI device_node */
slot
->
hotplug_slot
->
private
=
slot
;
exit:
slot
->
hotplug_slot
->
ops
=
&
rpaphp_hotplug_slot_ops
;
slot
->
hotplug_slot
->
release
=
&
rpaphp_release_slot
;
slot
->
dn
=
dn
;
/*
* Initilize the slot info structure with some known
* good values.
*/
if
(
setup_hotplug_slot_info
(
slot
))
continue
;
slot
->
bridge
=
rpaphp_find_bridge_pdev
(
slot
);
if
(
!
slot
->
bridge
&&
slot_name
)
{
/* slot being added doesn't have pci_dev yet*/
dbg
(
"%s: no pci_dev for bridge dn %s
\n
"
,
__FUNCTION__
,
slot_name
);
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
->
name
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
continue
;
}
/* find slot's pci_dev if it's not empty*/
if
(
slot
->
hotplug_slot
->
info
->
adapter_status
==
EMPTY
)
{
slot
->
state
=
EMPTY
;
/* slot is empty */
slot
->
dev
=
NULL
;
}
else
{
/* slot is occupied */
if
(
!
(
slot
->
dn
->
child
))
{
/* non-empty slot has to have child */
err
(
"%s: slot[%s]'s device_node doesn't have child for adapter
\n
"
,
__FUNCTION__
,
slot
->
name
);
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
->
name
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
continue
;
}
slot
->
dev
=
rpaphp_find_adapter_pdev
(
slot
);
if
(
slot
->
dev
)
{
slot
->
state
=
CONFIGURED
;
pci_dev_get
(
slot
->
dev
);
}
else
{
/* DLPAR add as opposed to
* boot time */
slot
->
state
=
NOT_CONFIGURED
;
}
}
dbg
(
"%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]
\n
"
,
__FUNCTION__
,
dn
->
full_name
,
slot
->
index
,
slot
->
name
,
slot
->
power_domain
,
slot
->
type
);
retval
=
register_slot
(
slot
);
if
(
retval
)
goto
exit
;
num_slots
++
;
if
(
slot_name
)
goto
exit
;
}
/* for indexes */
}
/* "pci" */
}
/* find_all_nodes */
exit:
dbg
(
"%s - Exit: num_slots=%d rc[%d]
\n
"
,
dbg
(
"%s - Exit: num_slots=%d rc[%d]
\n
"
,
__FUNCTION__
,
num_slots
,
retval
);
__FUNCTION__
,
num_slots
,
retval
);
return
retval
;
return
retval
;
...
@@ -785,31 +346,28 @@ int rpaphp_add_slot(char *slot_name)
...
@@ -785,31 +346,28 @@ int rpaphp_add_slot(char *slot_name)
* init_slots - initialize 'struct slot' structures for each slot
* init_slots - initialize 'struct slot' structures for each slot
*
*
*/
*/
static
int
init_slots
(
void
)
static
void
init_slots
(
void
)
{
{
int
retval
=
0
;
struct
device_node
*
dn
;
retval
=
rpaphp_add_slot
(
NULL
);
return
retval
;
for
(
dn
=
find_all_nodes
();
dn
;
dn
=
dn
->
next
)
rpaphp_add_slot
(
dn
);
}
}
static
int
init_rpa
(
void
)
static
int
init_rpa
(
void
)
{
{
int
retval
=
0
;
init_MUTEX
(
&
rpaphp_sem
);
init_MUTEX
(
&
rpaphp_sem
);
/* initialize internal data structure etc. */
/* initialize internal data structure etc. */
retval
=
init_slots
();
init_slots
();
if
(
!
num_slots
)
if
(
!
num_slots
)
ret
val
=
-
ENODEV
;
ret
urn
-
ENODEV
;
return
retval
;
return
0
;
}
}
static
void
cleanup_slots
(
void
)
static
void
cleanup_slots
(
void
)
{
{
struct
list_head
*
tmp
,
*
n
;
struct
list_head
*
tmp
,
*
n
;
struct
slot
*
slot
;
struct
slot
*
slot
;
...
@@ -820,99 +378,62 @@ static void cleanup_slots (void)
...
@@ -820,99 +378,62 @@ static void cleanup_slots (void)
* memory will be freed in release_slot callback.
* memory will be freed in release_slot callback.
*/
*/
list_for_each_safe
(
tmp
,
n
,
&
rpaphp_slot_head
)
{
list_for_each_safe
(
tmp
,
n
,
&
rpaphp_slot_head
)
{
char
*
rm_link
;
slot
=
list_entry
(
tmp
,
struct
slot
,
rpaphp_slot_list
);
slot
=
list_entry
(
tmp
,
struct
slot
,
rpaphp_slot_list
);
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
if
(
slot
->
dev_type
==
PCI_DEV
)
slot
->
bridge
->
slot_name
);
rm_link
=
pci_name
(
slot
->
bridge
);
else
rm_link
=
strstr
(
slot
->
dn
->
full_name
,
"@"
);
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
rm_link
);
list_del
(
&
slot
->
rpaphp_slot_list
);
list_del
(
&
slot
->
rpaphp_slot_list
);
pci_hp_deregister
(
slot
->
hotplug_slot
);
pci_hp_deregister
(
slot
->
hotplug_slot
);
}
}
return
;
return
;
}
}
static
int
__init
rpaphp_init
(
void
)
static
int
__init
rpaphp_init
(
void
)
{
{
int
retval
=
0
;
info
(
DRIVER_DESC
" version: "
DRIVER_VERSION
"
\n
"
);
info
(
DRIVER_DESC
" version: "
DRIVER_VERSION
"
\n
"
);
/* read all the PRA info from the system */
/* read all the PRA info from the system */
retval
=
init_rpa
();
return
init_rpa
();
return
retval
;
}
}
static
void
__exit
rpaphp_exit
(
void
)
static
void
__exit
rpaphp_exit
(
void
)
{
{
cleanup_slots
();
cleanup_slots
();
}
}
static
int
enable_slot
(
struct
hotplug_slot
*
hotplug_slot
)
static
int
enable_slot
(
struct
hotplug_slot
*
hotplug_slot
)
{
{
int
retval
=
0
,
state
;
int
retval
=
0
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
if
(
slot
==
NULL
)
if
(
slot
==
NULL
)
return
-
ENODEV
;
return
-
ENODEV
;
if
(
slot
->
state
==
CONFIGURED
)
{
if
(
slot
->
state
==
CONFIGURED
)
{
dbg
(
"%s: %s is already enabled
\n
"
,
dbg
(
"%s: %s is already enabled
\n
"
,
__FUNCTION__
,
slot
->
name
);
__FUNCTION__
,
slot
->
name
);
goto
exit
;
goto
exit
;
}
}
dbg
(
"ENABLING SLOT %s
\n
"
,
slot
->
name
);
dbg
(
"ENABLING SLOT %s
\n
"
,
slot
->
name
);
down
(
&
rpaphp_sem
);
down
(
&
rpaphp_sem
);
switch
(
slot
->
dev_type
)
{
retval
=
rpaphp_get_sensor_state
(
slot
->
index
,
&
state
);
case
PCI_DEV
:
retval
=
rpaphp_enable_pci_slot
(
slot
);
if
(
retval
)
break
;
goto
exit
;
case
VIO_DEV
:
retval
=
rpaphp_enable_vio_slot
(
slot
);
dbg
(
"%s: sensor state[%d]
\n
"
,
__FUNCTION__
,
state
);
break
;
default:
/* if slot is not empty, enable the adapter */
if
(
state
==
PRESENT
)
{
dbg
(
"%s : slot[%s] is occupid.
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
dev
=
rpaphp_config_adapter
(
slot
);
if
(
slot
->
dev
!=
NULL
)
{
slot
->
state
=
CONFIGURED
;
dbg
(
"%s: adapter %s in slot[%s] has been configured
\n
"
,
__FUNCTION__
,
slot
->
dev
->
slot_name
,
slot
->
name
);
}
else
{
slot
->
state
=
NOT_CONFIGURED
;
dbg
(
"%s: no pci_dev struct for adapter in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
}
}
else
if
(
state
==
EMPTY
)
{
dbg
(
"%s : slot[%s] is empty
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
state
=
EMPTY
;
}
else
{
err
(
"%s: slot[%s] is in invalid state
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
state
=
NOT_VALID
;
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
}
}
exit:
if
(
slot
->
state
!=
NOT_VALID
)
rpaphp_set_attention_status
(
slot
,
LED_ON
);
else
rpaphp_set_attention_status
(
slot
,
LED_ID
);
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
exit:
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
return
retval
;
}
}
...
@@ -924,18 +445,30 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
...
@@ -924,18 +445,30 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
if
(
slot
==
NULL
)
if
(
slot
==
NULL
)
return
-
ENODEV
;
return
-
ENODEV
;
dbg
(
"
DISABLING SLOT %s
\n
"
,
slot
->
name
);
dbg
(
"
%s - Entry: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
down
(
&
rpaphp_sem
);
if
(
slot
->
state
==
NOT_CONFIGURED
)
{
dbg
(
"%s: %s is already disabled
\n
"
,
__FUNCTION__
,
slot
->
name
);
goto
exit
;
}
dbg
(
"DISABLING SLOT %s
\n
"
,
slot
->
name
);
down
(
&
rpaphp_sem
);
switch
(
slot
->
dev_type
)
{
case
PCI_DEV
:
rpaphp_set_attention_status
(
slot
,
LED_ID
);
rpaphp_set_attention_status
(
slot
,
LED_ID
);
retval
=
rpaphp_unconfig_pci_adapter
(
slot
);
retval
=
rpaphp_unconfig_adapter
(
slot
);
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
break
;
case
VIO_DEV
:
retval
=
rpaphp_unconfig_vio_adapter
(
slot
);
break
;
default:
retval
=
-
ENODEV
;
}
up
(
&
rpaphp_sem
);
up
(
&
rpaphp_sem
);
exit:
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
return
retval
;
}
}
...
...
drivers/pci/hotplug/rpaphp_pci.c
View file @
4960aefd
...
@@ -23,32 +23,35 @@
...
@@ -23,32 +23,35 @@
*
*
*/
*/
#include <linux/pci.h>
#include <linux/pci.h>
#include <asm/pci-bridge.h>
/* for pci_controller */
#include <asm/pci-bridge.h>
#include "
rpaphp.h"
#include "
../pci.h"
/* for pci_add_new_bus */
#include "rpaphp.h"
struct
pci_dev
*
rpaphp_find_pci_dev
(
struct
device_node
*
dn
)
struct
pci_dev
*
rpaphp_find_pci_dev
(
struct
device_node
*
dn
)
{
{
struct
pci_dev
*
retval_dev
=
NULL
,
*
dev
=
NULL
;
struct
pci_dev
*
retval_dev
=
NULL
,
*
dev
=
NULL
;
char
bus_id
[
BUS_ID_SIZE
];
while
((
dev
=
pci_get_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
dev
))
!=
NULL
)
{
sprintf
(
bus_id
,
"%04x:%02x:%02x.%d"
,
dn
->
phb
->
global_number
,
if
(
!
dev
->
bus
)
dn
->
busno
,
PCI_SLOT
(
dn
->
devfn
),
PCI_FUNC
(
dn
->
devfn
));
continue
;
if
(
dev
->
devfn
!=
dn
->
devfn
)
dbg
(
"Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s
\n
"
,
continue
;
dn
->
full_name
,
bus_id
)
;
if
(
dn
->
phb
->
global_number
==
pci_domain_nr
(
dev
->
bus
)
&&
while
((
dev
=
pci_find_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
dev
))
!=
NULL
)
{
dn
->
busno
==
dev
->
bus
->
number
)
{
if
(
!
strcmp
(
pci_name
(
dev
),
bus_id
)
)
{
retval_dev
=
dev
;
retval_dev
=
dev
;
dbg
(
"rpaphp_find_pci_dev(): found dev=%p
\n\n
"
,
dev
);
break
;
break
;
}
}
}
}
return
retval_dev
;
return
retval_dev
;
}
}
EXPORT_SYMBOL_GPL
(
rpaphp_find_pci_dev
);
int
rpaphp_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
)
int
rpaphp_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
)
{
{
struct
resource
*
res
=
&
dev
->
resource
[
resource
];
struct
resource
*
res
=
&
dev
->
resource
[
resource
];
...
@@ -67,9 +70,329 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource)
...
@@ -67,9 +70,329 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource)
"No parent found for"
,
"No parent found for"
,
resource
,
dtype
,
pci_name
(
dev
),
res
->
start
,
res
->
end
);
resource
,
dtype
,
pci_name
(
dev
),
res
->
start
,
res
->
end
);
}
}
return
err
;
return
err
;
}
}
EXPORT_SYMBOL_GPL
(
rpaphp_find_pci_dev
);
EXPORT_SYMBOL_GPL
(
rpaphp_claim_resource
);
EXPORT_SYMBOL_GPL
(
rpaphp_claim_resource
);
static
struct
pci_dev
*
rpaphp_find_bridge_pdev
(
struct
slot
*
slot
)
{
return
rpaphp_find_pci_dev
(
slot
->
dn
);
}
static
struct
pci_dev
*
rpaphp_find_adapter_pdev
(
struct
slot
*
slot
)
{
return
rpaphp_find_pci_dev
(
slot
->
dn
->
child
);
}
static
int
rpaphp_get_sensor_state
(
struct
slot
*
slot
,
int
*
state
)
{
int
rc
;
int
setlevel
;
rc
=
rtas_get_sensor
(
DR_ENTITY_SENSE
,
slot
->
index
,
state
);
if
(
rc
)
{
if
(
rc
==
NEED_POWER
||
rc
==
PWR_ONLY
)
{
dbg
(
"%s: slot must be power up to get sensor-state
\n
"
,
__FUNCTION__
);
/* some slots have to be powered up
* before get-sensor will succeed.
*/
rc
=
rtas_set_power_level
(
slot
->
power_domain
,
POWER_ON
,
&
setlevel
);
if
(
rc
)
{
dbg
(
"%s: power on slot[%s] failed rc=%d.
\n
"
,
__FUNCTION__
,
slot
->
name
,
rc
);
}
else
{
rc
=
rtas_get_sensor
(
DR_ENTITY_SENSE
,
slot
->
index
,
state
);
}
}
else
if
(
rc
==
ERR_SENSE_USE
)
info
(
"%s: slot is unusable
\n
"
,
__FUNCTION__
);
else
err
(
"%s failed to get sensor state
\n
"
,
__FUNCTION__
);
}
return
rc
;
}
/*
* get_pci_adapter_status - get the status of a slot
*
* 0-- slot is empty
* 1-- adapter is configured
* 2-- adapter is not configured
* 3-- not valid
*/
int
rpaphp_get_pci_adapter_status
(
struct
slot
*
slot
,
int
is_init
,
u8
*
value
)
{
int
state
,
rc
;
*
value
=
NOT_VALID
;
rc
=
rpaphp_get_sensor_state
(
slot
,
&
state
);
if
(
rc
)
goto
exit
;
if
(
state
==
PRESENT
)
{
if
(
!
is_init
)
/* at run-time slot->state can be changed by */
/* config/unconfig adapter */
*
value
=
slot
->
state
;
else
{
if
(
!
slot
->
dn
->
child
)
dbg
(
"%s: %s is not valid OFDT node
\n
"
,
__FUNCTION__
,
slot
->
dn
->
full_name
);
else
if
(
rpaphp_find_pci_dev
(
slot
->
dn
->
child
))
*
value
=
CONFIGURED
;
else
{
dbg
(
"%s: can't find pdev of adapter in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
*
value
=
NOT_CONFIGURED
;
}
}
}
else
if
(
state
==
EMPTY
)
{
dbg
(
"slot is empty
\n
"
);
*
value
=
state
;
}
exit:
return
rc
;
}
/* Must be called before pci_bus_add_devices */
static
void
rpaphp_fixup_new_pci_devices
(
struct
pci_bus
*
bus
)
{
struct
pci_dev
*
dev
;
list_for_each_entry
(
dev
,
&
bus
->
devices
,
bus_list
)
{
/*
* Skip already-present devices (which are on the
* global device list.)
*/
if
(
list_empty
(
&
dev
->
global_list
))
{
int
i
;
pcibios_fixup_device_resources
(
dev
,
bus
);
pci_read_irq_line
(
dev
);
for
(
i
=
0
;
i
<
PCI_NUM_RESOURCES
;
i
++
)
{
struct
resource
*
r
=
&
dev
->
resource
[
i
];
if
(
r
->
parent
||
!
r
->
start
||
!
r
->
flags
)
continue
;
rpaphp_claim_resource
(
dev
,
i
);
}
}
}
}
static
void
rpaphp_pci_config_device
(
struct
pci_bus
*
pci_bus
,
struct
device_node
*
dn
)
{
int
num
;
num
=
pci_scan_slot
(
pci_bus
,
PCI_DEVFN
(
PCI_SLOT
(
dn
->
devfn
),
0
));
if
(
num
)
{
rpaphp_fixup_new_pci_devices
(
pci_bus
);
pci_bus_add_devices
(
pci_bus
);
}
return
;
}
static
int
rpaphp_pci_config_bridge
(
struct
pci_dev
*
dev
,
struct
device_node
*
dn
);
/*****************************************************************************
rpaphp_pci_config_dn() will recursively configure all devices under the
given slot->dn and return the dn's pci_dev.
*****************************************************************************/
static
struct
pci_dev
*
rpaphp_pci_config_dn
(
struct
device_node
*
dn
,
struct
pci_bus
*
bus
)
{
struct
device_node
*
local
;
struct
pci_dev
*
dev
;
for
(
local
=
dn
->
child
;
local
;
local
=
local
->
sibling
)
{
rpaphp_pci_config_device
(
bus
,
local
);
dev
=
rpaphp_find_pci_dev
(
local
);
if
(
!
rpaphp_pci_config_bridge
(
dev
,
local
))
return
NULL
;
}
return
dev
;
}
static
int
rpaphp_pci_config_bridge
(
struct
pci_dev
*
dev
,
struct
device_node
*
dn
)
{
if
(
dev
&&
dn
->
child
)
{
/* dn is a PCI bridge node */
struct
pci_bus
*
child
;
u8
sec_busno
;
/* get busno of downstream bus */
pci_read_config_byte
(
dev
,
PCI_SECONDARY_BUS
,
&
sec_busno
);
/* add to children of PCI bridge dev->bus */
child
=
pci_add_new_bus
(
dev
->
bus
,
dev
,
sec_busno
);
if
(
!
child
)
{
err
(
"%s: could not add second bus
\n
"
,
__FUNCTION__
);
return
0
;
}
sprintf
(
child
->
name
,
"PCI Bus #%02x"
,
child
->
number
);
/* Fixup subordinate bridge bases and resureces */
pcibios_fixup_bus
(
child
);
/* may need do more stuff here */
rpaphp_pci_config_dn
(
dn
,
dev
->
subordinate
);
}
return
1
;
}
static
struct
pci_dev
*
rpaphp_config_pci_adapter
(
struct
slot
*
slot
)
{
struct
pci_bus
*
pci_bus
;
struct
pci_dev
*
dev
=
NULL
;
dbg
(
"Entry %s: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
if
(
slot
->
bridge
)
{
pci_bus
=
slot
->
bridge
->
subordinate
;
if
(
!
pci_bus
)
{
err
(
"%s: can't find bus structure
\n
"
,
__FUNCTION__
);
goto
exit
;
}
dev
=
rpaphp_pci_config_dn
(
slot
->
dn
,
pci_bus
);
}
else
{
/* slot is not enabled */
err
(
"slot doesn't have pci_dev structure
\n
"
);
dev
=
NULL
;
goto
exit
;
}
exit:
dbg
(
"Exit %s: pci_dev %s
\n
"
,
__FUNCTION__
,
dev
?
"found"
:
"not found"
);
return
dev
;
}
int
rpaphp_unconfig_pci_adapter
(
struct
slot
*
slot
)
{
int
retval
=
0
;
dbg
(
"Entry %s: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
if
(
!
slot
->
dev
.
pci_dev
)
{
info
(
"%s: no card in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
retval
=
-
EINVAL
;
goto
exit
;
}
/* remove the device from the pci core */
pci_remove_bus_device
(
slot
->
dev
.
pci_dev
);
slot
->
state
=
NOT_CONFIGURED
;
info
(
"%s: adapter in slot[%s] unconfigured.
\n
"
,
__FUNCTION__
,
slot
->
name
);
exit:
dbg
(
"Exit %s, rc=0x%x
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
}
static
int
setup_pci_hotplug_slot_info
(
struct
slot
*
slot
)
{
dbg
(
"%s Initilize the PCI slot's hotplug->info structure ...
\n
"
,
__FUNCTION__
);
rpaphp_get_power_status
(
slot
,
&
slot
->
hotplug_slot
->
info
->
power_status
);
rpaphp_get_pci_adapter_status
(
slot
,
1
,
&
slot
->
hotplug_slot
->
info
->
adapter_status
);
if
(
slot
->
hotplug_slot
->
info
->
adapter_status
==
NOT_VALID
)
{
dbg
(
"%s: NOT_VALID: skip dn->full_name=%s
\n
"
,
__FUNCTION__
,
slot
->
dn
->
full_name
);
dealloc_slot_struct
(
slot
);
return
(
-
1
);
}
return
(
0
);
}
static
int
setup_pci_slot
(
struct
slot
*
slot
)
{
slot
->
bridge
=
rpaphp_find_bridge_pdev
(
slot
);
if
(
!
slot
->
bridge
)
{
/* slot being added doesn't have pci_dev yet */
dbg
(
"%s: no pci_dev for bridge dn %s
\n
"
,
__FUNCTION__
,
slot
->
name
);
dealloc_slot_struct
(
slot
);
return
1
;
}
/* find slot's pci_dev if it's not empty */
if
(
slot
->
hotplug_slot
->
info
->
adapter_status
==
EMPTY
)
{
slot
->
state
=
EMPTY
;
/* slot is empty */
slot
->
dev
.
pci_dev
=
NULL
;
}
else
{
/* slot is occupied */
if
(
!
(
slot
->
dn
->
child
))
{
/* non-empty slot has to have child */
err
(
"%s: slot[%s]'s device_node doesn't have child for adapter
\n
"
,
__FUNCTION__
,
slot
->
name
);
dealloc_slot_struct
(
slot
);
return
1
;
}
slot
->
dev
.
pci_dev
=
rpaphp_find_adapter_pdev
(
slot
);
if
(
slot
->
dev
.
pci_dev
)
{
slot
->
state
=
CONFIGURED
;
}
else
{
/* DLPAR add as opposed to
* boot time */
slot
->
state
=
NOT_CONFIGURED
;
}
}
return
0
;
}
int
register_pci_slot
(
struct
slot
*
slot
)
{
int
rc
=
1
;
slot
->
dev_type
=
PCI_DEV
;
if
(
setup_pci_hotplug_slot_info
(
slot
))
goto
exit_rc
;
if
(
setup_pci_slot
(
slot
))
goto
exit_rc
;
rc
=
register_slot
(
slot
);
exit_rc:
if
(
rc
)
dealloc_slot_struct
(
slot
);
return
rc
;
}
int
rpaphp_enable_pci_slot
(
struct
slot
*
slot
)
{
int
retval
=
0
,
state
;
retval
=
rpaphp_get_sensor_state
(
slot
,
&
state
);
if
(
retval
)
goto
exit
;
dbg
(
"%s: sensor state[%d]
\n
"
,
__FUNCTION__
,
state
);
/* if slot is not empty, enable the adapter */
if
(
state
==
PRESENT
)
{
dbg
(
"%s : slot[%s] is occupid.
\n
"
,
__FUNCTION__
,
slot
->
name
);
if
((
slot
->
dev
.
pci_dev
=
rpaphp_config_pci_adapter
(
slot
))
!=
NULL
)
{
slot
->
state
=
CONFIGURED
;
dbg
(
"%s: PCI adapter %s in slot[%s] has been configured
\n
"
,
__FUNCTION__
,
pci_name
(
slot
->
dev
.
pci_dev
),
slot
->
name
);
}
else
{
slot
->
state
=
NOT_CONFIGURED
;
dbg
(
"%s: no pci_dev struct for adapter in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
}
}
else
if
(
state
==
EMPTY
)
{
dbg
(
"%s : slot[%s] is empty
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
state
=
EMPTY
;
}
else
{
err
(
"%s: slot[%s] is in invalid state
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
state
=
NOT_VALID
;
retval
=
-
EINVAL
;
}
exit:
if
(
slot
->
state
!=
NOT_VALID
)
rpaphp_set_attention_status
(
slot
,
LED_ON
);
else
rpaphp_set_attention_status
(
slot
,
LED_ID
);
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
}
drivers/pci/hotplug/rpaphp_slot.c
0 → 100644
View file @
4960aefd
/*
* RPA Virtual I/O device functions
* Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <lxie@us.ibm.com>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/pci.h>
#include "rpaphp.h"
/* free up the memory user by a slot */
static
void
rpaphp_release_slot
(
struct
hotplug_slot
*
hotplug_slot
)
{
struct
slot
*
slot
=
hotplug_slot
?
(
struct
slot
*
)
hotplug_slot
->
private
:
NULL
;
if
(
slot
==
NULL
)
return
;
dealloc_slot_struct
(
slot
);
}
void
dealloc_slot_struct
(
struct
slot
*
slot
)
{
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
->
name
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
;
}
struct
slot
*
alloc_slot_struct
(
struct
device_node
*
dn
,
int
drc_index
,
char
*
drc_name
,
int
power_domain
)
{
struct
slot
*
slot
;
dbg
(
"Enter alloc_slot_struct(): dn->full_name=%s drc_index=0x%x drc_name=%s
\n
"
,
dn
->
full_name
,
drc_index
,
drc_name
);
slot
=
kmalloc
(
sizeof
(
struct
slot
),
GFP_KERNEL
);
if
(
!
slot
)
return
(
NULL
);
memset
(
slot
,
0
,
sizeof
(
struct
slot
));
slot
->
hotplug_slot
=
kmalloc
(
sizeof
(
struct
hotplug_slot
),
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
)
{
kfree
(
slot
);
return
(
NULL
);
}
memset
(
slot
->
hotplug_slot
,
0
,
sizeof
(
struct
hotplug_slot
));
slot
->
hotplug_slot
->
info
=
kmalloc
(
sizeof
(
struct
hotplug_slot_info
),
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
->
info
)
{
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
(
NULL
);
}
memset
(
slot
->
hotplug_slot
->
info
,
0
,
sizeof
(
struct
hotplug_slot_info
));
slot
->
hotplug_slot
->
name
=
kmalloc
(
strlen
(
drc_name
)
+
1
,
GFP_KERNEL
);
if
(
!
slot
->
hotplug_slot
->
name
)
{
kfree
(
slot
->
hotplug_slot
->
info
);
kfree
(
slot
->
hotplug_slot
);
kfree
(
slot
);
return
(
NULL
);
}
slot
->
name
=
slot
->
hotplug_slot
->
name
;
slot
->
dn
=
dn
;
slot
->
index
=
drc_index
;
strcpy
(
slot
->
name
,
drc_name
);
slot
->
power_domain
=
power_domain
;
slot
->
magic
=
SLOT_MAGIC
;
slot
->
hotplug_slot
->
private
=
slot
;
slot
->
hotplug_slot
->
ops
=
&
rpaphp_hotplug_slot_ops
;
slot
->
hotplug_slot
->
release
=
&
rpaphp_release_slot
;
dbg
(
"Exit alloc_slot_struct(): slot->dn->full_name=%s drc_index=0x%x drc_name=%s
\n
"
,
slot
->
dn
->
full_name
,
slot
->
index
,
slot
->
name
);
return
(
slot
);
}
int
register_slot
(
struct
slot
*
slot
)
{
int
retval
;
char
*
vio_uni_addr
=
NULL
;
dbg
(
"%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]
\n
"
,
__FUNCTION__
,
slot
->
dn
->
full_name
,
slot
->
index
,
slot
->
name
,
slot
->
power_domain
,
slot
->
type
);
retval
=
pci_hp_register
(
slot
->
hotplug_slot
);
if
(
retval
)
{
err
(
"pci_hp_register failed with error %d
\n
"
,
retval
);
rpaphp_release_slot
(
slot
->
hotplug_slot
);
return
(
retval
);
}
switch
(
slot
->
dev_type
)
{
case
PCI_DEV
:
/* create symlink between slot->name and it's bus_id */
dbg
(
"%s: sysfs_create_link: %s --> %s
\n
"
,
__FUNCTION__
,
pci_name
(
slot
->
bridge
),
slot
->
name
);
retval
=
sysfs_create_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
&
slot
->
hotplug_slot
->
kobj
,
pci_name
(
slot
->
bridge
));
if
(
retval
)
{
err
(
"sysfs_create_link failed with error %d
\n
"
,
retval
);
rpaphp_release_slot
(
slot
->
hotplug_slot
);
return
(
retval
);
}
break
;
case
VIO_DEV
:
/* create symlink between slot->name and it's uni-address */
vio_uni_addr
=
strchr
(
slot
->
dn
->
full_name
,
'@'
);
if
(
!
vio_uni_addr
)
return
(
1
);
dbg
(
"%s: sysfs_create_link: %s --> %s
\n
"
,
__FUNCTION__
,
vio_uni_addr
,
slot
->
name
);
retval
=
sysfs_create_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
&
slot
->
hotplug_slot
->
kobj
,
vio_uni_addr
);
if
(
retval
)
{
err
(
"sysfs_create_link failed with error %d
\n
"
,
retval
);
rpaphp_release_slot
(
slot
->
hotplug_slot
);
return
(
retval
);
}
break
;
default:
return
(
1
);
}
/* add slot to our internal list */
dbg
(
"%s adding slot[%s] to rpaphp_slot_list
\n
"
,
__FUNCTION__
,
slot
->
name
);
list_add
(
&
slot
->
rpaphp_slot_list
,
&
rpaphp_slot_head
);
if
(
vio_uni_addr
)
info
(
"Slot [%s](vio_uni_addr=%s) registered
\n
"
,
slot
->
name
,
vio_uni_addr
);
else
info
(
"Slot [%s](bus_id=%s) registered
\n
"
,
slot
->
name
,
pci_name
(
slot
->
bridge
));
num_slots
++
;
return
(
0
);
}
int
rpaphp_get_power_status
(
struct
slot
*
slot
,
u8
*
value
)
{
int
rc
;
rc
=
rtas_get_power_level
(
slot
->
power_domain
,
(
int
*
)
value
);
if
(
rc
)
err
(
"failed to get power-level for slot(%s), rc=0x%x
\n
"
,
slot
->
name
,
rc
);
return
rc
;
}
int
rpaphp_set_attention_status
(
struct
slot
*
slot
,
u8
status
)
{
int
rc
;
/* status: LED_OFF or LED_ON */
rc
=
rtas_set_indicator
(
DR_INDICATOR
,
slot
->
index
,
status
);
if
(
rc
)
err
(
"slot(%s) set attention-status(%d) failed! rc=0x%x
\n
"
,
slot
->
name
,
status
,
rc
);
return
rc
;
}
drivers/pci/hotplug/rpaphp_vio.c
0 → 100644
View file @
4960aefd
/*
* RPA Hot Plug Virtual I/O device functions
* Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <lxie@us.ibm.com>
*
*/
#include <asm/vio.h>
#include "rpaphp.h"
/*
* get_vio_adapter_status - get the status of a slot
*
* status:
*
* 1-- adapter is configured
* 2-- adapter is not configured
* 3-- not valid
*/
inline
int
rpaphp_get_vio_adapter_status
(
struct
slot
*
slot
,
int
is_init
,
u8
*
value
)
{
*
value
=
slot
->
state
;
return
0
;
}
int
rpaphp_unconfig_vio_adapter
(
struct
slot
*
slot
)
{
int
retval
=
0
;
dbg
(
"Entry %s: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
if
(
!
slot
->
dev
.
vio_dev
)
{
info
(
"%s: no VIOA in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
retval
=
-
EINVAL
;
goto
exit
;
}
/* remove the device from the vio core */
vio_unregister_device
(
slot
->
dev
.
vio_dev
);
slot
->
state
=
NOT_CONFIGURED
;
info
(
"%s: adapter in slot[%s] unconfigured.
\n
"
,
__FUNCTION__
,
slot
->
name
);
exit:
dbg
(
"Exit %s, rc=0x%x
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
}
static
int
setup_vio_hotplug_slot_info
(
struct
slot
*
slot
)
{
slot
->
hotplug_slot
->
info
->
power_status
=
1
;
rpaphp_get_vio_adapter_status
(
slot
,
1
,
&
slot
->
hotplug_slot
->
info
->
adapter_status
);
return
0
;
}
int
register_vio_slot
(
struct
device_node
*
dn
)
{
u32
*
index
;
char
*
name
;
int
rc
=
1
;
struct
slot
*
slot
=
NULL
;
index
=
(
u32
*
)
get_property
(
dn
,
"ibm,my-drc-index"
,
NULL
);
if
(
!
index
)
goto
exit_rc
;
name
=
get_property
(
dn
,
"ibm,loc-code"
,
NULL
);
if
(
!
name
)
goto
exit_rc
;
if
(
!
(
slot
=
alloc_slot_struct
(
dn
,
*
index
,
name
,
0
)))
{
rc
=
-
ENOMEM
;
goto
exit_rc
;
}
slot
->
dev_type
=
VIO_DEV
;
slot
->
dev
.
vio_dev
=
vio_find_node
(
dn
);
if
(
!
slot
->
dev
.
vio_dev
)
slot
->
dev
.
vio_dev
=
vio_register_device
(
dn
);
if
(
slot
->
dev
.
vio_dev
)
slot
->
state
=
CONFIGURED
;
else
slot
->
state
=
NOT_CONFIGURED
;
if
(
setup_vio_hotplug_slot_info
(
slot
))
goto
exit_rc
;
info
(
"%s: registered VIO device[name=%s vio_dev=%p]
\n
"
,
__FUNCTION__
,
slot
->
name
,
slot
->
dev
.
vio_dev
);
rc
=
register_slot
(
slot
);
exit_rc:
if
(
rc
&&
slot
)
dealloc_slot_struct
(
slot
);
return
(
rc
);
}
int
rpaphp_enable_vio_slot
(
struct
slot
*
slot
)
{
int
retval
=
0
;
if
((
slot
->
dev
.
vio_dev
=
vio_register_device
(
slot
->
dn
)))
{
info
(
"%s: VIO adapter %s in slot[%s] has been configured
\n
"
,
__FUNCTION__
,
slot
->
dn
->
name
,
slot
->
name
);
slot
->
state
=
CONFIGURED
;
}
else
{
info
(
"%s: no vio_dev struct for adapter in slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
slot
->
state
=
NOT_CONFIGURED
;
}
return
retval
;
}
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