]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/pci/hotplug/shpchp_ctrl.c
[PATCH] shpchp - bugfix: add missing serialization
[mv-sheeva.git] / drivers / pci / hotplug / shpchp_ctrl.c
index 58619359ad08f33662ba6a45166ef78ef2e66d68..1a7003d4ba965ce9b7b6c5af0f8d99c9af7e2249 100644 (file)
@@ -242,22 +242,10 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
        int rc = 0;
 
        dbg("%s: change to speed %d\n", __FUNCTION__, speed);
-       down(&ctrl->crit_sect);
        if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
                err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
-               up(&ctrl->crit_sect);
                return WRONG_BUS_FREQUENCY;
        }
-       wait_for_ctrl_irq (ctrl);
-               
-       if ((rc = p_slot->hpc_ops->check_cmd_status(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;
-       }
-       up(&ctrl->crit_sect);
        return rc;
 }
 
@@ -319,29 +307,12 @@ static int board_added(struct slot *p_slot)
                        __FUNCTION__, p_slot->device,
                        ctrl->slot_device_offset, hp_slot);
 
-       /* Wait for exclusive access to hardware */
-       down(&ctrl->crit_sect);
-
        /* Power on slot without connecting to bus */
        rc = p_slot->hpc_ops->power_on_slot(p_slot);
        if (rc) {
                err("%s: Failed to power on slot\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
-               return -1;
-       }
-                       
-       /* Wait for the command to complete */
-       wait_for_ctrl_irq (ctrl);
-       
-       rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-       if (rc) {
-               err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return -1;
        }
-
        
        if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
                if (slots_not_empty)
@@ -349,31 +320,14 @@ static int board_added(struct slot *p_slot)
                
                if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
                        err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
-                       up(&ctrl->crit_sect);
                        return WRONG_BUS_FREQUENCY;
                }
-               wait_for_ctrl_irq (ctrl);
                
-               if ((rc = p_slot->hpc_ops->check_cmd_status(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;
-               }
                /* turn on board, blink green LED, turn off Amber LED */
                if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
                        err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
-                       up(&ctrl->crit_sect);
                        return rc;
                }
-               wait_for_ctrl_irq (ctrl);
-
-               if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-                       err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-                       up(&ctrl->crit_sect);
-                       return rc;  
-               }
        }
  
        rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
@@ -385,16 +339,12 @@ static int board_added(struct slot *p_slot)
 
        if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
                err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return WRONG_BUS_FREQUENCY;
        }
 
        rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
        if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
                err("%s: Can't get bus operation speed\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return WRONG_BUS_FREQUENCY;
        }
 
@@ -404,9 +354,6 @@ static int board_added(struct slot *p_slot)
                max_bus_speed = bus_speed;
        }
 
-       /* Done with exclusive hardware access */
-       up(&ctrl->crit_sect);
-
        if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
                err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
                pi = 1;
@@ -487,22 +434,11 @@ static int board_added(struct slot *p_slot)
                                return rc;
        }
 
-       down(&ctrl->crit_sect);
        /* turn on board, blink green LED, turn off Amber LED */
        if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
                err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
-               up(&ctrl->crit_sect);
                return rc;
        }
-       wait_for_ctrl_irq (ctrl);
-
-       if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-               err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-               up(&ctrl->crit_sect);
-               return rc;  
-       }
-
-       up(&ctrl->crit_sect);
 
        /* Wait for ~1 second */
        wait_for_ctrl_irq (ctrl);
@@ -527,44 +463,17 @@ static int board_added(struct slot *p_slot)
        p_slot->is_a_board = 0x01;
        p_slot->pwr_save = 1;
 
-       /* Wait for exclusive access to hardware */
-       down(&ctrl->crit_sect);
-
        p_slot->hpc_ops->green_led_on(p_slot);
 
-       /* Wait for the command to complete */
-       wait_for_ctrl_irq (ctrl);
-
-       /* Done with exclusive hardware access */
-       up(&ctrl->crit_sect);
-
        return 0;
 
 err_exit:
-       /* Wait for exclusive access to hardware */
-       down(&ctrl->crit_sect);
-
        /* turn off slot, turn on Amber LED, turn off Green LED */
        rc = p_slot->hpc_ops->slot_disable(p_slot);
        if (rc) {
                err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return rc;
        }
