LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] e500v2 36 bit large physical HID0[EN_MAS7_UPDATE]
From: Micha Nelissen @ 2010-06-16  9:24 UTC (permalink / raw)
  To: Aggrwal Poonam-B10812, linuxppc-dev
In-Reply-To: <8660DA277DC57B4BAAC78225F03146B6AB1B5C@zin33exm24.fsl.freescale.net>

Aggrwal Poonam-B10812 wrote:
>> Attached is a patch to fix large physical address support for the
>
> This is already being done by u-boot, should linux set it again?

Yikes! Took me 5 min to reformat your email.

Our version of U-boot does not but it's not latest greatest.

IMHO:
1) Linux should not be dependent on U-boot or any other bootloader, or 
at least as possible
2) U-boot cannot (and does not want to) know whether Linux is going to 
use large physical addresses.

Regards,

Micha

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mitch Bradley @ 2010-06-16  7:40 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C18738C.4090809@compulab.co.il>

Mike Rapoport wrote:
> Mitch Bradley wrote:
>> Mike Rapoport wrote:
>>> Mitch Bradley wrote:
>>>> Mike Rapoport wrote:
>>>>> Mitch Bradley wrote:
>>>>>
>>>>>> The second topic is the hypothetical use of OFW as a HAL. That 
>>>>>> will not happen for several reasons.  The opposition to the idea 
>>>>>> is widespread and deeply held, and there are good arguments to 
>>>>>> support that opposition.   Furthermore, the economic conditions 
>>>>>> necessary for the creation of such a HAL do not exist in the ARM 
>>>>>> world, nor indeed in the Linux world in general.  (The necessary 
>>>>>> condition is the ability for one company to impose a substantial 
>>>>>> change by fiat - essentially a monopoly position.)
>>>>>>
>>>>>> Shall we agree, then, that any further discussion of the HAL 
>>>>>> issue is "just for fun", and that nobody needs to feel threatened 
>>>>>> that it would actually happen?
>>>>>
>>>>> I've recently worked with vendor versions of U-Boot for advanced 
>>>>> ARM SoCs. There is already *huge* chunk of HAL code in those 
>>>>> versions. And if there would be possibility to have callbacks into 
>>>>> the firmware these chunks would only grow, IMHO.
>>>>
>>>> How can there be HAL code in U-Boot unless there is already the 
>>>> possibility to have callbacks into the firmware?
>>>
>>> Currently it aims to abstract hardware from U-Boot and reuse the 
>>> same HW access code across operating systems and bootloaders. If 
>>> this code would have callbacks I afraid the things would became worse.
>>
>> The only way I can understand what you said is if I assume that by 
>> "callback", you mean the following sequence:
>>
>> a) U-boot loads and executes the OS, providing to the OS the address 
>> of some HW access routines that it can use
>> b) The OS calls one of those HW access routines
>> c) During the execution of that HW access routine, that routine calls 
>> "back" into the OS, before returning.  So a call into the OS is 
>> nested inside a call into U-boot resident code.
>>
>> If that is what you are worried about, it is not what we were 
>> discussing.  We were discussing - and many people were against - step 
>> (b).
>>
>> Are you saying that step (b) - the OS calling into routines provided 
>> by U-Boot - is already the status quo?
>
> I'm also objecting the step (b) and, fortunately, it's not yet the 
> status quo.
> Current U-Boot/kernel implementations I've encountered still do not 
> have OS calls to resident HW access routines. But if such calls would 
> be allowed, my impression is that SoC vendors would make extensive use 
> of them.

One could argue that a feature that vendors would use extensively is one 
that is sorely needed from their point of view.

One counterargument, of course, is that "there is a better way".  But it 
is only "better" under a cost function that values things differently 
than the vendors value them.  Were that not so, the vendors would gladly 
use the "better" way and not be tempted to use the objectionable 
feature. (Unless, of course, the vendors are just ignorant or unskilled 
- but I generally find that different cost functions cause more 
disconnects than lack of ability.)

Which of course raises the question:  How does the Linux community view 
such SoC vendors?  Are they embraced and eagerly supported, or (either 
openly or secretly) viewed as a nuisance?  How does the widespread 
objection to something that such vendors "would make extensive use of" 
mesh with that view?

>
>>>
>>>> It is not HAL if it can't be called.
>>>>
>>>>>
>>>>>
>>>>>> The potential for "vendors breaking out of the debugging use case 
>>>>>> and turning it into a HAL" is miniscule, because
>>>>>>
>>>>>> a) The callback is disabled by default
>>>>>> b) The technical challenges of the callback interface limit its 
>>>>>> applicability to specific "wizard user" scenarios
>>>>>> c) OFW is unlikely to achieve sufficient market penetration for 
>>>>>> the HAL thing to be worth doing
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> linux-arm-kernel mailing list
>>>>>> linux-arm-kernel@lists.infradead.org
>>>>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>>>
>>>>>
>>>
>>>
>
>

^ permalink raw reply

* Re: [PATCH 0/5] Rework MPC5121 DIU support (for 2.6.35)
From: Anatolij Gustschin @ 2010-06-16  7:38 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, devicetree-discuss, linuxppc-dev, yorksun
In-Reply-To: <AANLkTims596hCnLgN5Po6nS1bRFxKywEDlBA4mlreciV@mail.gmail.com>

Hi Timur,

On Fri, 4 Jun 2010 10:46:28 -0500
Timur Tabi <timur@freescale.com> wrote:

> On Tue, Jun 1, 2010 at 4:38 AM, Anatolij Gustschin <agust@denx.de> wrote:
> 
> > Could you please test these patches on MPC8610 HPCD? I think these
> > changes won't break that platform. The patches apply cleanly on
> > 2.6.35-rc1.
> 
> I'll try to get to them as soon as I can.

Any chance this could be done soon? I'd like to include the MPC5121e DIU
support in 2.6.36 since it is currently broken in mainline and the patches
provide the fix.

Thanks,
Anatolij

^ permalink raw reply

* RE: [PATCH] e500v2 36 bit large physical HID0[EN_MAS7_UPDATE]
From: Aggrwal Poonam-B10812 @ 2010-06-16  7:29 UTC (permalink / raw)
  To: Micha Nelissen, linuxppc-dev
In-Reply-To: <4C187616.4000303@neli.hopto.org>



> -----Original Message-----
> From:
linuxppc-dev-bounces+poonam.aggrwal=3Dfreescale.com@lists.ozlabs.org
> [mailto:linuxppc-dev-
> bounces+poonam.aggrwal=3Dfreescale.com@lists.ozlabs.org] On Behalf Of
Micha
> Nelissen
> Sent: Wednesday, June 16, 2010 12:29 PM
> To: linuxppc-dev@lists.ozlabs.org
> Subject: [PATCH] e500v2 36 bit large physical HID0[EN_MAS7_UPDATE]
>=20
> Hi,
>=20
> Attached is a patch to fix large physical address support for the
e500v2
> core. When >4GB addresses are used, the MAS7 register needs to be
valid
> for tlbsx instruction usage.
>=20
> Please review and apply.
[Aggrwal Poonam] This is already being done by u-boot, should linux set
it again?
>=20
> Micha

^ permalink raw reply

* [PATCH] e500v2 36 bit large physical HID0[EN_MAS7_UPDATE]
From: Micha Nelissen @ 2010-06-16  6:58 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 214 bytes --]

Hi,

Attached is a patch to fix large physical address support for the e500v2 
core. When >4GB addresses are used, the MAS7 register needs to be valid 
for tlbsx instruction usage.

Please review and apply.

Micha

