aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorTony Breeds <tony@bakeyournoodle.com>2011-06-30 16:44:24 -0400
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2011-07-12 09:03:23 -0400
commit112d1fe9f7715db423ffeec5ac1beccff6093dc4 (patch)
treece89fe15078e2d53e65db8654bd21f58fd78b97b /arch/powerpc/sysdev
parentaf9719c3062dfe216a0c3de3fa52be6d22b4456c (diff)
powerpc/4xx: Add check_link to struct ppc4xx_pciex_hwops
All current pcie controllers unconditionally use SDR to check the link and poll for reset. Refactor the code to include device reset in the port_init_hw() op and add a new check_link() op. This will make room fro new controllers that do not use SDR for these operations. Tested on 460ex. Signed-off-by: Tony Breeds <tony@bakeyournoodle.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c148
1 files changed, 83 insertions, 65 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 156aa7d36258..ad330fe69c26 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -650,12 +650,75 @@ struct ppc4xx_pciex_hwops
650 int (*core_init)(struct device_node *np); 650 int (*core_init)(struct device_node *np);
651 int (*port_init_hw)(struct ppc4xx_pciex_port *port); 651 int (*port_init_hw)(struct ppc4xx_pciex_port *port);
652 int (*setup_utl)(struct ppc4xx_pciex_port *port); 652 int (*setup_utl)(struct ppc4xx_pciex_port *port);
653 void (*check_link)(struct ppc4xx_pciex_port *port);
653}; 654};
654 655
655static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; 656static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
656 657
657#ifdef CONFIG_44x 658#ifdef CONFIG_44x
658 659
660static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
661 unsigned int sdr_offset,
662 unsigned int mask,
663 unsigned int value,
664 int timeout_ms)
665{
666 u32 val;
667
668 while(timeout_ms--) {
669 val = mfdcri(SDR0, port->sdr_base + sdr_offset);
670 if ((val & mask) == value) {
671 pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
672 port->index, sdr_offset, timeout_ms, val);
673 return 0;
674 }
675 msleep(1);
676 }
677 return -1;
678}
679
680static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port)
681{
682 printk(KERN_INFO "PCIE%d: Checking link...\n",
683 port->index);
684
685 /* Wait for reset to complete */
686 if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
687 printk(KERN_WARNING "PCIE%d: PGRST failed\n",
688 port->index);
689 return -1;
690 }
691 return 0;
692}
693
694static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
695{
696 /* Check for card presence detect if supported, if not, just wait for
697 * link unconditionally.
698 *
699 * note that we don't fail if there is no link, we just filter out
700 * config space accesses. That way, it will be easier to implement
701 * hotplug later on.
702 */
703 if (!port->has_ibpre ||
704 !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
705 1 << 28, 1 << 28, 100)) {
706 printk(KERN_INFO
707 "PCIE%d: Device detected, waiting for link...\n",
708 port->index);
709 if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
710 0x1000, 0x1000, 2000))
711 printk(KERN_WARNING
712 "PCIE%d: Link up failed\n", port->index);
713 else {
714 printk(KERN_INFO
715 "PCIE%d: link is up !\n", port->index);
716 port->link = 1;
717 }
718 } else
719 printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
720}
721
659/* Check various reset bits of the 440SPe PCIe core */ 722/* Check various reset bits of the 440SPe PCIe core */
660static int __init ppc440spe_pciex_check_reset(struct device_node *np) 723static int __init ppc440spe_pciex_check_reset(struct device_node *np)
661{ 724{
@@ -806,7 +869,7 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
806 dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 869 dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
807 (1 << 24) | (1 << 16), 1 << 12); 870 (1 << 24) | (1 << 16), 1 << 12);
808 871
809 return 0; 872 return ppc4xx_pciex_port_reset_sdr(port);
810} 873}
811 874
812static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 875static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
@@ -856,6 +919,7 @@ static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata =
856 .core_init = ppc440spe_pciex_core_init, 919 .core_init = ppc440spe_pciex_core_init,
857 .port_init_hw = ppc440speA_pciex_init_port_hw, 920 .port_init_hw = ppc440speA_pciex_init_port_hw,
858 .setup_utl = ppc440speA_pciex_init_utl, 921 .setup_utl = ppc440speA_pciex_init_utl,
922 .check_link = ppc4xx_pciex_check_link_sdr,
859}; 923};
860 924
861static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = 925static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
@@ -863,6 +927,7 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
863 .core_init = ppc440spe_pciex_core_init, 927 .core_init = ppc440spe_pciex_core_init,
864 .port_init_hw = ppc440speB_pciex_init_port_hw, 928 .port_init_hw = ppc440speB_pciex_init_port_hw,
865 .setup_utl = ppc440speB_pciex_init_utl, 929 .setup_utl = ppc440speB_pciex_init_utl,
930 .check_link = ppc4xx_pciex_check_link_sdr,
866}; 931};
867 932
868static int __init ppc460ex_pciex_core_init(struct device_node *np) 933static int __init ppc460ex_pciex_core_init(struct device_node *np)
@@ -944,7 +1009,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
944 1009
945 port->has_ibpre = 1; 1010 port->has_ibpre = 1;
946 1011
947 return 0; 1012 return ppc4xx_pciex_port_reset_sdr(port);
948} 1013}
949 1014
950static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) 1015static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
@@ -972,6 +1037,7 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
972 .core_init = ppc460ex_pciex_core_init, 1037 .core_init = ppc460ex_pciex_core_init,
973 .port_init_hw = ppc460ex_pciex_init_port_hw, 1038 .port_init_hw = ppc460ex_pciex_init_port_hw,
974 .setup_utl = ppc460ex_pciex_init_utl, 1039 .setup_utl = ppc460ex_pciex_init_utl,
1040 .check_link = ppc4xx_pciex_check_link_sdr,
975}; 1041};
976 1042
977static int __init ppc460sx_pciex_core_init(struct device_node *np) 1043static int __init ppc460sx_pciex_core_init(struct device_node *np)
@@ -1075,7 +1141,7 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
1075 1141
1076 port->has_ibpre = 1; 1142 port->has_ibpre = 1;
1077 1143
1078 return 0; 1144 return ppc4xx_pciex_port_reset_sdr(port);
1079} 1145}
1080 1146
1081static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) 1147static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
@@ -1089,6 +1155,7 @@ static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
1089 .core_init = ppc460sx_pciex_core_init, 1155 .core_init = ppc460sx_pciex_core_init,
1090 .port_init_hw = ppc460sx_pciex_init_port_hw, 1156 .port_init_hw = ppc460sx_pciex_init_port_hw,
1091 .setup_utl = ppc460sx_pciex_init_utl, 1157 .setup_utl = ppc460sx_pciex_init_utl,
1158 .check_link = ppc4xx_pciex_check_link_sdr,
1092}; 1159};
1093 1160
1094#endif /* CONFIG_44x */ 1161#endif /* CONFIG_44x */
@@ -1154,7 +1221,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
1154 1221
1155 port->has_ibpre = 1; 1222 port->has_ibpre = 1;
1156 1223
1157 return 0; 1224 return ppc4xx_pciex_port_reset_sdr(port);
1158} 1225}
1159 1226
1160static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) 1227static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
@@ -1183,11 +1250,11 @@ static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata =
1183 .core_init = ppc405ex_pciex_core_init, 1250 .core_init = ppc405ex_pciex_core_init,
1184 .port_init_hw = ppc405ex_pciex_init_port_hw, 1251 .port_init_hw = ppc405ex_pciex_init_port_hw,
1185 .setup_utl = ppc405ex_pciex_init_utl, 1252 .setup_utl = ppc405ex_pciex_init_utl,
1253 .check_link = ppc4xx_pciex_check_link_sdr,
1186}; 1254};
1187 1255
1188#endif /* CONFIG_40x */ 1256#endif /* CONFIG_40x */
1189 1257
1190
1191/* Check that the core has been initied and if not, do it */ 1258/* Check that the core has been initied and if not, do it */
1192static int __init ppc4xx_pciex_check_core_init(struct device_node *np) 1259static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
1193{ 1260{
@@ -1261,26 +1328,6 @@ static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port
1261 dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); 1328 dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0);
1262} 1329}
1263 1330
1264static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
1265 unsigned int sdr_offset,
1266 unsigned int mask,
1267 unsigned int value,
1268 int timeout_ms)
1269{
1270 u32 val;
1271
1272 while(timeout_ms--) {
1273 val = mfdcri(SDR0, port->sdr_base + sdr_offset);
1274 if ((val & mask) == value) {
1275 pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
1276 port->index, sdr_offset, timeout_ms, val);
1277 return 0;
1278 }
1279 msleep(1);
1280 }
1281 return -1;
1282}
1283
1284static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) 1331static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
1285{ 1332{
1286 int rc = 0; 1333 int rc = 0;
@@ -1291,40 +1338,8 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
1291 if (rc != 0) 1338 if (rc != 0)
1292 return rc; 1339 return rc;
1293 1340
1294 printk(KERN_INFO "PCIE%d: Checking link...\n", 1341 if (ppc4xx_pciex_hwops->check_link)
1295 port->index); 1342 ppc4xx_pciex_hwops->check_link(port);
1296
1297 /* Wait for reset to complete */
1298 if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
1299 printk(KERN_WARNING "PCIE%d: PGRST failed\n",
1300 port->index);
1301 return -1;
1302 }
1303
1304 /* Check for card presence detect if supported, if not, just wait for
1305 * link unconditionally.
1306 *
1307 * note that we don't fail if there is no link, we just filter out
1308 * config space accesses. That way, it will be easier to implement
1309 * hotplug later on.
1310 */
1311 if (!port->has_ibpre ||
1312 !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
1313 1 << 28, 1 << 28, 100)) {
1314 printk(KERN_INFO
1315 "PCIE%d: Device detected, waiting for link...\n",
1316 port->index);
1317 if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
1318 0x1000, 0x1000, 2000))
1319 printk(KERN_WARNING
1320 "PCIE%d: Link up failed\n", port->index);
1321 else {
1322 printk(KERN_INFO
1323 "PCIE%d: link is up !\n", port->index);
1324 port->link = 1;
1325 }
1326 } else
1327 printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
1328 1343
1329 /* 1344 /*
1330 * Initialize mapping: disable all regions and configure 1345 * Initialize mapping: disable all regions and configure
@@ -1347,14 +1362,17 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
1347 /* 1362 /*
1348 * Check for VC0 active and assert RDY. 1363 * Check for VC0 active and assert RDY.
1349 */ 1364 */
1350 if (port->link && 1365 if (port->sdr_base) {
1351 ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1366 if (port->link &&
1352 1 << 16, 1 << 16, 5000)) { 1367 ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
1353 printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); 1368 1 << 16, 1 << 16, 5000)) {
1354 port->link = 0; 1369 printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index);
1370 port->link = 0;
1371 }
1372
1373 dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20);
1355 } 1374 }
1356 1375
1357 dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20);
1358 msleep(100); 1376 msleep(100);
1359 1377
1360 return 0; 1378 return 0;