-       /* Wait for the command to complete */
-       wait_for_ctrl_irq (ctrl);
-
-       rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-       if (rc) {
-               err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
-               return rc;
-       }
-
-       /* Done with exclusive hardware access */
-       up(&ctrl->crit_sect);
 
        return(rc);
 }
@@ -592,40 +501,18 @@ static int remove_board(struct slot *p_slot)
        if (p_slot->is_a_board)
                p_slot->status = 0x01;
 
-       /* Wait for exclusive access to hardware */
-       down(&ctrl->crit_sect);
-
        /* turn off slot, turn on Amber LED, turn off Green LED */
        rc = p_slot->hpc_ops->slot_disable(p_slot);
        if (rc) {
                err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return rc;
        }
-       /* Wait for the command to complete */
-       wait_for_ctrl_irq (ctrl);
-
-       rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-       if (rc) {
-               err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
-               return rc;  
-       }
        
        rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
        if (rc) {
                err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
-               /* Done with exclusive hardware access */
-               up(&ctrl->crit_sect);
                return rc;
        }
-       /* Wait for the command to complete */
-       wait_for_ctrl_irq (ctrl);
-
-       /* Done with exclusive hardware access */
-       up(&ctrl->crit_sect);
 
        p_slot->pwr_save = 0;
        p_slot->is_a_board = 0;
@@ -670,18 +557,9 @@ static void shpchp_pushbutton_thread (unsigned long slot)
        } else {
                p_slot->state = POWERON_STATE;
 
-               if (shpchp_enable_slot(p_slot)) {
-                       /* Wait for exclusive access to hardware */
-                       down(&p_slot->ctrl->crit_sect);
-
+               if (shpchp_enable_slot(p_slot))
                        p_slot->hpc_ops->green_led_off(p_slot);
 
-                       /* Wait for the command to complete */
-                       wait_for_ctrl_irq (p_slot->ctrl);
-
-                       /* Done with exclusive hardware access */
-                       up(&p_slot->ctrl->crit_sect);
-               }
                p_slot->state = STATIC_STATE;
        }
 
@@ -707,7 +585,7 @@ static int event_thread(void* data)
                if (pushbutton_pending)
                        shpchp_pushbutton_thread(pushbutton_pending);
                else
-                       for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
+                       list_for_each_entry(ctrl, &shpchp_ctrl_list, ctrl_list)
                                interrupt_event_handler(ctrl);
        }
        dbg("event_thread signals exit\n");
@@ -786,36 +664,12 @@ static void interrupt_event_handler(struct controller *ctrl)
 
                                        switch (p_slot->state) {
                                        case BLINKINGOFF_STATE:
-                                               /* Wait for exclusive access to hardware */
-                                               down(&ctrl->crit_sect);
-
                                                p_slot->hpc_ops->green_led_on(p_slot);
-                                               /* Wait for the command to complete */
-                                               wait_for_ctrl_irq (ctrl);
-
                                                p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-                                               /* Wait for the command to complete */
-                                               wait_for_ctrl_irq (ctrl);
-
-                                               /* Done with exclusive hardware access */
-                                               up(&ctrl->crit_sect);
                                                break;
                                        case BLINKINGON_STATE:
-                                               /* Wait for exclusive access to hardware */
-                                               down(&ctrl->crit_sect);
-
                                                p_slot->hpc_ops->green_led_off(p_slot);
-                                               /* Wait for the command to complete */
-                                               wait_for_ctrl_irq (ctrl);
-
                                                p_slot->hpc_ops->set_attention_status(p_slot, 0);
-                                               /* Wait for the command to complete */
-                                               wait_for_ctrl_irq (ctrl);
-
-                                               /* Done with exclusive hardware access */
-                                               up(&ctrl->crit_sect);
-
                                                break;
                                        default:
                                                warn("Not a valid state\n");
@@ -840,22 +694,10 @@ static void interrupt_event_handler(struct controller *ctrl)
                                                info(msg_button_on, p_slot->number);
                                        }
 