[-- Attachment #2: en-mas7-update.diff --]
[-- Type: text/plain, Size: 1328 bytes --]

diff -u -ru linux-2.6.34/arch/powerpc/include/asm/reg.h linux-2.6.34-fix/arch/powerpc/include/asm/reg.h
--- linux-2.6.34/arch/powerpc/include/asm/reg.h	2010-05-16 23:17:36.000000000 +0200
+++ linux-2.6.34-fix/arch/powerpc/include/asm/reg.h	2010-06-16 08:43:28.000000000 +0200
@@ -272,6 +272,7 @@
 #define HID0_DAPUEN	(1<<8)		/* Debug APU enable */
 #define HID0_SGE	(1<<7)		/* Store Gathering Enable */
 #define HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
+#define HID0_EN_MAS7_UPDATE (1<<7)      /* tlbre/tlbsx update MAS7 - e500v2 */
 #define HID0_DCFA	(1<<6)		/* Data Cache Flush Assist */
 #define HID0_LRSTK	(1<<4)		/* Link register stack - 745x */
 #define HID0_BTIC	(1<<5)		/* Branch Target Instr Cache Enable */
diff -u -ru linux-2.6.34/arch/powerpc/kernel/head_fsl_booke.S linux-2.6.34-fix/arch/powerpc/kernel/head_fsl_booke.S
--- linux-2.6.34/arch/powerpc/kernel/head_fsl_booke.S	2010-05-16 23:17:36.000000000 +0200
+++ linux-2.6.34-fix/arch/powerpc/kernel/head_fsl_booke.S	2010-06-16 08:45:10.000000000 +0200
@@ -328,6 +328,13 @@
 	oris	r2,r2,HID0_DOZE@h
 	mtspr	SPRN_HID0, r2
 #endif
+#ifdef CONFIG_PTE_64BIT
+BEGIN_MMU_FTR_SECTION
+	mfspr	r2,SPRN_HID0
+	ori	r2,r2,HID0_EN_MAS7_UPDATE@l
+	mtspr	SPRN_HID0, r2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
+#endif
 
 #if !defined(CONFIG_BDI_SWITCH)
 	/*

^ permalink raw reply

* Re: Request review of device tree documentation
From: M. Warner Losh @ 2010-06-16  6:52 UTC (permalink / raw)
  To: wmb
  Cc: nico, microblaze-uclinux, devicetree-discuss, jamie, linuxppc-dev,
	mike, ppc6dev, jeremy.kerr, linux-arm-kernel
In-Reply-To: <4C187013.5000400@firmworks.com>

In message: <4C187013.5000400@firmworks.com>
            Mitch Bradley <wmb@firmworks.com> writes:
: Mike Rapoport wrote:
: > Mitch Bradley wrote:
: >> Mike Rapoport wrote:
: >>> Mitch Bradley wrote:
: >>>
: >>>> The second topic is the hypothetical use of OFW as a HAL. That will
: >>>> not happen for several reasons.  The opposition to the idea is
: >>>> widespread and deeply held, and there are good arguments to support
: >>>> that opposition.  Furthermore, the economic conditions necessary for
: >>>> the creation of such a HAL do not exist in the ARM world, nor indeed
: >>>> in the Linux world in general.  (The necessary condition is the
: >>>> ability for one company to impose a substantial change by fiat -
: >>>> essentially a monopoly position.)
: >>>>
: >>>> Shall we agree, then, that any further discussion of the HAL issue is
: >>>> "just for fun", and that nobody needs to feel threatened that it would
: >>>> actually happen?
: >>>
: >>> I've recently worked with vendor versions of U-Boot for advanced ARM
: >>> SoCs. There is already *huge* chunk of HAL code in those versions. And
: >>> if there would be possibility to have callbacks into the firmware
: >>> these chunks would only grow, IMHO.
: >>
: >> How can there be HAL code in U-Boot unless there is already the
: >> possibility to have callbacks into the firmware?
: >
: > Currently it aims to abstract hardware from U-Boot and reuse the same
: > HW access code across operating systems and bootloaders. If this code
: > would have callbacks I afraid the things would became worse.
: 
: The only way I can understand what you said is if I assume that by
: "callback", you mean the following sequence:
: 
: a) U-boot loads and executes the OS, providing to the OS the address
: of some HW access routines that it can use
: b) The OS calls one of those HW access routines
: c) During the execution of that HW access routine, that routine calls
: "back" into the OS, before returning.  So a call into the OS is nested
: inside a call into U-boot resident code.
: 
: If that is what you are worried about, it is not what we were
: discussing.  We were discussing - and many people were against - step
: (b).
: 
: Are you saying that step (b) - the OS calling into routines provided
: by U-Boot - is already the status quo?

I don't know about status quo, but it certainly is supported.  There's
an option to allow for a secondary boot loader, such as FreeBSD's
/boot/loader, to call back into uboot to read things from
flash/disk/whatever, do network access, etc.  Not so much a HAL, but
more of an echo of the functionality provided by PC BIOS functions.
/boot/loader can be viewed as a mini OS that calls back into uboot to
have it do things.  Once /boot/loader loads FreeBSD, btw, it and uboot
disappear from the scene, so this isn't exactly a HAL situation...

Warner


: >
: >> It is not HAL if it can't be called.
: >>
: >>>
: >>>
: >>>> The potential for "vendors breaking out of the debugging use case and
: >>>> turning it into a HAL" is miniscule, because
: >>>>
: >>>> a) The callback is disabled by default
: >>>> b) The technical challenges of the callback interface limit its
: >>>> applicability to specific "wizard user" scenarios
: >>>> c) OFW is unlikely to achieve sufficient market penetration for the
: >>>> HAL thing to be worth doing
: >>>>
: >>>>
: >>>> _______________________________________________
: >>>> linux-arm-kernel mailing list
: >>>> linux-arm-kernel@lists.infradead.org
: >>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
: >>>
: >>>
: >
: >
: _______________________________________________
: devicetree-discuss mailing list
: devicetree-discuss@lists.ozlabs.org
: https://lists.ozlabs.org/listinfo/devicetree-discuss
: 
: 

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mike Rapoport @ 2010-06-16  6:09 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Mike Rapoport, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C165FD1.6080505@firmworks.com>

Mitch Bradley wrote:

> The second topic is the hypothetical use of OFW as a HAL. That will not 
> happen for several reasons.  The opposition to the idea is widespread 
> and deeply held, and there are good arguments to support that 
> opposition.   Furthermore, the economic conditions necessary for the 
> creation of such a HAL do not exist in the ARM world, nor indeed in the 
> Linux world in general.  (The necessary condition is the ability for one 
> company to impose a substantial change by fiat - essentially a monopoly 
> position.)
> 
> Shall we agree, then, that any further discussion of the HAL issue is 
> "just for fun", and that nobody needs to feel threatened that it would 
> actually happen?

I've recently worked with vendor versions of U-Boot for advanced ARM 
SoCs. There is already *huge* chunk of HAL code in those versions. And 
if there would be possibility to have callbacks into the firmware these 
chunks would only grow, IMHO.


> The potential for "vendors breaking out of the debugging use case and 
> turning it into a HAL" is miniscule, because
> 
> a) The callback is disabled by default
> b) The technical challenges of the callback interface limit its 
> applicability to specific "wizard user" scenarios
> c) OFW is unlikely to achieve sufficient market penetration for the HAL 
> thing to be worth doing
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH 11/12] ptp: Added a clock driver for the IXP46x.
From: Richard Cochran @ 2010-06-16  6:54 UTC (permalink / raw)
  To: Grant Likely
  Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <AANLkTinPDaWNvUG8q8RdvRUga-qrPlSV2H5TkzVVMaFn@mail.gmail.com>

On Tue, Jun 15, 2010 at 12:41:56PM -0600, Grant Likely wrote:
> Nitpick.  We use all lower case names for structures in Linux.

Yes, I know, but in this case an exception makes sense.

I prefer to use the exact same register mnemonics as in the hardware
documentation, whenever possible. That way, anyone later working on
the driver with hardware manual in hand (and they should be doing that
way) will immediately see the connection.

> You want to get stuff as fast as possible, but there is a udelay()
> that just chews up CPU time.  Would cpu_relax() be sufficient with a
> time-based exit condition in the loop?

I am not sure. What does cpu_relax() do exactly, and when is it safe
to call?

Thanks,
Richard

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mike Rapoport @ 2010-06-16  6:47 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Mike Rapoport, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C187013.5000400@firmworks.com>

Mitch Bradley wrote:
> Mike Rapoport wrote:
>> Mitch Bradley wrote:
>>> Mike Rapoport wrote:
>>>> Mitch Bradley wrote:
>>>>
>>>>> The second topic is the hypothetical use of OFW as a HAL. That will 
>>>>> not happen for several reasons.  The opposition to the idea is 
>>>>> widespread and deeply held, and there are good arguments to support 
>>>>> that opposition.   Furthermore, the economic conditions necessary 
>>>>> for the creation of such a HAL do not exist in the ARM world, nor 
>>>>> indeed in the Linux world in general.  (The necessary condition is 
>>>>> the ability for one company to impose a substantial change by fiat 
>>>>> - essentially a monopoly position.)
>>>>>
>>>>> Shall we agree, then, that any further discussion of the HAL issue 
>>>>> is "just for fun", and that nobody needs to feel threatened that it 
>>>>> would actually happen?
>>>>
>>>> I've recently worked with vendor versions of U-Boot for advanced ARM 
>>>> SoCs. There is already *huge* chunk of HAL code in those versions. 
>>>> And if there would be possibility to have callbacks into the 
>>>> firmware these chunks would only grow, IMHO.
>>>
>>> How can there be HAL code in U-Boot unless there is already the 
>>> possibility to have callbacks into the firmware?
>>
>> Currently it aims to abstract hardware from U-Boot and reuse the same 
>> HW access code across operating systems and bootloaders. If this code 
>> would have callbacks I afraid the things would became worse.
> 
> The only way I can understand what you said is if I assume that by 
> "callback", you mean the following sequence:
> 
> a) U-boot loads and executes the OS, providing to the OS the address of 
> some HW access routines that it can use
> b) The OS calls one of those HW access routines
> c) During the execution of that HW access routine, that routine calls 
> "back" into the OS, before returning.  So a call into the OS is nested 
> inside a call into U-boot resident code.
> 
> If that is what you are worried about, it is not what we were 
> discussing.  We were discussing - and many people were against - step (b).
> 
> Are you saying that step (b) - the OS calling into routines provided by 
> U-Boot - is already the status quo?

I'm also objecting the step (b) and, fortunately, it's not yet the 
status quo.
Current U-Boot/kernel implementations I've encountered still do not have 
OS calls to resident HW access routines. But if such calls would be 
allowed, my impression is that SoC vendors would make extensive use of them.

>>
>>> It is not HAL if it can't be called.
>>>
>>>>
>>>>
>>>>> The potential for "vendors breaking out of the debugging use case 
>>>>> and turning it into a HAL" is miniscule, because
>>>>>
>>>>> a) The callback is disabled by default
>>>>> b) The technical challenges of the callback interface limit its 
>>>>> applicability to specific "wizard user" scenarios
>>>>> c) OFW is unlikely to achieve sufficient market penetration for the 
>>>>> HAL thing to be worth doing
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> linux-arm-kernel mailing list
>>>>> linux-arm-kernel@lists.infradead.org
>>>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>>
>>>>
>>
>>


-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH 10/12] ptp: Added a clock that uses the eTSEC found on the MPC85xx.
From: Richard Cochran @ 2010-06-16  6:45 UTC (permalink / raw)
  To: Grant Likely
  Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <AANLkTikFc15j-Qhw9M2CnKLKq58Wi1xD7E2dtVNsVgeA@mail.gmail.com>

On Tue, Jun 15, 2010 at 11:20:41AM -0600, Grant Likely wrote:
> 
> Is this header file used by anything other than gianfar_ptp.c?  If
> not, then roll the two files together.

I anticipate that it might be necessary to share the header's contents
with gianfar.c one day.

> Use dash ('-') not underscore ('_') in property names.

Okay, can do.

> If you encode this value as a string, then it will be friendly for humans too.

Okay.

> I could use more explication here.  Is this a divider value?
> Computers are good at making calculations, and the driver can obtain
> the clock frequency supplied to the device.  It may be more useful to
> specify here the desired frequency rather than the divider.  Certainly
> more human-friendly too.

It is not that simple. The basic algorithm is described in the text,
and anyone wanting to use the eTSEC for PTP will have to consider the
issue themselves, since it is a design issue with a few tradeoffs
related to the board layout. It is really too thorny to do in the
driver automatically.

I can post a tcltk calculator script for finding appropriate values,
in anyone would like to see it.

> > +static struct etsects the_clock;
> 
> Will there ever be multiple instances of this device?

No, never. If you consider how PTP works, there can only be one clock
per system.

> Consider of_iomap(), it will simplify the code a bit.

> Move ptp_gianfar_exit() definition here so it is immediately before
> the module_exit() line.

Okay.


Thanks for the review,

Richard

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mitch Bradley @ 2010-06-16  6:32 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C186C72.2020506@compulab.co.il>

Mike Rapoport wrote:
> Mitch Bradley wrote:
>> Mike Rapoport wrote:
>>> Mitch Bradley wrote:
>>>
>>>> The second topic is the hypothetical use of OFW as a HAL. That will 
>>>> not happen for several reasons.  The opposition to the idea is 
>>>> widespread and deeply held, and there are good arguments to support 
>>>> that opposition.   Furthermore, the economic conditions necessary 
>>>> for the creation of such a HAL do not exist in the ARM world, nor 
>>>> indeed in the Linux world in general.  (The necessary condition is 
>>>> the ability for one company to impose a substantial change by fiat 
>>>> - essentially a monopoly position.)
>>>>
>>>> Shall we agree, then, that any further discussion of the HAL issue 
>>>> is "just for fun", and that nobody needs to feel threatened that it 
>>>> would actually happen?
>>>
>>> I've recently worked with vendor versions of U-Boot for advanced ARM 
>>> SoCs. There is already *huge* chunk of HAL code in those versions. 
>>> And if there would be possibility to have callbacks into the 
>>> firmware these chunks would only grow, IMHO.
>>
>> How can there be HAL code in U-Boot unless there is already the 
>> possibility to have callbacks into the firmware?
>
> Currently it aims to abstract hardware from U-Boot and reuse the same 
> HW access code across operating systems and bootloaders. If this code 
> would have callbacks I afraid the things would became worse.

The only way I can understand what you said is if I assume that by 
"callback", you mean the following sequence:

a) U-boot loads and executes the OS, providing to the OS the address of 
some HW access routines that it can use
b) The OS calls one of those HW access routines
c) During the execution of that HW access routine, that routine calls 
"back" into the OS, before returning.  So a call into the OS is nested 
inside a call into U-boot resident code.

If that is what you are worried about, it is not what we were 
discussing.  We were discussing - and many people were against - step (b).

Are you saying that step (b) - the OS calling into routines provided by 
U-Boot - is already the status quo?

>
>> It is not HAL if it can't be called.
>>
>>>
>>>
>>>> The potential for "vendors breaking out of the debugging use case 
>>>> and turning it into a HAL" is miniscule, because
>>>>
>>>> a) The callback is disabled by default
>>>> b) The technical challenges of the callback interface limit its 
>>>> applicability to specific "wizard user" scenarios
>>>> c) OFW is unlikely to achieve sufficient market penetration for the 
>>>> HAL thing to be worth doing
>>>>
>>>>
>>>> _______________________________________________
>>>> linux-arm-kernel mailing list
>>>> linux-arm-kernel@lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>>>
>
>

^ permalink raw reply

* Re: [PATCH 04/12] phylib: add a way to make PHY time stamps possible.
From: Richard Cochran @ 2010-06-16  6:29 UTC (permalink / raw)
  To: netdev; +Cc: devicetree-discuss, linuxppc-dev, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <27c0ad283f025c2bb71e7ceb71be07f969939429.1276615626.git.richard.cochran@omicron.at>

On Tue, Jun 15, 2010 at 06:08:20PM +0200, Richard Cochran wrote:

> +static inline void skb_tx_timetamp(struct phy_device *phy, struct sk_buff *skb)
> +{
> +	union skb_shared_tx *shtx = skb_tx(skb);
> +
> +	if (shtx->hardware && phy && phy->drv->txtstamp)
> +		phy->drv->txtstamp(phy, skb);
> +
> +	if (shtx->software && !shtx->in_progress)
> +		skb_tstamp_tx(skb, NULL);
> +}

I forgot to mention this patch also provides a way to fix the broken
software timestamp fallback mode of the SO_TIMESTAMPING API.

We would have to add this inline call to every MAC driver in an
appropriate spot within the hard_xmit function. It is not too pretty,
but providing this as a compile time option will promote
standardization of the SO_TIMESTAMPING API for applications.

Richard

^ permalink raw reply

* Re: [PATCH 05/12] phylib: Allow reading and writing a mii bus from atomic context.
From: Richard Cochran @ 2010-06-16  6:20 UTC (permalink / raw)
  To: Grant Likely
  Cc: netdev, devicetree-discuss, Thomas Gleixner, linuxppc-dev,
	linux-arm-kernel, Krzysztof Halasa
In-Reply-To: <AANLkTin8RI4UKzA58k_qER_urdwnD037u5GZrVQS8IoS@mail.gmail.com>

> That's right, and I fully agree with that change.  To me, going back
> to allowing spin locks is a regression because it adds a new source of
> scheduling latency.

I think that the change was not about reducing scheduling
latency. Rather, the idea was simply to allow mdio bus drivers that
sleep. Here is the change log message:

    commit 35b5f6b1a82b5c586e0b24c711dc6ba944e88ef1

    PHYLIB: Locking fixes for PHY I/O potentially sleeping
    
    PHY read/write functions can potentially sleep (e.g., a PHY accessed
    via I2C).  The following changes were made to account for this:
    
        * Change spin locks to mutex locks
        * Add a BUG_ON() to phy_read() phy_write() to warn against
          calling them from an interrupt context.
        * Use work queue for PHY state machine handling since
          it can potentially sleep
        * Change phydev lock from spinlock to mutex

The fundamental issue is this: Fro the SO_TIMESTAMPING API, receive
timestamps must appear in a control message along with the packet
data. Only the MAC driver (or the PHY driver) knows how to get the
timestamp. The stack calls the MAC driver via its napi poll
function. During the call, the driver must provide the skb with Rx
timestamp.

The only reasonable way to do this is to have the driver fetch the
timestamp durng the napi poll function. For MAC drivers with fast
register access, the performance penalty is small. For PHY drivers
with must go via the MDIO bus, the performance penalty is obviously
larger, and the user must be willing to live with it.

You might suggest the alternate that the driver would defer the
netif_receive_skb() callback until a work queue completes, providing
the Rx timestamp. The driver would then call netif_receive_skb() at
some later time.

However, there are a number of problems with this idea:

1. It is really icky for the drivers to be creating new skb queues for
   this purpose. MAC drivers would have to maintain such queues on
   behalf of the PHY drivers, but only when the PHYs support
   timestamping. Yuck.

2. There is a (soft) real time constraint on the delivery of the PTP
   packets to the user space application. Basicly, delays and jitter
   in the time to receive the packet negatively affect the clock servo
   loop.

3. It cannot work for many kinds of PTP timestamping hardware. Some of
   hardware only timestamps PTP packets. That means that not every
   received packet will have a timestamp. Such hardware provides some
   key data from the packet (like PTP UUID and sequence number) with
   the timestamp. Software must match this information to a particular
   packet. In order to defer a skb, the driver must first obtain the
   timestamp information. This is a catch-22.

Having said all that, I am still open to suggestions...

Richard

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mike Rapoport @ 2010-06-16  6:17 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C186B7B.1060308@firmworks.com>

Mitch Bradley wrote:
> Mike Rapoport wrote:
>> Mitch Bradley wrote:
>>
>>> The second topic is the hypothetical use of OFW as a HAL. That will 
>>> not happen for several reasons.  The opposition to the idea is 
>>> widespread and deeply held, and there are good arguments to support 
>>> that opposition.   Furthermore, the economic conditions necessary for 
>>> the creation of such a HAL do not exist in the ARM world, nor indeed 
>>> in the Linux world in general.  (The necessary condition is the 
>>> ability for one company to impose a substantial change by fiat - 
>>> essentially a monopoly position.)
>>>
>>> Shall we agree, then, that any further discussion of the HAL issue is 
>>> "just for fun", and that nobody needs to feel threatened that it 
>>> would actually happen?
>>
>> I've recently worked with vendor versions of U-Boot for advanced ARM 
>> SoCs. There is already *huge* chunk of HAL code in those versions. And 
>> if there would be possibility to have callbacks into the firmware 
>> these chunks would only grow, IMHO.
> 
> How can there be HAL code in U-Boot unless there is already the 
> possibility to have callbacks into the firmware?

Currently it aims to abstract hardware from U-Boot and reuse the same HW 
access code across operating systems and bootloaders. If this code would 
have callbacks I afraid the things would became worse.

> It is not HAL if it can't be called.
> 
>>
>>
>>> The potential for "vendors breaking out of the debugging use case and 
>>> turning it into a HAL" is miniscule, because
>>>
>>> a) The callback is disabled by default
>>> b) The technical challenges of the callback interface limit its 
>>> applicability to specific "wizard user" scenarios
>>> c) OFW is unlikely to achieve sufficient market penetration for the 
>>> HAL thing to be worth doing
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>>


-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: Request review of device tree documentation
From: Mitch Bradley @ 2010-06-16  6:13 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Nicolas Pitre, microblaze-uclinux, devicetree-discuss,
	Jamie Lokier, linuxppc-dev, Dan Malek, Jeremy Kerr,
	linux-arm-kernel, David Gibson
In-Reply-To: <4C186AA8.4040709@compulab.co.il>

Mike Rapoport wrote:
> Mitch Bradley wrote:
>
>> The second topic is the hypothetical use of OFW as a HAL. That will 
>> not happen for several reasons.  The opposition to the idea is 
>> widespread and deeply held, and there are good arguments to support 
>> that opposition.   Furthermore, the economic conditions necessary for 
>> the creation of such a HAL do not exist in the ARM world, nor indeed 
>> in the Linux world in general.  (The necessary condition is the 
>> ability for one company to impose a substantial change by fiat - 
>> essentially a monopoly position.)
>>
>> Shall we agree, then, that any further discussion of the HAL issue is 
>> "just for fun", and that nobody needs to feel threatened that it 
>> would actually happen?
>
> I've recently worked with vendor versions of U-Boot for advanced ARM 
> SoCs. There is already *huge* chunk of HAL code in those versions. And 
> if there would be possibility to have callbacks into the firmware 
> these chunks would only grow, IMHO.

How can there be HAL code in U-Boot unless there is already the 
possibility to have callbacks into the firmware?

It is not HAL if it can't be called.

>
>
>> The potential for "vendors breaking out of the debugging use case and 
>> turning it into a HAL" is miniscule, because
>>
>> a) The callback is disabled by default
>> b) The technical challenges of the callback interface limit its 
>> applicability to specific "wizard user" scenarios
>> c) OFW is unlikely to achieve sufficient market penetration for the 
>> HAL thing to be worth doing
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>

^ permalink raw reply

* Re: [PATCH 04/12] phylib: add a way to make PHY time stamps possible.
From: Richard Cochran @ 2010-06-16  5:40 UTC (permalink / raw)
  To: Grant Likely
  Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <AANLkTimhAvu0_WuMCwnCrw9Rbcy6dKxvTlzepJm7ZDdR@mail.gmail.com>

On Tue, Jun 15, 2010 at 10:33:51AM -0600, Grant Likely wrote:
> > +config NETWORK_PHY_TIMESTAMPING
> Some overhead?  At a brief glance of the series it looks like it could
> add a lot of overhead, but I'm not fully clear on what the full
> process is.  Can you describe how the hardware timestamping works?  I
> could use an overview of what the kernel has to do.

First of all, I want to emphasize that this network stack option is
purely voluntary. Only those people who know that they have a PTP
capable PHY and really want the timestamps will (or should) enable
this option. When it is not enabled, it has no effect at all.

Hardware timestamping is described in

   Documentation/networking/timestamping.txt
   Documentation/networking/timestamping/timestamping.c

The PTP subsystem is described in

   Documentation/ptp/ptp.txt

There really is more to say about the issue than appears in those
documents, but they are a good starting place for discussion.

BTW I am submitting a conference paper on the design on the PTP
subsystem. If you would like to have it, just ask me off-list.

Richard

^ permalink raw reply

* Re: [PATCH] Restore kexec uImage-ppc to working state
From: Simon Horman @ 2010-06-16  2:38 UTC (permalink / raw)
  To: Matthew McClintock; +Cc: linuxppc-dev, kexec
In-Reply-To: <1276544322-30412-1-git-send-email-msm@freescale.com>

CCed linuxppc-dev to fish for an ack.

On Mon, Jun 14, 2010 at 02:38:42PM -0500, Matthew McClintock wrote:
> Booting with uImage-ppc was broken by previous work, this
> patch should restore it to working order
> 
> Signed-off-by: Matthew McClintock <msm@freescale.com>
> ---
>  kexec/arch/ppc/kexec-ppc.c         |   68 ++++++++++++++++++++++-------------
>  kexec/arch/ppc/kexec-uImage-ppc.c  |    5 +--
>  purgatory/arch/ppc/purgatory-ppc.c |    5 +++
>  3 files changed, 49 insertions(+), 29 deletions(-)
> 
> diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
> index 55cadd6..c073f56 100644
> --- a/kexec/arch/ppc/kexec-ppc.c
> +++ b/kexec/arch/ppc/kexec-ppc.c
> @@ -261,11 +261,28 @@ static int get_base_ranges(void)
>  					break;
>  				}
>  			}
> -			base_memory_range[local_memory_ranges].start =
> -				((uint32_t *)buf)[0];
> -			base_memory_range[local_memory_ranges].end  =
> -				base_memory_range[local_memory_ranges].start +
> -				((uint32_t *)buf)[1];
> +
> +			if (n == 8)
> +			{
> +				base_memory_range[local_memory_ranges].start =
> +					((uint32_t *)buf)[0];
> +				base_memory_range[local_memory_ranges].end  =
> +					base_memory_range[local_memory_ranges].start +
> +					((uint32_t *)buf)[1];
> +			}
> +			else if (n == 16)
> +			{
> +				base_memory_range[local_memory_ranges].start =
> +                                        ((uint64_t *)buf)[0];
> +                                base_memory_range[local_memory_ranges].end  =
> +                                        base_memory_range[local_memory_ranges].start +
> +                                        ((uint64_t *)buf)[1];
> +			}
> +			else
> +			{
> +				fprintf(stderr, "Mem node has invalid size: %d\n", n);
> +				return -1;
> +			}
>  			base_memory_range[local_memory_ranges].type = RANGE_RAM;
>  			local_memory_ranges++;
>  			dbgprintf("%016llx-%016llx : %x\n",
> @@ -327,27 +344,28 @@ static int get_devtree_details(unsigned long kexec_flags)
>  		}
>  
>  		if (strncmp(dentry->d_name, "chosen", 6) == 0) {
> -			strcat(fname, "/linux,kernel-end");
> -			file = fopen(fname, "r");
> -			if (!file) {
> -				perror(fname);
> -				goto error_opencdir;
> -			}
> -			if (fread(&tmp_long, sizeof(unsigned long), 1, file)
> -					!= 1) {
> -				perror(fname);
> -				goto error_openfile;
> -			}
> -			kernel_end = tmp_long;
> -			fclose(file);
> -
> -			/* Add kernel memory to exclude_range */
> -			exclude_range[i].start = 0x0UL;
> -			exclude_range[i].end = kernel_end;
> -			i++;
> -			if (i >= max_memory_ranges)
> -				realloc_memory_ranges();
> +			/* only reserve kernel region if we are doing a crash kernel */
>  			if (kexec_flags & KEXEC_ON_CRASH) {
> +				strcat(fname, "/linux,kernel-end");
> +				file = fopen(fname, "r");
> +				if (!file) {
> +					perror(fname);
> +					goto error_opencdir;
> +				}
> +				if (fread(&tmp_long, sizeof(unsigned long), 1, file)
> +						!= 1) {
> +					perror(fname);
> +					goto error_openfile;
> +				}
> +				kernel_end = tmp_long;
> +				fclose(file);
> +
> +				/* Add kernel memory to exclude_range */
> +				exclude_range[i].start = 0x0UL;
> +				exclude_range[i].end = kernel_end;
> +				i++;
> +				if (i >= max_memory_ranges)
> +					realloc_memory_ranges();
>  				memset(fname, 0, sizeof(fname));
>  				strcpy(fname, device_tree);
>  				strcat(fname, dentry->d_name);
> diff --git a/kexec/arch/ppc/kexec-uImage-ppc.c b/kexec/arch/ppc/kexec-uImage-ppc.c
> index 45cde2f..4a8d28d 100644
> --- a/kexec/arch/ppc/kexec-uImage-ppc.c
> +++ b/kexec/arch/ppc/kexec-uImage-ppc.c
> @@ -133,13 +133,10 @@ static int ppc_load_bare_bits(int argc, char **argv, const char *buf,
>  	addr = dtb_addr;
>  	elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
>  
> -	addr = rmo_top;
> -	elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
> -
>  #define PUL_STACK_SIZE  (16 * 1024)
>  	addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, -1, 1);
>  	addr += PUL_STACK_SIZE;
> -	elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
> +	elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr));
>  	/* No allocation past here in order not to overwrite the stack */
>  #undef PUL_STACK_SIZE
>  
> diff --git a/purgatory/arch/ppc/purgatory-ppc.c b/purgatory/arch/ppc/purgatory-ppc.c
> index 3d7d484..349e750 100644
> --- a/purgatory/arch/ppc/purgatory-ppc.c
> +++ b/purgatory/arch/ppc/purgatory-ppc.c
> @@ -39,3 +39,8 @@ void post_verification_setup_arch(void)
>  	if (panic_kernel)
>  		crashdump_backup_memory();
>  }
> +
> +void crashdump_backup_memory(void)
> +{
> +	return;
> +}
> -- 
> 1.6.0.6
> 
> 
> _______________________________________________
> kexec mailing list
> kexec@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply

