Commit 5a7db1eb authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

merge fixups.

parents 3e13e3b2 4cd5d72a
......@@ -166,8 +166,9 @@ count on these devices by calling pci_dev_put().
~~~~~~~~~~~~~~~~~~~
Before you do anything with the device you've found, you need to enable
it by calling pci_enable_device() which enables I/O and memory regions of
the device, assigns missing resources if needed and wakes up the device
if it was in suspended state. Please note that this function can fail.
the device, allocates an IRQ if necessary, assigns missing resources if
needed and wakes up the device if it was in suspended state. Please note
that this function can fail.
If you want to use the device in bus mastering mode, call pci_set_master()
which enables the bus master bit in PCI_COMMAND register and also fixes
......
......@@ -286,11 +286,11 @@ wake event from:
+------------------+
| Bit | State |
+------------------+
| 15 | D0 |
| 14 | D1 |
| 11 | D0 |
| 12 | D1 |
| 13 | D2 |
| 12 | D3hot |
| 11 | D3cold |
| 14 | D3hot |
| 15 | D3cold |
+------------------+
A device can use this to enable wake events:
......
......@@ -313,6 +313,22 @@ static __init int disable_smbus(struct dmi_blacklist *d)
return 0;
}
/*
* Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to
* IRQ 11 even though it is actually wired to IRQ 10
*/
static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d)
{
#ifdef CONFIG_PCI
extern int acer_tm360_irqrouting;
if (acer_tm360_irqrouting == 0) {
acer_tm360_irqrouting = 1;
printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
}
#endif
return 0;
}
/*
* Check for clue free BIOS implementations who use
* the following QA technique
......@@ -799,6 +815,13 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
NO_MATCH, NO_MATCH
} },
{ fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", {
MATCH(DMI_SYS_VENDOR, "Acer"),
MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
NO_MATCH, NO_MATCH
} },
/*
* Generic per vendor APM settings
*/
......@@ -986,6 +1009,13 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_BOARD_NAME, "PR-DLS"),
MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
MATCH(DMI_BIOS_DATE, "03/21/2003") }},
{ disable_acpi_pci, "Acer TravelMate 36x Laptop", {
MATCH(DMI_SYS_VENDOR, "Acer"),
MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
NO_MATCH, NO_MATCH
} },
#endif
{ NULL, }
......
......@@ -24,6 +24,7 @@
#define PIRQ_VERSION 0x0100
static int broken_hp_bios_irq9;
int acer_tm360_irqrouting;
static struct irq_routing_table *pirq_table;
......@@ -746,6 +747,14 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
r->set(pirq_router_dev, dev, pirq, 11);
}
/* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) {
pirq = 0x68;
mask = 0x400;
dev->irq = r->get(pirq_router_dev, dev, pirq);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
/*
* Find the best IRQ to assign: use the one
* reported by the device if possible.
......
......@@ -1058,6 +1058,34 @@ static int is_bridge(struct pci_func * func)
hotplug controller logic
*/
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
/* turn off slot, turn on Amber LED, turn off Green LED */
if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return;
}
wait_for_ctrl_irq (ctrl);
pslot->hpc_ops->green_led_off(pslot);
wait_for_ctrl_irq (ctrl);
/* turn on Amber LED */
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return;
}
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
}
/**
* board_added - Called after a board has been added to the system.
......@@ -1071,7 +1099,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
u8 hp_slot;
int index;
u32 temp_register = 0xFFFFFFFF;
u32 retval, rc = 0;
u32 rc = 0;
struct pci_func *new_func = NULL;
struct slot *p_slot;
struct resource_lists res_lists;
......@@ -1086,8 +1114,10 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
/* Power on slot */
rc = p_slot->hpc_ops->power_on_slot(p_slot);
if (rc)
if (rc) {
up(&ctrl->crit_sect);
return -1;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
......@@ -1105,11 +1135,12 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
wait_for_ctrl_irq (ctrl);
dbg("%s: afterlong_delay\n", __FUNCTION__);
/* Make this to check for link training status */
/* Check link training status */
rc = p_slot->hpc_ops->check_lnk_status(ctrl);
if (rc) {
err("%s: Failed to check link status\n", __FUNCTION__);
return -1;
set_slot_off(ctrl, p_slot);
return rc;
}
dbg("%s: func status = %x\n", __FUNCTION__, func->status);
......@@ -1159,36 +1190,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
pciehp_resource_sort_and_combine(&(ctrl->bus_head));
if (rc) {
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
/* turn off slot, turn on Amber LED, turn off Green LED */
retval = p_slot->hpc_ops->power_off_slot(p_slot);
/* In PCI Express, just power off slot */
if (retval) {
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
return retval;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* turn on Amber LED */
retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (retval) {
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
return retval;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
set_slot_off(ctrl, p_slot);
return rc;
}
pciehp_save_slot_config(ctrl, func);
......@@ -1223,37 +1225,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
up(&ctrl->crit_sect);
} else {
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
/* turn off slot, turn on Amber LED, turn off Green LED */
retval = p_slot->hpc_ops->power_off_slot(p_slot);
/* In PCI Express, just power off slot */
if (retval) {
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
return retval;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* turn on Amber LED */
retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (retval) {
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
return retval;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
return rc;
set_slot_off(ctrl, p_slot);
return -1;
}
return 0;
}
......@@ -1320,6 +1293,7 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
rc = p_slot->hpc_ops->power_off_slot(p_slot);
if (rc) {
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return rc;
}
/* Wait for the command to complete */
......@@ -1406,7 +1380,6 @@ static void pciehp_pushbutton_thread(unsigned long slot)
{
struct slot *p_slot = (struct slot *) slot;
u8 getstatus;
int rc;
pushbutton_pending = 0;
......@@ -1420,23 +1393,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
p_slot->state = POWEROFF_STATE;
dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
if (pciehp_disable_slot(p_slot)) {
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
/* Turn on the Attention LED */
rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (rc) {
err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
return;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
up(&p_slot->ctrl->crit_sect);
}
pciehp_disable_slot(p_slot);
p_slot->state = STATIC_STATE;
} else {
p_slot->state = POWERON_STATE;
......@@ -1446,15 +1403,6 @@ static void pciehp_pushbutton_thread(unsigned long slot)
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
/* Turn off the green LED */
rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (rc) {
err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
return;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
......@@ -1664,7 +1612,10 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect);
p_slot->hpc_ops->set_attention_status(p_slot, 1);
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->green_led_off(p_slot);
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1701,21 +1652,21 @@ int pciehp_enable_slot(struct slot *p_slot)
if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
up(&p_slot->ctrl->crit_sect);
......@@ -1788,21 +1739,21 @@ int pciehp_disable_slot(struct slot *p_slot)
if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 0;
return 1;
}
up(&p_slot->ctrl->crit_sect);
......
......@@ -349,7 +349,9 @@ static int hpc_check_lnk_status(struct controller *ctrl)
return retval;
}
if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) {
dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
!(lnk_status & NEG_LINK_WD)) {
err("%s : Link Training Error occurs \n", __FUNCTION__);
retval = -1;
return retval;
......
......@@ -218,6 +218,10 @@ static void acpi_get__hpp ( struct acpi_bridge *ab)
}
ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
if (!ab->_hpp) {
err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name);
goto free_and_return;
}
memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
ab->_hpp->cache_line_size = nui[0];
......@@ -1393,7 +1397,7 @@ static int configure_existing_function(
static int bind_pci_resources_to_slots ( struct controller *ctrl)
{
struct pci_func *func;
struct pci_func *func, new_func;
int busn = ctrl->slot_bus;
int devn, funn;
u32 vid;
......@@ -1411,12 +1415,20 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl)
if (vid != 0xFFFFFFFF) {
dbg("%s: vid = %x\n", __FUNCTION__, vid);
func = pciehp_slot_find(busn, devn, funn);
if (!func)
continue;
if (!func) {
memset(&new_func, 0, sizeof(struct pci_func));
new_func.bus = busn;
new_func.device = devn;
new_func.function = funn;
new_func.is_a_board = 1;
configure_existing_function(ctrl, &new_func);
pciehprm_dump_func_res(&new_func);
} else {
configure_existing_function(ctrl, func);
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
pciehprm_dump_func_res(func);
}
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
}
}
}
......
......@@ -276,7 +276,7 @@ static int pciehprm_delete_resource(
static int bind_pci_resources_to_slots ( struct controller *ctrl)
{
struct pci_func *func;
struct pci_func *func, new_func;
int busn = ctrl->slot_bus;
int devn, funn;
u32 vid;
......@@ -297,12 +297,20 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl)
vid, busn, devn, funn);
func = pciehp_slot_find(busn, devn, funn);
dbg("%s: func = %p\n", __FUNCTION__,func);
if (!func)
continue;
if (!func) {
memset(&new_func, 0, sizeof(struct pci_func));
new_func.bus = busn;
new_func.device = devn;
new_func.function = funn;
new_func.is_a_board = 1;
configure_existing_function(ctrl, &new_func);
phprm_dump_func_res(&new_func);
} else {
configure_existing_function(ctrl, func);
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
phprm_dump_func_res(func);
}
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
}
}
}
......
......@@ -24,25 +24,6 @@
static DECLARE_MUTEX(rpadlpar_sem);
static inline int is_hotplug_capable(struct device_node *dn)
{
unsigned char *ptr = get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL);
return (int) (ptr != NULL);
}
static char *get_node_drc_name(struct device_node *dn)
{
char *ptr = NULL;
int *drc_names;
drc_names = (int *) get_property(dn, "ibm,drc-names", NULL);
if (drc_names)
ptr = (char *) &drc_names[1];
return ptr;
}
static struct device_node *find_php_slot_vio_node(char *drc_name)
{
struct device_node *child;
......@@ -55,7 +36,7 @@ static struct device_node *find_php_slot_vio_node(char *drc_name)
for (child = of_get_next_child(parent, NULL);
child; child = of_get_next_child(parent, child)) {
loc_code = get_property(child, "ibm,loc-code", NULL);
if (loc_code && !strcmp(loc_code, drc_name))
if (loc_code && !strncmp(loc_code, drc_name, strlen(drc_name)))
return child;
}
......@@ -69,7 +50,7 @@ static struct device_node *find_php_slot_pci_node(char *drc_name)
while ((np = of_find_node_by_type(np, "pci")))
if (is_hotplug_capable(np)) {
name = get_node_drc_name(np);
name = rpaphp_get_drc_name(np);
if (name && (!strcmp(drc_name, name)))
break;
}
......@@ -324,6 +305,7 @@ int dlpar_remove_pci_slot(struct slot *slot, char *drc_name)
}
/* Remove pci bus */
if (dlpar_pci_remove_bus(bridge_dev)) {
printk(KERN_ERR "%s: unable to remove pci bus %s\n",
__FUNCTION__, drc_name);
......
......@@ -30,6 +30,9 @@
#include <linux/pci.h>
#include "pci_hotplug.h"
#define HOTPLUG 1
#define EMBEDDED 0
#define DR_INDICATOR 9002
#define DR_ENTITY_SENSE 9003
......@@ -73,6 +76,11 @@ extern int debug;
#define CONFIGURED 1
#define EMPTY 0
struct rpaphp_pci_func {
struct pci_dev *pci_dev;
struct list_head sibling;
};
/*
* struct slot - slot information for each *physical* slot
*/
......@@ -83,14 +91,13 @@ struct slot {
u32 power_domain;
char *name;
char *location;
u8 removable;
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 */
struct list_head pci_funcs; /* pci_devs in PCI slot */
struct vio_dev *vio_dev; /* vio_dev in VIO slot */
} dev;
u8 dev_type; /* VIO or PCI */
struct hotplug_slot *hotplug_slot;
......@@ -101,6 +108,13 @@ extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
extern struct list_head rpaphp_slot_head;
extern int num_slots;
static inline int is_hotplug_capable(struct device_node *dn)
{
unsigned char *ptr = get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL);
return (int) (ptr != NULL);
}
/* function prototypes */
/* rpaphp_pci.c */
......@@ -110,10 +124,12 @@ 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);
extern struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev);
/* rpaphp_core.c */
extern int rpaphp_add_slot(struct device_node *dn);
extern int rpaphp_remove_slot(struct slot *slot);
extern char *rpaphp_get_drc_name(struct device_node *dn);
/* rpaphp_vio.c */
extern int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 * value);
......@@ -125,8 +141,8 @@ extern int rpaphp_enable_vio_slot(struct slot *slot);
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 deregister_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);
extern void rpaphp_sysfs_remove_attr_location(struct hotplug_slot *slot);
#endif /* _PPC64PHP_H */
......@@ -54,6 +54,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
void eeh_register_disable_func(int (*)(struct pci_dev *));
module_param(debug, bool, 0644);
static int enable_slot(struct hotplug_slot *slot);
......@@ -63,6 +65,7 @@ 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 rpaphp_disable_slot(struct pci_dev *dev);
struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.owner = THIS_MODULE,
......@@ -89,7 +92,7 @@ static int rpaphp_get_attention_status(struct slot *slot)
*/
static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
{
int retval;
int retval = 0;
struct slot *slot = (struct slot *)hotplug_slot->private;
down(&rpaphp_sem);
......@@ -208,47 +211,53 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int rpaphp_remove_slot(struct slot *slot)
{
int retval = 0;
struct hotplug_slot *php_slot = slot->hotplug_slot;
return deregister_slot(slot);
}
list_del(&slot->rpaphp_slot_list);
static int get_dn_properties(struct device_node *dn, int **indexes, int **names,
int **types, int **power_domains)
{
*indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL);
/* &names[1] contains NULL terminated slot names */
*names = (int *) get_property(dn, "ibm,drc-names", NULL);
/* remove "php_location" file */
rpaphp_sysfs_remove_attr_location(php_slot);
/* &types[1] contains NULL terminated slot types */
*types = (int *) get_property(dn, "ibm,drc-types", NULL);
retval = pci_hp_deregister(php_slot);
if (retval)
err("Problem unregistering a slot %s\n", slot->name);
/* power_domains[1...n] are the slot power domains */
*power_domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL);
num_slots--;
if (*indexes && *names && *types && *power_domains)
return (1);
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
return (0);
}
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);
if (!*indexes)
return 0;
/* &names[1] contains NULL terminated slot names */
*names = (int *) get_property(dn, "ibm,drc-names", NULL);
if (!*names)
return 0;
/* &types[1] contains NULL terminated slot types */
*types = (int *) get_property(dn, "ibm,drc-types", NULL);
if (!*types)
return 0;
/* power_domains[1...n] are the slot power domains */
*power_domains = (int *) get_property(dn,
"ibm,drc-power-domains", NULL);
if (!*power_domains)
return 0;
if (strcmp(dn->name, "pci") == 0 &&
!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
return 0;
return 1;
if (!is_hotplug_capable(dn))
return (0);
if (!get_dn_properties(dn, indexes, names, types, power_domains))
return (0);
return (1);
}
static int is_dr_dn(struct device_node *dn, int **indexes, int **names, int **types,
int **power_domains, int **my_drc_index)
{
if (!is_hotplug_capable(dn))
return (0);
*my_drc_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
if(!*my_drc_index)
return (0);
if (!dn->parent)
return (0);
return get_dn_properties(dn->parent, indexes, names, types, power_domains);
}
static inline int is_vdevice_root(struct device_node *dn)
......@@ -256,15 +265,48 @@ static inline int is_vdevice_root(struct device_node *dn)
return !strcmp(dn->name, "vdevice");
}
/**
* rpaphp_add_slot: Add Hot Plug slot(s) to sysfs
*
*/
char *rpaphp_get_drc_name(struct device_node *dn)
{
char *name, *ptr = NULL;
int *drc_names, *drc_indexes, i;
struct device_node *parent = dn->parent;
u32 *my_drc_index;
if (!parent)
return NULL;
my_drc_index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
if (!my_drc_index)
return NULL;
drc_names = (int *) get_property(parent, "ibm,drc-names", NULL);
drc_indexes = (int *) get_property(parent, "ibm,drc-indexes", NULL);
if (!drc_names || !drc_indexes)
return NULL;
name = (char *) &drc_names[1];
for (i = 0; i < drc_indexes[0]; i++, name += (strlen(name) + 1)) {
if (drc_indexes[i + 1] == *my_drc_index) {
ptr = (char *) name;
break;
}
}
return ptr;
}
/****************************************************************
* rpaphp not only registers PCI hotplug slots(HOTPLUG),
* but also logical DR slots(EMBEDDED).
* HOTPLUG slot: An adapter can be physically added/removed.
* EMBEDDED slot: An adapter can be logically removed/added
* from/to a partition with the slot.
***************************************************************/
int rpaphp_add_slot(struct device_node *dn)
{
struct slot *slot;
int retval = 0;
int i;
int i, *my_drc_index, slot_type;
int *indexes, *names, *types, *power_domains;
char *name, *type;
......@@ -277,42 +319,65 @@ int rpaphp_add_slot(struct device_node *dn)
}
/* register PCI devices */
if (dn->name != 0 && strcmp(dn->name, "pci") == 0 &&
is_php_dn(dn, &indexes, &names, &types, &power_domains)) {
if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
if (is_php_dn(dn, &indexes, &names, &types, &power_domains))
slot_type = HOTPLUG;
else if (is_dr_dn(dn, &indexes, &names, &types, &power_domains, &my_drc_index))
slot_type = EMBEDDED;
else goto exit;
name = (char *) &names[1];
type = (char *) &types[1];
for (i = 0; i < indexes[0];
i++,
name += (strlen(name) + 1),
type += (strlen(type) + 1)) {
for (i = 0; i < indexes[0]; i++,
name += (strlen(name) + 1), type += (strlen(type) + 1)) {
if ( slot_type == HOTPLUG ||
(slot_type == EMBEDDED && indexes[i + 1] == my_drc_index[0])) {
if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
power_domains[i + 1]))) {
retval = -ENOMEM;
goto exit;
}
if (slot_type == EMBEDDED)
slot->type = EMBEDDED;
else
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 */
dbg(" Found drc-index:0x%x drc-name:%s drc-type:%s\n",
indexes[i + 1], name, type);
retval = register_pci_slot(slot);
if (slot_type == EMBEDDED)
goto exit;
}
}
}
exit:
dbg("%s - Exit: num_slots=%d rc[%d]\n",
__FUNCTION__, num_slots, retval);
return retval;
}
static int __init init_rpa(void)
/*
* init_slots - initialize 'struct slot' structures for each slot
*
*/
static void init_slots(void)
{
struct device_node *dn;
for (dn = find_all_nodes(); dn; dn = dn->next)
rpaphp_add_slot(dn);
}
static int __init init_rpa(void)
{
init_MUTEX(&rpaphp_sem);
/* initialize internal data structure etc. */
for (dn = find_all_nodes(); dn; dn = dn->next)
rpaphp_add_slot(dn);
init_slots();
if (!num_slots)
return -ENODEV;
......@@ -342,12 +407,18 @@ static int __init rpaphp_init(void)
{
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
/* let EEH know they can use hotplug */
eeh_register_disable_func(&rpaphp_disable_slot);
/* read all the PRA info from the system */
return init_rpa();
}
static void __exit rpaphp_exit(void)
{
/* let EEH know we are going away */
eeh_register_disable_func(NULL);
cleanup_slots();
}
......@@ -374,11 +445,16 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
retval = -EINVAL;
}
up(&rpaphp_sem);
exit:
exit:
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
}
static int rpaphp_disable_slot(struct pci_dev *dev)
{
return disable_slot(rpaphp_find_hotplug_slot(dev));
}
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
int retval;
......@@ -395,9 +471,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
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);
......@@ -406,7 +480,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
retval = -ENODEV;
}
up(&rpaphp_sem);
exit:
exit:
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
}
......@@ -417,3 +491,4 @@ module_exit(rpaphp_exit);
EXPORT_SYMBOL_GPL(rpaphp_add_slot);
EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
EXPORT_SYMBOL_GPL(rpaphp_slot_head);
EXPORT_SYMBOL_GPL(rpaphp_get_drc_name);
This diff is collapsed.
......@@ -29,6 +29,35 @@
#include <linux/pci.h>
#include "rpaphp.h"
static ssize_t removable_read_file (struct hotplug_slot *php_slot, char *buf)
{
u8 value;
int retval = -ENOENT;
struct slot *slot = (struct slot *)php_slot->private;
if (!slot)
return retval;
value = slot->removable;
retval = sprintf (buf, "%d\n", value);
return retval;
}
static struct hotplug_slot_attribute hotplug_slot_attr_removable = {
.attr = {.name = "phy_removable", .mode = S_IFREG | S_IRUGO},
.show = removable_read_file,
};
static void rpaphp_sysfs_add_attr_removable (struct hotplug_slot *slot)
{
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
}
static void rpaphp_sysfs_remove_attr_removable (struct hotplug_slot *slot)
{
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
}
static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
{
char *value;
......@@ -53,7 +82,7 @@ static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
}
void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
{
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
}
......@@ -68,6 +97,17 @@ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
void dealloc_slot_struct(struct slot *slot)
{
struct list_head *ln, *n;
if (slot->dev_type == PCI_DEV) {
list_for_each_safe (ln, n, &slot->dev.pci_funcs) {
struct rpaphp_pci_func *func;
func = list_entry(ln, struct rpaphp_pci_func, sibling);
kfree(func);
}
}
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
......@@ -107,9 +147,8 @@ struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_
slot->hotplug_slot->private = slot;
slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
slot->hotplug_slot->release = &rpaphp_release_slot;
slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
return slot;
return (slot);
error_name:
kfree(slot->hotplug_slot->name);
......@@ -123,15 +162,56 @@ struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_
return NULL;
}
static int is_registered(struct slot *slot)
{
struct slot *tmp_slot;
list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
if (!strcmp(tmp_slot->name, slot->name))
return 1;
}
return 0;
}
int deregister_slot(struct slot *slot)
{
int retval = 0;
struct hotplug_slot *php_slot = slot->hotplug_slot;
dbg("%s - Entry: deregistering slot=%s\n",
__FUNCTION__, slot->name);
list_del(&slot->rpaphp_slot_list);
/* remove "phy_location" file */
rpaphp_sysfs_remove_attr_location(php_slot);
/* remove "phy_removable" file */
rpaphp_sysfs_remove_attr_removable(php_slot);
retval = pci_hp_deregister(php_slot);
if (retval)
err("Problem unregistering a slot %s\n", slot->name);
else
num_slots--;
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
}
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);
/* should not try to register the same slot twice */
if (is_registered(slot)) { /* should't be here */
err("register_slot: slot[%s] is already registered\n", slot->name);
rpaphp_release_slot(slot->hotplug_slot);
return 1;
}
retval = pci_hp_register(slot->hotplug_slot);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
......@@ -142,30 +222,40 @@ int register_slot(struct slot *slot)
/* create "phy_locatoin" file */
rpaphp_sysfs_add_attr_location(slot->hotplug_slot);
/* create "phy_removable" file */
rpaphp_sysfs_add_attr_removable(slot->hotplug_slot);
/* 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);
if (slot->dev_type == VIO_DEV)
info("Slot [%s](VIO location=%s) registered\n",
slot->name, slot->location);
else
info("Slot [%s](bus_id=%s) registered\n",
slot->name, pci_name(slot->bridge));
info("Slot [%s](PCI location=%s) registered\n",
slot->name, slot->location);
num_slots++;
return 0;
}
int rpaphp_get_power_status(struct slot *slot, u8 * value)
{
int rc;
int rc = 0;
if (slot->type == EMBEDDED) {
dbg("%s set to POWER_ON for EMBEDDED slot %s\n",
__FUNCTION__, slot->location);
*value = POWER_ON;
}
else {
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);
slot->location, rc);
}
return rc;
}
......@@ -177,8 +267,8 @@ int rpaphp_set_attention_status(struct slot *slot, u8 status)
/* 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);
err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
slot->name, slot->location, slot->index, status, rc);
return rc;
}
......@@ -74,12 +74,12 @@ int register_vio_slot(struct device_node *dn)
int rc = 1;
struct slot *slot = NULL;
name = rpaphp_get_drc_name(dn);
if (!name)
goto exit_rc;
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;
......
......@@ -61,6 +61,7 @@ struct pci_func {
u8 configured;
u8 switch_save;
u8 presence_save;
u8 pwr_save;
u32 base_length[0x06];
u8 base_type[0x06];
u16 reserved2;
......
......@@ -137,6 +137,8 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
func->presence_save, func->pwr_save);
if (getstatus) {
/*
......@@ -145,6 +147,10 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
func->switch_save = 0;
taskInfo->event_type = INT_SWITCH_OPEN;
if (func->pwr_save && func->presence_save) {
taskInfo->event_type = INT_POWER_FAULT;
err("Surprise Removal of card\n");
}
} else {
/*
* Switch closed
......@@ -1427,6 +1433,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
if (rc) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY;
}
......@@ -1438,6 +1445,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
__FUNCTION__);
err("%s: Error code (%d)\n", __FUNCTION__, rc);
up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY;
}
/* Done with exclusive hardware access */
......@@ -1589,8 +1597,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
func->status = 0;
func->switch_save = 0x10;
func->is_a_board = 0x01;
func->pwr_save = 1;
/* next, we will instantiate the linux pci_dev structures
/* Next, we will instantiate the linux pci_dev structures
* (with appropriate driver notification, if already present)
*/
index = 0;
......@@ -1781,6 +1790,7 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
func->function = 0;
func->configured = 0;
func->switch_save = 0x10;
func->pwr_save = 0;
func->is_a_board = 0;
}
......@@ -1807,7 +1817,6 @@ static void shpchp_pushbutton_thread (unsigned long slot)
{
struct slot *p_slot = (struct slot *) slot;
u8 getstatus;
int rc;
pushbutton_pending = 0;
......@@ -1821,23 +1830,7 @@ static void shpchp_pushbutton_thread (unsigned long slot)
p_slot->state = POWEROFF_STATE;
dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
if (shpchp_disable_slot(p_slot)) {
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
/* Turn on the Attention LED */
rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (rc) {
err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
return;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
up(&p_slot->ctrl->crit_sect);
}
shpchp_disable_slot(p_slot);
p_slot->state = STATIC_STATE;
} else {
p_slot->state = POWERON_STATE;
......@@ -1847,15 +1840,6 @@ static void shpchp_pushbutton_thread (unsigned long slot)
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
/* Turn off the green LED */
rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
if (rc) {
err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
return;
}
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
......@@ -2096,7 +2080,7 @@ int shpchp_enable_slot (struct slot *p_slot)
func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
if (!func) {
dbg("%s: Error! slot NULL\n", __FUNCTION__);
return (1);
return 1;
}
/* Check to see if (latch closed, card present, power off) */
......@@ -2105,19 +2089,19 @@ int shpchp_enable_slot (struct slot *p_slot)
if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
up(&p_slot->ctrl->crit_sect);
......@@ -2125,7 +2109,7 @@ int shpchp_enable_slot (struct slot *p_slot)
func = shpchp_slot_create(p_slot->bus);
if (func == NULL)
return (1);
return 1;
func->bus = p_slot->bus;
func->device = p_slot->device;
......@@ -2135,6 +2119,8 @@ int shpchp_enable_slot (struct slot *p_slot)
/* We have to save the presence info for these slots */
p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save));
dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
func->switch_save = !getstatus? 0x10:0;
......@@ -2181,7 +2167,7 @@ int shpchp_disable_slot (struct slot *p_slot)
struct pci_func *func;
if (!p_slot->ctrl)
return (1);
return 1;
/* Check to see if (latch closed, card present, power on) */
down(&p_slot->ctrl->crit_sect);
......@@ -2190,19 +2176,19 @@ int shpchp_disable_slot (struct slot *p_slot)
if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return (0);
return 1;
}
up(&p_slot->ctrl->crit_sect);
......
......@@ -263,6 +263,7 @@ int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slot
new_slot->function = (u8) function;
new_slot->is_a_board = 1;
new_slot->switch_save = 0x10;
new_slot->pwr_save = 1;
/* In case of unsupported board */
new_slot->status = DevError;
new_slot->pci_dev = pci_find_slot(new_slot->bus,
......
......@@ -218,6 +218,10 @@ static void acpi_get__hpp ( struct acpi_bridge *ab)
}
ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
if (!ab->_hpp) {
err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);
goto free_and_return;
}
memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
ab->_hpp->cache_line_size = nui[0];
......@@ -1391,7 +1395,7 @@ static int configure_existing_function(
static int bind_pci_resources_to_slots ( struct controller *ctrl)
{
struct pci_func *func;
struct pci_func *func, new_func;
int busn = ctrl->bus;
int devn, funn;
u32 vid;
......@@ -1406,12 +1410,20 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl)
if (vid != 0xFFFFFFFF) {
func = shpchp_slot_find(busn, devn, funn);
if (!func)
continue;
if (!func) {
memset(&new_func, 0, sizeof(struct pci_func));
new_func.bus = busn;
new_func.device = devn;
new_func.function = funn;
new_func.is_a_board = 1;
configure_existing_function(ctrl, &new_func);
shpchprm_dump_func_res(&new_func);
} else {
configure_existing_function(ctrl, func);
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
shpchprm_dump_func_res(func);
}
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
}
}
}
......
......@@ -208,7 +208,7 @@ static int configure_existing_function(
static int bind_pci_resources_to_slots ( struct controller *ctrl)
{
struct pci_func *func;
struct pci_func *func, new_func;
int busn = ctrl->slot_bus;
int devn, funn;
u32 vid;
......@@ -226,12 +226,20 @@ static int bind_pci_resources_to_slots ( struct controller *ctrl)
if (vid != 0xFFFFFFFF) {
func = shpchp_slot_find(busn, devn, funn);
if (!func)
continue;
if (!func) {
memset(&new_func, 0, sizeof(struct pci_func));
new_func.bus = busn;
new_func.device = devn;
new_func.function = funn;
new_func.is_a_board = 1;
configure_existing_function(ctrl, &new_func);
phprm_dump_func_res(&new_func);
} else {
configure_existing_function(ctrl, func);
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
phprm_dump_func_res(func);
}
dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
}
}
}
......
......@@ -442,7 +442,7 @@ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable)
pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
value &= PCI_PM_CAP_PME_MASK;
value >>= ffs(value); /* First bit of mask */
value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
/* Check if it can generate PME# from requested state. */
if (!value || !(value & (1 << state)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment