diff mbox

[v3,3/3] pci: dra7xx: use pdata callbacks to perform reset

Message ID 1452780672-14339-4-git-send-email-kishon@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kishon Vijay Abraham I Jan. 14, 2016, 2:11 p.m. UTC
Use assert/deassert callbacks populated in the platform data to
to perform reset of PCIe.

Use these callbacks until a reset controller driver is
is available in the kernel to reset PCIe.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/pci/host/pci-dra7xx.c |   66 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

Comments

Tony Lindgren Jan. 27, 2016, 5:31 p.m. UTC | #1
* Kishon Vijay Abraham I <kishon@ti.com> [160114 06:12]:
> Use assert/deassert callbacks populated in the platform data to
> to perform reset of PCIe.
> 
> Use these callbacks until a reset controller driver is
> is available in the kernel to reset PCIe.
...

> --- a/drivers/pci/host/pci-dra7xx.c
> +++ b/drivers/pci/host/pci-dra7xx.c
> @@ -347,6 +404,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
>  	enum of_gpio_flags flags;
>  	unsigned long gpio_flags;
>  
> +	ret = dra7xx_pcie_reset(pdev);
> +	if (ret)
> +		return ret;
> +
>  	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
>  	if (!dra7xx)
>  		return -ENOMEM;

With the hwmod data properly configured the reset already happens
for the device by the bus driver, the hwmod code in this case?

> @@ -457,6 +518,7 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
>  	struct pcie_port *pp = &dra7xx->pp;
>  	struct device *dev = &pdev->dev;
>  	int count = dra7xx->phy_count;
> +	int ret;
>  
>  	if (pp->irq_domain)
>  		irq_domain_remove(pp->irq_domain);
> @@ -467,6 +529,10 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
>  		phy_exit(dra7xx->phy[count]);
>  	}
>  
> +	ret = dra7xx_pcie_assert_reset(pdev);
> +	if (ret < 0)
> +		return ret;
> +
>  	return 0;
>  }

Why do you need another reset here? Can't you just implement PM runtime
in the driver and do the usual pm_runtime_put_sync followed by
pm_runtime_disable?

Basically I'm wondering how come we need these platform data callbacks
at all.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suman Anna Jan. 27, 2016, 6:16 p.m. UTC | #2
Hi Tony,

On 01/27/2016 11:31 AM, Tony Lindgren wrote:
> * Kishon Vijay Abraham I <kishon@ti.com> [160114 06:12]:
>> Use assert/deassert callbacks populated in the platform data to
>> to perform reset of PCIe.
>>
>> Use these callbacks until a reset controller driver is
>> is available in the kernel to reset PCIe.
> ...
> 
>> --- a/drivers/pci/host/pci-dra7xx.c
>> +++ b/drivers/pci/host/pci-dra7xx.c
>> @@ -347,6 +404,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
>>  	enum of_gpio_flags flags;
>>  	unsigned long gpio_flags;
>>  
>> +	ret = dra7xx_pcie_reset(pdev);
>> +	if (ret)
>> +		return ret;
>> +
>>  	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
>>  	if (!dra7xx)
>>  		return -ENOMEM;
> 
> With the hwmod data properly configured the reset already happens
> for the device by the bus driver, the hwmod code in this case?
> 
>> @@ -457,6 +518,7 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
>>  	struct pcie_port *pp = &dra7xx->pp;
>>  	struct device *dev = &pdev->dev;
>>  	int count = dra7xx->phy_count;
>> +	int ret;
>>  
>>  	if (pp->irq_domain)
>>  		irq_domain_remove(pp->irq_domain);
>> @@ -467,6 +529,10 @@ static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
>>  		phy_exit(dra7xx->phy[count]);
>>  	}
>>  
>> +	ret = dra7xx_pcie_assert_reset(pdev);
>> +	if (ret < 0)
>> +		return ret;
>> +
>>  	return 0;
>>  }
> 
> Why do you need another reset here? Can't you just implement PM runtime
> in the driver and do the usual pm_runtime_put_sync followed by
> pm_runtime_disable?

The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
with clocks, and we need to invoke the reset functions separately.
Modules with softresets in SYSCONFIG are ok, as they are dealt with
properly.

> Basically I'm wondering how come we need these platform data callbacks
> at all.