* [PATCH RFC] ppc: fix default_machine_crash_shutdown #ifdef botch
From: Paul E. McKenney @ 2010-06-16  0:48 UTC (permalink / raw)
  To: linuxppc-dev

crash_kexec_wait_realmode() is defined only if CONFIG_PPC_STD_MMU_64
and CONFIG_SMP, but is called if CONFIG_PPC_STD_MMU_64 even if !CONFIG_SMP.
Fix the conditional compilation around the invocation.

Untested, probably does not compile.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index b46f2e0..29df48f 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -447,7 +447,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
 	crash_kexec_prepare_cpus(crashing_cpu);
 	cpu_set(crashing_cpu, cpus_in_crash);
 	crash_kexec_stop_spus();
-#ifdef CONFIG_PPC_STD_MMU_64
+#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP)
 	crash_kexec_wait_realmode(crashing_cpu);
 #endif
 	if (ppc_md.kexec_cpu_down)

^ permalink raw reply related

* Re: [PATCH 5/5] of/address: restrict 'no-ranges' kludge to powerpc
From: Benjamin Herrenschmidt @ 2010-06-16  0:33 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Stephen Rothwell, devicetree-discuss, linuxppc-dev
In-Reply-To: <1C7A9067-DDE6-47D3-AC78-FDC081354519@kernel.crashing.org>

