X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fpci%2Fhotplug%2Fpciehp_hpc.c;h=016eea94a8a5729d1cf6e5908a2c6a205d4b6149;hb=f2154eef2a926435cdf79156cd361092d6cba91e;hp=fbc64aa2dd68a32f24d21fde630665e316150d65;hpb=64106104dd2d4a6280777e88c1cbf9f7a52c30bd;p=linux-2.6 diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index fbc64aa2dd..016eea94a8 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -71,6 +71,8 @@ #define DBG_LEAVE_ROUTINE #endif /* DEBUG */ +static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); + struct ctrl_reg { u8 cap_id; u8 nxt_ptr; @@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define EMI_STATE 0x0080 #define EMI_STATUS_BIT 7 -static spinlock_t hpc_event_lock; - DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static int ctlr_seq_num = 0; /* Controller sequence # */ static irqreturn_t pcie_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); @@ -276,11 +275,19 @@ static inline int pcie_wait_cmd(struct controller *ctrl) return retval; } -static int pcie_write_cmd(struct slot *slot, u16 cmd) +/** + * pcie_write_cmd - Issue controller command + * @slot: slot to which the command is issued + * @cmd: command value written to slot control register + * @mask: bitmask of slot control register to be modified + */ +static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) { struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; + u16 slot_ctrl; + unsigned long flags; DBG_ENTER_ROUTINE @@ -300,17 +307,29 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd) __FUNCTION__); } - ctrl->cmd_busy = 1; - retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE)); + spin_lock_irqsave(&ctrl->lock, flags); + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); - goto out; + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + goto out_spin_unlock; } + slot_ctrl &= ~mask; + slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE); + + ctrl->cmd_busy = 1; + retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); + if (retval) + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + + out_spin_unlock: + spin_unlock_irqrestore(&ctrl->lock, flags); + /* * Wait for command completion. */ - retval = pcie_wait_cmd(ctrl); + if (!retval) + retval = pcie_wait_cmd(ctrl); out: mutex_unlock(&ctrl->ctrl_lock); DBG_LEAVE_ROUTINE @@ -503,25 +522,20 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) static int hpc_toggle_emi(struct slot *slot) { - struct controller *ctrl = slot->ctrl; - u16 slot_cmd = 0; - u16 slot_ctrl; - int rc = 0; + u16 slot_cmd; + u16 cmd_mask; + int rc; DBG_ENTER_ROUTINE - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", - __FUNCTION__); - return rc; - } - - slot_cmd = (slot_ctrl | EMI_CTRL); - if (!pciehp_poll_mode) + slot_cmd = EMI_CTRL; + cmd_mask = EMI_CTRL; + if (!pciehp_poll_mode) { slot_cmd = slot_cmd | HP_INTR_ENABLE; + cmd_mask = cmd_mask | HP_INTR_ENABLE; + } - pcie_write_cmd(slot, slot_cmd); + rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); DBG_LEAVE_ROUTINE return rc; @@ -530,35 +544,32 @@ static int hpc_toggle_emi(struct slot *slot) static int hpc_set_attention_status(struct slot *slot, u8 value) { struct controller *ctrl = slot->ctrl; - u16 slot_cmd = 0; - u16 slot_ctrl; - int rc = 0; + u16 slot_cmd; + u16 cmd_mask; + int rc; DBG_ENTER_ROUTINE - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return rc; - } - + cmd_mask = ATTN_LED_CTRL; switch (value) { case 0 : /* turn off */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0; + slot_cmd = 0x00C0; break; case 1: /* turn on */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; + slot_cmd = 0x0040; break; case 2: /* turn blink */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; + slot_cmd = 0x0080; break; default: return -1; } - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; + if (!pciehp_poll_mode) { + slot_cmd = slot_cmd | HP_INTR_ENABLE; + cmd_mask = cmd_mask | HP_INTR_ENABLE; + } - pcie_write_cmd(slot, slot_cmd); + rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -571,21 +582,18 @@ static void hpc_set_green_led_on(struct slot *slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl; - int rc = 0; + u16 cmd_mask; DBG_ENTER_ROUTINE - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return; + slot_cmd = 0x0100; + cmd_mask = PWR_LED_CTRL; + if (!pciehp_poll_mode) { + slot_cmd = slot_cmd | HP_INTR_ENABLE; + cmd_mask = cmd_mask | HP_INTR_ENABLE; } - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - pcie_write_cmd(slot, slot_cmd); + pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -597,22 +605,18 @@ static void hpc_set_green_led_off(struct slot *slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl; - int rc = 0; + u16 cmd_mask; DBG_ENTER_ROUTINE - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return; + slot_cmd = 0x0300; + cmd_mask = PWR_LED_CTRL; + if (!pciehp_poll_mode) { + slot_cmd = slot_cmd | HP_INTR_ENABLE; + cmd_mask = cmd_mask | HP_INTR_ENABLE; } - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; - - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - pcie_write_cmd(slot, slot_cmd); + pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -624,22 +628,18 @@ static void hpc_set_green_led_blink(struct slot *slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl; - int rc = 0; + u16 cmd_mask; DBG_ENTER_ROUTINE - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return; + slot_cmd = 0x0200; + cmd_mask = PWR_LED_CTRL; + if (!pciehp_poll_mode) { + slot_cmd = slot_cmd | HP_INTR_ENABLE; + cmd_mask = cmd_mask | HP_INTR_ENABLE; } - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; - - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - pcie_write_cmd(slot, slot_cmd); + pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -656,6 +656,13 @@ static void hpc_release_ctlr(struct controller *ctrl) else free_irq(ctrl->pci_dev->irq, ctrl); + /* + * If this is the last controller to be released, destroy the + * pciehp work queue + */ + if (atomic_dec_and_test(&pciehp_num_controllers)) + destroy_workqueue(pciehp_wq); + DBG_LEAVE_ROUTINE } @@ -663,7 +670,8 @@ static int hpc_power_on_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl, slot_status; + u16 cmd_mask; + u16 slot_status; int retval = 0; DBG_ENTER_ROUTINE @@ -686,23 +694,23 @@ static int hpc_power_on_slot(struct slot * slot) } } - retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (retval) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return retval; - } - - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; - + slot_cmd = POWER_ON; + cmd_mask = PWR_CTRL; /* Enable detection that we turned off at slot power-off time */ - if (!pciehp_poll_mode) + if (!pciehp_poll_mode) { slot_cmd = slot_cmd | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | PRSN_DETECT_ENABLE | HP_INTR_ENABLE; + cmd_mask = cmd_mask | + PWR_FAULT_DETECT_ENABLE | + MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE | + HP_INTR_ENABLE; + } - retval = pcie_write_cmd(slot, slot_cmd); + retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); if (retval) { err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); @@ -720,21 +728,15 @@ static int hpc_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl; + u16 cmd_mask; int retval = 0; DBG_ENTER_ROUTINE dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (retval) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - return retval; - } - - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; - + slot_cmd = POWER_OFF; + cmd_mask = PWR_CTRL; /* * If we get MRL or presence detect interrupts now, the isr * will notice the sticky power-fault bit too and issue power @@ -742,14 +744,19 @@ static int hpc_power_off_slot(struct slot * slot) * of command completions, since the power-fault bit remains on * till the slot is powered on again. */ - if (!pciehp_poll_mode) + if (!pciehp_poll_mode) { slot_cmd = (slot_cmd & ~PWR_FAULT_DETECT_ENABLE & ~MRL_DETECT_ENABLE & ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; + cmd_mask = cmd_mask | + PWR_FAULT_DETECT_ENABLE | + MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE | + HP_INTR_ENABLE; + } - retval = pcie_write_cmd(slot, slot_cmd); - + retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); return -1; @@ -769,6 +776,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) u16 temp_word; int hp_slot = 0; /* only 1 slot per PCI Express port */ int rc = 0; + unsigned long flags; rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { @@ -788,10 +796,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); /* Mask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { + spin_lock_irqsave(&ctrl->lock, flags); rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOT_CTRL register\n", __FUNCTION__); + spin_unlock_irqrestore(&ctrl->lock, flags); return IRQ_NONE; } @@ -802,8 +812,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + spin_unlock_irqrestore(&ctrl->lock, flags); return IRQ_NONE; } + spin_unlock_irqrestore(&ctrl->lock, flags); rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { @@ -853,10 +865,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) } /* Unmask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { + spin_lock_irqsave(&ctrl->lock, flags); rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + spin_unlock_irqrestore(&ctrl->lock, flags); return IRQ_NONE; } @@ -867,8 +881,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + spin_unlock_irqrestore(&ctrl->lock, flags); return IRQ_NONE; } + spin_unlock_irqrestore(&ctrl->lock, flags); rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { @@ -1152,7 +1168,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) int pcie_init(struct controller * ctrl, struct pcie_device *dev) { int rc; - static int first = 1; u16 temp_word; u16 cap_reg; u16 intr_enable = 0; @@ -1221,11 +1236,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - if (first) { - spin_lock_init(&hpc_event_lock); - first = 0; - } - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, @@ -1237,6 +1247,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); + spin_lock_init(&ctrl->lock); /* setup wait queue */ init_waitqueue_head(&ctrl->queue); @@ -1286,7 +1297,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", - __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); + __FUNCTION__, ctrl->pci_dev->irq, + atomic_read(&pciehp_num_controllers), rc); if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); @@ -1296,6 +1308,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); + /* + * If this is the first controller to be initialized, + * initialize the pciehp work queue + */ + if (atomic_add_return(1, &pciehp_num_controllers) == 1) { + pciehp_wq = create_singlethread_workqueue("pciehpd"); + if (!pciehp_wq) { + rc = -ENOMEM; + goto abort_free_irq; + } + } + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); @@ -1349,7 +1373,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) goto abort_disable_intr; } - ctlr_seq_num++; ctrl->hpc_ops = &pciehp_hpc_ops; DBG_LEAVE_ROUTINE