The hardresets are controlled through the
omap_device_assert(deassert)_hardreset functions, and since these are
limited to mach-omap2, we are invoking them through platform data callbacks.


regards
Suman
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tony Lindgren Jan. 27, 2016, 6:56 p.m. UTC | #3
* Suman Anna <s-anna@ti.com> [160127 10:17]:
> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
> > Why do you need another reset here? Can't you just implement PM runtime
> > in the driver and do the usual pm_runtime_put_sync followed by
> > pm_runtime_disable?
> 
> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
> with clocks, and we need to invoke the reset functions separately.
> Modules with softresets in SYSCONFIG are ok, as they are dealt with
> properly.

Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:

	if (oh->class->reset) {
		r = oh->class->reset(oh);
	} else {
		if (oh->rst_lines_cnt > 0) {
			for (i = 0; i < oh->rst_lines_cnt; i++)
				_assert_hardreset(oh, oh->rst_lines[i].name);
			return 0;
		} else {
			r = _ocp_softreset(oh);
			if (r == -ENOENT)
				r = 0;
		}
	}

Care to explain what exactly the problem with the hwmod code not doing
the reset on init?

And why do you need to do another reset in dra7xx_pcie_remove()?

> > Basically I'm wondering how come we need these platform data callbacks
> > at all.
> 
> The hardresets are controlled through the
> omap_device_assert(deassert)_hardreset functions, and since these are
> limited to mach-omap2, we are invoking them through platform data callbacks.

Right.. But I'm wondering about the why you need to do this in the
driver at all part :)

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suman Anna Jan. 27, 2016, 11:16 p.m. UTC | #4
On 01/27/2016 12:56 PM, Tony Lindgren wrote:
> * Suman Anna <s-anna@ti.com> [160127 10:17]:
>> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
>>> Why do you need another reset here? Can't you just implement PM runtime
>>> in the driver and do the usual pm_runtime_put_sync followed by
>>> pm_runtime_disable?
>>
>> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
>> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
>> with clocks, and we need to invoke the reset functions separately.
>> Modules with softresets in SYSCONFIG are ok, as they are dealt with
>> properly.
> 
> Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:
> 
> 	if (oh->class->reset) {
> 		r = oh->class->reset(oh);
> 	} else {
> 		if (oh->rst_lines_cnt > 0) {
> 			for (i = 0; i < oh->rst_lines_cnt; i++)
> 				_assert_hardreset(oh, oh->rst_lines[i].name);
> 			return 0;
> 		} else {
> 			r = _ocp_softreset(oh);
> 			if (r == -ENOENT)
> 				r = 0;
> 		}
> 	}

Right, hwmod code does the initial reset.

> Care to explain what exactly the problem with the hwmod code not doing
> the reset on init?

And we only need to deassert the reset in probe. Technically, we don't
need to assert first and deassert in probe, and that was a design choice
made by Kishon.

> And why do you need to do another reset in dra7xx_pcie_remove()?

Primarily to restore the reset state back to what it was after the
driver remove gets called. We cannot call deassert twice without calling
a assert in between. Kishon had originally added the assert and deassert
only in probe, but nothing in remove, they ought to be deassert in probe
and assert in remove to match initial hardware state, and to also make
it work across multiple probe/remove.

>>> Basically I'm wondering how come we need these platform data callbacks
>>> at all.
>>
>> The hardresets are controlled through the
>> omap_device_assert(deassert)_hardreset functions, and since these are
>> limited to mach-omap2, we are invoking them through platform data callbacks.
> 
> Right.. But I'm wondering about the why you need to do this in the
> driver at all part :)

The initial reset at init time is okay, but hwmod _enable() bails out if
the resets lines are asserted. This was a change made long time back, I
believe to deal with the problems around the DSP enabling sequences. As
such, pm_runtime_get_sync() and put_sync() do not deassert and assert
the resets.