On Tue, 2010-06-15 at 18:23 +0200, Segher Boessenkool wrote:
> >> Certain Apple machines don't use the ranges property correctly,  
> >> but the
> >> workaround should not be applied on other architectures.  This patch
> >> disables the workaround for non-powerpc architectures.
> >
> > I'm half tempted to add it to the quirk list (which should really be
> > made generic) so I can disable it on more 'modern' powerpc as well.
> 
> Oh please oh please oh please yes do.
> 
> OTOH, it would be even better to just fix up the device tree in the
> early platform code.  Quirks are for broken hardware; software, we
> can fix.

That would work if I could bloody remember which machines need what on
what nodes ... some of those are ancient and I don't have access to all
of them.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH v2] lite5200: fix ethernet phy address
From: Dmitry Eremin-Solenikov @ 2010-06-15 22:19 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1276154181-25534-1-git-send-email-dbaryshkov__1637.54533646188$1276154215$gmane$org@gmail.com>

Dmitry Eremin-Solenikov wrote:

> According to my schematics, on Lite5200 board ethernet phy uses address
> 0 (all ADDR lines are pulled down). With this change I can talk to
> onboard phy (LXT971) and correctly use autonegotiation.

What about this patch?

-- 
With best wishes
Dmitry

^ permalink raw reply

* Porting a driver to powerpc using FDT
From: Chris Alfred (Internode) @ 2010-06-15 22:18 UTC (permalink / raw)
  To: linuxppc-dev

I am trying to port a DSA (Distributed Switch Architecture) driver for 
the Micrel KS8995M managed switch connected to a MPC5200. There is an 
SPI interface and MII interface managed by the DSA driver.

I can't understand how probe gets called when the flatted device tree 
(FDT) system is used, and how to bind such a driver using the FDT (if 
you have to at all).

The DSA driver is initialised via:

    // net/dsa/dsa.c

    static struct platform_driver dsa_driver = {
     .probe  = dsa_probe,
     .remove  = dsa_remove,
     .shutdown = dsa_shutdown,
     .driver = {
      .name = "dsa",
      .owner = THIS_MODULE,
     },
    };

    static int __init dsa_init_module(void)
    {
     return platform_driver_register(&dsa_driver);
    }

dsa_init_module is being called; but how do I get the system to call 
.probe?

Chris

^ permalink raw reply

* Porting a driver to powerpc using FDT
From: Chris Alfred @ 2010-06-15 22:19 UTC (permalink / raw)
  To: linuxppc-dev

I am trying to port a DSA (Distributed Switch Architecture) driver for
the Micrel KS8995M managed switch connected to a MPC5200. There is an
SPI interface and MII interface managed by the DSA driver.

I can't understand how probe gets called when the flatted device tree
(FDT) system is used, and how to bind such a driver using the FDT (if
you have to at all).

The DSA driver is initialised via:

    // net/dsa/dsa.c

    static struct platform_driver dsa_driver = {
     .probe  = dsa_probe,
     .remove  = dsa_remove,
     .shutdown = dsa_shutdown,
     .driver = {
      .name = "dsa",
      .owner = THIS_MODULE,
     },
    };

    static int __init dsa_init_module(void)
    {
     return platform_driver_register(&dsa_driver);
    }

dsa_init_module is being called; but how do I get the system to call
.probe?

Chris

^ permalink raw reply

* [PATCH 1/2 v4] powerpc/5200: add mpc5200_psc_ac97_gpio_reset
From: Eric Millbrandt @ 2010-06-15 21:53 UTC (permalink / raw)
  To: Grant Likely; +Cc: Mark Brown, linuxppc-dev, Eric Millbrandt
In-Reply-To: <1276617907-10862-2-git-send-email-emillbrandt@dekaresearch.com>

Work around a silicon bug in the ac97 reset functionality of the
mpc5200(b).  The implementation of the ac97 "cold" reset is flawed.
If the sync and output lines are high when reset is asserted the
attached ac97 device may go into test mode.  Avoid this by
reconfiguring the psc to gpio mode and generating the reset manually.

>From MPC5200B User's Manual:
"Some AC97 devices goes to a test mode, if the Sync line is high
during the Res line is low (reset phase). To avoid this behavior the
Sync line must be also forced to zero during the reset phase. To do
that, the pin muxing should switch to GPIO mode and the GPIO control
register should be used to control the output lines."

Signed-off-by: Eric Millbrandt <emillbrandt@dekaresearch.com>
---

changes since v1
- Amended with comments from Mark Brown
- Fall back to the original reset implementation if no gpio pins are define=
d
  in the device tree

changes since v2
- Refactored to move the port_config manipulation to platform code.
- Remove the gpio pins from the device-tree

changes since v3
- Remove redundant checks around call to mpc5200_psc_ac97_gpio_reset()

changes since v4
- cleanup inverted logic

 arch/powerpc/include/asm/mpc52xx.h           |    1 +
 arch/powerpc/include/asm/mpc52xx_psc.h       |    1 +
 arch/powerpc/platforms/52xx/mpc52xx_common.c |  111 ++++++++++++++++++++++=
++++
 3 files changed, 113 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/=
mpc52xx.h
index b664ce7..1f41382 100644
--- a/arch/powerpc/include/asm/mpc52xx.h
+++ b/arch/powerpc/include/asm/mpc52xx.h
@@ -271,6 +271,7 @@ struct mpc52xx_intr {
 /* mpc52xx_common.c */
 extern void mpc5200_setup_xlb_arbiter(void);
 extern void mpc52xx_declare_of_platform_devices(void);
+extern int mpc5200_psc_ac97_gpio_reset(int psc_number);
 extern void mpc52xx_map_common_devices(void);
 extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
 extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node);
diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/=
asm/mpc52xx_psc.h
index ecc4fc6..2966df6 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -131,6 +131,7 @@
 #define MPC52xx_PSC_SICR_SIM_FIR               (0x6 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_24          (0x7 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_32          (0xf << 24)
+#define MPC52xx_PSC_SICR_ACRB                  (0x8 << 24)
 #define MPC52xx_PSC_SICR_AWR                   (1 << 30)
 #define MPC52xx_PSC_SICR_GENCLK                        (1 << 23)
 #define MPC52xx_PSC_SICR_I2S                   (1 << 22)
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/pl=
atforms/52xx/mpc52xx_common.c
index a46bad0..1887872 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -12,9 +12,11 @@

 #undef DEBUG

+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/mpc52xx.h>
@@ -82,6 +84,14 @@ mpc5200_setup_xlb_arbiter(void)
        iounmap(xlb);
 }

+/*
+ * This variable is mapped in mpc52xx_map_common_devices and
+ * used in mpc5200_psc_ac97_gpio_reset().
+ */
+static DEFINE_SPINLOCK(gpio_lock);
+struct mpc52xx_gpio __iomem *simple_gpio;
+struct mpc52xx_gpio_wkup __iomem *wkup_gpio;
+
 /**
  * mpc52xx_declare_of_platform_devices: register internal devices and chil=
dren
  *                                     of the localplus bus to the of_plat=
form
@@ -109,6 +119,19 @@ static struct of_device_id mpc52xx_cdm_ids[] __initdat=
a =3D {
        { .compatible =3D "mpc5200-cdm", }, /* old */
        {}
 };