-                                       /* Wait for exclusive access to hardware */
-                                       down(&ctrl->crit_sect);
-
                                        /* blink green LED and turn off amber */
                                        p_slot->hpc_ops->green_led_blink(p_slot);
-                                       /* Wait for the command to complete */
-                                       wait_for_ctrl_irq (ctrl);
-                                       
                                        p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-                                       /* Wait for the command to complete */
-                                       wait_for_ctrl_irq (ctrl);
-
-                                       /* Done with exclusive hardware access */
-                                       up(&ctrl->crit_sect);
-
                                        init_timer(&p_slot->task_event);
                                        p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
                                        p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -866,19 +708,8 @@ static void interrupt_event_handler(struct controller *ctrl)
                                } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
                                        /***********POWER FAULT********************/
                                        dbg("%s: power fault\n", __FUNCTION__);
-                                       /* Wait for exclusive access to hardware */
-                                       down(&ctrl->crit_sect);
-
                                        p_slot->hpc_ops->set_attention_status(p_slot, 1);
-                                       /* 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);
-
-                                       /* Done with exclusive hardware access */
-                                       up(&ctrl->crit_sect);
                                } else {
                                        /* refresh notification */
                                        if (p_slot)
@@ -899,29 +730,25 @@ static void interrupt_event_handler(struct controller *ctrl)
 int shpchp_enable_slot (struct slot *p_slot)
 {
        u8 getstatus = 0;
-       int rc;
+       int rc, retval = -ENODEV;
 
        /* Check to see if (latch closed, card present, power off) */
-       down(&p_slot->ctrl->crit_sect);
+       mutex_lock(&p_slot->ctrl->crit_sect);
        rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
        if (rc || !getstatus) {
                info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-               up(&p_slot->ctrl->crit_sect);
-               return -ENODEV;
+               goto out;
        }
        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 -ENODEV;
+               goto out;
        }
        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 -ENODEV;
+               goto out;
        }
-       up(&p_slot->ctrl->crit_sect);
 
        p_slot->is_a_board = 1;
 
@@ -931,51 +758,61 @@ int shpchp_enable_slot (struct slot *p_slot)
        dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
        p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 
-       rc = board_added(p_slot);
-       if (rc) {
+       if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
+           (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
+            && p_slot->ctrl->num_slots == 1) {
+               /* handle amd pogo errata; this must be done before enable  */
+               amd_pogo_errata_save_misc_reg(p_slot);
+               retval = board_added(p_slot);
+               /* handle amd pogo errata; this must be done after enable  */
+               amd_pogo_errata_restore_misc_reg(p_slot);
+       } else
+               retval = board_added(p_slot);
+
+       if (retval) {
                p_slot->hpc_ops->get_adapter_status(p_slot,
                                &(p_slot->presence_save));
                p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
        }
 
        update_slot_info(p_slot);
-       return rc;
+ out:
+       mutex_unlock(&p_slot->ctrl->crit_sect);
+       return retval;
 }
 
 
 int shpchp_disable_slot (struct slot *p_slot)
 {
        u8 getstatus = 0;
-       int ret = 0;
+       int rc, retval = -ENODEV;
 
        if (!p_slot->ctrl)
                return -ENODEV;
 
        /* Check to see if (latch closed, card present, power on) */
-       down(&p_slot->ctrl->crit_sect);
+       mutex_lock(&p_slot->ctrl->crit_sect);
 
-       ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
-       if (ret || !getstatus) {
+       rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+       if (rc || !getstatus) {
                info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-               up(&p_slot->ctrl->crit_sect);
-               return -ENODEV;
+               goto out;
        }
-       ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-       if (ret || getstatus) {
+       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 -ENODEV;
+               goto out;
        }
-       ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
-       if (ret || !getstatus) {
+       rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+       if (rc || !getstatus) {
                info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
-               up(&p_slot->ctrl->crit_sect);
-               return -ENODEV;
+               goto out;
        }
-       up(&p_slot->ctrl->crit_sect);
 
-       ret = remove_board(p_slot);
+       retval = remove_board(p_slot);
        update_slot_info(p_slot);
-       return ret;
+ out:
+       mutex_unlock(&p_slot->ctrl->crit_sect);
+       return retval;
 }