regards
Suman
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tony Lindgren Jan. 28, 2016, 6:31 p.m. UTC | #5
* Suman Anna <s-anna@ti.com> [160127 15:17]:
> On 01/27/2016 12:56 PM, Tony Lindgren wrote:
> > * Suman Anna <s-anna@ti.com> [160127 10:17]:
> >> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
> >>> Why do you need another reset here? Can't you just implement PM runtime
> >>> in the driver and do the usual pm_runtime_put_sync followed by
> >>> pm_runtime_disable?
> >>
> >> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
> >> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
> >> with clocks, and we need to invoke the reset functions separately.
> >> Modules with softresets in SYSCONFIG are ok, as they are dealt with
> >> properly.
> > 
> > Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:
> > 
> > 	if (oh->class->reset) {
> > 		r = oh->class->reset(oh);
> > 	} else {
> > 		if (oh->rst_lines_cnt > 0) {
> > 			for (i = 0; i < oh->rst_lines_cnt; i++)
> > 				_assert_hardreset(oh, oh->rst_lines[i].name);
> > 			return 0;
> > 		} else {
> > 			r = _ocp_softreset(oh);
> > 			if (r == -ENOENT)
> > 				r = 0;
> > 		}
> > 	}
> 
> Right, hwmod code does the initial reset.
> 
> > Care to explain what exactly the problem with the hwmod code not doing
> > the reset on init?
> 
> And we only need to deassert the reset in probe. Technically, we don't
> need to assert first and deassert in probe, and that was a design choice
> made by Kishon.

OK so if hwmod code has already done the reset, then why would you need
to deassert reset in the device driver probe?

> > And why do you need to do another reset in dra7xx_pcie_remove()?
> 
> Primarily to restore the reset state back to what it was after the
> driver remove gets called. We cannot call deassert twice without calling
> a assert in between. Kishon had originally added the assert and deassert
> only in probe, but nothing in remove, they ought to be deassert in probe
> and assert in remove to match initial hardware state, and to also make
> it work across multiple probe/remove.

I don't understand this part either.. Usually you just power up and init
the registers to a sane state in a device driver probe and on exit just
power down the device.

> >>> Basically I'm wondering how come we need these platform data callbacks
> >>> at all.
> >>
> >> The hardresets are controlled through the
> >> omap_device_assert(deassert)_hardreset functions, and since these are
> >> limited to mach-omap2, we are invoking them through platform data callbacks.
> > 
> > Right.. But I'm wondering about the why you need to do this in the
> > driver at all part :)
> 
> The initial reset at init time is okay, but hwmod _enable() bails out if
> the resets lines are asserted. This was a change made long time back, I
> believe to deal with the problems around the DSP enabling sequences. As
> such, pm_runtime_get_sync() and put_sync() do not deassert and assert
> the resets.

OK if the hwmod code does not deassert reset lines properly on enable,
then that sounds like a bug that should be fixed instead of adding
device specific work arounds.

Sorry to keep dragging this on a bit longer, but I think we need to
hear Paul's comments on this one.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suman Anna Jan. 28, 2016, 9:15 p.m. UTC | #6
On 01/28/2016 12:31 PM, Tony Lindgren wrote:
> * Suman Anna <s-anna@ti.com> [160127 15:17]:
>> On 01/27/2016 12:56 PM, Tony Lindgren wrote:
>>> * Suman Anna <s-anna@ti.com> [160127 10:17]:
>>>> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
>>>>> Why do you need another reset here? Can't you just implement PM runtime
>>>>> in the driver and do the usual pm_runtime_put_sync followed by
>>>>> pm_runtime_disable?
>>>>
>>>> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
>>>> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
>>>> with clocks, and we need to invoke the reset functions separately.
>>>> Modules with softresets in SYSCONFIG are ok, as they are dealt with
>>>> properly.
>>>
>>> Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:
>>>
>>> 	if (oh->class->reset) {
>>> 		r = oh->class->reset(oh);
>>> 	} else {
>>> 		if (oh->rst_lines_cnt > 0) {
>>> 			for (i = 0; i < oh->rst_lines_cnt; i++)
>>> 				_assert_hardreset(oh, oh->rst_lines[i].name);
>>> 			return 0;
>>> 		} else {
>>> 			r = _ocp_softreset(oh);
>>> 			if (r == -ENOENT)
>>> 				r = 0;
>>> 		}
>>> 	}
>>
>> Right, hwmod code does the initial reset.
>>
>>> Care to explain what exactly the problem with the hwmod code not doing
>>> the reset on init?
>>
>> And we only need to deassert the reset in probe. Technically, we don't
>> need to assert first and deassert in probe, and that was a design choice
>> made by Kishon.
> 
> OK so if hwmod code has already done the reset, then why would you need
> to deassert reset in the device driver probe?