+static const struct of_device_id mpc52xx_gpio_simple[] =3D {
+       {
+               .compatible =3D "fsl,mpc5200-gpio",
+       },
+       {}
+};
+static const struct of_device_id mpc52xx_gpio_wkup[] =3D {
+       {
+               .compatible =3D "fsl,mpc5200-gpio-wkup",
+       },
+       {}
+};
+

 /**
  * mpc52xx_map_common_devices: iomap devices required by common code
@@ -135,6 +158,16 @@ mpc52xx_map_common_devices(void)
        np =3D of_find_matching_node(NULL, mpc52xx_cdm_ids);
        mpc52xx_cdm =3D of_iomap(np, 0);
        of_node_put(np);
+
+       /* simple_gpio registers */
+       np =3D of_find_matching_node(NULL, mpc52xx_gpio_simple);
+       simple_gpio =3D of_iomap(np, 0);
+       of_node_put(np);
+
+       /* wkup_gpio registers */
+       np =3D of_find_matching_node(NULL, mpc52xx_gpio_wkup);
+       wkup_gpio =3D of_iomap(np, 0);
+       of_node_put(np);
 }

 /**
@@ -233,3 +266,81 @@ mpc52xx_restart(char *cmd)

        while (1);
 }
+
+#define PSC1_RESET     0x1
+#define PSC1_SYNC      0x4
+#define PSC1_SDATA_OUT 0x1
+#define PSC2_RESET     0x2
+#define PSC2_SYNC      (0x4<<4)
+#define PSC2_SDATA_OUT (0x1<<4)
+#define MPC52xx_GPIO_PSC1_MASK 0x7
+#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)
+
+/**
+ * mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus
+ *
+ * @psc: psc number to reset (only psc 1 and 2 support ac97)
+ */
+int mpc5200_psc_ac97_gpio_reset(int psc_number)
+{
+       unsigned long flags;
+       u32 gpio;
+       u32 mux;
+       int out;
+       int reset;
+       int sync;
+
+       if ((!simple_gpio) || (!wkup_gpio))
+               return -ENODEV;
+
+       switch (psc_number) {
+       case 0:
+               reset   =3D PSC1_RESET;           /* AC97_1_RES */
+               sync    =3D PSC1_SYNC;            /* AC97_1_SYNC */
+               out     =3D PSC1_SDATA_OUT;       /* AC97_1_SDATA_OUT */
+               gpio    =3D MPC52xx_GPIO_PSC1_MASK;
+               break;
+       case 1:
+               reset   =3D PSC2_RESET;           /* AC97_2_RES */
+               sync    =3D PSC2_SYNC;            /* AC97_2_SYNC */
+               out     =3D PSC2_SDATA_OUT;       /* AC97_2_SDATA_OUT */
+               gpio    =3D MPC52xx_GPIO_PSC2_MASK;
+               break;
+       default:
+               printk(KERN_ERR __FILE__ ": "
+                     "Unable to determine PSC, no ac97 cold-reset will be =
"
+                     "performed\n");
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /* Reconfiure pin-muxing to gpio */
+       mux =3D in_be32(&simple_gpio->port_config);
+       out_be32(&simple_gpio->port_config, mux & (~gpio));
+
+       /* enable gpio pins for output */
+       setbits8(&wkup_gpio->wkup_gpioe, reset);
+       setbits32(&simple_gpio->simple_gpioe, sync | out);
+
+       setbits8(&wkup_gpio->wkup_ddr, reset);
+       setbits32(&simple_gpio->simple_ddr, sync | out);
+
+       /* Assert cold reset */
+       clrbits32(&simple_gpio->simple_dvo, sync | out);
+       clrbits8(&wkup_gpio->wkup_dvo, reset);
+
+       /* wait at lease 1 us */
+       udelay(2);
+
+       /* Deassert reset */
+       setbits8(&wkup_gpio->wkup_dvo, reset);
+
+       /* Restore pin-muxing */
+       out_be32(&simple_gpio->port_config, mux);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset);
--
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-

1.6.3.1


This e-mail and the information, including any attachments, it contains are=
 intended to be a confidential communication only to the person or entity t=
o whom it is addressed and may contain information that is privileged. If t=
he reader of this message is not the intended recipient, you are hereby not=
ified that any dissemination, distribution or copying of this communication=
 is strictly prohibited. If you have received this communication in error, =
please immediately notify the sender and destroy the original message.

Thank you.

Please consider the environment before printing this email.

^ permalink raw reply related

* Re: [PATCH 08/12] ptp: Added a brand new class driver for ptp clocks.
From: Grant Likely @ 2010-06-15 19:11 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, devicetree-discuss, Thomas Gleixner, linuxppc-dev,
	linux-arm-kernel, Krzysztof Halasa
In-Reply-To: <4a030d2bace90f089f2f3f61496b918c6f1dfb52.1276615626.git.richard.cochran@omicron.at>

On Tue, Jun 15, 2010 at 10:09 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch adds an infrastructure for hardware clocks that implement
> IEEE 1588, the Precision Time Protocol (PTP). A class driver offers a
> registration method to particular hardware clock drivers. Each clock is
> exposed to user space as a character device with ioctls that allow tuning
> of the PTP clock.
>
> Signed-off-by: Richard Cochran <richard.cochran@omicron.at>

Hi Richard,

Some more comments on this patch...

> ---
> =A0Documentation/ptp/ptp.txt =A0 =A0 =A0 =A0| =A0 95 +++++++
> =A0Documentation/ptp/testptp.c =A0 =A0 =A0| =A0269 ++++++++++++++++++++
> =A0Documentation/ptp/testptp.mk =A0 =A0 | =A0 33 +++
> =A0drivers/Kconfig =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =A02 +
> =A0drivers/Makefile =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A01 +
> =A0drivers/ptp/Kconfig =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 26 ++
> =A0drivers/ptp/Makefile =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A05 +
> =A0drivers/ptp/ptp_clock.c =A0 =A0 =A0 =A0 =A0| =A0514 ++++++++++++++++++=
++++++++++++++++++++
> =A0include/linux/Kbuild =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A01 +
> =A0include/linux/ptp_clock.h =A0 =A0 =A0 =A0| =A0 79 ++++++
> =A0include/linux/ptp_clock_kernel.h | =A0137 ++++++++++
> =A011 files changed, 1162 insertions(+), 0 deletions(-)
> =A0create mode 100644 Documentation/ptp/ptp.txt
> =A0create mode 100644 Documentation/ptp/testptp.c
> =A0create mode 100644 Documentation/ptp/testptp.mk
> =A0create mode 100644 drivers/ptp/Kconfig
> =A0create mode 100644 drivers/ptp/Makefile
> =A0create mode 100644 drivers/ptp/ptp_clock.c
> =A0create mode 100644 include/linux/ptp_clock.h
> =A0create mode 100644 include/linux/ptp_clock_kernel.h
>
> diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
> new file mode 100644
> index 0000000..b86695c
> --- /dev/null
> +++ b/drivers/ptp/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for PTP 1588 clock support.
> +#
> +
> +obj-$(CONFIG_PTP_1588_CLOCK) =A0 =A0 =A0 =A0 =A0 +=3D ptp_clock.o
> diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
> new file mode 100644
> index 0000000..4753bf3
> --- /dev/null
> +++ b/drivers/ptp/ptp_clock.c
> @@ -0,0 +1,514 @@
> +/*
> + * PTP 1588 clock support
> + *
> + * Partially adapted from the Linux PPS driver.
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * =A0This program is free software; you can redistribute it and/or modi=
fy
> + * =A0it under the terms of the GNU General Public License as published =
by
> + * =A0the Free Software Foundation; either version 2 of the License, or
> + * =A0(at your option) any later version.
> + *
> + * =A0This program is distributed in the hope that it will be useful,
> + * =A0but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * =A0MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the
> + * =A0GNU General Public License for more details.
> + *
> + * =A0You should have received a copy of the GNU General Public License
> + * =A0along with this program; if not, write to the Free Software
> + * =A0Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include <linux/bitops.h>
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +#include <linux/ptp_clock_kernel.h>
> +#include <linux/ptp_clock.h>
> +
> +#define PTP_MAX_ALARMS 4
> +#define PTP_MAX_CLOCKS BITS_PER_LONG
> +#define PTP_MAX_TIMESTAMPS 128
> +
> +struct alarm {
> + =A0 =A0 =A0 struct pid *pid;
> + =A0 =A0 =A0 int sig;
> +};
> +
> +struct timestamp_event_queue {
> + =A0 =A0 =A0 struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
> + =A0 =A0 =A0 int head;
> + =A0 =A0 =A0 int tail;
> + =A0 =A0 =A0 int overflow;
> +};
> +
> +struct ptp_clock {
> + =A0 =A0 =A0 struct list_head list;
> + =A0 =A0 =A0 struct cdev cdev;
> + =A0 =A0 =A0 struct device *dev;
> + =A0 =A0 =A0 struct ptp_clock_info *info;
> + =A0 =A0 =A0 dev_t devid;
> + =A0 =A0 =A0 int index; /* index into clocks.map, also the minor number =
*/
> +
> + =A0 =A0 =A0 struct alarm alarm[PTP_MAX_ALARMS];
> + =A0 =A0 =A0 struct mutex alarm_mux; /* one process at a time setting an=
 alarm */
> +
> + =A0 =A0 =A0 struct timestamp_event_queue tsevq; /* simple fifo for time=
 stamps */
> + =A0 =A0 =A0 struct mutex tsevq_mux; /* one process at a time reading th=
e fifo */
> + =A0 =A0 =A0 wait_queue_head_t tsev_wq;
> +};
> +
> +/* private globals */
> +
> +static const struct file_operations ptp_fops;
> +static dev_t ptp_devt;
> +static struct class *ptp_class;
> +
> +static struct {
> + =A0 =A0 =A0 struct list_head list;
> + =A0 =A0 =A0 DECLARE_BITMAP(map, PTP_MAX_CLOCKS);
> +} clocks;
> +static DEFINE_SPINLOCK(clocks_lock); /* protects 'clocks' */

Doesn't appear that clocks is manipulated at atomic context.  Mutex instead=
?

> +
> +/* time stamp event queue operations */
> +
> +static inline int queue_cnt(struct timestamp_event_queue *q)
> +{
> + =A0 =A0 =A0 int cnt =3D q->tail - q->head;
> + =A0 =A0 =A0 return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
> +}
> +
> +static inline int queue_free(struct timestamp_event_queue *q)
> +{
> + =A0 =A0 =A0 return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1;
> +}
> +
> +static void enqueue_external_timestamp(struct timestamp_event_queue *que=
ue,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0struct ptp_clock_event *src)
> +{
> + =A0 =A0 =A0 struct ptp_extts_event *dst;
> + =A0 =A0 =A0 u32 remainder;
> +
> + =A0 =A0 =A0 dst =3D &queue->buf[queue->tail];
> +
> + =A0 =A0 =A0 dst->index =3D src->index;
> + =A0 =A0 =A0 dst->ts.tv_sec =3D div_u64_rem(src->timestamp, 1000000000, =
&remainder);
> + =A0 =A0 =A0 dst->ts.tv_nsec =3D remainder;
> +
> + =A0 =A0 =A0 if (!queue_free(queue))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 queue->overflow++;
> +
> + =A0 =A0 =A0 queue->tail =3D (queue->tail + 1) % PTP_MAX_TIMESTAMPS;
> +}
> +
> +/* public interface */
> +
> +struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp;
> + =A0 =A0 =A0 int err =3D 0, index, major =3D MAJOR(ptp_devt);
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 if (info->n_alarm > PTP_MAX_ALARMS)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return ERR_PTR(-EINVAL);

Okay, this is my opinion here, and other maintainers may disagree with
me, but the ERR_PTR() pattern is a horrible idea.  It is non-obvious
when reading code when the pattern is used, and the compiler will not
catch misinterpretation of the return value for you.  Please don't add
new instances of using it.  Just return NULL on error and log it with
printk() or pr_error().  Very seldom do I find the actual error code
to be actually useful anyway.  Generally callers only care about
whether or not the operation succeeded.

> +
> + =A0 =A0 =A0 /* Find a free clock slot and reserve it. */
> + =A0 =A0 =A0 err =3D -EBUSY;
> + =A0 =A0 =A0 spin_lock_irqsave(&clocks_lock, flags);
> + =A0 =A0 =A0 index =3D find_first_zero_bit(clocks.map, PTP_MAX_CLOCKS);
> + =A0 =A0 =A0 if (index < PTP_MAX_CLOCKS) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_bit(index, clocks.map);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&clocks_lock, flags)=
;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&clocks_lock, flags)=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto no_clock;
> + =A0 =A0 =A0 }

If the spinlock is changed to a mutex that is held for the entire
function call, then the logic here can be simpler.

