diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 70dffb8388ef..06b5648111a3 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -631,13 +631,12 @@ struct msm_pcie_sid_info_t { /* PCIe device info structure */ struct msm_pcie_device_info { + struct list_head pcidev_node; u32 bdf; struct pci_dev *dev; short short_bdf; u32 sid; int domain; - struct msm_pcie_register_event *event_reg; - bool registered; }; /* DRV IPC command type */ @@ -844,9 +843,8 @@ struct msm_pcie_dev_t { uint64_t l23_rdy_poll_timeout; bool suspending; ulong wake_counter; - u32 num_active_ep; - u32 num_ep; - bool pending_ep_reg; + struct list_head enum_ep_list; + struct list_head susp_ep_list; u32 num_parf_testbus_sel; u32 phy_len; struct msm_pcie_phy_info_t *phy_sequence; @@ -858,7 +856,8 @@ struct msm_pcie_dev_t { u32 rc_shadow[PCIE_CONF_SPACE_DW]; bool shadow_en; bool bridge_found; - struct msm_pcie_register_event *event_reg; + struct list_head event_reg_list; + spinlock_t evt_reg_list_lock; bool power_on; void *ipc_log; void *ipc_log_long; @@ -1642,12 +1641,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->aux_clk_freq); PCIE_DBG_FS(dev, "user_suspend is %d\n", dev->user_suspend); - PCIE_DBG_FS(dev, "num_ep: %d\n", - dev->num_ep); - PCIE_DBG_FS(dev, "num_active_ep: %d\n", - dev->num_active_ep); - PCIE_DBG_FS(dev, "pending_ep_reg: %s\n", - dev->pending_ep_reg ? "true" : "false"); PCIE_DBG_FS(dev, "num_parf_testbus_sel is 0x%x", dev->num_parf_testbus_sel); PCIE_DBG_FS(dev, "phy_len is %d", @@ -2868,11 +2861,11 @@ static bool msm_pcie_check_ltssm_state(struct msm_pcie_dev_t *dev, u32 state) * @host_addr: - region start address on host * @host_end: - region end address (low 32 bit) on host, * upper 32 bits are same as for @host_addr - * @target_addr: - region start address on target + * @bdf: - bus:device:function */ static void msm_pcie_iatu_config(struct msm_pcie_dev_t *dev, int nr, u8 type, - unsigned long host_addr, u32 host_end, - unsigned long target_addr) + unsigned long host_addr, u32 host_end, + u32 bdf) { void __iomem *iatu_base = dev->iatu ? dev->iatu : dev->dm_core; @@ -2885,6 +2878,10 @@ static void msm_pcie_iatu_config(struct msm_pcie_dev_t *dev, int nr, u8 type, u32 iatu_ltar_offset; u32 iatu_utar_offset; + /* configure iATU only for endpoints */ + if (!bdf) + return; + if (dev->iatu) { iatu_viewport_offset = 0; iatu_ctrl1_offset = PCIE_IATU_CTRL1(nr); @@ -2905,25 +2902,6 @@ static void msm_pcie_iatu_config(struct msm_pcie_dev_t *dev, int nr, u8 type, iatu_utar_offset = PCIE20_PLR_IATU_UTAR; } - if (dev->shadow_en && iatu_viewport_offset) { - dev->rc_shadow[PCIE20_PLR_IATU_VIEWPORT / 4] = - nr; - dev->rc_shadow[PCIE20_PLR_IATU_CTRL1 / 4] = - type; - dev->rc_shadow[PCIE20_PLR_IATU_LBAR / 4] = - lower_32_bits(host_addr); - dev->rc_shadow[PCIE20_PLR_IATU_UBAR / 4] = - upper_32_bits(host_addr); - dev->rc_shadow[PCIE20_PLR_IATU_LAR / 4] = - host_end; - dev->rc_shadow[PCIE20_PLR_IATU_LTAR / 4] = - lower_32_bits(target_addr); - dev->rc_shadow[PCIE20_PLR_IATU_UTAR / 4] = - upper_32_bits(target_addr); - dev->rc_shadow[PCIE20_PLR_IATU_CTRL2 / 4] = - BIT(31); - } - /* select region */ if (iatu_viewport_offset) msm_pcie_write_reg(iatu_base, iatu_viewport_offset, nr); @@ -2937,36 +2915,9 @@ static void msm_pcie_iatu_config(struct msm_pcie_dev_t *dev, int nr, u8 type, msm_pcie_write_reg(iatu_base, iatu_ubar_offset, upper_32_bits(host_addr)); msm_pcie_write_reg(iatu_base, iatu_lar_offset, host_end); - msm_pcie_write_reg(iatu_base, iatu_ltar_offset, - lower_32_bits(target_addr)); - msm_pcie_write_reg(iatu_base, iatu_utar_offset, - upper_32_bits(target_addr)); + msm_pcie_write_reg(iatu_base, iatu_ltar_offset, lower_32_bits(bdf)); + msm_pcie_write_reg(iatu_base, iatu_utar_offset, 0); msm_pcie_write_reg(iatu_base, iatu_ctrl2_offset, BIT(31)); - - if (dev->enumerated) { - PCIE_DBG2(dev, "IATU for Endpoint %02x:%02x.%01x\n", - dev->pcidev_table[nr].bdf >> 24, - dev->pcidev_table[nr].bdf >> 19 & 0x1f, - dev->pcidev_table[nr].bdf >> 16 & 0x07); - if (iatu_viewport_offset) - PCIE_DBG2(dev, "IATU_VIEWPORT:0x%x\n", - readl_relaxed(dev->dm_core + - PCIE20_PLR_IATU_VIEWPORT)); - PCIE_DBG2(dev, "IATU_CTRL1:0x%x\n", - readl_relaxed(iatu_base + iatu_ctrl1_offset)); - PCIE_DBG2(dev, "IATU_LBAR:0x%x\n", - readl_relaxed(iatu_base + iatu_lbar_offset)); - PCIE_DBG2(dev, "IATU_UBAR:0x%x\n", - readl_relaxed(iatu_base + iatu_ubar_offset)); - PCIE_DBG2(dev, "IATU_LAR:0x%x\n", - readl_relaxed(iatu_base + iatu_lar_offset)); - PCIE_DBG2(dev, "IATU_LTAR:0x%x\n", - readl_relaxed(iatu_base + iatu_ltar_offset)); - PCIE_DBG2(dev, "IATU_UTAR:0x%x\n", - readl_relaxed(iatu_base + iatu_utar_offset)); - PCIE_DBG2(dev, "IATU_CTRL2:0x%x\n\n", - readl_relaxed(iatu_base + iatu_ctrl2_offset)); - } } /** @@ -4790,62 +4741,45 @@ static void msm_pcie_disable(struct msm_pcie_dev_t *dev) static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *) pdev; - int ret = 0; - u32 rc_idx = pcie_dev->rc_idx; - u32 i; - u32 bdf = 0; + struct msm_pcie_device_info *dev_info; + int ret; PCIE_DBG(pcie_dev, "PCI device found: vendor-id:0x%x device-id:0x%x\n", pcidev->vendor, pcidev->device); - if (!pcidev->bus->number) - return ret; + if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_ENDPOINT) { + dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); + if (!dev_info) + return -ENOMEM; - bdf = BDF_OFFSET(pcidev->bus->number, pcidev->devfn); + dev_info->dev = pcidev; + list_add_tail(&dev_info->pcidev_node, &pcie_dev->enum_ep_list); + } - for (i = 0; i < MAX_DEVICE_NUM; i++) { - struct msm_pcie_device_info *dev_table_t = - &pcie_dev->pcidev_table[i]; - - if (dev_table_t->bdf != bdf) - continue; - - dev_table_t->dev = pcidev; - dev_table_t->domain = rc_idx; - - if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_ENDPOINT) { - pcie_dev->num_ep++; - dev_table_t->registered = false; + /* for upstream port of a switch */ + if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_UPSTREAM) { + ret = pci_enable_device(pcidev); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: BDF 0x%04x pci_enable_device failed\n", + PCI_DEVID(pcidev->bus->number, pcidev->devfn)); + return ret; } + pci_set_master(pcidev); + } - if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_UPSTREAM) - pci_set_master(pcidev); - - if (pcie_dev->num_ep > 1) - pcie_dev->pending_ep_reg = true; - - if (pcie_dev->aer_enable) { + if (pcie_dev->aer_enable) { #ifdef CONFIG_PCI_QTI - if (pci_enable_pcie_error_reporting(pcidev)) - PCIE_ERR(pcie_dev, - "PCIe: RC%d: PCIE error reporting unavailable on %02x:%02x:%01x\n", - pcie_dev->rc_idx, pcidev->bus->number, - PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn)); + if (pci_enable_pcie_error_reporting(pcidev)) + PCIE_ERR(pcie_dev, + "PCIe: RC%d: PCIE error reporting unavailable on %02x:%02x:%01x\n", + pcie_dev->rc_idx, pcidev->bus->number, + PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn)); #endif - } - - break; } - if (i == MAX_DEVICE_NUM) { - PCIE_ERR(pcie_dev, - "PCIe: RC%d: could not find device in the table: %02x:%02x:%01x\n", - pcie_dev->rc_idx, pcidev->bus->number, - PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn)); - ret = -ENODEV; - } - return ret; + return 0; } static void msm_pcie_config_sid(struct msm_pcie_dev_t *dev) @@ -5059,37 +4993,38 @@ EXPORT_SYMBOL(msm_pcie_enumerate); static void msm_pcie_notify_client(struct msm_pcie_dev_t *dev, enum msm_pcie_event event) { - if (dev->event_reg && dev->event_reg->callback && - (dev->event_reg->events & event)) { - struct msm_pcie_notify *notify = &dev->event_reg->notify; - struct msm_pcie_notify client_notify; + struct msm_pcie_register_event *reg_itr; + struct msm_pcie_notify *notify; + struct msm_pcie_notify client_notify; - client_notify.event = event; - client_notify.user = dev->event_reg->user; - client_notify.data = notify->data; - client_notify.options = notify->options; - PCIE_DUMP(dev, "PCIe: callback RC%d for event %d\n", - dev->rc_idx, event); - dev->event_reg->callback(&client_notify); + spin_lock(&dev->evt_reg_list_lock); + list_for_each_entry(reg_itr, &dev->event_reg_list, node) { + if ((reg_itr->events & event) && reg_itr->callback) { + notify = ®_itr->notify; + client_notify.event = event; + client_notify.user = reg_itr->user; + client_notify.data = notify->data; + client_notify.options = notify->options; + PCIE_DUMP(dev, "PCIe: callback RC%d for event %d\n", + dev->rc_idx, event); + reg_itr->callback(&client_notify); - if ((dev->event_reg->options & MSM_PCIE_CONFIG_NO_RECOVERY) && - (event == MSM_PCIE_EVENT_LINKDOWN)) { - dev->user_suspend = true; - PCIE_DBG(dev, - "PCIe: Client of RC%d will recover the link later.\n", - dev->rc_idx); - return; + if ((reg_itr->options & MSM_PCIE_CONFIG_NO_RECOVERY) && + (event == MSM_PCIE_EVENT_LINKDOWN)) { + dev->user_suspend = true; + PCIE_DBG(dev, + "PCIe: Client of RC%d will recover the link later.\n", + dev->rc_idx); + } + + break; } - } else { - PCIE_DBG2(dev, - "PCIe: Client of RC%d does not have registration for event %d\n", - dev->rc_idx, event); } + spin_unlock(&dev->evt_reg_list_lock); } static void handle_wake_func(struct work_struct *work) { - int i, ret; struct msm_pcie_dev_t *dev = container_of(work, struct msm_pcie_dev_t, handle_wake_work); @@ -5097,65 +5032,26 @@ static void handle_wake_func(struct work_struct *work) mutex_lock(&dev->recovery_lock); - if (!dev->enumerated) { - PCIE_DBG(dev, - "PCIe: Start enumeration for RC%d upon the wake from endpoint.\n", - dev->rc_idx); - - ret = msm_pcie_enumerate(dev->rc_idx); - if (ret) { - PCIE_ERR(dev, - "PCIe: failed to enable RC%d upon wake request from the device.\n", - dev->rc_idx); - goto out; - } - - if (dev->num_ep > 1) { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - dev->event_reg = dev->pcidev_table[i].event_reg; - - if ((dev->link_status == MSM_PCIE_LINK_ENABLED) - && dev->event_reg && - dev->event_reg->callback && - (dev->event_reg->events & - MSM_PCIE_EVENT_LINKUP)) { - struct msm_pcie_notify *notify = - &dev->event_reg->notify; - notify->event = MSM_PCIE_EVENT_LINKUP; - notify->user = dev->event_reg->user; - PCIE_DBG(dev, - "PCIe: Linkup callback for RC%d after enumeration is successful in wake IRQ handling\n", - dev->rc_idx); - dev->event_reg->callback(notify); - } - } - } else { - if ((dev->link_status == MSM_PCIE_LINK_ENABLED) && - dev->event_reg && dev->event_reg->callback && - (dev->event_reg->events & - MSM_PCIE_EVENT_LINKUP)) { - struct msm_pcie_notify *notify = - &dev->event_reg->notify; - notify->event = MSM_PCIE_EVENT_LINKUP; - notify->user = dev->event_reg->user; - PCIE_DBG(dev, - "PCIe: Linkup callback for RC%d after enumeration is successful in wake IRQ handling\n", - dev->rc_idx); - dev->event_reg->callback(notify); - } else { - PCIE_DBG(dev, - "PCIe: Client of RC%d does not have registration for linkup event.\n", - dev->rc_idx); - } - } - goto out; - } else { + if (dev->enumerated) { PCIE_ERR(dev, - "PCIe: The enumeration for RC%d has already been done.\n", - dev->rc_idx); + "PCIe: The enumeration for RC%d has already been done.\n", + dev->rc_idx); goto out; } + PCIE_DBG(dev, + "PCIe: Start enumeration for RC%d upon the wake from endpoint.\n", + dev->rc_idx); + + if (msm_pcie_enumerate(dev->rc_idx)) { + PCIE_ERR(dev, + "PCIe: failed to enable RC%d upon wake request from the device.\n", + dev->rc_idx); + goto out; + } + + msm_pcie_notify_client(dev, MSM_PCIE_EVENT_LINKUP); + out: mutex_unlock(&dev->recovery_lock); } @@ -5314,7 +5210,6 @@ static irqreturn_t handle_wake_irq(int irq, void *data) { struct msm_pcie_dev_t *dev = data; unsigned long irqsave_flags; - int i; spin_lock_irqsave(&dev->irq_lock, irqsave_flags); @@ -5334,23 +5229,14 @@ static irqreturn_t handle_wake_irq(int irq, void *data) __pm_stay_awake(dev->ws); __pm_relax(dev->ws); - 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_WAKEUP); - } - } else { - if (dev->drv_supported && !dev->suspending && - dev->link_status == MSM_PCIE_LINK_ENABLED) { - pcie_phy_dump(dev); - pcie_parf_dump(dev); - pcie_dm_core_dump(dev); - } - - msm_pcie_notify_client(dev, MSM_PCIE_EVENT_WAKEUP); + if (dev->drv_supported && !dev->suspending && + dev->link_status == MSM_PCIE_LINK_ENABLED) { + pcie_phy_dump(dev); + pcie_parf_dump(dev); + pcie_dm_core_dump(dev); } + + msm_pcie_notify_client(dev, MSM_PCIE_EVENT_WAKEUP); } spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags); @@ -5360,8 +5246,6 @@ static irqreturn_t handle_wake_irq(int irq, void *data) static void msm_pcie_handle_linkdown(struct msm_pcie_dev_t *dev) { - int i; - if (dev->link_status == MSM_PCIE_LINK_DOWN) return; @@ -5387,16 +5271,7 @@ static void msm_pcie_handle_linkdown(struct msm_pcie_dev_t *dev) 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); - } + msm_pcie_notify_client(dev, MSM_PCIE_EVENT_LINKDOWN); } static irqreturn_t handle_linkdown_irq(int irq, void *data) @@ -6349,9 +6224,6 @@ static int msm_pcie_probe(struct platform_device *pdev) pcie_dev->pcidev_table[i].dev = NULL; pcie_dev->pcidev_table[i].short_bdf = 0; pcie_dev->pcidev_table[i].sid = 0; - pcie_dev->pcidev_table[i].domain = rc_idx; - pcie_dev->pcidev_table[i].event_reg = NULL; - pcie_dev->pcidev_table[i].registered = true; } dev_set_drvdata(&pdev->dev, pcie_dev); @@ -6476,6 +6348,7 @@ static int msm_pcie_remove(struct platform_device *pdev) { int ret = 0; int rc_idx; + struct msm_pcie_device_info *dev_info; mutex_lock(&pcie_drv.drv_lock); @@ -6495,6 +6368,18 @@ static int msm_pcie_remove(struct platform_device *pdev) msm_pcie_gpio_deinit(&msm_pcie_dev[rc_idx]); msm_pcie_release_resources(&msm_pcie_dev[rc_idx]); + list_for_each_entry(dev_info, &msm_pcie_dev[rc_idx].enum_ep_list, + pcidev_node) { + list_del(&dev_info->pcidev_node); + kfree(dev_info); + } + + list_for_each_entry(dev_info, &msm_pcie_dev[rc_idx].susp_ep_list, + pcidev_node) { + list_del(&dev_info->pcidev_node); + kfree(dev_info); + } + out: mutex_unlock(&pcie_drv.drv_lock); @@ -6923,8 +6808,6 @@ static void msm_pcie_drv_notify_client(struct pcie_drv_sta *pcie_drv, for (i = 0; i < MAX_RC_NUM; i++, pcie_dev++) { struct msm_pcie_drv_info *drv_info = pcie_dev->drv_info; - struct msm_pcie_register_event *event_reg = - pcie_dev->event_reg; PCIE_DBG(pcie_dev, "PCIe: RC%d: event %d received\n", pcie_dev->rc_idx, event); @@ -6933,9 +6816,6 @@ static void msm_pcie_drv_notify_client(struct pcie_drv_sta *pcie_drv, if (!drv_info) continue; - if (!event_reg || !(event_reg->events & event)) - continue; - if (drv_info->ep_connected) { msm_pcie_notify_client(pcie_dev, event); if (event & MSM_PCIE_EVENT_DRV_DISCONNECT) { @@ -7106,21 +6986,11 @@ static void msm_pcie_drv_connect_worker(struct work_struct *work) for (i = 0; i < MAX_RC_NUM; i++, pcie_dev++) { struct msm_pcie_drv_info *drv_info = pcie_dev->drv_info; - struct msm_pcie_register_event *event_reg = - pcie_dev->event_reg; /* does not support DRV or has not been probed yet */ if (!drv_info || drv_info->ep_connected) continue; - /* no DRV support over a switch */ - if (pcie_dev->num_ep != 1) - continue; - - if (!event_reg || - !(event_reg->events & MSM_PCIE_EVENT_DRV_CONNECT)) - continue; - msm_pcie_notify_client(pcie_dev, MSM_PCIE_EVENT_DRV_CONNECT); @@ -7245,6 +7115,7 @@ static int __init pcie_init(void) "PCIe IPC logging %s is enable for RC%d\n", rc_name, i); spin_lock_init(&msm_pcie_dev[i].cfg_lock); + spin_lock_init(&msm_pcie_dev[i].evt_reg_list_lock); msm_pcie_dev[i].cfg_access = true; mutex_init(&msm_pcie_dev[i].enumerate_lock); mutex_init(&msm_pcie_dev[i].setup_lock); @@ -7258,6 +7129,9 @@ static int __init pcie_init(void) msm_pcie_drv_disable_pc); INIT_WORK(&msm_pcie_dev[i].drv_enable_pc_work, msm_pcie_drv_enable_pc); + INIT_LIST_HEAD(&msm_pcie_dev[i].enum_ep_list); + INIT_LIST_HEAD(&msm_pcie_dev[i].susp_ep_list); + INIT_LIST_HEAD(&msm_pcie_dev[i].event_reg_list); } if (i2c_add_driver(&pcie_i2c_ctrl_driver)) @@ -7877,9 +7751,10 @@ 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; + struct msm_pcie_device_info *dev_info_itr, *dev_info = NULL; + struct pci_dev *pcidev; if (!user) { pr_err("PCIe: endpoint device is NULL\n"); @@ -7890,10 +7765,9 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, pcie_dev = PCIE_BUS_PRIV_DATA(((struct pci_dev *)user)->bus); if (pcie_dev) { - rc_idx = pcie_dev->rc_idx; PCIE_DBG(pcie_dev, - "PCIe: RC%d: pm_opt:%d;busnr:%d;options:%d\n", - rc_idx, pm_opt, busnr, options); + "PCIe: RC%d: pm_opt:%d;busnr:%d;options:%d\n", + pcie_dev->rc_idx, pm_opt, busnr, options); } else { pr_err( "PCIe: did not find RC for pci endpoint device.\n" @@ -7902,20 +7776,22 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, goto out; } - dev = msm_pcie_dev[rc_idx].dev; + dev = pcie_dev->dev; - if (!msm_pcie_dev[rc_idx].drv_ready) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "RC%d has not been successfully probed yet\n", - rc_idx); + pcidev = (struct pci_dev *)user; + + if (!pcie_dev->drv_ready) { + PCIE_ERR(pcie_dev, + "RC%d has not been successfully probed yet\n", + pcie_dev->rc_idx); return -EPROBE_DEFER; } switch (pm_opt) { case MSM_PCIE_DRV_SUSPEND: PCIE_DBG(pcie_dev, - "PCIe: RC%d: DRV: user requests for DRV suspend\n", - rc_idx); + "PCIe: RC%d: DRV: user requests for DRV suspend\n", + pcie_dev->rc_idx); /* make sure disable pc is done before enabling drv */ flush_work(&pcie_dev->drv_disable_pc_work); @@ -7923,51 +7799,80 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, ret = msm_pcie_drv_suspend(pcie_dev, options); break; case MSM_PCIE_SUSPEND: - PCIE_DBG(&msm_pcie_dev[rc_idx], - "User of RC%d requests to suspend the link\n", rc_idx); - if (msm_pcie_dev[rc_idx].link_status != MSM_PCIE_LINK_ENABLED) - PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: requested to suspend when link is not enabled:%d.\n", - rc_idx, msm_pcie_dev[rc_idx].link_status); - - if (!msm_pcie_dev[rc_idx].power_on) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: requested to suspend when link is powered down:%d.\n", - rc_idx, msm_pcie_dev[rc_idx].link_status); - break; - } - - if (msm_pcie_dev[rc_idx].pending_ep_reg) { - PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: request to suspend the link is rejected\n", - rc_idx); - break; - } - - if (pcie_dev->num_active_ep) { + PCIE_DBG(pcie_dev, + "User of RC%d requests to suspend the link\n", + pcie_dev->rc_idx); + if (pcie_dev->link_status != MSM_PCIE_LINK_ENABLED) PCIE_DBG(pcie_dev, - "RC%d: an EP requested to suspend the link, but other EPs are still active: %d\n", - pcie_dev->rc_idx, pcie_dev->num_active_ep); - return ret; + "PCIe: RC%d: requested to suspend when link is not enabled:%d.\n", + pcie_dev->rc_idx, pcie_dev->link_status); + + if (!pcie_dev->power_on) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: requested to suspend when link is powered down:%d.\n", + pcie_dev->rc_idx, pcie_dev->link_status); + break; } - msm_pcie_dev[rc_idx].user_suspend = true; + mutex_lock(&pcie_dev->enumerate_lock); - mutex_lock(&msm_pcie_dev[rc_idx].recovery_lock); + /* + * Remove current user requesting for suspend from ep list and + * add it to suspend ep list. Reject susp if list is still not + * empty. + */ + list_for_each_entry(dev_info_itr, &pcie_dev->enum_ep_list, + pcidev_node) { + if (dev_info_itr->dev == pcidev) { + list_del(&dev_info_itr->pcidev_node); + dev_info = dev_info_itr; + list_add_tail(&dev_info->pcidev_node, + &pcie_dev->susp_ep_list); + break; + } + } + + if (!dev_info) + PCIE_DBG(pcie_dev, + "PCIe: RC%d: ep BDF 0x%04x not in enum list\n", + pcie_dev->rc_idx, PCI_DEVID( + pcidev->bus->number, + pcidev->devfn)); + + if (!list_empty(&pcie_dev->enum_ep_list)) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: request to suspend the link is rejected\n", + pcie_dev->rc_idx); + mutex_unlock(&pcie_dev->enumerate_lock); + break; + } + + pcie_dev->user_suspend = true; + + mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_suspend(dev, user, data, options); if (ret) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: user failed to suspend the link.\n", - rc_idx); - msm_pcie_dev[rc_idx].user_suspend = false; + PCIE_ERR(pcie_dev, + "PCIe: RC%d: user failed to suspend the link.\n", + pcie_dev->rc_idx); + pcie_dev->user_suspend = false; + + if (dev_info) { + list_del(&dev_info->pcidev_node); + list_add_tail(&dev_info->pcidev_node, + &pcie_dev->enum_ep_list); + } } - mutex_unlock(&msm_pcie_dev[rc_idx].recovery_lock); + mutex_unlock(&pcie_dev->recovery_lock); + + mutex_unlock(&pcie_dev->enumerate_lock); break; case MSM_PCIE_RESUME: - PCIE_DBG(&msm_pcie_dev[rc_idx], - "User of RC%d requests to resume the link\n", rc_idx); + PCIE_DBG(pcie_dev, + "User of RC%d requests to resume the link\n", + pcie_dev->rc_idx); /* DRV resume */ if (pcie_dev->link_status == MSM_PCIE_LINK_DRV) { @@ -7975,68 +7880,97 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, break; } - if (msm_pcie_dev[rc_idx].power_on) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: requested to resume when link is already powered on. Number of active EP(s): %d\n", - rc_idx, msm_pcie_dev[rc_idx].num_active_ep); + /* when link was suspended and link resume is requested */ + mutex_lock(&pcie_dev->enumerate_lock); + list_for_each_entry(dev_info_itr, &pcie_dev->susp_ep_list, + pcidev_node) { + if (dev_info_itr->dev == user) { + list_del(&dev_info_itr->pcidev_node); + dev_info = dev_info_itr; + list_add_tail(&dev_info->pcidev_node, + &pcie_dev->enum_ep_list); + break; + } + } + + if (!dev_info) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: ep BDF 0x%04x not in susp list\n", + pcie_dev->rc_idx, PCI_DEVID( + pcidev->bus->number, + pcidev->devfn)); + } + mutex_unlock(&pcie_dev->enumerate_lock); + + if (pcie_dev->power_on) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: requested to resume when link is already powered on.\n", + pcie_dev->rc_idx); break; } - mutex_lock(&msm_pcie_dev[rc_idx].recovery_lock); + mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_resume(dev, user, data, options); if (ret) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: user failed to resume the link.\n", - rc_idx); - } else { - PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: user succeeded to resume the link.\n", - rc_idx); + PCIE_ERR(pcie_dev, + "PCIe: RC%d: user failed to resume the link.\n", + pcie_dev->rc_idx); - msm_pcie_dev[rc_idx].user_suspend = false; + mutex_lock(&pcie_dev->enumerate_lock); + if (dev_info) { + list_del(&dev_info->pcidev_node); + list_add_tail(&dev_info->pcidev_node, + &pcie_dev->susp_ep_list); + } + mutex_unlock(&pcie_dev->enumerate_lock); + } else { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: user succeeded to resume the link.\n", + pcie_dev->rc_idx); + + pcie_dev->user_suspend = false; } - mutex_unlock(&msm_pcie_dev[rc_idx].recovery_lock); + mutex_unlock(&pcie_dev->recovery_lock); break; case MSM_PCIE_DISABLE_PC: - PCIE_DBG(&msm_pcie_dev[rc_idx], - "User of RC%d requests to keep the link always alive.\n", - rc_idx); - spin_lock_irqsave(&msm_pcie_dev[rc_idx].cfg_lock, - msm_pcie_dev[rc_idx].irqsave_flags); - if (msm_pcie_dev[rc_idx].suspending) { - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d Link has been suspended before request\n", - rc_idx); + PCIE_DBG(pcie_dev, + "User of RC%d requests to keep the link always alive.\n", + pcie_dev->rc_idx); + spin_lock_irqsave(&pcie_dev->cfg_lock, pcie_dev->irqsave_flags); + if (pcie_dev->suspending) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d Link has been suspended before request\n", + pcie_dev->rc_idx); ret = MSM_PCIE_ERROR; } else { - msm_pcie_dev[rc_idx].disable_pc = true; + pcie_dev->disable_pc = true; } - spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock, - msm_pcie_dev[rc_idx].irqsave_flags); + spin_unlock_irqrestore(&pcie_dev->cfg_lock, + pcie_dev->irqsave_flags); break; case MSM_PCIE_ENABLE_PC: - PCIE_DBG(&msm_pcie_dev[rc_idx], - "User of RC%d cancels the request of alive link.\n", - rc_idx); - spin_lock_irqsave(&msm_pcie_dev[rc_idx].cfg_lock, - msm_pcie_dev[rc_idx].irqsave_flags); - msm_pcie_dev[rc_idx].disable_pc = false; - spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock, - msm_pcie_dev[rc_idx].irqsave_flags); + PCIE_DBG(pcie_dev, + "User of RC%d cancels the request of alive link.\n", + pcie_dev->rc_idx); + spin_lock_irqsave(&pcie_dev->cfg_lock, pcie_dev->irqsave_flags); + pcie_dev->disable_pc = false; + spin_unlock_irqrestore(&pcie_dev->cfg_lock, + pcie_dev->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); + PCIE_DBG(pcie_dev, + "User of RC%d requests handling link down.\n", + pcie_dev->rc_idx); + spin_lock_irqsave(&pcie_dev->irq_lock, flags); msm_pcie_handle_linkdown(pcie_dev); - spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].irq_lock, flags); + spin_unlock_irqrestore(&pcie_dev->irq_lock, flags); break; case MSM_PCIE_DRV_PC_CTRL: - PCIE_DBG(&msm_pcie_dev[rc_idx], - "User of RC%d requests handling drv pc options %u.\n", - rc_idx, options); + PCIE_DBG(pcie_dev, + "User of RC%d requests handling drv pc options %u.\n", + pcie_dev->rc_idx, options); mutex_lock(&pcie_dev->drv_pc_lock); pcie_dev->drv_disable_pc_vote = @@ -8058,9 +7992,9 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, mutex_unlock(&pcie_dev->drv_pc_lock); break; default: - PCIE_ERR(&msm_pcie_dev[rc_idx], - "PCIe: RC%d: unsupported pm operation:%d.\n", - rc_idx, pm_opt); + PCIE_ERR(pcie_dev, + "PCIe: RC%d: unsupported pm operation:%d.\n", + pcie_dev->rc_idx, pm_opt); ret = -ENODEV; goto out; } @@ -8088,8 +8022,10 @@ EXPORT_SYMBOL(msm_pcie_l1ss_timeout_enable); int msm_pcie_register_event(struct msm_pcie_register_event *reg) { - int i, ret = 0; + int ret = 0; struct msm_pcie_dev_t *pcie_dev; + struct msm_pcie_register_event *reg_itr; + struct pci_dev *pcidev; if (!reg) { pr_err("PCIe: Event registration is NULL\n"); @@ -8104,56 +8040,28 @@ int msm_pcie_register_event(struct msm_pcie_register_event *reg) pcie_dev = PCIE_BUS_PRIV_DATA(((struct pci_dev *)reg->user)->bus); if (!pcie_dev) { - PCIE_ERR(pcie_dev, "%s", - "PCIe: did not find RC for pci endpoint device.\n"); + pr_err("PCIe: did not find RC for pci endpoint device.\n"); return -ENODEV; } - if (pcie_dev->num_ep > 1) { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (reg->user == - pcie_dev->pcidev_table[i].dev) { - pcie_dev->event_reg = - pcie_dev->pcidev_table[i].event_reg; + pcidev = (struct pci_dev *)reg->user; - if (!pcie_dev->event_reg) { - pcie_dev->pcidev_table[i].registered = - true; - - pcie_dev->num_active_ep++; - PCIE_DBG(pcie_dev, - "PCIe: RC%d: number of active EP(s): %d.\n", - pcie_dev->rc_idx, - pcie_dev->num_active_ep); - } - - pcie_dev->event_reg = reg; - pcie_dev->pcidev_table[i].event_reg = reg; - PCIE_DBG(pcie_dev, - "Event 0x%x is registered for RC %d\n", - reg->events, - pcie_dev->rc_idx); - - break; - } + spin_lock(&pcie_dev->evt_reg_list_lock); + list_for_each_entry(reg_itr, &pcie_dev->event_reg_list, node) { + if (reg_itr->user == reg->user) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: EP BDF 0x%4x already registered\n", + pcie_dev->rc_idx, + PCI_DEVID(pcidev->bus->number, pcidev->devfn)); + spin_unlock(&pcie_dev->evt_reg_list_lock); + return -EEXIST; } - - if (pcie_dev->pending_ep_reg) { - for (i = 0; i < MAX_DEVICE_NUM; i++) - if (!pcie_dev->pcidev_table[i].registered) - break; - - if (i == MAX_DEVICE_NUM) - pcie_dev->pending_ep_reg = false; - } - } else { - pcie_dev->event_reg = reg; - PCIE_DBG(pcie_dev, - "Event 0x%x is registered for RC %d\n", reg->events, - pcie_dev->rc_idx); - - schedule_work(&pcie_drv.drv_connect); } + list_add_tail(®->node, &pcie_dev->event_reg_list); + spin_unlock(&pcie_dev->evt_reg_list_lock); + + if (pcie_dev->drv_supported) + schedule_work(&pcie_drv.drv_connect); return ret; } @@ -8161,8 +8069,9 @@ EXPORT_SYMBOL(msm_pcie_register_event); int msm_pcie_deregister_event(struct msm_pcie_register_event *reg) { - int i, ret = 0; struct msm_pcie_dev_t *pcie_dev; + struct pci_dev *pcidev; + struct msm_pcie_register_event *reg_itr; if (!reg) { pr_err("PCIe: Event deregistration is NULL\n"); @@ -8182,33 +8091,28 @@ int msm_pcie_deregister_event(struct msm_pcie_register_event *reg) return -ENODEV; } - if (pcie_dev->num_ep > 1) { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (reg->user == pcie_dev->pcidev_table[i].dev) { - if (pcie_dev->pcidev_table[i].event_reg) { - pcie_dev->num_active_ep--; - PCIE_DBG(pcie_dev, - "PCIe: RC%d: number of active EP(s) left: %d.\n", - pcie_dev->rc_idx, - pcie_dev->num_active_ep); - } + pcidev = (struct pci_dev *)reg->user; - pcie_dev->event_reg = NULL; - pcie_dev->pcidev_table[i].event_reg = NULL; - PCIE_DBG(pcie_dev, - "Event is deregistered for RC %d\n", - pcie_dev->rc_idx); - - break; - } + spin_lock(&pcie_dev->evt_reg_list_lock); + list_for_each_entry(reg_itr, &pcie_dev->event_reg_list, node) { + if (reg_itr->user == reg->user) { + list_del(®->node); + spin_unlock(&pcie_dev->evt_reg_list_lock); + PCIE_DBG(pcie_dev, + "PCIe: RC%d: Event deregistered for BDF 0x%04x\n", + pcie_dev->rc_idx, + PCI_DEVID(pcidev->bus->number, pcidev->devfn)); + return 0; } - } else { - pcie_dev->event_reg = NULL; - PCIE_DBG(pcie_dev, "Event is deregistered for RC %d\n", - pcie_dev->rc_idx); } + spin_unlock(&pcie_dev->evt_reg_list_lock); - return ret; + PCIE_DBG(pcie_dev, + "PCIe: RC%d: Failed to deregister event for BDF 0x%04x\n", + pcie_dev->rc_idx, + PCI_DEVID(pcidev->bus->number, pcidev->devfn)); + + return -EINVAL; } EXPORT_SYMBOL(msm_pcie_deregister_event); diff --git a/include/linux/msm_pcie.h b/include/linux/msm_pcie.h index 80c6d70ba900..6910eb4c76cf 100644 --- a/include/linux/msm_pcie.h +++ b/include/linux/msm_pcie.h @@ -49,6 +49,7 @@ struct msm_pcie_notify { }; struct msm_pcie_register_event { + struct list_head node; u32 events; void *user; enum msm_pcie_trigger mode;