So the _reset() above asserts the reset for IPs with PRCM reset lines,
but module is not enabled (no register accesses even if clocks enabled).
The _enable() code bails out if there are PRCM reset lines (there are
varied IPs with resets including processors, and we really cannot enable
and idle it without loading some code that would have executed WFI).

> 
>>> And why do you need to do another reset in dra7xx_pcie_remove()?
>>
>> Primarily to restore the reset state back to what it was after the
>> driver remove gets called. We cannot call deassert twice without calling
>> a assert in between. Kishon had originally added the assert and deassert
>> only in probe, but nothing in remove, they ought to be deassert in probe
>> and assert in remove to match initial hardware state, and to also make
>> it work across multiple probe/remove.
> 
> I don't understand this part either.. Usually you just power up and init
> the registers to a sane state in a device driver probe and on exit just
> power down the device.

Yes, in the case of IPs with hard-reset lines, that init is left to the
drivers.

> 
>>>>> Basically I'm wondering how come we need these platform data callbacks
>>>>> at all.
>>>>
>>>> The hardresets are controlled through the
>>>> omap_device_assert(deassert)_hardreset functions, and since these are
>>>> limited to mach-omap2, we are invoking them through platform data callbacks.
>>>
>>> Right.. But I'm wondering about the why you need to do this in the
>>> driver at all part :)
>>
>> The initial reset at init time is okay, but hwmod _enable() bails out if
>> the resets lines are asserted. This was a change made long time back, I
>> believe to deal with the problems around the DSP enabling sequences. As
>> such, pm_runtime_get_sync() and put_sync() do not deassert and assert
>> the resets.
> 
> OK if the hwmod code does not deassert reset lines properly on enable,
> then that sounds like a bug that should be fixed instead of adding
> device specific work arounds.

As I said above, not all IPs with hard-reset lines have the same power
on/power off sequences.. IPs with only SYSCONFIG based soft-reset all
pretty much follow the PRCM HW_Auto idling, so dealing with them is
rather straightforward in the common hwmod code. I have had to do rather
funky stuff in our product kernels when doing suspend/resume on IOMMUs,
remoteprocs.

> Sorry to keep dragging this on a bit longer, but I think we need to
> hear Paul's comments on this one.

Yeah, it would be good to restart this discussion, as I will be adding
the DT support for the remoteproc devices a bit later.

regards
Suman

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I Feb. 2, 2016, 10:40 a.m. UTC | #7
Hi,

On Friday 29 January 2016 12:01 AM, Tony Lindgren wrote:
> * Suman Anna <s-anna@ti.com> [160127 15:17]:
>> On 01/27/2016 12:56 PM, Tony Lindgren wrote:
>>> * Suman Anna <s-anna@ti.com> [160127 10:17]:
>>>> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
>>>>> Why do you need another reset here? Can't you just implement PM runtime
>>>>> in the driver and do the usual pm_runtime_put_sync followed by
>>>>> pm_runtime_disable?
>>>>
>>>> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
>>>> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
>>>> with clocks, and we need to invoke the reset functions separately.
>>>> Modules with softresets in SYSCONFIG are ok, as they are dealt with
>>>> properly.
>>>
>>> Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:
>>>
>>> 	if (oh->class->reset) {
>>> 		r = oh->class->reset(oh);
>>> 	} else {
>>> 		if (oh->rst_lines_cnt > 0) {
>>> 			for (i = 0; i < oh->rst_lines_cnt; i++)
>>> 				_assert_hardreset(oh, oh->rst_lines[i].name);
>>> 			return 0;
>>> 		} else {
>>> 			r = _ocp_softreset(oh);
>>> 			if (r == -ENOENT)
>>> 				r = 0;
>>> 		}
>>> 	}
>>
>> Right, hwmod code does the initial reset.
>>
>>> Care to explain what exactly the problem with the hwmod code not doing
>>> the reset on init?
>>
>> And we only need to deassert the reset in probe. Technically, we don't
>> need to assert first and deassert in probe, and that was a design choice
>> made by Kishon.
> 
> OK so if hwmod code has already done the reset, then why would you need
> to deassert reset in the device driver probe?

