Commit 08dfd470 authored by Dely Sy's avatar Dely Sy Committed by Greg Kroah-Hartman

[PATCH] Fixes for hot-plug drivers (updated)

Here is the updated patch (against 2.6.7-rc1) for the shpchp and pciehp
drivers that fixes the following issues:
- proper LED status when latch is open or card is not present while the
  user tries to power up the slot; (reported by D. Keck)
- check if kmalloc() return NULL before proceeding in acpi_get__hpp();
  (provided by L. Capitulino)
- add up(&ctrl->crit_sect) before return in error cases in several
  places;
- proper handling of resources when there are other onboard devices
  behind the p2p bridge that has the hot-plug capabaility;
- need to check negotiated link width in check_lnk_status();
- cleanup board_added() in pciehp
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 0badbe1a
......@@ -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);
}
}
}
......
......@@ -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);
}
}
}
......
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