aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/fsl_pci.c
diff options
context:
space:
mode:
authorWang Dongsheng <dongsheng.wang@freescale.com>2014-03-19 23:19:37 -0400
committerScott Wood <scottwood@freescale.com>2014-03-19 23:37:44 -0400
commit48b16180d0d91324e5d2423c6d53d97bbe3dcc14 (patch)
tree522da33ee1abe3f0a3ed55a337756903cb7ea74e /arch/powerpc/sysdev/fsl_pci.c
parent093943735718a28d45dcfcc74a737ed39e402893 (diff)
fsl/pci: The new pci suspend/resume implementation
If we do nothing in suspend/resume, some platform PCIe ip-block can't guarantee the link back to L0 state from sleep, then, when we read the EP device will hang. Only we send pme turnoff message in pci controller suspend, and send pme exit message in resume, the link state will be normal. When we send pme turnoff message in pci controller suspend, the links will into l2/l3 ready, then, host cannot communicate with ep device, but pci-driver will call back EP device to save them state. So we need to change platform_driver->suspend/resume to syscore->suspend/resume. So the new suspend/resume implementation, send pme turnoff message in suspend, and send pme exit message in resume. And add a PME handler, to response PME & message interrupt. Change platform_driver->suspend/resume to syscore->suspend/resume. pci-driver will call back EP device, to save EP state in pci_pm_suspend_noirq, so we need to keep the link, until pci_pm_suspend_noirq finish. Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com> Signed-off-by: Scott Wood <scottwood@freescale.com>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_pci.c')
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c170
1 files changed, 146 insertions, 24 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 8cdd34482575..3f415e252ea5 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -22,10 +22,13 @@
22#include <linux/delay.h> 22#include <linux/delay.h>
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/interrupt.h>
25#include <linux/bootmem.h> 26#include <linux/bootmem.h>
26#include <linux/memblock.h> 27#include <linux/memblock.h>
27#include <linux/log2.h> 28#include <linux/log2.h>
28#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/suspend.h>
31#include <linux/syscore_ops.h>
29#include <linux/uaccess.h> 32#include <linux/uaccess.h>
30 33
31#include <asm/io.h> 34#include <asm/io.h>
@@ -1094,55 +1097,171 @@ void fsl_pci_assign_primary(void)
1094 } 1097 }
1095} 1098}
1096 1099
1097static int fsl_pci_probe(struct platform_device *pdev) 1100#ifdef CONFIG_PM_SLEEP
1101static irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id)
1098{ 1102{
1099 int ret; 1103 struct pci_controller *hose = dev_id;
1100 struct device_node *node; 1104 struct ccsr_pci __iomem *pci = hose->private_data;
1105 u32 dr;
1101 1106
1102 node = pdev->dev.of_node; 1107 dr = in_be32(&pci->pex_pme_mes_dr);
1103 ret = fsl_add_bridge(pdev, fsl_pci_primary == node); 1108 if (!dr)
1109 return IRQ_NONE;
1104 1110
1105 mpc85xx_pci_err_probe(pdev); 1111 out_be32(&pci->pex_pme_mes_dr, dr);
1106 1112
1107 return 0; 1113 return IRQ_HANDLED;
1108} 1114}
1109 1115
1110#ifdef CONFIG_PM 1116static int fsl_pci_pme_probe(struct pci_controller *hose)
1111static int fsl_pci_resume(struct device *dev)
1112{ 1117{
1113 struct pci_controller *hose; 1118 struct ccsr_pci __iomem *pci;
1114 struct resource pci_rsrc; 1119 struct pci_dev *dev;
1120 int pme_irq;
1121 int res;
1122 u16 pms;
1115 1123
1116 hose = pci_find_hose_for_OF_device(dev->of_node); 1124 /* Get hose's pci_dev */
1117 if (!hose) 1125 dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list);
1118 return -ENODEV; 1126
1127 /* PME Disable */
1128 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
1129 pms &= ~PCI_PM_CTRL_PME_ENABLE;
1130 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
1131
1132 pme_irq = irq_of_parse_and_map(hose->dn, 0);
1133 if (!pme_irq) {
1134 dev_err(&dev->dev, "Failed to map PME interrupt.\n");
1135
1136 return -ENXIO;
1137 }
1138
1139 res = devm_request_irq(hose->parent, pme_irq,
1140 fsl_pci_pme_handle,
1141 IRQF_SHARED,
1142 "[PCI] PME", hose);
1143 if (res < 0) {
1144 dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq);
1145 irq_dispose_mapping(pme_irq);
1119 1146
1120 if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
1121 dev_err(dev, "Get pci register base failed.");
1122 return -ENODEV; 1147 return -ENODEV;
1123 } 1148 }
1124 1149
1125 setup_pci_atmu(hose); 1150 pci = hose->private_data;
1151
1152 /* Enable PTOD, ENL23D & EXL23D */
1153 out_be32(&pci->pex_pme_mes_disr, 0);
1154 setbits32(&pci->pex_pme_mes_disr,
1155 PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
1156
1157 out_be32(&pci->pex_pme_mes_ier, 0);
1158 setbits32(&pci->pex_pme_mes_ier,
1159 PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
1160
1161 /* PME Enable */
1162 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
1163 pms |= PCI_PM_CTRL_PME_ENABLE;
1164 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
1126 1165
1127 return 0; 1166 return 0;
1128} 1167}
1129 1168
1130static const struct dev_pm_ops pci_pm_ops = { 1169static void send_pme_turnoff_message(struct pci_controller *hose)
1131 .resume = fsl_pci_resume, 1170{
1132}; 1171 struct ccsr_pci __iomem *pci = hose->private_data;
1172 u32 dr;
1173 int i;
1133 1174
1134#define PCI_PM_OPS (&pci_pm_ops) 1175 /* Send PME_Turn_Off Message Request */
1176 setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
1135 1177
1136#else 1178 /* Wait trun off done */
1179 for (i = 0; i < 150; i++) {
1180 dr = in_be32(&pci->pex_pme_mes_dr);
1181 if (dr) {
1182 out_be32(&pci->pex_pme_mes_dr, dr);
1183 break;
1184 }
1137 1185
1138#define PCI_PM_OPS NULL 1186 udelay(1000);
1187 }
1188}
1139 1189
1190static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
1191{
1192 send_pme_turnoff_message(hose);
1193}
1194
1195static int fsl_pci_syscore_suspend(void)
1196{
1197 struct pci_controller *hose, *tmp;
1198
1199 list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
1200 fsl_pci_syscore_do_suspend(hose);
1201
1202 return 0;
1203}
1204
1205static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
1206{
1207 struct ccsr_pci __iomem *pci = hose->private_data;
1208 u32 dr;
1209 int i;
1210
1211 /* Send Exit L2 State Message */
1212 setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
1213
1214 /* Wait exit done */
1215 for (i = 0; i < 150; i++) {
1216 dr = in_be32(&pci->pex_pme_mes_dr);
1217 if (dr) {
1218 out_be32(&pci->pex_pme_mes_dr, dr);
1219 break;
1220 }
1221
1222 udelay(1000);
1223 }
1224
1225 setup_pci_atmu(hose);
1226}
1227
1228static void fsl_pci_syscore_resume(void)
1229{
1230 struct pci_controller *hose, *tmp;
1231
1232 list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
1233 fsl_pci_syscore_do_resume(hose);
1234}
1235
1236static struct syscore_ops pci_syscore_pm_ops = {
1237 .suspend = fsl_pci_syscore_suspend,
1238 .resume = fsl_pci_syscore_resume,
1239};
1140#endif 1240#endif
1141 1241
1242void fsl_pcibios_fixup_phb(struct pci_controller *phb)
1243{
1244#ifdef CONFIG_PM_SLEEP
1245 fsl_pci_pme_probe(phb);
1246#endif
1247}
1248
1249static int fsl_pci_probe(struct platform_device *pdev)
1250{
1251 struct device_node *node;
1252 int ret;
1253
1254 node = pdev->dev.of_node;
1255 ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
1256
1257 mpc85xx_pci_err_probe(pdev);
1258
1259 return 0;
1260}
1261
1142static struct platform_driver fsl_pci_driver = { 1262static struct platform_driver fsl_pci_driver = {
1143 .driver = { 1263 .driver = {
1144 .name = "fsl-pci", 1264 .name = "fsl-pci",
1145 .pm = PCI_PM_OPS,
1146 .of_match_table = pci_ids, 1265 .of_match_table = pci_ids,
1147 }, 1266 },
1148 .probe = fsl_pci_probe, 1267 .probe = fsl_pci_probe,
@@ -1150,6 +1269,9 @@ static struct platform_driver fsl_pci_driver = {
1150 1269
1151static int __init fsl_pci_init(void) 1270static int __init fsl_pci_init(void)
1152{ 1271{
1272#ifdef CONFIG_PM_SLEEP
1273 register_syscore_ops(&pci_syscore_pm_ops);
1274#endif
1153 return platform_driver_register(&fsl_pci_driver); 1275 return platform_driver_register(&fsl_pci_driver);
1154} 1276}
1155arch_initcall(fsl_pci_init); 1277arch_initcall(fsl_pci_init);