The hwmod code only asserts the reset lines and that is not enough to access
the PCI registers. The reset lines must be de-asserted before accessing the
PCIe registers.
> 
>>> And why do you need to do another reset in dra7xx_pcie_remove()?
>>
>> Primarily to restore the reset state back to what it was after the
>> driver remove gets called. We cannot call deassert twice without calling
>> a assert in between. Kishon had originally added the assert and deassert
>> only in probe, but nothing in remove, they ought to be deassert in probe
>> and assert in remove to match initial hardware state, and to also make
>> it work across multiple probe/remove.

right. I thought if some program like the bootloader requires the reset lines
to be in initial hw state, then it might break on 'reboot'. So restored it back
to the initial hw state.
> 
> I don't understand this part either.. Usually you just power up and init
> the registers to a sane state in a device driver probe and on exit just
> power down the device.
> 
>>>>> Basically I'm wondering how come we need these platform data callbacks
>>>>> at all.
>>>>
>>>> The hardresets are controlled through the
>>>> omap_device_assert(deassert)_hardreset functions, and since these are
>>>> limited to mach-omap2, we are invoking them through platform data callbacks.
>>>
>>> Right.. But I'm wondering about the why you need to do this in the
>>> driver at all part :)
>>
>> The initial reset at init time is okay, but hwmod _enable() bails out if
>> the resets lines are asserted. This was a change made long time back, I
>> believe to deal with the problems around the DSP enabling sequences. As
>> such, pm_runtime_get_sync() and put_sync() do not deassert and assert
>> the resets.
> 
> OK if the hwmod code does not deassert reset lines properly on enable,
> then that sounds like a bug that should be fixed instead of adding
> device specific work arounds.

I think some devices require the reset lines to be asserted and some devices
require it to be de-asserted and hwmod was designed when there was only the
first type of devices. I'm not sure though.
> 
> Sorry to keep dragging this on a bit longer, but I think we need to
> hear Paul's comments on this one.

I agree.
Paul, what do you think is the best way forward to perform reset?

Thanks
Kishon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I Feb. 5, 2016, 4:19 a.m. UTC | #8
Hi Paul,

On Tuesday 02 February 2016 04:10 PM, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Friday 29 January 2016 12:01 AM, Tony Lindgren wrote:
>> * Suman Anna <s-anna@ti.com> [160127 15:17]:
>>> On 01/27/2016 12:56 PM, Tony Lindgren wrote:
>>>> * Suman Anna <s-anna@ti.com> [160127 10:17]:
>>>>> On 01/27/2016 11:31 AM, Tony Lindgren wrote:
>>>>>> Why do you need another reset here? Can't you just implement PM runtime
>>>>>> in the driver and do the usual pm_runtime_put_sync followed by
>>>>>> pm_runtime_disable?
>>>>>
>>>>> The omap_hwmod_enable/disable code does not deal with hardresets (PRCM
>>>>> reset lines) and so the pm_runtime_get_sync/put_sync only end up dealing
>>>>> with clocks, and we need to invoke the reset functions separately.
>>>>> Modules with softresets in SYSCONFIG are ok, as they are dealt with
>>>>> properly.
>>>>
>>>> Hmm _reset() in omap_hwmod.c has this to call _assert_hardreset:
>>>>
>>>> 	if (oh->class->reset) {
>>>> 		r = oh->class->reset(oh);
>>>> 	} else {
>>>> 		if (oh->rst_lines_cnt > 0) {
>>>> 			for (i = 0; i < oh->rst_lines_cnt; i++)
>>>> 				_assert_hardreset(oh, oh->rst_lines[i].name);
>>>> 			return 0;
>>>> 		} else {
>>>> 			r = _ocp_softreset(oh);
>>>> 			if (r == -ENOENT)
>>>> 				r = 0;
>>>> 		}
>>>> 	}
>>>
>>> Right, hwmod code does the initial reset.
>>>
>>>> Care to explain what exactly the problem with the hwmod code not doing
>>>> the reset on init?
>>>
>>> And we only need to deassert the reset in probe. Technically, we don't
>>> need to assert first and deassert in probe, and that was a design choice
>>> made by Kishon.
>>
>> OK so if hwmod code has already done the reset, then why would you need
>> to deassert reset in the device driver probe?
> 
> The hwmod code only asserts the reset lines and that is not enough to access
> the PCI registers. The reset lines must be de-asserted before accessing the
> PCIe registers.
>>
>>>> And why do you need to do another reset in dra7xx_pcie_remove()?
>>>
>>> Primarily to restore the reset state back to what it was after the
>>> driver remove gets called. We cannot call deassert twice without calling
>>> a assert in between. Kishon had originally added the assert and deassert
>>> only in probe, but nothing in remove, they ought to be deassert in probe
>>> and assert in remove to match initial hardware state, and to also make
>>> it work across multiple probe/remove.
> 
> right. I thought if some program like the bootloader requires the reset lines
> to be in initial hw state, then it might break on 'reboot'. So restored it back
> to the initial hw state.
>>
>> I don't understand this part either.. Usually you just power up and init
>> the registers to a sane state in a device driver probe and on exit just
>> power down the device.
>>
>>>>>> Basically I'm wondering how come we need these platform data callbacks
>>>>>> at all.
>>>>>
>>>>> The hardresets are controlled through the
>>>>> omap_device_assert(deassert)_hardreset functions, and since these are
>>>>> limited to mach-omap2, we are invoking them through platform data callbacks.
>>>>
>>>> Right.. But I'm wondering about the why you need to do this in the
>>>> driver at all part :)
>>>
>>> The initial reset at init time is okay, but hwmod _enable() bails out if
>>> the resets lines are asserted. This was a change made long time back, I
>>> believe to deal with the problems around the DSP enabling sequences. As
>>> such, pm_runtime_get_sync() and put_sync() do not deassert and assert
>>> the resets.
>>
>> OK if the hwmod code does not deassert reset lines properly on enable,
>> then that sounds like a bug that should be fixed instead of adding
>> device specific work arounds.
> 
> I think some devices require the reset lines to be asserted and some devices
> require it to be de-asserted and hwmod was designed when there was only the
> first type of devices. I'm not sure though.
>>
>> Sorry to keep dragging this on a bit longer, but I think we need to
>> hear Paul's comments on this one.
> 
> I agree.
> Paul, what do you think is the best way forward to perform reset?

