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
9b528b6e
Commit
9b528b6e
authored
Mar 19, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/gregkh/linux/pci-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
f2abce48
1590e3d1
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1072 additions
and
796 deletions
+1072
-796
arch/ia64/pci/pci.c
arch/ia64/pci/pci.c
+1
-0
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/Makefile
+3
-1
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp.h
+1
-1
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/acpiphp_glue.c
+11
-16
drivers/pci/hotplug/acpiphp_pci.c
drivers/pci/hotplug/acpiphp_pci.c
+8
-12
drivers/pci/hotplug/acpiphp_res.c
drivers/pci/hotplug/acpiphp_res.c
+1
-1
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/pciehp_pci.c
+1
-1
drivers/pci/hotplug/pciehprm_acpi.c
drivers/pci/hotplug/pciehprm_acpi.c
+2
-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
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/hotplug/shpchp_pci.c
+1
-1
drivers/pci/setup-res.c
drivers/pci/setup-res.c
+7
-2
kernel/resource.c
kernel/resource.c
+1
-0
No files found.
arch/ia64/pci/pci.c
View file @
9b528b6e
...
...
@@ -367,6 +367,7 @@ pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus)
dev
->
resource
[
i
].
end
+=
window
->
offset
;
}
}
pci_claim_resource
(
dev
,
i
);
}
}
...
...
drivers/pci/hotplug/Makefile
View file @
9b528b6e
...
...
@@ -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/acpiphp.h
View file @
9b528b6e
...
...
@@ -235,7 +235,7 @@ extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
extern
struct
pci_dev
*
acpiphp_allocate_pcidev
(
struct
pci_bus
*
pbus
,
int
dev
,
int
fn
);
extern
int
acpiphp_configure_slot
(
struct
acpiphp_slot
*
slot
);
extern
int
acpiphp_configure_function
(
struct
acpiphp_func
*
func
);
extern
int
acpiphp_unconfigure_function
(
struct
acpiphp_func
*
func
);
extern
void
acpiphp_unconfigure_function
(
struct
acpiphp_func
*
func
);
extern
int
acpiphp_detect_pci_resource
(
struct
acpiphp_bridge
*
bridge
);
extern
int
acpiphp_init_func_resource
(
struct
acpiphp_func
*
func
);
...
...
drivers/pci/hotplug/acpiphp_glue.c
View file @
9b528b6e
...
...
@@ -694,14 +694,14 @@ static int power_on_slot(struct acpiphp_slot *slot)
func
=
list_entry
(
l
,
struct
acpiphp_func
,
sibling
);
if
(
func
->
flags
&
FUNC_HAS_PS0
)
{
dbg
(
"%s: executing _PS0 on %s
\n
"
,
__FUNCTION__
,
pci_name
(
func
->
pci_dev
));
dbg
(
"%s: executing _PS0
\n
"
,
__FUNCTION__
);
status
=
acpi_evaluate_object
(
func
->
handle
,
"_PS0"
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
{
warn
(
"%s: _PS0 failed
\n
"
,
__FUNCTION__
);
retval
=
-
1
;
goto
err_exit
;
}
}
else
break
;
}
}
...
...
@@ -737,7 +737,8 @@ static int power_off_slot(struct acpiphp_slot *slot)
warn
(
"%s: _PS3 failed
\n
"
,
__FUNCTION__
);
retval
=
-
1
;
goto
err_exit
;
}
}
else
break
;
}
}
...
...
@@ -757,7 +758,8 @@ static int power_off_slot(struct acpiphp_slot *slot)
warn
(
"%s: _EJ0 failed
\n
"
,
__FUNCTION__
);
retval
=
-
1
;
goto
err_exit
;
}
}
else
break
;
}
}
...
...
@@ -865,15 +867,8 @@ static int disable_device(struct acpiphp_slot *slot)
list_for_each
(
l
,
&
slot
->
funcs
)
{
func
=
list_entry
(
l
,
struct
acpiphp_func
,
sibling
);
if
(
func
->
pci_dev
)
{
if
(
acpiphp_unconfigure_function
(
func
)
==
0
)
{
func
->
pci_dev
=
NULL
;
}
else
{
err
(
"failed to unconfigure device
\n
"
);
retval
=
-
1
;
goto
err_exit
;
}
}
if
(
func
->
pci_dev
)
acpiphp_unconfigure_function
(
func
);
}
slot
->
flags
&=
(
~
SLOT_ENABLED
);
...
...
@@ -1269,7 +1264,7 @@ int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
up
(
&
slot
->
crit_sect
);
goto
err_exit
;
}
en
abled
++
;
dis
abled
++
;
}
}
else
{
/* if disabled but present, enable */
...
...
@@ -1280,7 +1275,7 @@ int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
up
(
&
slot
->
crit_sect
);
goto
err_exit
;
}
dis
abled
++
;
en
abled
++
;
}
}
}
...
...
drivers/pci/hotplug/acpiphp_pci.c
View file @
9b528b6e
...
...
@@ -83,8 +83,8 @@ static int init_config_space (struct acpiphp_func *func)
if
(
bar
&
PCI_BASE_ADDRESS_SPACE_IO
)
{
/* This is IO */
len
=
bar
&
0xFFFFFFFC
;
len
=
~
len
+
1
;
len
=
bar
&
(
PCI_BASE_ADDRESS_IO_MASK
&
0xFFFF
)
;
len
=
len
&
~
(
len
-
1
)
;
dbg
(
"len in IO %x, BAR %d
\n
"
,
len
,
count
);
...
...
@@ -226,8 +226,8 @@ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *
if
(
len
&
PCI_BASE_ADDRESS_SPACE_IO
)
{
/* This is IO */
base
=
bar
&
0xFFFFFFFC
;
len
&=
0xFFFFFFFC
;
len
=
~
len
+
1
;
len
=
len
&
(
PCI_BASE_ADDRESS_IO_MASK
&
0xFFFF
)
;
len
=
len
&
~
(
len
-
1
)
;
dbg
(
"BAR[%d] %08x - %08x (IO)
\n
"
,
count
,
(
u32
)
base
,
(
u32
)
base
+
len
-
1
);
...
...
@@ -351,8 +351,8 @@ int acpiphp_init_func_resource (struct acpiphp_func *func)
if
(
len
&
PCI_BASE_ADDRESS_SPACE_IO
)
{
/* This is IO */
base
=
bar
&
0xFFFFFFFC
;
len
&=
0xFFFFFFFC
;
len
=
~
len
+
1
;
len
=
len
&
(
PCI_BASE_ADDRESS_IO_MASK
&
0xFFFF
)
;
len
=
len
&
~
(
len
-
1
)
;
dbg
(
"BAR[%d] %08x - %08x (IO)
\n
"
,
count
,
(
u32
)
base
,
(
u32
)
base
+
len
-
1
);
...
...
@@ -485,14 +485,13 @@ int acpiphp_configure_function (struct acpiphp_func *func)
* @func: function to be unconfigured
*
*/
int
acpiphp_unconfigure_function
(
struct
acpiphp_func
*
func
)
void
acpiphp_unconfigure_function
(
struct
acpiphp_func
*
func
)
{
struct
acpiphp_bridge
*
bridge
;
int
retval
=
0
;
/* if pci_dev is NULL, ignore it */
if
(
!
func
->
pci_dev
)
goto
err_exit
;
return
;
pci_remove_bus_device
(
func
->
pci_dev
);
...
...
@@ -505,7 +504,4 @@ int acpiphp_unconfigure_function (struct acpiphp_func *func)
acpiphp_move_resource
(
&
func
->
p_mem_head
,
&
bridge
->
p_mem_head
);
acpiphp_move_resource
(
&
func
->
bus_head
,
&
bridge
->
bus_head
);
spin_unlock
(
&
bridge
->
res_lock
);
err_exit:
return
retval
;
}
drivers/pci/hotplug/acpiphp_res.c
View file @
9b528b6e
...
...
@@ -224,7 +224,7 @@ struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 si
}
/* End of too big on top end */
/* For IO make sure it's not in the ISA aliasing space */
if
(
node
->
base
&
0x300L
)
if
(
(
node
->
base
&
0x300L
)
&&
!
(
node
->
base
&
0xfffff000
)
)
continue
;
/* If we got here, then it is the right size
...
...
drivers/pci/hotplug/pciehp_pci.c
View file @
9b528b6e
...
...
@@ -103,7 +103,7 @@ int pciehp_unconfigure_device(struct pci_func* func)
*/
int
pciehp_set_irq
(
u8
bus_num
,
u8
dev_num
,
u8
int_pin
,
u8
irq_num
)
{
#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
#if
defined(CONFIG_X86) &&
!defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
int
rc
;
u16
temp_word
;
struct
pci_dev
fakedev
;
...
...
drivers/pci/hotplug/pciehprm_acpi.c
View file @
9b528b6e
...
...
@@ -1268,7 +1268,8 @@ static int print_acpi_resources (struct acpi_bridge *ab)
int
pciehprm_print_pirt
(
void
)
{
dbg
(
"PCIEHPRM ACPI Slots
\n
"
);
print_acpi_resources
(
acpi_bridges_head
);
if
(
acpi_bridges_head
)
print_acpi_resources
(
acpi_bridges_head
);
return
0
;
}
...
...
drivers/pci/hotplug/rpadlpar_core.c
View file @
9b528b6e
...
...
@@ -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
;
...
...
@@ -72,7 +93,7 @@ static inline struct hotplug_slot *find_php_slot(char *drc_name)
static
struct
slot
*
find_slot
(
char
*
drc_name
)
{
struct
hotplug_slot
*
php_slot
=
find_php_slot
(
drc_name
);
if
(
!
php_slot
)
return
NULL
;
...
...
@@ -127,14 +148,14 @@ static int pci_add_secondary_bus(struct device_node *dn,
rpadlpar_claim_one_bus
(
bridge_dev
->
bus
);
if
(
hose
->
last_busno
<
child
->
number
)
hose
->
last_busno
=
child
->
number
;
hose
->
last_busno
=
child
->
number
;
dn
->
bussubno
=
child
->
number
;
/* ioremap() for child bus */
if
(
remap_bus_range
(
child
))
{
printk
(
KERN_ERR
"%s: could not ioremap() child bus
\n
"
,
__FUNCTION__
);
__FUNCTION__
);
return
1
;
}
...
...
@@ -162,9 +183,9 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
return
NULL
;
}
if
(
dev
->
hdr_type
!=
PCI_HEADER_TYPE_BRIDGE
)
{
if
(
dev
->
hdr_type
!=
PCI_HEADER_TYPE_BRIDGE
)
{
printk
(
KERN_ERR
"%s: unexpected header type %d
\n
"
,
__FUNCTION__
,
dev
->
hdr_type
);
__FUNCTION__
,
dev
->
hdr_type
);
return
NULL
;
}
...
...
@@ -180,7 +201,7 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
if
(
!
bridge_dev
)
{
printk
(
KERN_ERR
"%s: unexpected null device
\n
"
,
__FUNCTION__
);
__FUNCTION__
);
return
1
;
}
...
...
@@ -188,11 +209,25 @@ static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
if
(
unmap_bus_range
(
secondary_bus
))
{
printk
(
KERN_ERR
"%s: failed to unmap bus range
\n
"
,
__FUNCTION__
);
__FUNCTION__
);
return
1
;
}
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,37 +247,33 @@ 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
;
goto
exit
;
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
);
__FUNCTION__
,
drc_name
);
rc
=
-
EIO
;
}
exit:
...
...
@@ -251,60 +282,107 @@ 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
;
__FUNCTION__
);
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
;
__FUNCTION__
,
drc_name
);
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
);
rc
=
-
EIO
;
__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:
up
(
&
rpadlpar_sem
);
...
...
@@ -324,7 +402,7 @@ int __init rpadlpar_io_init(void)
if
(
!
is_dlpar_capable
())
{
printk
(
KERN_WARNING
"%s: partition not DLPAR capable
\n
"
,
__FUNCTION__
);
__FUNCTION__
);
return
-
EPERM
;
}
...
...
drivers/pci/hotplug/rpaphp.h
View file @
9b528b6e
...
...
@@ -26,6 +26,8 @@
#ifndef _PPC64PHP_H
#define _PPC64PHP_H
#include <linux/pci.h>
#include "pci_hotplug.h"
#define DR_INDICATOR 9002
...
...
@@ -34,24 +36,22 @@
#define POWER_ON 100
#define POWER_OFF 0
#define LED_OFF 0
#define LED_ON 1
/* continuous on */
#define LED_OFF 0
#define LED_ON 1
/* continuous on */
#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 */
#define ERR_SENSE_USE -9002
/* No DR operation will succeed, slot is unusable */
#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 ERR_SENSE_USE -9002
/* No DR operation will succeed, slot is unusable */
/* Sensor values from rtas_get-sensor */
#define EMPTY
0
/* No card in slot */
#define PRESENT
1
/* Card in slot */
#define EMPTY
0
/* No card in slot */
#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
...
...
@@ -75,27 +79,55 @@
* struct slot - slot information for each *physical* slot
*/
struct
slot
{
u32
magic
;
int
state
;
u32
index
;
u32
type
;
u32
power_domain
;
char
*
name
;
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 */
/* it will be used for unconfig */
/* NULL if slot is empty */
struct
hotplug_slot
*
hotplug_slot
;
struct
list_head
rpaphp_slot_list
;
u32
magic
;
int
state
;
u32
index
;
u32
type
;
u32
power_domain
;
char
*
name
;
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 */
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
);
#endif
/* _PPC64PHP_H */
/* 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 @
9b528b6e
...
...
@@ -34,16 +34,15 @@
#include <asm/eeh.h>
/* for eeh_add_device() */
#include <asm/rtas.h>
/* rtas_call */
#include <asm/pci-bridge.h>
/* for pci_controller */
#include "../pci.h"
/* for pci_add_new_bus*/
/* and pci_do_scan_bus*/
#include "../pci.h"
/* for pci_add_new_bus
*/
/* and pci_do_scan_bus
*/
#include "rpaphp.h"
#include "pci_hotplug.h"
static
int
debug
;
int
debug
;
static
struct
semaphore
rpaphp_sem
;
static
LIST_HEAD
(
rpaphp_slot_head
);
static
int
num_slots
;
LIST_HEAD
(
rpaphp_slot_head
);
int
num_slots
;
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>"
...
...
@@ -60,109 +59,35 @@ module_param(debug, int, 0644);
static
int
enable_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
get_power_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_power_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_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
);
st
atic
st
ruct
hotplug_slot_ops
rpaphp_hotplug_slot_ops
=
{
.
owner
=
THIS_MODULE
,
.
enable_slot
=
enable_slot
,
.
disable_slot
=
disable_slot
,
.
set_attention_status
=
set_attention_status
,
.
get_power_status
=
get_power_status
,
.
get_attention_status
=
get_attention_status
,
.
get_adapter_status
=
get_adapter_status
,
.
get_max_bus_speed
=
get_max_bus_speed
,
.
get_cur_bus_speed
=
get_cur_bus_speed
,
struct
hotplug_slot_ops
rpaphp_hotplug_slot_ops
=
{
.
owner
=
THIS_MODULE
,
.
enable_slot
=
enable_slot
,
.
disable_slot
=
disable_slot
,
.
set_attention_status
=
set_attention_status
,
.
get_power_status
=
get_power_status
,
.
get_attention_status
=
get_attention_status
,
.
get_adapter_status
=
get_adapter_status
,
.
get_max_bus_speed
=
get_max_bus_speed
,
.
get_cur_bus_speed
=
get_cur_bus_speed
,
};
static
int
rpaphp_get_sensor_state
(
int
index
,
int
*
state
)
{
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
)
static
inline
struct
slot
*
get_slot
(
struct
hotplug_slot
*
hotplug_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
)
{
dbg
(
"%s - hotplug_slot == NULL
\n
"
,
function
);
return
NULL
;
}
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
;
return
(
struct
slot
*
)
hotplug_slot
->
private
;
}
static
int
rpaphp_get_attention_status
(
struct
slot
*
slot
)
{
return
slot
->
hotplug_slot
->
info
->
attention_status
;
}
...
...
@@ -173,7 +98,7 @@ static int rpaphp_get_attention_status(struct slot *slot)
* 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
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
...
@@ -183,25 +108,21 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
down
(
&
rpaphp_sem
);
switch
(
value
)
{
case
0
:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
hotplug_slot
->
info
->
attention_status
=
0
;
break
;
case
1
:
default:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ON
);
hotplug_slot
->
info
->
attention_status
=
1
;
break
;
case
2
:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ID
);
hotplug_slot
->
info
->
attention_status
=
2
;
break
;
case
0
:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
hotplug_slot
->
info
->
attention_status
=
0
;
break
;
case
1
:
default:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ON
);
hotplug_slot
->
info
->
attention_status
=
1
;
break
;
case
2
:
retval
=
rpaphp_set_attention_status
(
slot
,
LED_ID
);
hotplug_slot
->
info
->
attention_status
=
2
;
break
;
}
up
(
&
rpaphp_sem
);
return
retval
;
}
...
...
@@ -212,7 +133,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
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
...
@@ -223,7 +144,6 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
down
(
&
rpaphp_sem
);
retval
=
rpaphp_get_power_status
(
slot
,
value
);
up
(
&
rpaphp_sem
);
return
retval
;
}
...
...
@@ -232,7 +152,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
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
...
...
@@ -240,81 +160,36 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
if
(
slot
==
NULL
)
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
*
value
=
rpaphp_get_attention_status
(
slot
);
up
(
&
rpaphp_sem
);
return
retval
;
}
/*
* 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
)
static
int
get_adapter_status
(
struct
hotplug_slot
*
hotplug_slot
,
u8
*
value
)
{
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
int
retval
=
0
;
if
(
slot
==
NULL
)
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
/* 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
);
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__
);
...
...
@@ -322,46 +197,42 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
return
-
ENODEV
;
down
(
&
rpaphp_sem
);
switch
(
slot
->
type
)
{
case
1
:
case
2
:
case
3
:
case
4
:
case
5
:
case
6
:
*
value
=
PCI_SPEED_33MHz
;
/* speed for case 1-6 */
break
;
case
7
:
case
8
:
*
value
=
PCI_SPEED_66MHz
;
break
;
case
11
:
case
14
:
*
value
=
PCI_SPEED_66MHz_PCIX
;
break
;
case
12
:
case
15
:
*
value
=
PCI_SPEED_100MHz_PCIX
;
break
;
case
13
:
case
16
:
*
value
=
PCI_SPEED_133MHz_PCIX
;
break
;
default:
*
value
=
PCI_SPEED_UNKNOWN
;
break
;
case
1
:
case
2
:
case
3
:
case
4
:
case
5
:
case
6
:
*
value
=
PCI_SPEED_33MHz
;
/* speed for case 1-6 */
break
;
case
7
:
case
8
:
*
value
=
PCI_SPEED_66MHz
;
break
;
case
11
:
case
14
:
*
value
=
PCI_SPEED_66MHz_PCIX
;
break
;
case
12
:
case
15
:
*
value
=
PCI_SPEED_100MHz_PCIX
;
break
;
case
13
:
case
16
:
*
value
=
PCI_SPEED_133MHz_PCIX
;
break
;
default:
*
value
=
PCI_SPEED_UNKNOWN
;
break
;
}
up
(
&
rpaphp_sem
);
return
0
;
}
/* 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__
);
...
...
@@ -369,416 +240,106 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
return
-
ENODEV
;
*
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
;
}
/* 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
retval
=
0
;
char
*
rm_link
;
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
slot
->
bridge
->
slot_name
);
dbg
(
"%s - Entry: slot[%s]
\n
"
,
__FUNCTION__
,
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
);
retval
=
pci_hp_deregister
(
slot
->
hotplug_slot
);
if
(
retval
)
err
(
"Problem unregistering a slot %s
\n
"
,
slot
->
name
);
num_slots
--
;
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
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
)
return
(
0
);
return
(
0
);
/* &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
)
return
(
0
);
return
(
0
);
/* &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
)
return
(
0
);
return
(
0
);
/* power_domains[1...n] are the slot power domains */
*
power_domains
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-power-domains"
,
NULL
);
*
power_domains
=
(
int
*
)
get_property
(
dn
,
"ibm,drc-power-domains"
,
NULL
);
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
;
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
);
return
!
strcmp
(
dn
->
name
,
"vdevice"
);
}
/*************************************
* 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
;
int
retval
=
0
;
int
i
;
struct
device_node
*
dn
;
int
*
indexes
,
*
names
,
*
types
,
*
power_domains
;
char
*
name
,
*
type
;
for
(
dn
=
find_all_nodes
();
dn
;
dn
=
dn
->
next
)
{
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
"
,
__FUNCTION__
,
dn
->
full_name
,
dn
->
name
);
name
=
(
char
*
)
&
names
[
1
];
type
=
(
char
*
)
&
types
[
1
];
for
(
i
=
0
;
i
<
indexes
[
0
];
i
++
,
name
+=
(
strlen
(
name
)
+
1
),
type
+=
(
strlen
(
type
)
+
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
;
goto
exit
;
}
slot
->
name
=
slot
->
hotplug_slot
->
name
;
slot
->
index
=
indexes
[
i
+
1
];
strcpy
(
slot
->
name
,
name
);
slot
->
type
=
simple_strtoul
(
type
,
NULL
,
10
);
if
(
slot
->
type
<
1
||
slot
->
type
>
16
)
slot
->
type
=
0
;
slot
->
power_domain
=
power_domains
[
i
+
1
];
slot
->
magic
=
SLOT_MAGIC
;
slot
->
hotplug_slot
->
private
=
slot
;
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:
struct
slot
*
slot
;
int
retval
=
0
;
int
i
;
int
*
indexes
,
*
names
,
*
types
,
*
power_domains
;
char
*
name
,
*
type
;
dbg
(
"Entry %s: dn->full_name=%s
\n
"
,
__FUNCTION__
,
dn
->
full_name
);
if
(
dn
->
parent
&&
is_vdevice_root
(
dn
->
parent
))
{
/* register a VIO device */
retval
=
register_vio_slot
(
dn
);
goto
exit
;
}
/* register PCI devices */
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
];
i
++
,
name
+=
(
strlen
(
name
)
+
1
),
type
+=
(
strlen
(
type
)
+
1
))
{
if
(
!
(
slot
=
alloc_slot_struct
(
dn
,
indexes
[
i
+
1
],
name
,
power_domains
[
i
+
1
])))
{
retval
=
-
ENOMEM
;
goto
exit
;
}
slot
->
type
=
simple_strtoul
(
type
,
NULL
,
10
);
if
(
slot
->
type
<
1
||
slot
->
type
>
16
)
slot
->
type
=
0
;
retval
=
register_pci_slot
(
slot
);
}
/* for indexes */
}
/* end of PCI device_node */
exit:
dbg
(
"%s - Exit: num_slots=%d rc[%d]
\n
"
,
__FUNCTION__
,
num_slots
,
retval
);
__FUNCTION__
,
num_slots
,
retval
);
return
retval
;
}
...
...
@@ -786,31 +347,28 @@ int rpaphp_add_slot(char *slot_name)
* init_slots - initialize 'struct slot' structures for each slot
*
*/
static
int
init_slots
(
void
)
static
void
init_slots
(
void
)
{
int
retval
=
0
;
retval
=
rpaphp_add_slot
(
NULL
);
struct
device_node
*
dn
;
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
);
/* initialize internal data structure etc. */
retval
=
init_slots
();
init_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
slot
*
slot
;
...
...
@@ -818,125 +376,100 @@ static void cleanup_slots (void)
/*
* Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated.
* 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
);
sysfs_remove_link
(
slot
->
hotplug_slot
->
kobj
.
parent
,
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
);
pci_hp_deregister
(
slot
->
hotplug_slot
);
}
return
;
}
static
int
__init
rpaphp_init
(
void
)
{
int
retval
=
0
;
info
(
DRIVER_DESC
" version: "
DRIVER_VERSION
"
\n
"
);
/* read all the PRA info from the system */
retval
=
init_rpa
();
return
retval
;
return
init_rpa
();
}
static
void
__exit
rpaphp_exit
(
void
)
{
cleanup_slots
();
}
static
int
enable_slot
(
struct
hotplug_slot
*
hotplug_slot
)
{
int
retval
=
0
,
state
;
int
retval
=
0
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
if
(
slot
==
NULL
)
return
-
ENODEV
;
if
(
slot
->
state
==
CONFIGURED
)
{
dbg
(
"%s: %s is already enabled
\n
"
,
__FUNCTION__
,
slot
->
name
);
dbg
(
"%s: %s is already enabled
\n
"
,
__FUNCTION__
,
slot
->
name
);
goto
exit
;
}
dbg
(
"ENABLING SLOT %s
\n
"
,
slot
->
name
);
down
(
&
rpaphp_sem
);
retval
=
rpaphp_get_sensor_state
(
slot
->
index
,
&
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
);
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
;
switch
(
slot
->
dev_type
)
{
case
PCI_DEV
:
retval
=
rpaphp_enable_pci_slot
(
slot
);
break
;
case
VIO_DEV
:
retval
=
rpaphp_enable_vio_slot
(
slot
);
break
;
default:
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
);
exit:
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
}
static
int
disable_slot
(
struct
hotplug_slot
*
hotplug_slot
)
{
int
retval
;
int
retval
;
struct
slot
*
slot
=
get_slot
(
hotplug_slot
,
__FUNCTION__
);
if
(
slot
==
NULL
)
return
-
ENODEV
;
dbg
(
"DISABLING SLOT %s
\n
"
,
slot
->
name
);
down
(
&
rpaphp_sem
);
rpaphp_set_attention_status
(
slot
,
LED_ID
);
dbg
(
"%s - Entry: slot[%s]
\n
"
,
__FUNCTION__
,
slot
->
name
);
retval
=
rpaphp_unconfig_adapter
(
slot
);
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
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
);
retval
=
rpaphp_unconfig_pci_adapter
(
slot
);
rpaphp_set_attention_status
(
slot
,
LED_OFF
);
break
;
case
VIO_DEV
:
retval
=
rpaphp_unconfig_vio_adapter
(
slot
);
break
;
default:
retval
=
-
ENODEV
;
}
up
(
&
rpaphp_sem
);
exit:
dbg
(
"%s - Exit: rc[%d]
\n
"
,
__FUNCTION__
,
retval
);
return
retval
;
}
...
...
drivers/pci/hotplug/rpaphp_pci.c
View file @
9b528b6e
...
...
@@ -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
;
while
((
dev
=
pci_get_device
(
PCI_ANY_ID
,
PCI_ANY_ID
,
dev
))
!=
NULL
)
{
if
(
!
dev
->
bus
)
continue
;
struct
pci_dev
*
retval_dev
=
NULL
,
*
dev
=
NULL
;
char
bus_id
[
BUS_ID_SIZE
];
if
(
dev
->
devfn
!=
dn
->
devfn
)
continue
;
sprintf
(
bus_id
,
"%04x:%02x:%02x.%d"
,
dn
->
phb
->
global_number
,
dn
->
busno
,
PCI_SLOT
(
dn
->
devfn
),
PCI_FUNC
(
dn
->
devfn
))
;
if
(
dn
->
phb
->
global_number
==
pci_domain_nr
(
dev
->
bus
)
&&
dn
->
busno
==
dev
->
bus
->
number
)
{
dbg
(
"Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s
\n
"
,
dn
->
full_name
,
bus_id
);
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
];
...
...
@@ -63,13 +66,333 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource)
if
(
err
)
{
err
(
"PCI: %s region %d of %s %s [%lx:%lx]
\n
"
,
root
?
"Address space collision on"
:
"No parent found for"
,
resource
,
dtype
,
pci_name
(
dev
),
res
->
start
,
res
->
end
);
root
?
"Address space collision on"
:
"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 @
9b528b6e
/*
* 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 @
9b528b6e
/*
* 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
;
}
drivers/pci/hotplug/shpchp_pci.c
View file @
9b528b6e
...
...
@@ -101,7 +101,7 @@ int shpchp_unconfigure_device(struct pci_func* func)
*/
int
shpchp_set_irq
(
u8
bus_num
,
u8
dev_num
,
u8
int_pin
,
u8
irq_num
)
{
#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
#if
defined(CONFIG_X86) &&
!defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
int
rc
;
u16
temp_word
;
struct
pci_dev
fakedev
;
...
...
drivers/pci/setup-res.c
View file @
9b528b6e
...
...
@@ -94,13 +94,18 @@ int __init
pci_claim_resource
(
struct
pci_dev
*
dev
,
int
resource
)
{
struct
resource
*
res
=
&
dev
->
resource
[
resource
];
struct
resource
*
root
=
pci_find_parent_resource
(
dev
,
res
)
;
struct
resource
*
root
=
NULL
;
char
*
dtype
=
resource
<
PCI_BRIDGE_RESOURCES
?
"device"
:
"bridge"
;
int
err
;
if
(
res
->
flags
&
IORESOURCE_IO
)
root
=
&
ioport_resource
;
if
(
res
->
flags
&
IORESOURCE_MEM
)
root
=
&
iomem_resource
;
err
=
-
EINVAL
;
if
(
root
!=
NULL
)
err
=
reques
t_resource
(
root
,
res
);
err
=
inser
t_resource
(
root
,
res
);
if
(
err
)
{
printk
(
KERN_ERR
"PCI: %s region %d of %s %s [%lx:%lx]
\n
"
,
...
...
kernel/resource.c
View file @
9b528b6e
...
...
@@ -335,6 +335,7 @@ int insert_resource(struct resource *parent, struct resource *new)
/* existing resource overlaps end of new resource */
if
(
next
->
end
>
new
->
end
)
{
parent
=
next
;
result
=
0
;
goto
begin
;
}
...
...
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