> +
> + =A0 =A0 =A0 /* Initialize a clock structure. */
> + =A0 =A0 =A0 err =3D -ENOMEM;
> + =A0 =A0 =A0 ptp =3D kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
> + =A0 =A0 =A0 if (ptp =3D=3D NULL)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto no_memory;
> +
> + =A0 =A0 =A0 ptp->info =3D info;
> + =A0 =A0 =A0 ptp->devid =3D MKDEV(major, index);
> + =A0 =A0 =A0 ptp->index =3D index;
> + =A0 =A0 =A0 mutex_init(&ptp->alarm_mux);
> + =A0 =A0 =A0 mutex_init(&ptp->tsevq_mux);
> + =A0 =A0 =A0 init_waitqueue_head(&ptp->tsev_wq);
> +
> + =A0 =A0 =A0 /* Create a new device in our class. */
> + =A0 =A0 =A0 ptp->dev =3D device_create(ptp_class, NULL, ptp->devid, ptp=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"ptp_clo=
ck_%d", ptp->index);
> + =A0 =A0 =A0 if (IS_ERR(ptp->dev))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto no_device;
> +
> + =A0 =A0 =A0 dev_set_drvdata(ptp->dev, ptp);
> +
> + =A0 =A0 =A0 /* Register a character device. */
> + =A0 =A0 =A0 cdev_init(&ptp->cdev, &ptp_fops);
> + =A0 =A0 =A0 ptp->cdev.owner =3D info->owner;
> + =A0 =A0 =A0 err =3D cdev_add(&ptp->cdev, ptp->devid, 1);
> + =A0 =A0 =A0 if (err)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto no_cdev;
> +
> + =A0 =A0 =A0 /* Clock is ready, add it into the list. */
> + =A0 =A0 =A0 spin_lock_irqsave(&clocks_lock, flags);
> + =A0 =A0 =A0 list_add(&ptp->list, &clocks.list);
> + =A0 =A0 =A0 spin_unlock_irqrestore(&clocks_lock, flags);
> +
> + =A0 =A0 =A0 return ptp;
> +
> +no_cdev:
> + =A0 =A0 =A0 device_destroy(ptp_class, ptp->devid);
> +no_device:
> + =A0 =A0 =A0 mutex_destroy(&ptp->alarm_mux);
> + =A0 =A0 =A0 mutex_destroy(&ptp->tsevq_mux);
> + =A0 =A0 =A0 kfree(ptp);
> +no_memory:
> + =A0 =A0 =A0 spin_lock_irqsave(&clocks_lock, flags);
> + =A0 =A0 =A0 clear_bit(index, clocks.map);
> + =A0 =A0 =A0 spin_unlock_irqrestore(&clocks_lock, flags);
> +no_clock:
> + =A0 =A0 =A0 return ERR_PTR(err);
> +}
> +EXPORT_SYMBOL(ptp_clock_register);
> +
> +int ptp_clock_unregister(struct ptp_clock *ptp)
> +{
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 /* Release the clock's resources. */
> + =A0 =A0 =A0 cdev_del(&ptp->cdev);
> + =A0 =A0 =A0 device_destroy(ptp_class, ptp->devid);
> + =A0 =A0 =A0 mutex_destroy(&ptp->alarm_mux);
> + =A0 =A0 =A0 mutex_destroy(&ptp->tsevq_mux);
> +
> + =A0 =A0 =A0 /* Remove the clock from the list. */
> + =A0 =A0 =A0 spin_lock_irqsave(&clocks_lock, flags);
> + =A0 =A0 =A0 list_del(&ptp->list);
> + =A0 =A0 =A0 clear_bit(ptp->index, clocks.map);
> + =A0 =A0 =A0 spin_unlock_irqrestore(&clocks_lock, flags);
> +
> + =A0 =A0 =A0 kfree(ptp);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +EXPORT_SYMBOL(ptp_clock_unregister);
> +
> +void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *even=
t)
> +{
> + =A0 =A0 =A0 switch (event->type) {
> +
> + =A0 =A0 =A0 case PTP_CLOCK_ALARM:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 kill_pid(ptp->alarm[event->index].pid,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->alarm[event->index]=
.sig, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_EXTTS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 enqueue_external_timestamp(&ptp->tsevq, eve=
nt);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 wake_up_interruptible(&ptp->tsev_wq);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_PPS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +}
> +EXPORT_SYMBOL(ptp_clock_event);
> +
> +/* character device operations */
> +
> +static int ptp_ioctl(struct inode *node, struct file *fp,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int cmd, unsigned long=
 arg)
> +{
> + =A0 =A0 =A0 struct ptp_clock_caps caps;
> + =A0 =A0 =A0 struct ptp_clock_request req;
> + =A0 =A0 =A0 struct ptp_clock_timer timer;
> + =A0 =A0 =A0 struct ptp_clock *ptp =3D fp->private_data;
> + =A0 =A0 =A0 struct ptp_clock_info *ops =3D ptp->info;
> + =A0 =A0 =A0 void *priv =3D ops->priv;
> + =A0 =A0 =A0 struct timespec ts;
> + =A0 =A0 =A0 int flags, index;
> + =A0 =A0 =A0 int err =3D 0;
> +
> + =A0 =A0 =A0 switch (cmd) {
> +
> + =A0 =A0 =A0 case PTP_CLOCK_APIVERS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D put_user(PTP_CLOCK_VERSION, (u32 __=
user *)arg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_ADJFREQ:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!capable(CAP_SYS_TIME))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EPERM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->adjfreq(priv, arg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_ADJTIME:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!capable(CAP_SYS_TIME))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EPERM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (copy_from_user(&ts, (void __user *)arg,=
 sizeof(ts)))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EFAULT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->adjtime(priv, =
&ts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_GETTIME:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->gettime(priv, &ts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (err)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D copy_to_user((void __user *)arg, &t=
s, sizeof(ts));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_SETTIME:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!capable(CAP_SYS_TIME))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EPERM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (copy_from_user(&ts, (void __user *)arg,=
 sizeof(ts)))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EFAULT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->settime(priv, =
&ts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_GETCAPS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(&caps, 0, sizeof(caps));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 caps.max_adj =3D ptp->info->max_adj;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 caps.n_alarm =3D ptp->info->n_alarm;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 caps.n_ext_ts =3D ptp->info->n_ext_ts;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 caps.n_per_out =3D ptp->info->n_per_out;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 caps.pps =3D ptp->info->pps;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D copy_to_user((void __user *)arg, &c=
aps, sizeof(caps));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_GETTIMER:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (copy_from_user(&timer, (void __user *)a=
rg, sizeof(timer))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EFAULT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 index =3D timer.alarm_index;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (index < 0 || index >=3D ptp->info->n_al=
arm) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->gettimer(priv, index, &timer.t=
sp);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (err)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D copy_to_user((void __user *)arg, &t=
imer, sizeof(timer));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_CLOCK_SETTIMER:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (copy_from_user(&timer, (void __user *)a=
rg, sizeof(timer))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EFAULT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 index =3D timer.alarm_index;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (index < 0 || index >=3D ptp->info->n_al=
arm) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!valid_signal(timer.signum))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 flags =3D timer.flags;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags & (flags !=3D TIMER_ABSTIME)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mutex_lock_interruptible(&ptp->alarm_mu=
x))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ERESTARTSYS;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ptp->alarm[index].pid)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_pid(ptp->alarm[index].p=
id);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp->alarm[index].pid =3D get_pid(task_pid(=
current));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp->alarm[index].sig =3D timer.signum;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->settimer(priv, index, flags, &=
timer.tsp);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&ptp->alarm_mux);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case PTP_FEATURE_REQUEST:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (copy_from_user(&req, (void __user *)arg=
, sizeof(req))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EFAULT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 switch (req.type) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case PTP_REQUEST_EXTTS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case PTP_REQUEST_PEROUT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case PTP_REQUEST_PPS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!capable(CAP_SYS_TIME))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EPE=
RM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (err)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D ops->enable(priv, &req,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 req.fla=
gs & PTP_ENABLE_FEATURE ? 1 : 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -ENOTTY;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return err;
> +}
> +
> +static int ptp_open(struct inode *inode, struct file *fp)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp;
> + =A0 =A0 =A0 ptp =3D container_of(inode->i_cdev, struct ptp_clock, cdev)=
;
> +
> + =A0 =A0 =A0 fp->private_data =3D ptp;
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static unsigned int ptp_poll(struct file *fp, poll_table *wait)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp =3D fp->private_data;
> +
> + =A0 =A0 =A0 poll_wait(fp, &ptp->tsev_wq, wait);
> +
> + =A0 =A0 =A0 return queue_cnt(&ptp->tsevq) ? POLLIN : 0;
> +}
> +
> +static ssize_t ptp_read(struct file *fp, char __user *buf,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 size_t cnt, loff_t *off)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp =3D fp->private_data;
> + =A0 =A0 =A0 struct timestamp_event_queue *queue =3D &ptp->tsevq;
> + =A0 =A0 =A0 struct ptp_extts_event *event;
> + =A0 =A0 =A0 size_t qcnt;
> +
> + =A0 =A0 =A0 if (mutex_lock_interruptible(&ptp->tsevq_mux))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ERESTARTSYS;
> +
> + =A0 =A0 =A0 cnt =3D cnt / sizeof(struct ptp_extts_event);
> +
> + =A0 =A0 =A0 if (wait_event_interruptible(ptp->tsev_wq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
(qcnt =3D queue_cnt(&ptp->tsevq)))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&ptp->tsevq_mux);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ERESTARTSYS;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (cnt > qcnt)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 cnt =3D qcnt;
> +
> + =A0 =A0 =A0 event =3D &queue->buf[queue->head];
> +
> + =A0 =A0 =A0 if (copy_to_user(buf, event, cnt * sizeof(struct ptp_extts_=
event))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mutex_unlock(&ptp->tsevq_mux);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EFAULT;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 queue->head =3D (queue->head + cnt) % PTP_MAX_TIMESTAMPS;
> +
> + =A0 =A0 =A0 mutex_unlock(&ptp->tsevq_mux);
> +
> + =A0 =A0 =A0 return cnt * sizeof(struct ptp_extts_event);
> +}
> +
> +static int ptp_release(struct inode *inode, struct file *fp)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp;
> + =A0 =A0 =A0 struct itimerspec ts =3D {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 {0, 0}, {0, 0}
> + =A0 =A0 =A0 };
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 ptp =3D container_of(inode->i_cdev, struct ptp_clock, cdev)=
;
> +
> + =A0 =A0 =A0 for (i =3D 0; i < ptp->info->n_alarm; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ptp->alarm[i].pid) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp->info->settimer(ptp->in=
fo->priv, i, 0, &ts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 put_pid(ptp->alarm[i].pid);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp->alarm[i].pid =3D NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static const struct file_operations ptp_fops =3D {
> + =A0 =A0 =A0 .owner =A0 =A0 =A0 =A0 =A0=3D THIS_MODULE,
> + =A0 =A0 =A0 .ioctl =A0 =A0 =A0 =A0 =A0=3D ptp_ioctl,
> + =A0 =A0 =A0 .open =A0 =A0 =A0 =A0 =A0 =3D ptp_open,
> + =A0 =A0 =A0 .poll =A0 =A0 =A0 =A0 =A0 =3D ptp_poll,
> + =A0 =A0 =A0 .read =A0 =A0 =A0 =A0 =A0 =3D ptp_read,
> + =A0 =A0 =A0 .release =A0 =A0 =A0 =A0=3D ptp_release,
> +};
> +
> +/* sysfs */
> +
> +static ssize_t ptp_show_status(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct devic=
e_attribute *attr, char *buf)
> +{
> + =A0 =A0 =A0 struct ptp_clock *ptp =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 return sprintf(buf,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"maximum adjustment: =A0%d\n=
"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"programmable alarms: %d\n"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"external timestamps: %d\n"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"periodic outputs: =A0 =A0%d=
\n"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"has pps: =A0 =A0 =A0 =A0 =
=A0 =A0 %d\n"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"device index: =A0 =A0 =A0 =
=A0%d\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->info->max_adj,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->info->n_alarm,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->info->n_ext_ts,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->info->n_per_out,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->info->pps,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptp->index);
> +}

Don't do this in a sysfs file.  Use a debugfs file if you want to
export freeform data like this.  sysfs files should contain either
only one value, or a simple list-of-same-type values.  Formatted data
is completely out.

> +
> +struct device_attribute ptp_attrs[] =3D {
> + =A0 =A0 =A0 __ATTR(capabilities, S_IRUGO, ptp_show_status, NULL),
> + =A0 =A0 =A0 __ATTR_NULL,
> +};
> +
> +/* module operations */
> +
> +static void __exit ptp_exit(void)
> +{
> + =A0 =A0 =A0 class_destroy(ptp_class);
> + =A0 =A0 =A0 unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
> +}
> +
> +static int __init ptp_init(void)
> +{
> + =A0 =A0 =A0 int err;
> +
> + =A0 =A0 =A0 INIT_LIST_HEAD(&clocks.list);
> +
> + =A0 =A0 =A0 ptp_class =3D class_create(THIS_MODULE, "ptp");
> + =A0 =A0 =A0 if (!ptp_class) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "ptp: failed to allocate cl=
ass\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 ptp_class->dev_attrs =3D ptp_attrs;
> +
> + =A0 =A0 =A0 err =3D alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "=
ptp");
> + =A0 =A0 =A0 if (err < 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "ptp: failed to allocate ch=
ar device region\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto no_region;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 pr_info("PTP clock support registered\n");
> + =A0 =A0 =A0 return 0;
> +
> +no_region:
> + =A0 =A0 =A0 class_destroy(ptp_class);
> + =A0 =A0 =A0 return err;
> +}
> +
> +subsys_initcall(ptp_init);
> +module_exit(ptp_exit);
> +
> +MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
> +MODULE_DESCRIPTION("PTP clocks support");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/Kbuild b/include/linux/Kbuild
> index 2fc8e14..9959fe4 100644
> --- a/include/linux/Kbuild
> +++ b/include/linux/Kbuild
> @@ -140,6 +140,7 @@ header-y +=3D pkt_sched.h
> =A0header-y +=3D posix_types.h
> =A0header-y +=3D ppdev.h
> =A0header-y +=3D prctl.h
> +header-y +=3D ptp_clock.h
> =A0header-y +=3D qnxtypes.h
> =A0header-y +=3D qnx4_fs.h
> =A0header-y +=3D radeonfb.h
> diff --git a/include/linux/ptp_clock.h b/include/linux/ptp_clock.h
> new file mode 100644
> index 0000000..5a509c5
> --- /dev/null
> +++ b/include/linux/ptp_clock.h
> @@ -0,0 +1,79 @@
> +/*
> + * PTP 1588 clock support - user space interface
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * =A0This program is free software; you can redistribute it and/or modi=
fy
> + * =A0it under the terms of the GNU General Public License as published =
by
> + * =A0the Free Software Foundation; either version 2 of the License, or
> + * =A0(at your option) any later version.
> + *
> + * =A0This program is distributed in the hope that it will be useful,
> + * =A0but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * =A0MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the
> + * =A0GNU General Public License for more details.
> + *
> + * =A0You should have received a copy of the GNU General Public License
> + * =A0along with this program; if not, write to the Free Software
> + * =A0Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _PTP_CLOCK_H_
> +#define _PTP_CLOCK_H_
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +
> +#define PTP_ENABLE_FEATURE (1<<0)
> +#define PTP_RISING_EDGE =A0 =A0(1<<1)
> +#define PTP_FALLING_EDGE =A0 (1<<2)
> +
> +enum ptp_request_types {
> + =A0 =A0 =A0 PTP_REQUEST_EXTTS,
> + =A0 =A0 =A0 PTP_REQUEST_PEROUT,
> + =A0 =A0 =A0 PTP_REQUEST_PPS,
> +};
> +
> +struct ptp_clock_caps {
> + =A0 =A0 =A0 __s32 max_adj; /* Maximum frequency adjustment, parts per b=
illon. */
> + =A0 =A0 =A0 int n_alarm; =A0 /* Number of programmable alarms. */
> + =A0 =A0 =A0 int n_ext_ts; =A0/* Number of external time stamp channels.=
 */
> + =A0 =A0 =A0 int n_per_out; /* Number of programmable periodic signals. =
*/
> + =A0 =A0 =A0 int pps; =A0 =A0 =A0 /* Whether the clock supports a PPS ca=
llback. */
> +};
> +
> +struct ptp_clock_timer {
> + =A0 =A0 =A0 int alarm_index; =A0 =A0 =A0 /* Which alarm to query or con=
figure. */
> + =A0 =A0 =A0 int signum; =A0 =A0 =A0 =A0 =A0 =A0/* Requested signal. */
> + =A0 =A0 =A0 int flags; =A0 =A0 =A0 =A0 =A0 =A0 /* Zero or TIMER_ABSTIME=
, see TIMER_SETTIME(2) */
> + =A0 =A0 =A0 struct itimerspec tsp; /* See TIMER_SETTIME(2) */
> +};
> +
> +struct ptp_clock_request {
> + =A0 =A0 =A0 int type; =A0/* One of the ptp_request_types enumeration va=
lues. */
> + =A0 =A0 =A0 int index; /* Which channel to configure. */
> + =A0 =A0 =A0 struct timespec ts; /* For period signals, the desired peri=
od. */
> + =A0 =A0 =A0 int flags; /* Bit field for PTP_ENABLE_FEATURE or other fla=
gs. */
> +};
> +
> +struct ptp_extts_event {
> + =A0 =A0 =A0 int index;
> + =A0 =A0 =A0 struct timespec ts;
> +};
> +
> +#define PTP_CLOCK_VERSION 0x00000001
> +
> +#define PTP_CLK_MAGIC '=3D'
> +
> +#define PTP_CLOCK_APIVERS _IOR (PTP_CLK_MAGIC, 1, __u32)
> +#define PTP_CLOCK_ADJFREQ _IO =A0(PTP_CLK_MAGIC, 2)
> +#define PTP_CLOCK_ADJTIME _IOW (PTP_CLK_MAGIC, 3, struct timespec)
> +#define PTP_CLOCK_GETTIME _IOR (PTP_CLK_MAGIC, 4, struct timespec)
> +#define PTP_CLOCK_SETTIME _IOW (PTP_CLK_MAGIC, 5, struct timespec)
> +
> +#define PTP_CLOCK_GETCAPS =A0 _IOR =A0(PTP_CLK_MAGIC, 6, struct ptp_cloc=
k_caps)
> +#define PTP_CLOCK_GETTIMER =A0_IOWR (PTP_CLK_MAGIC, 7, struct ptp_clock_=
timer)
> +#define PTP_CLOCK_SETTIMER =A0_IOW =A0(PTP_CLK_MAGIC, 8, struct ptp_cloc=
k_timer)
> +#define PTP_FEATURE_REQUEST _IOW =A0(PTP_CLK_MAGIC, 9, struct ptp_clock_=
request)
> +
> +#endif
> diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_k=
ernel.h
> new file mode 100644
> index 0000000..d6cc158
> --- /dev/null
> +++ b/include/linux/ptp_clock_kernel.h
> @@ -0,0 +1,137 @@
> +/*
> + * PTP 1588 clock support
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * =A0This program is free software; you can redistribute it and/or modi=
fy
> + * =A0it under the terms of the GNU General Public License as published =
by
> + * =A0the Free Software Foundation; either version 2 of the License, or
> + * =A0(at your option) any later version.
> + *
> + * =A0This program is distributed in the hope that it will be useful,
> + * =A0but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * =A0MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the
> + * =A0GNU General Public License for more details.
> + *
> + * =A0You should have received a copy of the GNU General Public License
> + * =A0along with this program; if not, write to the Free Software
> + * =A0Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _PTP_CLOCK_KERNEL_H_
> +#define _PTP_CLOCK_KERNEL_H_
> +
> +#include <linux/ptp_clock.h>
> +
> +/**
> + * struct ptp_clock_info - decribes a PTP hardware clock
> + *
> + * @owner: =A0 =A0 The clock driver should set to THIS_MODULE.
> + * @name: =A0 =A0 =A0A short name to identify the clock.
> + * @max_adj: =A0 The maximum possible frequency adjustment, in parts per=
 billon.
> + * @n_alarm: =A0 The number of programmable alarms.
> + * @n_ext_ts: =A0The number of external time stamp channels.
> + * @n_per_out: The number of programmable periodic signals.
> + * @pps: =A0 =A0 =A0 Indicates whether the clock supports a PPS callback=
.
> + * @priv: =A0 =A0 =A0Passed to the clock operations, for the driver's pr=
ivate use.
> + *
> + * clock operations
> + *
> + * @adjfreq: =A0Adjusts the frequency of the hardware clock.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter delta: Desired period change in part=
s per billion.
> + *
> + * @adjtime: =A0Shifts the time of the hardware clock.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter ts: Desired change in seconds and na=
noseconds.
> + *
> + * @gettime: =A0Reads the current time from the hardware clock.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter ts: Holds the result.
> + *
> + * @settime: =A0Set the current time on the hardware clock.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter ts: Time value to set.
> + *
> + * @gettimer: Reads the time remaining from the given timer.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter index: Which alarm to query.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter ts: Holds the result.
> + *
> + * @settimer: Arms the given timer for periodic or one shot operation.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter index: Which alarm to set.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter abs: TIMER_ABSTIME, or zero for rela=
tive timer.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter ts: Alarm time and period to set.
> + *
> + * @enable: =A0 Request driver to enable or disable an ancillary feature=
.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter request: Desired resource to enable =
or disable.
> + * =A0 =A0 =A0 =A0 =A0 =A0parameter on: Caller passes one to enable or z=
ero to disable.
> + *
> + * The callbacks must all return zero on success, non-zero otherwise.
> + */
> +
> +struct ptp_clock_info {
> + =A0 =A0 =A0 struct module *owner;
> + =A0 =A0 =A0 char name[16];
> + =A0 =A0 =A0 s32 max_adj;
> + =A0 =A0 =A0 int n_alarm;
> + =A0 =A0 =A0 int n_ext_ts;
> + =A0 =A0 =A0 int n_per_out;
> + =A0 =A0 =A0 int pps;
> + =A0 =A0 =A0 void *priv;
> + =A0 =A0 =A0 int (*adjfreq)(void *priv, s32 delta);
> + =A0 =A0 =A0 int (*adjtime)(void *priv, struct timespec *ts);
> + =A0 =A0 =A0 int (*gettime)(void *priv, struct timespec *ts);
> + =A0 =A0 =A0 int (*settime)(void *priv, struct timespec *ts);
> + =A0 =A0 =A0 int (*gettimer)(void *priv, int index, struct itimerspec *t=
s);
> + =A0 =A0 =A0 int (*settimer)(void *priv, int index, int abs, struct itim=
erspec *ts);
> + =A0 =A0 =A0 int (*enable)(void *priv, struct ptp_clock_request *request=
, int on);
> +};
> +
> +struct ptp_clock;
> +
> +/**
> + * ptp_clock_register() - register a PTP hardware clock driver
> + *
> + * @info: =A0Structure describing the new clock.
> + */
> +
> +extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)=
;
> +
> +/**
> + * ptp_clock_unregister() - unregister a PTP hardware clock driver
> + *
> + * @ptp: =A0The clock to remove from service.
> + */
> +
> +extern int ptp_clock_unregister(struct ptp_clock *ptp);
> +
> +
> +enum ptp_clock_events {
> + =A0 =A0 =A0 PTP_CLOCK_ALARM,
> + =A0 =A0 =A0 PTP_CLOCK_EXTTS,
> + =A0 =A0 =A0 PTP_CLOCK_PPS,
> +};
> +
> +/**
> + * struct ptp_clock_event - decribes a PTP hardware clock event
> + *
> + * @type: =A0One of the ptp_clock_events enumeration values.
> + * @index: Identifies the source of the event.
> + * @timestamp: When the event occured.
> + */
> +
> +struct ptp_clock_event {
> + =A0 =A0 =A0 int type;
> + =A0 =A0 =A0 int index;
> + =A0 =A0 =A0 u64 timestamp;
> +};
> +
> +/**
> + * ptp_clock_event() - notify the PTP layer about an event
> + *
> + * This function should only be called from interrupt context.
> + *
> + * @ptp: =A0 =A0The clock obtained from ptp_clock_register().
> + * @event: =A0Message structure describing the event.
> + */
> +
> +extern void ptp_clock_event(struct ptp_clock *ptp,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct ptp_clock_ev=
ent *event);
> +
> +#endif
> --
> 1.6.3.3
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 12/12] ptp: Added a clock driver for the National Semiconductor PHYTER.
From: Grant Likely @ 2010-06-15 18:49 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <37f5015b186bdd51f8451ade042f90c8b39a5cc8.1276615626.git.richard.cochran@omicron.at>

