mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00:00
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>
This commit is contained in:
parent
af9719c306
commit
112d1fe9f7
1 changed files with 83 additions and 65 deletions
|
@ -650,12 +650,75 @@ struct ppc4xx_pciex_hwops
|
|||
int (*core_init)(struct device_node *np);
|
||||
int (*port_init_hw)(struct ppc4xx_pciex_port *port);
|
||||
int (*setup_utl)(struct ppc4xx_pciex_port *port);
|
||||
void (*check_link)(struct ppc4xx_pciex_port *port);
|
||||
};
|
||||
|
||||
static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
|
||||
|
||||
#ifdef CONFIG_44x
|
||||
|
||||
static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
|
||||
unsigned int sdr_offset,
|
||||
unsigned int mask,
|
||||
unsigned int value,
|
||||
int timeout_ms)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
while(timeout_ms--) {
|
||||
val = mfdcri(SDR0, port->sdr_base + sdr_offset);
|
||||
if ((val & mask) == value) {
|
||||
pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
|
||||
port->index, sdr_offset, timeout_ms, val);
|
||||
return 0;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port)
|
||||
{
|
||||
printk(KERN_INFO "PCIE%d: Checking link...\n",
|
||||
port->index);
|
||||
|
||||
/* Wait for reset to complete */
|
||||
if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
|
||||
printk(KERN_WARNING "PCIE%d: PGRST failed\n",
|
||||
port->index);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
|
||||
{
|
||||
/* Check for card presence detect if supported, if not, just wait for
|
||||
* link unconditionally.
|
||||
*
|
||||
* note that we don't fail if there is no link, we just filter out
|
||||
* config space accesses. That way, it will be easier to implement
|
||||
* hotplug later on.
|
||||
*/
|
||||
if (!port->has_ibpre ||
|
||||
!ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
|
||||
1 << 28, 1 << 28, 100)) {
|
||||
printk(KERN_INFO
|
||||
"PCIE%d: Device detected, waiting for link...\n",
|
||||
port->index);
|
||||
if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
|
||||
0x1000, 0x1000, 2000))
|
||||
printk(KERN_WARNING
|
||||
"PCIE%d: Link up failed\n", port->index);
|
||||
else {
|
||||
printk(KERN_INFO
|
||||
"PCIE%d: link is up !\n", port->index);
|
||||
port->link = 1;
|
||||
}
|
||||
} else
|
||||
printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
|
||||
}
|
||||
|
||||
/* Check various reset bits of the 440SPe PCIe core */
|
||||
static int __init ppc440spe_pciex_check_reset(struct device_node *np)
|
||||
{
|
||||
|
@ -806,7 +869,7 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
|
|||
dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
|
||||
(1 << 24) | (1 << 16), 1 << 12);
|
||||
|
||||
return 0;
|
||||
return ppc4xx_pciex_port_reset_sdr(port);
|
||||
}
|
||||
|
||||
static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
|
||||
|
@ -856,6 +919,7 @@ static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata =
|
|||
.core_init = ppc440spe_pciex_core_init,
|
||||
.port_init_hw = ppc440speA_pciex_init_port_hw,
|
||||
.setup_utl = ppc440speA_pciex_init_utl,
|
||||
.check_link = ppc4xx_pciex_check_link_sdr,
|
||||
};
|
||||
|
||||
static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
|
||||
|
@ -863,6 +927,7 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
|
|||
.core_init = ppc440spe_pciex_core_init,
|
||||
.port_init_hw = ppc440speB_pciex_init_port_hw,
|
||||
.setup_utl = ppc440speB_pciex_init_utl,
|
||||
.check_link = ppc4xx_pciex_check_link_sdr,
|
||||
};
|
||||
|
||||
static 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)
|
|||
|
||||
port->has_ibpre = 1;
|
||||
|
||||
return 0;
|
||||
return ppc4xx_pciex_port_reset_sdr(port);
|
||||
}
|
||||
|
||||
static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
|
||||
|
@ -972,6 +1037,7 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
|
|||
.core_init = ppc460ex_pciex_core_init,
|
||||
.port_init_hw = ppc460ex_pciex_init_port_hw,
|
||||
.setup_utl = ppc460ex_pciex_init_utl,
|
||||
.check_link = ppc4xx_pciex_check_link_sdr,
|
||||
};
|
||||
|
||||
static 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)
|
|||
|
||||
port->has_ibpre = 1;
|
||||
|
||||
return 0;
|
||||
return ppc4xx_pciex_port_reset_sdr(port);
|
||||
}
|
||||
|
||||
static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
|
||||
|
@ -1089,6 +1155,7 @@ static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
|
|||
.core_init = ppc460sx_pciex_core_init,
|
||||
.port_init_hw = ppc460sx_pciex_init_port_hw,
|
||||
.setup_utl = ppc460sx_pciex_init_utl,
|
||||
.check_link = ppc4xx_pciex_check_link_sdr,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_44x */
|
||||
|
@ -1154,7 +1221,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
|
|||
|
||||
port->has_ibpre = 1;
|
||||
|
||||
return 0;
|
||||
return ppc4xx_pciex_port_reset_sdr(port);
|
||||
}
|
||||
|
||||
static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
|
||||
|
@ -1183,11 +1250,11 @@ static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata =
|
|||
.core_init = ppc405ex_pciex_core_init,
|
||||
.port_init_hw = ppc405ex_pciex_init_port_hw,
|
||||
.setup_utl = ppc405ex_pciex_init_utl,
|
||||
.check_link = ppc4xx_pciex_check_link_sdr,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_40x */
|
||||
|
||||
|
||||
/* Check that the core has been initied and if not, do it */
|
||||
static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
|
||||
{
|
||||
|
@ -1261,26 +1328,6 @@ static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port
|
|||
dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0);
|
||||
}
|
||||
|
||||
static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
|
||||
unsigned int sdr_offset,
|
||||
unsigned int mask,
|
||||
unsigned int value,
|
||||
int timeout_ms)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
while(timeout_ms--) {
|
||||
val = mfdcri(SDR0, port->sdr_base + sdr_offset);
|
||||
if ((val & mask) == value) {
|
||||
pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
|
||||
port->index, sdr_offset, timeout_ms, val);
|
||||
return 0;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -1291,40 +1338,8 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
|
|||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
printk(KERN_INFO "PCIE%d: Checking link...\n",
|
||||
port->index);
|
||||
|
||||
/* Wait for reset to complete */
|
||||
if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
|
||||
printk(KERN_WARNING "PCIE%d: PGRST failed\n",
|
||||
port->index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for card presence detect if supported, if not, just wait for
|
||||
* link unconditionally.
|
||||
*
|
||||
* note that we don't fail if there is no link, we just filter out
|
||||
* config space accesses. That way, it will be easier to implement
|
||||
* hotplug later on.
|
||||
*/
|
||||
if (!port->has_ibpre ||
|
||||
!ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
|
||||
1 << 28, 1 << 28, 100)) {
|
||||
printk(KERN_INFO
|
||||
"PCIE%d: Device detected, waiting for link...\n",
|
||||
port->index);
|
||||
if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
|
||||
0x1000, 0x1000, 2000))
|
||||
printk(KERN_WARNING
|
||||
"PCIE%d: Link up failed\n", port->index);
|
||||
else {
|
||||
printk(KERN_INFO
|
||||
"PCIE%d: link is up !\n", port->index);
|
||||
port->link = 1;
|
||||
}
|
||||
} else
|
||||
printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
|
||||
if (ppc4xx_pciex_hwops->check_link)
|
||||
ppc4xx_pciex_hwops->check_link(port);
|
||||
|
||||
/*
|
||||
* Initialize mapping: disable all regions and configure
|
||||
|
@ -1347,14 +1362,17 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
|
|||
/*
|
||||
* Check for VC0 active and assert RDY.
|
||||
*/
|
||||
if (port->link &&
|
||||
ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
|
||||
1 << 16, 1 << 16, 5000)) {
|
||||
printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index);
|
||||
port->link = 0;
|
||||
if (port->sdr_base) {
|
||||
if (port->link &&
|
||||
ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
|
||||
1 << 16, 1 << 16, 5000)) {
|
||||
printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index);
|
||||
port->link = 0;
|
||||
}
|
||||
|
||||
dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20);
|
||||
}
|
||||
|
||||
dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20);
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue