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
Expand all
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 \
acpiphp_res.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_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)
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
;
char
*
name
;
...
...
@@ -193,6 +214,20 @@ static int dlpar_pci_remove_bus(struct pci_dev *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
;
}
...
...
@@ -212,35 +247,31 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
*/
int
dlpar_add_slot
(
char
*
drc_name
)
{
struct
device_node
*
dn
=
find_php_slot_node
(
drc_name
);
struct
pci_dev
*
dev
;
struct
device_node
*
dn
;
int
rc
=
0
;
if
(
down_interruptible
(
&
rpadlpar_sem
))
return
-
ERESTARTSYS
;
if
(
!
dn
)
{
rc
=
-
ENODEV
;
goto
exit
;
}
/* Check for existing hotplug slot */
if
(
find_slot
(
drc_name
))
{
rc
=
-
EINVAL
;
goto
exit
;
}
/* Add pci bus */
dev
=
dlpar_pci_add_bus
(
dn
);
if
(
!
dev
)
{
printk
(
KERN_ERR
"%s: unable to add bus %s
\n
"
,
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
dn
=
find_php_slot_vio_node
(
drc_name
);
if
(
!
dn
)
{
dn
=
find_php_slot_pci_node
(
drc_name
);
if
(
dn
)
rc
=
dlpar_add_pci_slot
(
drc_name
,
dn
);
else
{
rc
=
-
ENODEV
;
goto
exit
;
}
}
/* Add hotplug slot for new
bus
*/
if
(
rpaphp_add_slot
(
drc_name
))
{
/* Add hotplug slot for new
VIOA or PCI
*/
if
(
!
rc
&&
rpaphp_add_slot
(
dn
))
{
printk
(
KERN_ERR
"%s: unable to add hotplug slot %s
\n
"
,
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
...
...
@@ -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
*
* Remove the kernel and hotplug representations
* of an I/O Slot.
* Return Codes:
* 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
* -EINVAL Slot already removed
* -ERESTARTSYS Signalled before obtaining lock
* -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
slot
*
slot
;
struct
device_node
*
dn
=
find_php_slot_pci_node
(
drc_name
);
struct
pci_dev
*
bridge_dev
;
int
rc
=
0
;
if
(
down_interruptible
(
&
rpadlpar_sem
))
return
-
ERESTARTSYS
;
if
(
!
dn
)
{
rc
=
-
ENODEV
;
goto
exit
;
}
slot
=
find_slot
(
drc_name
);
if
(
!
slot
)
{
rc
=
-
EINVAL
;
goto
exit
;
}
if
(
!
dn
)
return
-
ENODEV
;
bridge_dev
=
slot
->
bridge
;
if
(
!
bridge_dev
)
{
printk
(
KERN_ERR
"%s: unexpected null bridge device
\n
"
,
__FUNCTION__
);
rc
=
-
EIO
;
goto
exit
;
return
-
EIO
;
}
/* Remove hotplug slot */
if
(
rpaphp_remove_slot
(
slot
))
{
printk
(
KERN_ERR
"%s: unable to remove hotplug slot %s
\n
"
,
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
goto
exit
;
return
-
EIO
;
}
/* Remove pci bus */
if
(
dlpar_pci_remove_bus
(
bridge_dev
))
{
printk
(
KERN_ERR
"%s: unable to remove pci bus %s
\n
"
,
__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
;
}
exit:
...
...
drivers/pci/hotplug/rpaphp.h
View file @
4960aefd
...
...
@@ -26,6 +26,8 @@
#ifndef _PPC64PHP_H
#define _PPC64PHP_H
#include <linux/pci.h>
#include "pci_hotplug.h"
#define DR_INDICATOR 9002
...
...
@@ -39,8 +41,6 @@
#define LED_ID 2
/* slow blinking */
#define LED_ACTION 3
/* fast blinking */
#define SLOT_NAME_SIZE 12
/* Error status from rtas_get-sensor */
#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 */
...
...
@@ -51,7 +51,7 @@
#define PRESENT 1
/* Card in slot */
#define MY_NAME "rpaphp"
extern
int
debug
;
#define dbg(format, arg...) \
do { \
if (debug) \
...
...
@@ -64,6 +64,10 @@
#define SLOT_MAGIC 0x67267322
/* slot types */
#define VIO_DEV 1
#define PCI_DEV 2
/* slot states */
#define NOT_VALID 3
...
...
@@ -81,21 +85,49 @@ struct slot {
u32
type
;
u32
power_domain
;
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 */
struct
pci_dev
*
bridge
;
/* slot's pci_dev in pci_devices
*/
struct
pci_dev
*
dev
;
/* pci_dev of device in this slot
*/
struct
pci_dev
*
bridge
;
/* slot's pci_dev in pci_devices
*/
union
{
struct
pci_dev
*
pci_dev
;
/* pci_dev of device in this slot
*/
/* it will be used for unconfig */
/* 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
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
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_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 */
drivers/pci/hotplug/rpaphp_core.c
View file @
4960aefd
This diff is collapsed.
Click to expand it.
drivers/pci/hotplug/rpaphp_pci.c
View file @
4960aefd
...
...
@@ -23,32 +23,35 @@
*
*/
#include <linux/pci.h>
#include <asm/pci-bridge.h>
/* for pci_controller */
#include "
rpaphp.h"
#include <asm/pci-bridge.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
*
retval_dev
=
NULL
,
*
dev
=
NULL
;
char
bus_id
[
BUS_ID_SIZE
];
while
((
dev
=
pci_get_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
dev
))
!=
NULL
)
{
if
(
!
dev
->
bus
)
continue
;
sprintf
(
bus_id
,
"%04x:%02x:%02x.%d"
,
dn
->
phb
->
global_number
,
dn
->
busno
,
PCI_SLOT
(
dn
->
devfn
),
PCI_FUNC
(
dn
->
devfn
));
if
(
dev
->
devfn
!=
dn
->
devfn
)
continue
;
dbg
(
"Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s
\n
"
,
dn
->
full_name
,
bus_id
)
;
if
(
dn
->
phb
->
global_number
==
pci_domain_nr
(
dev
->
bus
)
&&
dn
->
busno
==
dev
->
bus
->
number
)
{
while
((
dev
=
pci_find_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
dev
))
!=
NULL
)
{
if
(
!
strcmp
(
pci_name
(
dev
),
bus_id
)
)
{
retval_dev
=
dev
;
dbg
(
"rpaphp_find_pci_dev(): found dev=%p
\n\n
"
,
dev
);
break
;
}
}
return
retval_dev
;
}
EXPORT_SYMBOL_GPL
(
rpaphp_find_pci_dev
);
int
rpaphp_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
)
{
struct
resource
*
res
=
&
dev
->
resource
[
resource
];
...
...
@@ -67,9 +70,329 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource)
"No parent found for"
,
resource
,
dtype
,
pci_name
(
dev
),
res
->
start
,
res
->
end
);
}
return
err
;
}
EXPORT_SYMBOL_GPL
(
rpaphp_find_pci_dev
);
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