On Tue, Jun 15, 2010 at 10:10 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch adds support for the PTP clock found on the DP83640. Only the
> basic clock operations have been implemented.
>
> Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
> ---
> =A0drivers/net/phy/Kconfig =A0 | =A0 11 +++
> =A0drivers/net/phy/dp83640.c | =A0158 +++++++++++++++++++++++++++++++++++=
+++++++++-
> =A02 files changed, 168 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 430cab1..507c68a 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -79,9 +79,20 @@ config NATIONAL_PHY
>
> =A0config DP83640_PHY
> =A0 =A0 =A0 =A0tristate "Driver for the National Semiconductor DP83640 PH=
YTER"
> + =A0 =A0 =A0 depends on PTP_1588_CLOCK
> + =A0 =A0 =A0 depends on NETWORK_PHY_TIMESTAMPING

Won't this break things for existing DP83640 users?

> =A0 =A0 =A0 =A0---help---
> =A0 =A0 =A0 =A0 =A0Supports the DP83640 PHYTER with IEEE 1588 features.
>
> + =A0 =A0 =A0 =A0 This driver adds support for using the DP83640 as a PTP
> + =A0 =A0 =A0 =A0 clock. This clock is only useful if your PTP programs a=
re
> + =A0 =A0 =A0 =A0 getting hardware time stamps on the PTP Ethernet packet=
s
> + =A0 =A0 =A0 =A0 using the SO_TIMESTAMPING API.
> +
> + =A0 =A0 =A0 =A0 In order for this to work, your MAC driver must also
> + =A0 =A0 =A0 =A0 implement the the skb_tx_timetamp() and skb_rx_timetamp=
()
> + =A0 =A0 =A0 =A0 functions.
> +
> =A0config STE10XP
> =A0 =A0 =A0 =A0depends on PHYLIB
> =A0 =A0 =A0 =A0tristate "Driver for STMicroelectronics STe10Xp PHYs"
> diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
> index a3217ea..21eadc3 100644
> --- a/drivers/net/phy/dp83640.c
> +++ b/drivers/net/phy/dp83640.c
> @@ -26,6 +26,7 @@
> =A0#include <linux/netdevice.h>
> =A0#include <linux/phy.h>
> =A0#include <linux/ptp_classify.h>
> +#include <linux/ptp_clock_kernel.h>
>
> =A0#include "dp83640_reg.h"
>
> @@ -45,10 +46,13 @@ struct rxts {
> =A0};
>
> =A0struct dp83640_private {
> + =A0 =A0 =A0 struct phy_device *phydev;
> =A0 =A0 =A0 =A0int hwts_tx_en;
> =A0 =A0 =A0 =A0int hwts_rx_en;
> =A0 =A0 =A0 =A0int layer;
> =A0 =A0 =A0 =A0int version;
> + =A0 =A0 =A0 /* protects PTP_TDR register from concurrent access */
> + =A0 =A0 =A0 spinlock_t ptp_tdr_lock;
> =A0 =A0 =A0 =A0/* protects extended registers from concurrent access */
> =A0 =A0 =A0 =A0spinlock_t extreg_lock;
> =A0 =A0 =A0 =A0int page;
> @@ -60,6 +64,9 @@ struct dp83640_private {
>
> =A0/* globals */
>
> +static struct ptp_clock *dp83640_clock;
> +DEFINE_SPINLOCK(clock_lock); /* protects the one and only dp83640_clock =
*/

Why only one?  Is it not possible to have 2 of these PHYs in a system?

> +
> =A0static struct sock_filter ptp_filter[] =3D {
> =A0 =A0 =A0 =A0PTP_FILTER
> =A0};
> @@ -99,6 +106,129 @@ static void ext_write(struct phy_device *phydev, int=
 page, u32 regnum, u16 val)
> =A0 =A0 =A0 =A0spin_unlock(&dp83640->extreg_lock);
> =A0}
>
> +static int tdr_write(struct dp83640_private *dp83640,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct timespec *ts, u16 cmd)
> +{
> + =A0 =A0 =A0 struct phy_device *phydev =3D dp83640->phydev;
> +
> + =A0 =A0 =A0 spin_lock(&dp83640->ptp_tdr_lock);
> +
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* =
ns[15:0] */
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_TDR, ts->tv_nsec >> 16); =A0 /=
* ns[31:16] */
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* =
sec[15:0] */
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_TDR, ts->tv_sec >> 16); =A0 =
=A0/* sec[31:16] */
> +
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_CTL, cmd);
> +
> + =A0 =A0 =A0 spin_unlock(&dp83640->ptp_tdr_lock);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/* ptp clock methods */
> +
> +static int ptp_dp83640_adjfreq(void *priv, s32 ppb)
> +{
> + =A0 =A0 =A0 struct dp83640_private *dp83640 =3D priv;
> + =A0 =A0 =A0 struct phy_device *phydev =3D dp83640->phydev;
> + =A0 =A0 =A0 u64 rate;
> + =A0 =A0 =A0 int neg_adj =3D 0;
> + =A0 =A0 =A0 u16 hi, lo;
> +
> + =A0 =A0 =A0 if (!ppb)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0;
> +
> + =A0 =A0 =A0 if (ppb < 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 neg_adj =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ppb =3D -ppb;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 rate =3D ppb;
> + =A0 =A0 =A0 rate <<=3D 26;
> + =A0 =A0 =A0 rate =3D div_u64(rate, 1953125);
> +
> + =A0 =A0 =A0 hi =3D (rate >> 16) & PTP_RATE_HI_MASK;
> + =A0 =A0 =A0 if (neg_adj)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hi |=3D PTP_RATE_DIR;
> +
> + =A0 =A0 =A0 lo =3D rate & 0xffff;
> +
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_RATEH, hi);
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_RATEL, lo);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int ptp_dp83640_adjtime(void *priv, struct timespec *ts)
> +{
> + =A0 =A0 =A0 return tdr_write(priv, ts, PTP_STEP_CLK);
> +}
> +
> +static int ptp_dp83640_gettime(void *priv, struct timespec *ts)
> +{
> + =A0 =A0 =A0 struct dp83640_private *dp83640 =3D priv;
> + =A0 =A0 =A0 struct phy_device *phydev =3D dp83640->phydev;
> + =A0 =A0 =A0 unsigned int val[4];
> +
> + =A0 =A0 =A0 spin_lock(&dp83640->ptp_tdr_lock);
> +
> + =A0 =A0 =A0 ext_write(phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
> +
> + =A0 =A0 =A0 val[0] =3D ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
> + =A0 =A0 =A0 val[1] =3D ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] *=
/
> + =A0 =A0 =A0 val[2] =3D ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] *=
/
> + =A0 =A0 =A0 val[3] =3D ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] =
*/
> +
> + =A0 =A0 =A0 spin_unlock(&dp83640->ptp_tdr_lock);
> +
> + =A0 =A0 =A0 ts->tv_nsec =3D val[0] | (val[1] << 16);
> + =A0 =A0 =A0 ts->tv_sec =A0=3D val[2] | (val[3] << 16);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int ptp_dp83640_settime(void *priv, struct timespec *ts)
> +{
> + =A0 =A0 =A0 return tdr_write(priv, ts, PTP_LOAD_CLK);
> +}
> +
> +static int ptp_dp83640_gettimer(void *priv, int index, struct itimerspec=
 *ts)
