diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 7f8ae14cead7..2a487ae6de29 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -4584,10 +4584,41 @@ static irqreturn_t handle_wake_irq(int irq, void *data) return IRQ_HANDLED; } +static void msm_pcie_handle_linkdown(struct msm_pcie_dev_t *dev) +{ + int i; + + if (dev->link_status == MSM_PCIE_LINK_DOWN) + return; + + dev->link_status = MSM_PCIE_LINK_DOWN; + dev->shadow_en = false; + + /* assert PERST */ + if (!(msm_pcie_keep_resources_on & BIT(dev->rc_idx))) + gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, + dev->gpio[MSM_PCIE_GPIO_PERST].on); + + PCIE_ERR(dev, "PCIe link is down for RC%d\n", dev->rc_idx); + + if (dev->linkdown_panic) + panic("User has chosen to panic on linkdown\n"); + + if (dev->num_ep > 1) { + for (i = 0; i < MAX_DEVICE_NUM; i++) { + dev->event_reg = + dev->pcidev_table[i].event_reg; + msm_pcie_notify_client(dev, + MSM_PCIE_EVENT_LINKDOWN); + } + } else { + msm_pcie_notify_client(dev, MSM_PCIE_EVENT_LINKDOWN); + } +} + static irqreturn_t handle_linkdown_irq(int irq, void *data) { struct msm_pcie_dev_t *dev = data; - int i; dev->linkdown_counter++; @@ -4595,39 +4626,16 @@ static irqreturn_t handle_linkdown_irq(int irq, void *data) "PCIe: No. %ld linkdown IRQ for RC%d.\n", dev->linkdown_counter, dev->rc_idx); - if (!dev->enumerated || dev->link_status != MSM_PCIE_LINK_ENABLED) { + if (!dev->enumerated || dev->link_status != MSM_PCIE_LINK_ENABLED) PCIE_DBG(dev, "PCIe:Linkdown IRQ for RC%d when the link is not enabled\n", dev->rc_idx); - } else if (dev->suspending) { + else if (dev->suspending) PCIE_DBG(dev, "PCIe:the link of RC%d is suspending.\n", dev->rc_idx); - } else { - dev->link_status = MSM_PCIE_LINK_DOWN; - dev->shadow_en = false; - - if (dev->linkdown_panic) - panic("User has chosen to panic on linkdown\n"); - - /* assert PERST */ - if (!(msm_pcie_keep_resources_on & BIT(dev->rc_idx))) - gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num, - dev->gpio[MSM_PCIE_GPIO_PERST].on); - - PCIE_ERR(dev, "PCIe link is down for RC%d\n", dev->rc_idx); - - if (dev->num_ep > 1) { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - dev->event_reg = - dev->pcidev_table[i].event_reg; - msm_pcie_notify_client(dev, - MSM_PCIE_EVENT_LINKDOWN); - } - } else { - msm_pcie_notify_client(dev, MSM_PCIE_EVENT_LINKDOWN); - } - } + else + msm_pcie_handle_linkdown(dev); return IRQ_HANDLED; } @@ -6827,6 +6835,7 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, int ret = 0; struct pci_dev *dev; u32 rc_idx = 0; + unsigned long flags; struct msm_pcie_dev_t *pcie_dev; if (!user) { @@ -6972,6 +6981,13 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock, msm_pcie_dev[rc_idx].irqsave_flags); break; + case MSM_PCIE_HANDLE_LINKDOWN: + PCIE_DBG(&msm_pcie_dev[rc_idx], + "User of RC%d requests handling link down.\n", rc_idx); + spin_lock_irqsave(&msm_pcie_dev[rc_idx].irq_lock, flags); + msm_pcie_handle_linkdown(pcie_dev); + spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].irq_lock, flags); + break; default: PCIE_ERR(&msm_pcie_dev[rc_idx], "PCIe: RC%d: unsupported pm operation:%d.\n", diff --git a/include/linux/msm_pcie.h b/include/linux/msm_pcie.h index 5a2a2ef92321..e92000fba656 100644 --- a/include/linux/msm_pcie.h +++ b/include/linux/msm_pcie.h @@ -21,6 +21,7 @@ enum msm_pcie_pm_opt { MSM_PCIE_RESUME, MSM_PCIE_DISABLE_PC, MSM_PCIE_ENABLE_PC, + MSM_PCIE_HANDLE_LINKDOWN, }; enum msm_pcie_event {