Can you give your feedback as we are at the risk of PCIe driver being removed?

Thanks
Kishon

> 
> Thanks
> Kishon
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
index 8c36880..f9a3240 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/host/pci-dra7xx.c
@@ -25,6 +25,8 @@ 
 #include <linux/resource.h>
 #include <linux/types.h>
 
+#include <linux/platform_data/pci-dra7xx.h>
+
 #include "pcie-designware.h"
 
 /* PCIe controller wrapper DRA7XX configuration registers */
@@ -329,6 +331,61 @@  static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
 	return 0;
 }
 
+static int dra7xx_pcie_assert_reset(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct pci_dra7xx_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!(pdata && pdata->assert_reset)) {
+		dev_err(dev, "platform data for assert reset not found!\n");
+		return -EINVAL;
+	}
+
+	ret = pdata->assert_reset(pdev, pdata->reset_name);
+	if (ret) {
+		dev_err(dev, "assert_reset failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dra7xx_pcie_deassert_reset(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct pci_dra7xx_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!(pdata && pdata->deassert_reset)) {
+		dev_err(dev, "platform data for deassert reset not found!\n");
+		return -EINVAL;
+	}
+
+	ret = pdata->deassert_reset(pdev, pdata->reset_name);
+	if (ret) {
+		dev_err(dev, "deassert_reset failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dra7xx_pcie_reset(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = dra7xx_pcie_assert_reset(pdev);
+	if (ret < 0)
+		return ret;
+
+	ret = dra7xx_pcie_deassert_reset(pdev);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 {
 	u32 reg;
@@ -347,6 +404,10 @@  static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 	enum of_gpio_flags flags;
 	unsigned long gpio_flags;
 
+	ret = dra7xx_pcie_reset(pdev);
+	if (ret)
+		return ret;
+
 	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
 	if (!dra7xx)
 		return -ENOMEM;
@@ -457,6 +518,7 @@  static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
 	struct pcie_port *pp = &dra7xx->pp;
 	struct device *dev = &pdev->dev;
 	int count = dra7xx->phy_count;
+	int ret;
 
 	if (pp->irq_domain)
 		irq_domain_remove(pp->irq_domain);
@@ -467,6 +529,10 @@  static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
 		phy_exit(dra7xx->phy[count]);
 	}
 
+	ret = dra7xx_pcie_assert_reset(pdev);
+	if (ret < 0)
+		return ret;
+
 	return 0;
 }