> +{
> + =A0 =A0 =A0 /* We do not (yet) offer any ancillary features. */
> + =A0 =A0 =A0 return -EOPNOTSUPP;
> +}
> +
> +static int ptp_dp83640_settimer(void *p, int i, int abs, struct itimersp=
ec *ts)
> +{
> + =A0 =A0 =A0 /* We do not (yet) offer any ancillary features. */
> + =A0 =A0 =A0 return -EOPNOTSUPP;
> +}
> +
> +static int ptp_dp83640_enable(void *priv, struct ptp_clock_request *rq, =
int on)
> +{
> + =A0 =A0 =A0 /* We do not (yet) offer any ancillary features. */
> + =A0 =A0 =A0 return -EOPNOTSUPP;
> +}
> +
> +static struct ptp_clock_info ptp_dp83640_caps =3D {
> + =A0 =A0 =A0 .owner =A0 =A0 =A0 =A0 =A0=3D THIS_MODULE,
> + =A0 =A0 =A0 .name =A0 =A0 =A0 =A0 =A0 =3D "dp83640 timer",
> + =A0 =A0 =A0 .max_adj =A0 =A0 =A0 =A0=3D 1953124,
> + =A0 =A0 =A0 .n_alarm =A0 =A0 =A0 =A0=3D 0,
> + =A0 =A0 =A0 .n_ext_ts =A0 =A0 =A0 =3D 0,
> + =A0 =A0 =A0 .n_per_out =A0 =A0 =A0=3D 0,
> + =A0 =A0 =A0 .pps =A0 =A0 =A0 =A0 =A0 =A0=3D 0,
> + =A0 =A0 =A0 .priv =A0 =A0 =A0 =A0 =A0 =3D NULL,

ditto here, can leave the 0s and nulls out.

> + =A0 =A0 =A0 .adjfreq =A0 =A0 =A0 =A0=3D ptp_dp83640_adjfreq,
> + =A0 =A0 =A0 .adjtime =A0 =A0 =A0 =A0=3D ptp_dp83640_adjtime,
> + =A0 =A0 =A0 .gettime =A0 =A0 =A0 =A0=3D ptp_dp83640_gettime,
> + =A0 =A0 =A0 .settime =A0 =A0 =A0 =A0=3D ptp_dp83640_settime,
> + =A0 =A0 =A0 .gettimer =A0 =A0 =A0 =3D ptp_dp83640_gettimer,
> + =A0 =A0 =A0 .settimer =A0 =A0 =A0 =3D ptp_dp83640_settimer,
> + =A0 =A0 =A0 .enable =A0 =A0 =A0 =A0 =3D ptp_dp83640_enable,
> +};
> +
> +/* time stamping methods */
> +
> =A0static int expired(struct rxts *rxts)
> =A0{
> =A0 =A0 =A0 =A0return time_after(jiffies, rxts->tmo);
> @@ -144,6 +274,7 @@ static int match(struct sk_buff *skb, unsigned int ty=
pe, struct rxts *rxts)
> =A0static int dp83640_probe(struct phy_device *phydev)
> =A0{
> =A0 =A0 =A0 =A0struct dp83640_private *dp83640;
> + =A0 =A0 =A0 unsigned long flags;
> =A0 =A0 =A0 =A0int i;
>
> =A0 =A0 =A0 =A0if (sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter))) {
> @@ -155,8 +286,9 @@ static int dp83640_probe(struct phy_device *phydev)
> =A0 =A0 =A0 =A0if (!dp83640)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -ENOMEM;
>
> + =A0 =A0 =A0 dp83640->phydev =3D phydev;
> + =A0 =A0 =A0 spin_lock_init(&dp83640->ptp_tdr_lock);
> =A0 =A0 =A0 =A0spin_lock_init(&dp83640->extreg_lock);
> -
> =A0 =A0 =A0 =A0INIT_LIST_HEAD(&dp83640->rxts);
> =A0 =A0 =A0 =A0INIT_LIST_HEAD(&dp83640->pool);
>
> @@ -165,12 +297,36 @@ static int dp83640_probe(struct phy_device *phydev)
>
> =A0 =A0 =A0 =A0phydev->priv =3D dp83640;
>
> + =A0 =A0 =A0 spin_lock_irqsave(&clock_lock, flags);
> +
> + =A0 =A0 =A0 if (!dp83640_clock) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp_dp83640_caps.priv =3D dp83640;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dp83640_clock =3D ptp_clock_register(&ptp_d=
p83640_caps);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (IS_ERR(dp83640_clock)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&clo=
ck_lock, flags);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 kfree(dp83640);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return PTR_ERR(dp83640_cloc=
k);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 spin_unlock_irqrestore(&clock_lock, flags);
> +
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> =A0static void dp83640_remove(struct phy_device *phydev)
> =A0{
> =A0 =A0 =A0 =A0struct dp83640_private *dp83640 =3D phydev->priv;
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&clock_lock, flags);
> +
> + =A0 =A0 =A0 if (ptp_dp83640_caps.priv =3D=3D dp83640) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp_clock_unregister(dp83640_clock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dp83640_clock =3D NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ptp_dp83640_caps.priv =3D NULL;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 spin_unlock_irqrestore(&clock_lock, flags);
> +
> =A0 =A0 =A0 =A0kfree(dp83640);
> =A0}
>
> --
> 1.6.3.3
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox