LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Inconsistent fsl_get_sys_freq() implementation
From: Wolfgang Grandegger @ 2009-03-31  7:28 UTC (permalink / raw)
  To: linuxppc-dev, devicetree-discuss

Hello,

we realized an inconsistent implementation of fsl_get_sys_freq():

http://lxr.linux.no/linux+v2.6.29/arch/powerpc/sysdev/fsl_soc.c#L80

For 826x and 827x boards, the function is available but it cannot be
used because the "bus-frequency" property is not defined for the SOC and
U-Boot also does not try to do a fixup. I think that's a mistake, and
the DTS files and U-Boot should be fixed, right?
Furthermore, I find the name confusing. fsl_get_soc_bus_freq() would be
more appropriate also to distinguish from the frequencies of the CPU.
And why does the MPC52xx use a different name mpc52xx_find_ipb_freq()
for that frequency? It makes support for common hardware like I2C awkward.

Thanks.

Wolfgang.

^ permalink raw reply

* Re: Inconsistent fsl_get_sys_freq() implementation
From: Grant Likely @ 2009-03-31  7:33 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <49D1C624.2050502@grandegger.com>

On Tue, Mar 31, 2009 at 1:28 AM, Wolfgang Grandegger <wg@grandegger.com> wrote:
>
> Hello,
>
> we realized an inconsistent implementation of fsl_get_sys_freq():
>
> http://lxr.linux.no/linux+v2.6.29/arch/powerpc/sysdev/fsl_soc.c#L80
>
> For 826x and 827x boards, the function is available but it cannot be
> used because the "bus-frequency" property is not defined for the SOC and
> U-Boot also does not try to do a fixup. I think that's a mistake, and
> the DTS files and U-Boot should be fixed, right?
> Furthermore, I find the name confusing. fsl_get_soc_bus_freq() would be
> more appropriate also to distinguish from the frequencies of the CPU.
> And why does the MPC52xx use a different name mpc52xx_find_ipb_freq()
> for that frequency? It makes support for common hardware like I2C awkward.

I haven't looked at fsl_get_soc_bus_freq(), but if the functions are
duplicated, then I've got no problem changing the 52xx support to use
common code.

g.

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

^ permalink raw reply

* Re: Inconsistent fsl_get_sys_freq() implementation
From: Wolfgang Grandegger @ 2009-03-31  7:48 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <fa686aa40903310033n4284ab8l35147ee6f8b0db63@mail.gmail.com>

Grant Likely wrote:
> On Tue, Mar 31, 2009 at 1:28 AM, Wolfgang Grandegger <wg@grandegger.com> wrote:
>> Hello,
>>
>> we realized an inconsistent implementation of fsl_get_sys_freq():
>>
>> http://lxr.linux.no/linux+v2.6.29/arch/powerpc/sysdev/fsl_soc.c#L80
>>
>> For 826x and 827x boards, the function is available but it cannot be
>> used because the "bus-frequency" property is not defined for the SOC and
>> U-Boot also does not try to do a fixup. I think that's a mistake, and
>> the DTS files and U-Boot should be fixed, right?
>> Furthermore, I find the name confusing. fsl_get_soc_bus_freq() would be
>> more appropriate also to distinguish from the frequencies of the CPU.
>> And why does the MPC52xx use a different name mpc52xx_find_ipb_freq()
>> for that frequency? It makes support for common hardware like I2C awkward.
> 
> I haven't looked at fsl_get_soc_bus_freq(), but if the functions are
> duplicated, then I've got no problem changing the 52xx support to use
> common code.

The name used for devices using CONFIG_FSL_SOC is fsl_get_sys_freq(),
see the link above. Both functions return the bus frequency of the SOC
but they are implemented differently and allow some variation (which
needs some double-checking).

Wolfgang.

^ permalink raw reply

* Re: [PATCH] linux-next remove wmb() from ide-dma-sff.c and scc_pata.c
From: Geert Uytterhoeven @ 2009-03-31  7:51 UTC (permalink / raw)
  To: Grant Grundler, Atsushi Nemoto
  Cc: IDE/ATA Devel, LKML, Linux/MIPS Development,
	Bartlomiej Zolnierkiewicz, Linux/PPC Development
In-Reply-To: <da824cf30903301739l688e8eb2r46086953245ebbe5@mail.gmail.com>

On Mon, 30 Mar 2009, Grant Grundler wrote:
> Followup to "[PATCH 03/10] ide: destroy DMA mappings after ending DMA"
> email on March 14th:
>     http://lkml.org/lkml/2009/3/14/17
> 
> No maintainer is listed for "Toshiba CELL Reference Set IDE" (BLK_DEV_CELLEB)
> or tx4939ide.c in MAINTAINERS. I've CC'd "Ishizaki Kou" @Toshiba (Maintainer for
> "Spidernet Network Driver for CELL") and linuxppc-dev list in the hope
> someone else
> would know or would be able to ACK this patch.

tx49xx is MIPS, for Nemoto-san.

> This patch:
> o replaces "mask" variable in ide_dma_end() with #define.
> o removes use of wmb() in ide-dma-sff.c and scc_pata.c.
> o is not tested - I don't have (or want) the HW.
> 
> I did NOT remove wmb() use in tx4939ide.c. tx4939ide.c __raw_writeb()
> for MMIO transactions. __raw_writeb() does NOT guarantee memory
> transaction ordering.
> 
> tx4939ide also uses mmiowb(). AFAIK, mmiowb() only has an effect on
> SGI IA64 NUMA machines. I'm not going to guess how this driver might work.
> 
> Gmail is broken for sending patches (word wrap). My apologies.
> I've attached the patch: diff-next-remove_wmb_from_ide-01.txt
> 
> Patch is against linux-next tree:
>      git://git.kernel.org/pub/scm/linux/kernel/git/sfr/linux-next
> 
> Signed-off-by: Grant Grundler <grundler@google.com>

[ attachment converted to inline ]

> diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
> index 16fc46e..e4cdf78 100644
> --- a/drivers/ide/ide-dma-sff.c
> +++ b/drivers/ide/ide-dma-sff.c
> @@ -277,8 +277,6 @@ void ide_dma_start(ide_drive_t *drive)
>  		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
>  		outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
>  	}
> -
> -	wmb();
>  }
>  EXPORT_SYMBOL_GPL(ide_dma_start);
>  
> @@ -286,7 +284,7 @@ EXPORT_SYMBOL_GPL(ide_dma_start);
>  int ide_dma_end(ide_drive_t *drive)
>  {
>  	ide_hwif_t *hwif = drive->hwif;
> -	u8 dma_stat = 0, dma_cmd = 0, mask;
> +	u8 dma_stat = 0, dma_cmd = 0;
>  
>  	/* stop DMA */
>  	if (hwif->host_flags & IDE_HFLAG_MMIO) {
> @@ -304,11 +302,10 @@ int ide_dma_end(ide_drive_t *drive)
>  	/* clear INTR & ERROR bits */
>  	ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
>  
> -	wmb();
> +#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
>  
>  	/* verify good DMA status */
> -	mask = ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR;
> -	if ((dma_stat & mask) != ATA_DMA_INTR)
> +	if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR)
>  		return 0x10 | dma_stat;
>  	return 0;
>  }
> diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c
> index 97f8e0e..dcbb299 100644
> --- a/drivers/ide/scc_pata.c
> +++ b/drivers/ide/scc_pata.c
> @@ -337,7 +337,6 @@ static void scc_dma_start(ide_drive_t *drive)
>  
>  	/* start DMA */
>  	scc_ide_outb(dma_cmd | 1, hwif->dma_base);
> -	wmb();
>  }
>  
>  static int __scc_dma_end(ide_drive_t *drive)
> @@ -354,7 +353,6 @@ static int __scc_dma_end(ide_drive_t *drive)
>  	/* clear the INTR & ERROR bits */
>  	scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
>  	/* verify good DMA status */
> -	wmb();
>  	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
>  }

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010

^ permalink raw reply

* Re: [PATCH] ucc_geth: Rework the TX logic.
From: Li Yang @ 2009-03-31  8:16 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Joakim Tjernlund, netdev
In-Reply-To: <49D0FFBB.7000009@freescale.com>

On Tue, Mar 31, 2009 at 1:22 AM, Scott Wood <scottwood@freescale.com> wrote=
:
> Joakim Tjernlund wrote:
>>
>> gianfar does not seem to use in_/out_ functions for the BDs. Works just
>> fine that too it seems.
>
> It does now that it has explicit barriers in a few places. =C2=A0Before t=
hey were
> added, it would sometimes fail under load. =C2=A0That was due to a compil=
er
> reordering, but CPU reordering was possible as well.

I noticed that in gianfar these memory access is not protected by
"volatile".  Can this be the reason why the compiler did some unwanted
optimization?

- Leo

^ permalink raw reply

* [PATCH 00/14] Add common OF device tree support for MDIO busses
From: Grant Likely @ 2009-03-31  8:26 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund

This series adds common code for reading PHY connection data out of
the OpenFirmware device tree.  This simplifies the network drivers
which use the device tree and which currently implement their own
solutions for reading the PHY data out of the device tree directly.

This series was depending on changes in both the netdev and powerpc
-next trees.  Now that both trees have been merged by Linus, I'm
able to post this series in a usable form.

David, as I mentioned below, I'd really like to get the core changes
(1, 4, 5  6) merged into 2.6.30 (assuming Andy confirms they are okay).
Due to dependencies, I think it is easiest if all of them go in via the
same tree.  Are you willing to merge them via yours?  Two of the patches
are outside of drivers/net (patches 1 and 6 touch drivers/of/), but I
personally have no issues if those changes go through you.  I just need
to double check with BenH.

Patches 1, 4, 5 and 6 are the core changes.  They have been tested and
I think they are ready to be merged.  Andy, can you please reply and
confirm that you're okay with these 4?  I'd like to see them go in the
2.6.30 merge window.
	[01/14] of: add of_parse_phandle() helper for parsing phandle
	[04/14] phylib: rework to prepare for OF registration of PHYs
	[05/14] phylib: add *_direct() variants of phy_connect and phy_attach
	[06/14] openfirmware: Add OF phylib support code

Patches 2, 3, and 7 (sorry about the funny ordering) are changes to the
fec_mpc52xx driver.  Actually, 2 & 3 are a cleanup and bug fix, but
patch 7 depends on them so I'm including them here.  All three are
tested and working.
	[02/14] net/fec_mpc52xx: Migrate to net_device_ops.
	[03/14] net/fec_mpc52xx: Don't dereference phy_device if it is NULL
	[07/14] net: Rework mpc5200 fec driver to use of_mdio infrastructure.

Patches 8, 9, 10, 12 & 13 are compile tested, but not tested with
hardware.  They are not ready to be merged, and I would like it if
someone with hardware can try them out.  I need to review these ones
again.
	[08/14] net: rework fsl_pq_mdio driver to use of_mdio infrastructure
	[09/14] net: Rework gianfar driver to use of_mdio infrastructure.
	[10/14] net: Rework ucc_geth driver to use of_mdio infrastructure
	[12/14] powerpc/82xx: Rework Embedded Planet ep8248e platform to use of_mdio
	[13/14] net: Rework fs_enet driver to use of_mdio infrastructure

Patch 11 has been tested by Olof Johansson.  It is ready to be merged.
	[11/14] net: Rework pasemi_mac driver to use of_mdio infrastructure

Patch 14 is a new Ethernet driver.  It needs review, but it has been
tested with the new of_mdio infrastructure.  It is not ready.
	[14/14] net: add Xilinx ll_temac device driver

For those who are interested, I've pushed these changes out to by git
server along with a bug fix patch to fec_52xx.c:

The following changes since commit 15f7176eb1cccec0a332541285ee752b935c1c85:
  Linus Torvalds (1):
        Merge git://git.kernel.org/.../davem/net-2.6

are available in the git repository at:

  git://git.secretlab.ca/git/linux-2.6-mpc52xx for-davem

Grant Likely (15):
      net/fec_mpc52xx: fix BUG on missing dma_ops
      of: add of_parse_phandle() helper for parsing phandle properties
      net/fec_mpc52xx: Migrate to net_device_ops.
      net/fec_mpc52xx: Don't dereference phy_device if it is NULL
      phylib: rework to prepare for OF registration of PHYs
      phylib: add *_direct() variants of phy_connect and phy_attach functions
      openfirmware: Add OF phylib support code
      net: Rework mpc5200 fec driver to use of_mdio infrastructure.
      net: rework fsl_pq_mdio driver to use of_mdio infrastructure
      net: Rework gianfar driver to use of_mdio infrastructure.
      net: Rework ucc_geth driver to use of_mdio infrastructure
      net: Rework pasemi_mac driver to use of_mdio infrastructure
      powerpc/82xx: Rework Embedded Planet ep8248e platform to use of_mdio
      net: Rework fs_enet driver to use of_mdio infrastructure
      net: add Xilinx ll_temac device driver

 arch/powerpc/platforms/82xx/ep8248e.c     |    9 +-
 arch/powerpc/platforms/pasemi/gpio_mdio.c |   32 +-
 drivers/net/Kconfig                       |    8 +
 drivers/net/Makefile                      |    2 +
 drivers/net/fec_mpc52xx.c                 |  256 +++-----
 drivers/net/fec_mpc52xx_phy.c             |   26 +-
 drivers/net/fs_enet/fs_enet-main.c        |   69 +--
 drivers/net/fs_enet/mii-bitbang.c         |   29 +-
 drivers/net/fs_enet/mii-fec.c             |   26 +-
 drivers/net/fsl_pq_mdio.c                 |   53 +--
 drivers/net/gianfar.c                     |  103 ++--
 drivers/net/gianfar.h                     |    3 +-
 drivers/net/pasemi_mac.c                  |   28 +-
 drivers/net/pasemi_mac.h                  |    1 -
 drivers/net/phy/mdio_bus.c                |   29 +-
 drivers/net/phy/phy_device.c              |  163 ++++--
 drivers/net/ucc_geth.c                    |   47 +-
 drivers/net/ucc_geth.h                    |    2 +-
 drivers/net/xilinx_temac.c                |  970 +++++++++++++++++++++++++++++
 drivers/net/xilinx_temac.h                |  374 +++++++++++
 drivers/net/xilinx_temac_mdio.c           |  119 ++++
 drivers/of/Kconfig                        |    6 +
 drivers/of/Makefile                       |    1 +
 drivers/of/base.c                         |   24 +
 drivers/of/of_mdio.c                      |  139 ++++
 include/linux/fs_enet_pd.h                |    6 +-
 include/linux/of.h                        |    3 +
 include/linux/of_mdio.h                   |   22 +
 include/linux/phy.h                       |    6 +
 29 files changed, 1990 insertions(+), 566 deletions(-)
 create mode 100644 drivers/net/xilinx_temac.c
 create mode 100644 drivers/net/xilinx_temac.h
 create mode 100644 drivers/net/xilinx_temac_mdio.c
 create mode 100644 drivers/of/of_mdio.c
 create mode 100644 include/linux/of_mdio.h

Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH 01/14] of: add of_parse_phandle() helper for parsing phandle properties
From: Grant Likely @ 2009-03-31  8:26 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

of_parse_phandle() is a helper function to read and parse a phandle
property and return a pointer to the resulting device_node.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: Michael Ellerman <michael@ellerman.id.au>
---

 drivers/of/base.c  |   24 ++++++++++++++++++++++++
 include/linux/of.h |    3 +++
 2 files changed, 27 insertions(+), 0 deletions(-)


diff --git a/drivers/of/base.c b/drivers/of/base.c
index cd17092..104b8c0 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -494,6 +494,30 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
 EXPORT_SYMBOL_GPL(of_modalias_node);
 
 /**
+ * of_parse_phandle - Resolve a phandle property to a device_node pointer
+ * @np: Pointer to device node holding phandle property
+ * @phandle_name: Name of property holding a phandle value
+ * @index: For properties holding a table of phandles, this is the index into
+ *         the table
+ *
+ * Returns the device_node pointer with refcount incremented.  Use
+ * of_node_put() on it when done.
+ */
+struct device_node *
+of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
+{
+	const phandle *phandle;
+	int size;
+
+	phandle = of_get_property(np, phandle_name, &size);
+	if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
+		return NULL;
+
+	return of_find_node_by_phandle(phandle[index]);
+}
+EXPORT_SYMBOL(of_parse_phandle);
+
+/**
  * of_parse_phandles_with_args - Find a node pointed by phandle in a list
  * @np:		pointer to a device tree node containing a list
  * @list_name:	property name that contains a list
diff --git a/include/linux/of.h b/include/linux/of.h
index 6a7efa2..7be2d10 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -77,6 +77,9 @@ extern int of_n_size_cells(struct device_node *np);
 extern const struct of_device_id *of_match_node(
 	const struct of_device_id *matches, const struct device_node *node);
 extern int of_modalias_node(struct device_node *node, char *modalias, int len);
+extern struct device_node *of_parse_phandle(struct device_node *np,
+					    const char *phandle_name,
+					    int index);
 extern int of_parse_phandles_with_args(struct device_node *np,
 	const char *list_name, const char *cells_name, int index,
 	struct device_node **out_node, const void **out_args);

^ permalink raw reply related

* [PATCH 02/14] net/fec_mpc52xx: Migrate to net_device_ops.
From: Grant Likely @ 2009-03-31  8:26 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

Since not using net_device_ops gets you shunned out the cool crowd,
this patch modifies the fec_mpc52xx Ethernet driver to provide the
management hooks via a struct net_device_ops.

Reported-by: Henk Stegeman <henk.stegeman@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/fec_mpc52xx.c |   35 +++++++++++++++++++----------------
 1 files changed, 19 insertions(+), 16 deletions(-)


diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index f99463f..75d0569 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -371,7 +371,7 @@ static int mpc52xx_fec_close(struct net_device *dev)
  * invariant will hold if you make sure that the netif_*_queue()
  * calls are done at the proper times.
  */
-static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 	struct bcom_fec_bd *bd;
@@ -379,7 +379,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d
 	if (bcom_queue_full(priv->tx_dmatsk)) {
 		if (net_ratelimit())
 			dev_err(&dev->dev, "transmit queue overrun\n");
-		return 1;
+		return NETDEV_TX_BUSY;
 	}
 
 	spin_lock_irq(&priv->lock);
@@ -400,7 +400,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d
 
 	spin_unlock_irq(&priv->lock);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -890,6 +890,21 @@ static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 	return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
 }
 
+static const struct net_device_ops mpc52xx_fec_netdev_ops = {
+	.ndo_open = mpc52xx_fec_open,
+	.ndo_stop = mpc52xx_fec_close,
+	.ndo_start_xmit = mpc52xx_fec_start_xmit,
+	.ndo_set_multicast_list = mpc52xx_fec_set_multicast_list,
+	.ndo_set_mac_address = mpc52xx_fec_set_mac_address,
+	.ndo_validate_addr = eth_validate_addr,
+	.ndo_do_ioctl = mpc52xx_fec_ioctl,
+	.ndo_tx_timeout = mpc52xx_fec_tx_timeout,
+	.ndo_get_stats = mpc52xx_fec_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = mpc52xx_fec_poll_controller,
+#endif
+};
+
 /* ======================================================================== */
 /* OF Driver                                                                */
 /* ======================================================================== */
@@ -934,22 +949,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 		return -EBUSY;
 
 	/* Init ether ndev with what we have */
-	ndev->open		= mpc52xx_fec_open;
-	ndev->stop		= mpc52xx_fec_close;
-	ndev->hard_start_xmit	= mpc52xx_fec_hard_start_xmit;
-	ndev->do_ioctl		= mpc52xx_fec_ioctl;
+	ndev->netdev_ops	= &mpc52xx_fec_netdev_ops;
 	ndev->ethtool_ops	= &mpc52xx_fec_ethtool_ops;
-	ndev->get_stats		= mpc52xx_fec_get_stats;
-	ndev->set_mac_address	= mpc52xx_fec_set_mac_address;
-	ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
-	ndev->tx_timeout	= mpc52xx_fec_tx_timeout;
 	ndev->watchdog_timeo	= FEC_WATCHDOG_TIMEOUT;
 	ndev->base_addr		= mem.start;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	ndev->poll_controller = mpc52xx_fec_poll_controller;
-#endif
-
-	priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
 
 	spin_lock_init(&priv->lock);
 

^ permalink raw reply related

* [PATCH 03/14] net/fec_mpc52xx: Don't dereference phy_device if it is NULL
From: Grant Likely @ 2009-03-31  8:26 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

The FEC Ethernet device isn't always attached to a phy.  Be careful
not to dereference phy_device if it is NULL.

Reported-by: Henk Stegeman <henk.stegeman@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/fec_mpc52xx.c |   22 ++++++++++++----------
 1 files changed, 12 insertions(+), 10 deletions(-)


diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index 75d0569..e10eb2c 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -271,15 +271,6 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
 	phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
 }
 
-static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
-		struct mii_ioctl_data *mii_data, int cmd)
-{
-	if (!priv->phydev)
-		return -ENOTSUPP;
-
-	return phy_mii_ioctl(priv->phydev, mii_data, cmd);
-}
-
 static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
 {
 	struct mpc52xx_fec __iomem *fec = priv->fec;
@@ -852,12 +843,20 @@ static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
 static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+	if (!priv->phydev)
+		return -ENODEV;
+
 	return phy_ethtool_gset(priv->phydev, cmd);
 }
 
 static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+	if (!priv->phydev)
+		return -ENODEV;
+
 	return phy_ethtool_sset(priv->phydev, cmd);
 }
 
@@ -887,7 +886,10 @@ static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 
-	return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
+	if (!priv->phydev)
+		return -ENOTSUPP;
+
+	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
 }
 
 static const struct net_device_ops mpc52xx_fec_netdev_ops = {

^ permalink raw reply related

* [PATCH 04/14] phylib: rework to prepare for OF registration of PHYs
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch makes changes in preparation for supporting open firmware
device tree descriptions of MDIO busses.  Changes include:
- Cleanup handling of phy_map[] entries; they are already NULLed when
  registering and so don't need to be re-cleared, and it is good practice
  to clear them out when unregistering.
- Split phy_device registration out into a new function so that the
  OF helpers can do two stage registration (separate allocation and
  registration steps).

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: linuxppc-dev@ozlabs.org
CC: netdev@vger.kernel.org
CC: Andy Fleming <afleming@freescale.com>
---

 drivers/net/phy/mdio_bus.c   |   29 +++------------------------
 drivers/net/phy/phy_device.c |   45 ++++++++++++++++++++++++++++++++++++++----
 include/linux/phy.h          |    1 +
 3 files changed, 45 insertions(+), 30 deletions(-)


diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index b754020..bd4e8d7 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -113,7 +113,6 @@ int mdiobus_register(struct mii_bus *bus)
 		bus->reset(bus);
 
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		bus->phy_map[i] = NULL;
 		if ((bus->phy_mask & (1 << i)) == 0) {
 			struct phy_device *phydev;
 
@@ -150,6 +149,7 @@ void mdiobus_unregister(struct mii_bus *bus)
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
 		if (bus->phy_map[i])
 			device_unregister(&bus->phy_map[i]->dev);
+		bus->phy_map[i] = NULL;
 	}
 }
 EXPORT_SYMBOL(mdiobus_unregister);
@@ -188,35 +188,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
 	if (IS_ERR(phydev) || phydev == NULL)
 		return phydev;
 
-	/* There's a PHY at this address
-	 * We need to set:
-	 * 1) IRQ
-	 * 2) bus_id
-	 * 3) parent
-	 * 4) bus
-	 * 5) mii_bus
-	 * And, we need to register it */
-
-	phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;
-
-	phydev->dev.parent = bus->parent;
-	phydev->dev.bus = &mdio_bus_type;
-	dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr);
-
-	phydev->bus = bus;
-
-	/* Run all of the fixups for this PHY */
-	phy_scan_fixups(phydev);
-
-	err = device_register(&phydev->dev);
+	err = phy_device_register(phydev);
 	if (err) {
-		printk(KERN_ERR "phy %d failed to register\n", addr);
 		phy_device_free(phydev);
-		phydev = NULL;
+		return NULL;
 	}
 
-	bus->phy_map[addr] = phydev;
-
 	return phydev;
 }
 EXPORT_SYMBOL(mdiobus_scan);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 0a06e4f..9352ca8 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -39,20 +39,21 @@ MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
-static struct phy_driver genphy_driver;
-extern int mdio_bus_init(void);
-extern void mdio_bus_exit(void);
-
 void phy_device_free(struct phy_device *phydev)
 {
 	kfree(phydev);
 }
+EXPORT_SYMBOL(phy_device_free);
 
 static void phy_device_release(struct device *dev)
 {
 	phy_device_free(to_phy_device(dev));
 }
 
+static struct phy_driver genphy_driver;
+extern int mdio_bus_init(void);
+extern void mdio_bus_exit(void);
+
 static LIST_HEAD(phy_fixup_list);
 static DEFINE_MUTEX(phy_fixup_lock);
 
@@ -166,6 +167,10 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 	dev->addr = addr;
 	dev->phy_id = phy_id;
 	dev->bus = bus;
+	dev->dev.parent = bus->parent;
+	dev->dev.bus = &mdio_bus_type;
+	dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;
+	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
 
 	dev->state = PHY_DOWN;
 
@@ -235,6 +240,38 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
 
 	return dev;
 }
+EXPORT_SYMBOL(get_phy_device);
+
+/**
+ * phy_device_register - Register the phy device on the MDIO bus
+ * @phy_device: phy_device structure to be added to the MDIO bus
+ */
+int phy_device_register(struct phy_device *phydev)
+{
+	int err;
+
+	/* Don't register a phy if one is already registered at this
+	 * address */
+	if (phydev->bus->phy_map[phydev->addr])
+		return -EINVAL;
+	phydev->bus->phy_map[phydev->addr] = phydev;
+
+	/* Run all of the fixups for this PHY */
+	phy_scan_fixups(phydev);
+
+	err = device_register(&phydev->dev);
+	if (err) {
+		pr_err("phy %d failed to register\n", phydev->addr);
+		goto out;
+	}
+
+	return 0;
+
+ out:
+	phydev->bus->phy_map[phydev->addr] = NULL;
+	return err;
+}
+EXPORT_SYMBOL(phy_device_register);
 
 /**
  * phy_prepare_link - prepares the PHY layer to monitor link status
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 32cf14a..c0cf354 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -438,6 +438,7 @@ static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
 
 int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
 struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
+int phy_device_register(struct phy_device *phy);
 int phy_clear_interrupt(struct phy_device *phydev);
 int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
 struct phy_device * phy_attach(struct net_device *dev,

^ permalink raw reply related

* [PATCH 05/14] phylib: add *_direct() variants of phy_connect and phy_attach functions
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

Add phy_connect_direct() and phy_attach_direct() functions so that
drivers can use a pointer to the phy_device instead of trying to determine
the phy's bus_id string.

This patch is useful for OF device tree descriptions of phy devices where
the driver doesn't need or know what the bus_id value in order to get a
phy_device pointer.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/phy/phy_device.c |  118 ++++++++++++++++++++++++++++++------------
 include/linux/phy.h          |    5 ++
 2 files changed, 90 insertions(+), 33 deletions(-)


diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9352ca8..3c8c1de 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -292,6 +292,33 @@ void phy_prepare_link(struct phy_device *phydev,
 }
 
 /**
+ * phy_connect_direct - connect an ethernet device to a specific phy_device
+ * @dev: the network device to connect
+ * @phydev: the pointer to the phy device
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ */
+int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
+		       void (*handler)(struct net_device *), u32 flags,
+		       phy_interface_t interface)
+{
+	int rc;
+
+	rc = phy_attach_direct(dev, phydev, flags, interface);
+	if (rc)
+		return rc;
+
+	phy_prepare_link(phydev, handler);
+	phy_start_machine(phydev, NULL);
+	if (phydev->irq > 0)
+		phy_start_interrupts(phydev);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_connect_direct);
+
+/**
  * phy_connect - connect an ethernet device to a PHY device
  * @dev: the network device to connect
  * @bus_id: the id string of the PHY device to connect
@@ -312,18 +339,21 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
 		phy_interface_t interface)
 {
 	struct phy_device *phydev;
+	struct device *d;
+	int rc;
 
-	phydev = phy_attach(dev, bus_id, flags, interface);
-
-	if (IS_ERR(phydev))
-		return phydev;
-
-	phy_prepare_link(phydev, handler);
-
-	phy_start_machine(phydev, NULL);
+	/* Search the list of PHY devices on the mdio bus for the
+	 * PHY with the requested name */
+	d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);
+	if (!d) {
+		pr_err("PHY %s not found\n", bus_id);
+		return ERR_PTR(-ENODEV);
+	}
+	phydev = to_phy_device(d);
 
-	if (phydev->irq > 0)
-		phy_start_interrupts(phydev);
+	rc = phy_attach_direct(dev, phydev, flags, interface);
+	if (rc)
+		return ERR_PTR(rc);
 
 	return phydev;
 }
@@ -347,9 +377,9 @@ void phy_disconnect(struct phy_device *phydev)
 EXPORT_SYMBOL(phy_disconnect);
 
 /**
- * phy_attach - attach a network device to a particular PHY device
+ * phy_attach_direct - attach a network device to a given PHY device pointer
  * @dev: network device to attach
- * @bus_id: PHY device to attach
+ * @phydev: Pointer to phy_device to attach
  * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  *
@@ -360,22 +390,10 @@ EXPORT_SYMBOL(phy_disconnect);
  *     the attaching device, and given a callback for link status
  *     change.  The phy_device is returned to the attaching driver.
  */
-struct phy_device *phy_attach(struct net_device *dev,
-		const char *bus_id, u32 flags, phy_interface_t interface)
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+		      u32 flags, phy_interface_t interface)
 {
-	struct bus_type *bus = &mdio_bus_type;
-	struct phy_device *phydev;
-	struct device *d;
-
-	/* Search the list of PHY devices on the mdio bus for the
-	 * PHY with the requested name */
-	d = bus_find_device_by_name(bus, NULL, bus_id);
-	if (d) {
-		phydev = to_phy_device(d);
-	} else {
-		printk(KERN_ERR "%s not found\n", bus_id);
-		return ERR_PTR(-ENODEV);
-	}
+	struct device *d = &phydev->dev;
 
 	/* Assume that if there is no driver, that it doesn't
 	 * exist, and we should use the genphy driver. */
@@ -388,13 +406,12 @@ struct phy_device *phy_attach(struct net_device *dev,
 			err = device_bind_driver(d);
 
 		if (err)
-			return ERR_PTR(err);
+			return err;
 	}
 
 	if (phydev->attached_dev) {
-		printk(KERN_ERR "%s: %s already attached\n",
-				dev->name, bus_id);
-		return ERR_PTR(-EBUSY);
+		dev_err(&dev->dev, "PHY already attached\n");
+		return -EBUSY;
 	}
 
 	phydev->attached_dev = dev;
@@ -412,13 +429,48 @@ struct phy_device *phy_attach(struct net_device *dev,
 		err = phy_scan_fixups(phydev);
 
 		if (err < 0)
-			return ERR_PTR(err);
+			return err;
 
 		err = phydev->drv->config_init(phydev);
 
 		if (err < 0)
-			return ERR_PTR(err);
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_attach_direct);
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @bus_id: Bus ID of PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ *
+ * Description: Same as phy_attach_direct() except that a PHY bus_id
+ *     string is passed instead of a pointer to a struct phy_device.
+ */
+struct phy_device *phy_attach(struct net_device *dev,
+		const char *bus_id, u32 flags, phy_interface_t interface)
+{
+	struct bus_type *bus = &mdio_bus_type;
+	struct phy_device *phydev;
+	struct device *d;
+	int rc;
+
+	/* Search the list of PHY devices on the mdio bus for the
+	 * PHY with the requested name */
+	d = bus_find_device_by_name(bus, NULL, bus_id);
+	if (!d) {
+		pr_err("PHY %s not found\n", bus_id);
+		return ERR_PTR(-ENODEV);
 	}
+	phydev = to_phy_device(d);
+
+	rc = phy_attach_direct(dev, phydev, flags, interface);
+	if (rc)
+		return ERR_PTR(rc);
 
 	return phydev;
 }
diff --git a/include/linux/phy.h b/include/linux/phy.h
index c0cf354..cd404f1 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -441,8 +441,13 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
 int phy_device_register(struct phy_device *phy);
 int phy_clear_interrupt(struct phy_device *phydev);
 int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+		u32 flags, phy_interface_t interface);
 struct phy_device * phy_attach(struct net_device *dev,
 		const char *bus_id, u32 flags, phy_interface_t interface);
+int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
+		void (*handler)(struct net_device *), u32 flags,
+		phy_interface_t interface);
 struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
 		void (*handler)(struct net_device *), u32 flags,
 		phy_interface_t interface);

^ permalink raw reply related

* [PATCH 06/14] openfirmware: Add OF phylib support code
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

Add support for parsing the device tree for PHY devices on an MDIO bus

CC: Andy Fleming <afleming@freescale.com>
CC: linuxppc-dev@ozlabs.org
CC: devtree-discuss@ozlabs.org

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/of/Kconfig      |    6 ++
 drivers/of/Makefile     |    1 
 drivers/of/of_mdio.c    |  139 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_mdio.h |   22 +++++++
 4 files changed, 168 insertions(+), 0 deletions(-)
 create mode 100644 drivers/of/of_mdio.c
 create mode 100644 include/linux/of_mdio.h


diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index f821dbc..6fe043b 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -19,3 +19,9 @@ config OF_SPI
 	depends on OF && PPC_OF && SPI
 	help
 	  OpenFirmware SPI accessors
+
+config OF_MDIO
+	def_tristate PHYLIB
+	depends on OF && PHYLIB
+	help
+	  OpenFirmware MDIO bus (Ethernet PHY) accessors
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 4c3c6f8..bdfb5f5 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
 obj-$(CONFIG_OF_I2C)	+= of_i2c.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
+obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
new file mode 100644
index 0000000..aee967d
--- /dev/null
+++ b/drivers/of/of_mdio.c
@@ -0,0 +1,139 @@
+/*
+ * OF helpers for the MDIO (Ethernet PHY) API
+ *
+ * Copyright (c) 2009 Secret Lab Technologies, Ltd.
+ *
+ * This file is released under the GPLv2
+ *
+ * This file provides helper functions for extracting PHY device information
+ * out of the OpenFirmware device tree and using it to populate an mii_bus.
+ */
+
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/**
+ * of_mdiobus_register - Register mii_bus and create PHYs from the device tree
+ * @mdio: pointer to mii_bus structure
+ * @np: pointer to device_node of MDIO bus.
+ *
+ * This function registers the mii_bus structure and registers a phy_device
+ * for each child node of @np.
+ */
+int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
+{
+	struct phy_device *phy;
+	struct device_node *child;
+	int rc, i;
+
+	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
+	 * the device tree are populated after the bus has been registered */
+	mdio->phy_mask = ~0;
+
+	/* Clear all the IRQ properties */
+	if (mdio->irq)
+		for (i=0; i<PHY_MAX_ADDR; i++)
+			mdio->irq[i] = PHY_POLL;
+
+	/* Register the MDIO bus */
+	rc = mdiobus_register(mdio);
+	if (rc)
+		return rc;
+
+	/* Loop over the child nodes and register a phy_device for each one */
+	for_each_child_of_node(np, child) {
+		const u32 *addr;
+		int len;
+
+		/* A PHY must have a reg property in the range [0-31] */
+		addr = of_get_property(child, "reg", &len);
+		if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) {
+			dev_err(&mdio->dev, "%s has invalid PHY address\n",
+				child->full_name);
+			continue;
+		}
+
+		if (mdio->irq) {
+			mdio->irq[*addr] = irq_of_parse_and_map(child, 0);
+			if (!mdio->irq[*addr])
+				mdio->irq[*addr] = PHY_POLL;
+		}
+
+		phy = get_phy_device(mdio, *addr);
+		if (!phy) {
+			dev_err(&mdio->dev, "error probing PHY at address %i\n",
+				*addr);
+			continue;
+		}
+		phy_scan_fixups(phy);
+
+		/* Associate the OF node with the device structure so it
+		 * can be looked up later */
+		of_node_get(child);
+		dev_archdata_set_node(&phy->dev.archdata, child);
+
+		/* All data is now stored in the phy struct; register it */
+		rc = phy_device_register(phy);
+		if (rc) {
+			phy_device_free(phy);
+			of_node_put(child);
+			continue;
+		}
+
+		dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
+			child->name, *addr);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(of_mdiobus_register);
+
+/**
+ * of_phy_find_device - Give a PHY node, find the phy_device
+ * @phy_np: Pointer to the phy's device tree node
+ *
+ * Returns a pointer to the phy_device.
+ */
+struct phy_device *of_phy_find_device(struct device_node *phy_np)
+{
+	struct device *d;
+	int match(struct device *dev, void *phy_np)
+	{
+		return dev_archdata_get_node(&dev->archdata) == phy_np;
+	}
+
+	if (!phy_np)
+		return NULL;
+
+	d = bus_find_device(&mdio_bus_type, NULL, phy_np, match);
+	return d ? to_phy_device(d) : NULL;
+}
+EXPORT_SYMBOL(of_phy_find_device);
+
+/**
+ * of_phy_connect - Connect to the phy described in the device tree
+ * @dev: pointer to net_device claiming the phy
+ * @phy_np: Pointer to device tree node for the PHY
+ * @hndlr: Link state callback for the network device
+ * @iface: PHY data interface type
+ *
+ * Returns a pointer to the phy_device if successfull.  NULL otherwise
+ */
+struct phy_device *of_phy_connect(struct net_device *dev,
+				  struct device_node *phy_np,
+				  void (*hndlr)(struct net_device *), u32 flags,
+				  phy_interface_t iface)
+{
+	struct phy_device *phy = of_phy_find_device(phy_np);
+
+	if (!phy)
+		return NULL;
+
+	return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
+}
+EXPORT_SYMBOL(of_phy_connect);
diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h
new file mode 100644
index 0000000..c9663c6
--- /dev/null
+++ b/include/linux/of_mdio.h
@@ -0,0 +1,22 @@
+/*
+ * OF helpers for the MDIO (Ethernet PHY) API
+ *
+ * Copyright (c) 2009 Secret Lab Technologies, Ltd.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_MDIO_H
+#define __LINUX_OF_MDIO_H
+
+#include <linux/phy.h>
+#include <linux/of.h>
+
+extern int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np);
+extern struct phy_device *of_phy_find_device(struct device_node *phy_np);
+extern struct phy_device *of_phy_connect(struct net_device *dev,
+					 struct device_node *phy_np,
+					 void (*hndlr)(struct net_device *),
+					 u32 flags, phy_interface_t iface);
+
+#endif /* __LINUX_OF_MDIO_H */

^ permalink raw reply related

* [PATCH 07/14] net: Rework mpc5200 fec driver to use of_mdio infrastructure.
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

The patch reworks the MPC5200 Fast Ethernet Controller (FEC) driver to
use the of_mdio infrastructure for registering PHY devices from data out
openfirmware device tree, and eliminates the assumption that the PHY
for the FEC is always attached to the FEC's own MDIO bus.  With this
patch, the FEC can use a PHY attached to any MDIO bus if it is described
in the device tree.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/fec_mpc52xx.c     |  180 ++++++++++++-----------------------------
 drivers/net/fec_mpc52xx_phy.c |   26 +-----
 2 files changed, 59 insertions(+), 147 deletions(-)


diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e10eb2c..0ebd4ec 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -25,6 +25,7 @@
 #include <linux/hardirq.h>
 #include <linux/delay.h>
 #include <linux/of_device.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include <linux/netdevice.h>
@@ -43,11 +44,9 @@
 
 #define DRIVER_NAME "mpc52xx-fec"
 
-#define FEC5200_PHYADDR_NONE	(-1)
-#define FEC5200_PHYADDR_7WIRE	(-2)
-
 /* Private driver data structure */
 struct mpc52xx_fec_priv {
+	struct net_device *ndev;
 	int duplex;
 	int speed;
 	int r_irq;
@@ -59,10 +58,11 @@ struct mpc52xx_fec_priv {
 	int msg_enable;
 
 	/* MDIO link details */
-	int phy_addr;
-	unsigned int phy_speed;
+	unsigned int mdio_speed;
+	struct device_node *phy_node;
 	struct phy_device *phydev;
 	enum phy_state link;
+	int seven_wire_mode;
 };
 
 
@@ -211,85 +211,25 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev)
 		phy_print_status(phydev);
 }
 
-static int mpc52xx_fec_init_phy(struct net_device *dev)
-{
-	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
-	struct phy_device *phydev;
-	char phy_id[BUS_ID_SIZE];
-
-	snprintf(phy_id, sizeof(phy_id), "%x:%02x",
-			(unsigned int)dev->base_addr, priv->phy_addr);
-
-	priv->link = PHY_DOWN;
-	priv->speed = 0;
-	priv->duplex = -1;
-
-	phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
-	if (IS_ERR(phydev)) {
-		dev_err(&dev->dev, "phy_connect failed\n");
-		return PTR_ERR(phydev);
-	}
-	dev_info(&dev->dev, "attached phy %i to driver %s\n",
-			phydev->addr, phydev->drv->name);
-
-	priv->phydev = phydev;
-
-	return 0;
-}
-
-static int mpc52xx_fec_phy_start(struct net_device *dev)
-{
-	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
-	int err;
-
-	if (priv->phy_addr < 0)
-		return 0;
-
-	err = mpc52xx_fec_init_phy(dev);
-	if (err) {
-		dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
-		return err;
-	}
-
-	/* reset phy - this also wakes it from PDOWN */
-	phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
-	phy_start(priv->phydev);
-
-	return 0;
-}
-
-static void mpc52xx_fec_phy_stop(struct net_device *dev)
-{
-	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
-
-	if (!priv->phydev)
-		return;
-
-	phy_disconnect(priv->phydev);
-	/* power down phy */
-	phy_stop(priv->phydev);
-	phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
-}
-
-static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
-{
-	struct mpc52xx_fec __iomem *fec = priv->fec;
-
-	if (priv->phydev)
-		return;
-
-	out_be32(&fec->mii_speed, priv->phy_speed);
-}
-
 static int mpc52xx_fec_open(struct net_device *dev)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 	int err = -EBUSY;
 
+	if (priv->phy_node) {
+		priv->phydev = of_phy_connect(priv->ndev, priv->phy_node,
+					      mpc52xx_fec_adjust_link, 0, 0);
+		if (!priv->phydev) {
+			dev_err(&dev->dev, "of_phy_connect failed\n");
+			return -ENODEV;
+		}
+		phy_start(priv->phydev);
+	}
+
 	if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED,
 	                DRIVER_NAME "_ctrl", dev)) {
 		dev_err(&dev->dev, "ctrl interrupt request failed\n");
-		goto out;
+		goto free_phy;
 	}
 	if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0,
 	                DRIVER_NAME "_rx", dev)) {
@@ -311,10 +251,6 @@ static int mpc52xx_fec_open(struct net_device *dev)
 		goto free_irqs;
 	}
 
-	err = mpc52xx_fec_phy_start(dev);
-	if (err)
-		goto free_skbs;
-
 	bcom_enable(priv->rx_dmatsk);
 	bcom_enable(priv->tx_dmatsk);
 
@@ -324,16 +260,18 @@ static int mpc52xx_fec_open(struct net_device *dev)
 
 	return 0;
 
- free_skbs:
-	mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);
-
  free_irqs:
 	free_irq(priv->t_irq, dev);
  free_2irqs:
 	free_irq(priv->r_irq, dev);
  free_ctrl_irq:
 	free_irq(dev->irq, dev);
- out:
+ free_phy:
+	if (priv->phydev) {
+		phy_stop(priv->phydev);
+		phy_disconnect(priv->phydev);
+		priv->phydev = NULL;
+	}
 
 	return err;
 }
@@ -352,7 +290,12 @@ static int mpc52xx_fec_close(struct net_device *dev)
 	free_irq(priv->r_irq, dev);
 	free_irq(priv->t_irq, dev);
 
-	mpc52xx_fec_phy_stop(dev);
+	if (priv->phydev) {
+		/* power down phy */
+		phy_stop(priv->phydev);
+		phy_disconnect(priv->phydev);
+		priv->phydev = NULL;
+	}
 
 	return 0;
 }
@@ -696,7 +639,7 @@ static void mpc52xx_fec_hw_init(struct net_device *dev)
 	/* set phy speed.
 	 * this can't be done in phy driver, since it needs to be called
 	 * before fec stuff (even on resume) */
-	mpc52xx_fec_phy_hw_init(priv);
+	out_be32(&fec->mii_speed, priv->mdio_speed);
 }
 
 /**
@@ -732,7 +675,7 @@ static void mpc52xx_fec_start(struct net_device *dev)
 	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
 	rcntrl |= FEC_RCNTRL_FCE;
 
-	if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
+	if (!priv->seven_wire_mode)
 		rcntrl |= FEC_RCNTRL_MII_MODE;
 
 	if (priv->duplex == DUPLEX_FULL)
@@ -798,8 +741,6 @@ static void mpc52xx_fec_stop(struct net_device *dev)
 
 	/* Stop FEC */
 	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
-
-	return;
 }
 
 /* reset fec and bestcomm tasks */
@@ -817,9 +758,11 @@ static void mpc52xx_fec_reset(struct net_device *dev)
 
 	mpc52xx_fec_hw_init(dev);
 
-	phy_stop(priv->phydev);
-	phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
-	phy_start(priv->phydev);
+	if (priv->phydev) {
+		phy_stop(priv->phydev);
+		phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+		phy_start(priv->phydev);
+	}
 
 	bcom_fec_rx_reset(priv->rx_dmatsk);
 	bcom_fec_tx_reset(priv->tx_dmatsk);
@@ -918,8 +861,6 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 	struct net_device *ndev;
 	struct mpc52xx_fec_priv *priv = NULL;
 	struct resource mem;
-	struct device_node *phy_node;
-	const phandle *phy_handle;
 	const u32 *prop;
 	int prop_size;
 
@@ -932,6 +873,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 		return -ENOMEM;
 
 	priv = netdev_priv(ndev);
+	priv->ndev = ndev;
 
 	/* Reserve FEC control zone */
 	rv = of_address_to_resource(op->node, 0, &mem);
@@ -955,6 +897,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 	ndev->ethtool_ops	= &mpc52xx_fec_ethtool_ops;
 	ndev->watchdog_timeo	= FEC_WATCHDOG_TIMEOUT;
 	ndev->base_addr		= mem.start;
+	SET_NETDEV_DEV(ndev, &op->dev);
 
 	spin_lock_init(&priv->lock);
 
@@ -1002,14 +945,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 	 */
 
 	/* Start with safe defaults for link connection */
-	priv->phy_addr = FEC5200_PHYADDR_NONE;
 	priv->speed = 100;
 	priv->duplex = DUPLEX_HALF;
-	priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
-
-	/* the 7-wire property means don't use MII mode */
-	if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
-		priv->phy_addr = FEC5200_PHYADDR_7WIRE;
+	priv->mdio_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
 
 	/* The current speed preconfigures the speed of the MII link */
 	prop = of_get_property(op->node, "current-speed", &prop_size);
@@ -1018,43 +956,23 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 		priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
 	}
 
-	/* If there is a phy handle, setup link to that phy */
-	phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
-	if (phy_handle && (prop_size >= sizeof(phandle))) {
-		phy_node = of_find_node_by_phandle(*phy_handle);
-		prop = of_get_property(phy_node, "reg", &prop_size);
-		if (prop && (prop_size >= sizeof(u32)))
-			if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
-				priv->phy_addr = *prop;
-		of_node_put(phy_node);
+	/* If there is a phy handle, then get the PHY node */
+	priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0);
+
+	/* the 7-wire property means don't use MII mode */
+	if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) {
+		priv->seven_wire_mode = 1;
+		dev_info(&ndev->dev, "using 7-wire PHY mode\n");
 	}
 
 	/* Hardware init */
 	mpc52xx_fec_hw_init(ndev);
-
 	mpc52xx_fec_reset_stats(ndev);
 
-	SET_NETDEV_DEV(ndev, &op->dev);
-
-	/* Register the new network device */
 	rv = register_netdev(ndev);
 	if (rv < 0)
 		goto probe_error;
 
-	/* Now report the link setup */
-	switch (priv->phy_addr) {
-	 case FEC5200_PHYADDR_NONE:
-		dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
-			 priv->speed, priv->duplex ? 'F' : 'H');
-		break;
-	 case FEC5200_PHYADDR_7WIRE:
-		dev_info(&ndev->dev, "using 7-wire PHY mode\n");
-		break;
-	 default:
-		dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
-			 priv->phy_addr);
-	}
-
 	/* We're done ! */
 	dev_set_drvdata(&op->dev, ndev);
 
@@ -1064,6 +982,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
 	/* Error handling - free everything that might be allocated */
 probe_error:
 
+	if (priv->phy_node)
+		of_node_put(priv->phy_node);
+	priv->phy_node = NULL;
+
 	irq_dispose_mapping(ndev->irq);
 
 	if (priv->rx_dmatsk)
@@ -1092,6 +1014,10 @@ mpc52xx_fec_remove(struct of_device *op)
 
 	unregister_netdev(ndev);
 
+	if (priv->phy_node)
+		of_node_put(priv->phy_node);
+	priv->phy_node = NULL;
+
 	irq_dispose_mapping(ndev->irq);
 
 	bcom_fec_rx_release(priv->rx_dmatsk);
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index dd9bfa4..fec9f24 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -14,12 +14,14 @@
 #include <linux/netdevice.h>
 #include <linux/phy.h>
 #include <linux/of_platform.h>
+#include <linux/of_mdio.h>
 #include <asm/io.h>
 #include <asm/mpc52xx.h>
 #include "fec_mpc52xx.h"
 
 struct mpc52xx_fec_mdio_priv {
 	struct mpc52xx_fec __iomem *regs;
+	int mdio_irqs[PHY_MAX_ADDR];
 };
 
 static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
@@ -27,7 +29,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
 {
 	struct mpc52xx_fec_mdio_priv *priv = bus->priv;
 	struct mpc52xx_fec __iomem *fec;
-	int tries = 100;
+	int tries = 3;
 
 	value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
 	value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
@@ -38,7 +40,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
 
 	/* wait for it to finish, this takes about 23 us on lite5200b */
 	while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
-		udelay(5);
+		msleep(1);
 
 	if (!tries)
 		return -ETIMEDOUT;
@@ -64,7 +66,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
 {
 	struct device *dev = &of->dev;
 	struct device_node *np = of->node;
-	struct device_node *child = NULL;
 	struct mii_bus *bus;
 	struct mpc52xx_fec_mdio_priv *priv;
 	struct resource res = {};
@@ -85,22 +86,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
 	bus->write = mpc52xx_fec_mdio_write;
 
 	/* setup irqs */
-	bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
-	if (bus->irq == NULL) {
-		err = -ENOMEM;
-		goto out_free;
-	}
-	for (i=0; i<PHY_MAX_ADDR; i++)
-		bus->irq[i] = PHY_POLL;
-
-	while ((child = of_get_next_child(np, child)) != NULL) {
-		int irq = irq_of_parse_and_map(child, 0);
-		if (irq != NO_IRQ) {
-			const u32 *id = of_get_property(child, "reg", NULL);
-			if (id)
-				bus->irq[*id] = irq;
-		}
-	}
+	bus->irq = priv->mdio_irqs;
 
 	/* setup registers */
 	err = of_address_to_resource(np, 0, &res);
@@ -122,7 +108,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
 	out_be32(&priv->regs->mii_speed,
 		((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
 
-	err = mdiobus_register(bus);
+	err = of_mdiobus_register(bus, np);
 	if (err)
 		goto out_unmap;
 

^ permalink raw reply related

* [PATCH 08/14] net: rework fsl_pq_mdio driver to use of_mdio infrastructure
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch simplifies the driver by making use of more common code.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/fsl_pq_mdio.c |   53 +++------------------------------------------
 1 files changed, 4 insertions(+), 49 deletions(-)


diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index b3079a5..83a98f4 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -34,6 +34,7 @@
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/of.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include <asm/io.h>
@@ -154,44 +155,6 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus)
 	return 0;
 }
 
-/* Allocate an array which provides irq #s for each PHY on the given bus */
-static int *create_irq_map(struct device_node *np)
-{
-	int *irqs;
-	int i;
-	struct device_node *child = NULL;
-
-	irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
-
-	if (!irqs)
-		return NULL;
-
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		irqs[i] = PHY_POLL;
-
-	while ((child = of_get_next_child(np, child)) != NULL) {
-		int irq = irq_of_parse_and_map(child, 0);
-		const u32 *id;
-
-		if (irq == NO_IRQ)
-			continue;
-
-		id = of_get_property(child, "reg", NULL);
-
-		if (!id)
-			continue;
-
-		if (*id < PHY_MAX_ADDR && *id >= 0)
-			irqs[*id] = irq;
-		else
-			printk(KERN_WARNING "%s: "
-					"%d is not a valid PHY address\n",
-					np->full_name, *id);
-	}
-
-	return irqs;
-}
-
 void fsl_pq_mdio_bus_name(char *name, struct device_node *np)
 {
 	const u32 *addr;
@@ -314,7 +277,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 
 	new_bus->priv = (void __force *)regs;
 
-	new_bus->irq = create_irq_map(np);
+	new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
 
 	if (NULL == new_bus->irq) {
 		err = -ENOMEM;
@@ -383,16 +346,8 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 
 	out_be32(tbipa, tbiaddr);
 
-	/*
-	 * The TBIPHY-only buses will find PHYs at every address,
-	 * so we mask them all but the TBI
-	 */
-	if (!of_device_is_compatible(np, "fsl,gianfar-mdio"))
-		new_bus->phy_mask = ~(1 << tbiaddr);
-
-	err = mdiobus_register(new_bus);
-
-	if (err) {
+	err = of_mdiobus_register(new_bus, np);
+	if (err != 0) {
 		printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
 				new_bus->name);
 		goto err_free_irqs;

^ permalink raw reply related

* [PATCH 09/14] net: Rework gianfar driver to use of_mdio infrastructure.
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch simplifies the driver by making use of more common code.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/gianfar.c |  103 ++++++++++++++++++-------------------------------
 drivers/net/gianfar.h |    3 +
 2 files changed, 40 insertions(+), 66 deletions(-)


diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 65f5587..c22eba9 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -75,6 +75,7 @@
 #include <linux/if_vlan.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -168,17 +169,13 @@ static inline int gfar_uses_fcb(struct gfar_private *priv)
 
 static int gfar_of_init(struct net_device *dev)
 {
-	struct device_node *phy, *mdio;
-	const unsigned int *id;
 	const char *model;
 	const char *ctype;
 	const void *mac_addr;
-	const phandle *ph;
 	u64 addr, size;
 	int err = 0;
 	struct gfar_private *priv = netdev_priv(dev);
 	struct device_node *np = priv->node;
-	char bus_name[MII_BUS_ID_SIZE];
 	const u32 *stash;
 	const u32 *stash_len;
 	const u32 *stash_idx;
@@ -264,8 +261,8 @@ static int gfar_of_init(struct net_device *dev)
 	if (of_get_property(np, "fsl,magic-packet", NULL))
 		priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
 
-	ph = of_get_property(np, "phy-handle", NULL);
-	if (ph == NULL) {
+	priv->phy_node = of_parse_phandle(np, "phy-device", 0);
+	if (!priv->phy_node) {
 		u32 *fixed_link;
 
 		fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
@@ -273,57 +270,10 @@ static int gfar_of_init(struct net_device *dev)
 			err = -ENODEV;
 			goto err_out;
 		}
-
-		snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id),
-				PHY_ID_FMT, "0", fixed_link[0]);
-	} else {
-		phy = of_find_node_by_phandle(*ph);
-
-		if (phy == NULL) {
-			err = -ENODEV;
-			goto err_out;
-		}
-
-		mdio = of_get_parent(phy);
-
-		id = of_get_property(phy, "reg", NULL);
-
-		of_node_put(phy);
-
-		fsl_pq_mdio_bus_name(bus_name, mdio);
-		of_node_put(mdio);
-		snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x",
-				bus_name, *id);
 	}
 
 	/* Find the TBI PHY.  If it's not there, we don't support SGMII */
-	ph = of_get_property(np, "tbi-handle", NULL);
-	if (ph) {
-		struct device_node *tbi = of_find_node_by_phandle(*ph);
-		struct of_device *ofdev;
-		struct mii_bus *bus;
-
-		if (!tbi)
-			return 0;
-
-		mdio = of_get_parent(tbi);
-		if (!mdio)
-			return 0;
-
-		ofdev = of_find_device_by_node(mdio);
-
-		of_node_put(mdio);
-
-		id = of_get_property(tbi, "reg", NULL);
-		if (!id)
-			return 0;
-
-		of_node_put(tbi);
-
-		bus = dev_get_drvdata(&ofdev->dev);
-
-		priv->tbiphy = bus->phy_map[*id];
-	}
+	priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
 
 	return 0;
 
@@ -529,6 +479,10 @@ static int gfar_probe(struct of_device *ofdev,
 register_fail:
 	iounmap(priv->regs);
 regs_fail:
+	if (priv->phy_node)
+		of_node_put(priv->phy_node);
+	if (priv->tbi_node)
+		of_node_put(priv->tbi_node);
 	free_netdev(dev);
 	return err;
 }
@@ -537,6 +491,11 @@ static int gfar_remove(struct of_device *ofdev)
 {
 	struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
 
+	if (priv->phy_node)
+		of_node_put(priv->phy_node);
+	if (priv->tbi_node)
+		of_node_put(priv->tbi_node);
+
 	dev_set_drvdata(&ofdev->dev, NULL);
 
 	iounmap(priv->regs);
@@ -690,7 +649,6 @@ static int init_phy(struct net_device *dev)
 	uint gigabit_support =
 		priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
 		SUPPORTED_1000baseT_Full : 0;
-	struct phy_device *phydev;
 	phy_interface_t interface;
 
 	priv->oldlink = 0;
@@ -699,23 +657,38 @@ static int init_phy(struct net_device *dev)
 
 	interface = gfar_get_interface(dev);
 
-	phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface);
+	if (priv->phy_node) {
+		priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link,
+					      0, interface);
+		if (!priv->phydev) {
+			dev_err(&dev->dev, "error: Could not attach to PHY\n");
+			return -ENODEV;
+		}
+	}
+
+	if (priv->tbi_node) {
+		priv->tbiphy = of_phy_connect(dev, priv->tbi_node, &adjust_link,
+					      0, interface);
+		if (!priv->tbiphy) {
+			dev_err(&dev->dev, "error: Could not attach to TBI\n");
+			goto err_tbiphy;
+		}
+	}
 
 	if (interface == PHY_INTERFACE_MODE_SGMII)
 		gfar_configure_serdes(dev);
 
-	if (IS_ERR(phydev)) {
-		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-		return PTR_ERR(phydev);
-	}
-
 	/* Remove any features not supported by the controller */
-	phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
-	phydev->advertising = phydev->supported;
-
-	priv->phydev = phydev;
+	priv->phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
+	priv->phydev->advertising = priv->phydev->supported;
 
 	return 0;
+
+ err_tbiphy:
+	if (priv->phy_node)
+		phy_disconnect(priv->phydev);
+	priv->phydev = NULL;
+	return -ENODEV;
 }
 
 /*
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index dd499d7..4c69a3a 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -780,7 +780,8 @@ struct gfar_private {
 	spinlock_t bflock;
 
 	phy_interface_t interface;
-	char	phy_bus_id[BUS_ID_SIZE];
+	struct device_node *phy_node;
+	struct device_node *tbi_node;
 	u32 device_flags;
 	unsigned char rx_csum_enable:1,
 		extended_hash:1,

^ permalink raw reply related

* [PATCH 10/14] net: Rework ucc_geth driver to use of_mdio infrastructure
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch simplifies the driver by making use of more common code.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/ucc_geth.c |   47 ++++++++++++-----------------------------------
 drivers/net/ucc_geth.h |    2 +-
 2 files changed, 13 insertions(+), 36 deletions(-)


diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 933fcfb..471a30a 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -28,6 +28,7 @@
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/workqueue.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include <asm/uaccess.h>
@@ -1543,12 +1544,14 @@ static int init_phy(struct net_device *dev)
 	priv->oldspeed = 0;
 	priv->oldduplex = -1;
 
-	phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0,
-			     priv->phy_interface);
+	if (!ug_info->phy_node)
+		return 0;
 
-	if (IS_ERR(phydev)) {
+	phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
+				priv->phy_interface);
+	if (!phydev) {
 		printk("%s: Could not attach to PHY\n", dev->name);
-		return PTR_ERR(phydev);
+		return -ENODEV;
 	}
 
 	phydev->supported &= (ADVERTISED_10baseT_Half |
@@ -3520,14 +3523,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 {
 	struct device *device = &ofdev->dev;
 	struct device_node *np = ofdev->node;
-	struct device_node *mdio;
 	struct net_device *dev = NULL;
 	struct ucc_geth_private *ugeth = NULL;
 	struct ucc_geth_info *ug_info;
 	struct resource res;
 	struct device_node *phy;
 	int err, ucc_num, max_speed = 0;
-	const phandle *ph;
 	const u32 *fixed_link;
 	const unsigned int *prop;
 	const char *sprop;
@@ -3627,45 +3628,21 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 	ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
 	fixed_link = of_get_property(np, "fixed-link", NULL);
 	if (fixed_link) {
-		snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
-			 PHY_ID_FMT, "0", fixed_link[0]);
 		phy = NULL;
 	} else {
-		char bus_name[MII_BUS_ID_SIZE];
-
-		ph = of_get_property(np, "phy-handle", NULL);
-		phy = of_find_node_by_phandle(*ph);
-
+		phy = of_parse_phandle(np, "phy-handle", 0);
 		if (phy == NULL)
 			return -ENODEV;
-
-		/* set the PHY address */
-		prop = of_get_property(phy, "reg", NULL);
-		if (prop == NULL)
-			return -1;
-
-		/* Set the bus id */
-		mdio = of_get_parent(phy);
-
-		if (mdio == NULL)
-			return -ENODEV;
-
-		err = of_address_to_resource(mdio, 0, &res);
-
-		if (err) {
-			of_node_put(mdio);
-			return err;
-		}
-		fsl_pq_mdio_bus_name(bus_name, mdio);
-		of_node_put(mdio);
-		snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
-			"%s:%02x", bus_name, *prop);
 	}
+	ug_info->phy_node = phy;
 
 	/* get the phy interface type, or default to MII */
 	prop = of_get_property(np, "phy-connection-type", NULL);
 	if (!prop) {
 		/* handle interface property present in old trees */
+		if (!phy)
+			return -ENODEV;
+
 		prop = of_get_property(phy, "interface", NULL);
 		if (prop != NULL) {
 			phy_interface = enet_to_phy_interface[*prop];
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index e3a25e6..77e01de 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1101,7 +1101,7 @@ struct ucc_geth_info {
 	u32 eventRegMask;
 	u16 pausePeriod;
 	u16 extensionField;
-	char phy_bus_id[BUS_ID_SIZE];
+	struct device_node *phy_node;
 	u8 weightfactor[NUM_TX_QUEUES];
 	u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
 	u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];

^ permalink raw reply related

* [PATCH 11/14] net: Rework pasemi_mac driver to use of_mdio infrastructure
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch simplifies the driver by making use of more common code.

Tested-by: Olof Johansson <olof@lixom.net>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/platforms/pasemi/gpio_mdio.c |   32 +++++------------------------
 drivers/net/pasemi_mac.c                  |   28 ++++---------------------
 drivers/net/pasemi_mac.h                  |    1 -
 3 files changed, 9 insertions(+), 52 deletions(-)


diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
index 75cc165..3bf5467 100644
--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -29,7 +29,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/phy.h>
-#include <linux/platform_device.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #define DELAY 1
@@ -39,6 +39,7 @@ static void __iomem *gpio_regs;
 struct gpio_priv {
 	int mdc_pin;
 	int mdio_pin;
+	int mdio_irqs[PHY_MAX_ADDR];
 };
 
 #define MDC_PIN(bus)	(((struct gpio_priv *)bus->priv)->mdc_pin)
@@ -218,12 +219,11 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
 				     const struct of_device_id *match)
 {
 	struct device *dev = &ofdev->dev;
-	struct device_node *phy_dn, *np = ofdev->node;
+	struct device_node *np = ofdev->node;
 	struct mii_bus *new_bus;
 	struct gpio_priv *priv;
 	const unsigned int *prop;
 	int err;
-	int i;
 
 	err = -ENOMEM;
 	priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
@@ -244,27 +244,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
 	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop);
 	new_bus->priv = priv;
 
-	new_bus->phy_mask = 0;
-
-	new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-
-	if (!new_bus->irq)
-		goto out_free_bus;
-
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		new_bus->irq[i] = NO_IRQ;
-
-	for (phy_dn = of_get_next_child(np, NULL);
-	     phy_dn != NULL;
-	     phy_dn = of_get_next_child(np, phy_dn)) {
-		const unsigned int *ip, *regp;
-
-		ip = of_get_property(phy_dn, "interrupts", NULL);
-		regp = of_get_property(phy_dn, "reg", NULL);
-		if (!ip || !regp || *regp >= PHY_MAX_ADDR)
-			continue;
-		new_bus->irq[*regp] = irq_create_mapping(NULL, *ip);
-	}
+	new_bus->irq = priv->mdio_irqs;
 
 	prop = of_get_property(np, "mdc-pin", NULL);
 	priv->mdc_pin = *prop;
@@ -275,7 +255,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
 	new_bus->parent = dev;
 	dev_set_drvdata(dev, new_bus);
 
-	err = mdiobus_register(new_bus);
+	err = of_mdiobus_register(new_bus, np);
 
 	if (err != 0) {
 		printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
@@ -286,8 +266,6 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
 	return 0;
 
 out_free_irq:
-	kfree(new_bus->irq);
-out_free_bus:
 	kfree(new_bus);
 out_free_priv:
 	kfree(priv);
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 5eeb5a8..2edbba3 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -24,6 +24,7 @@
 #include <linux/dmaengine.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
+#include <linux/of_mdio.h>
 #include <linux/etherdevice.h>
 #include <asm/dma-mapping.h>
 #include <linux/in.h>
@@ -1086,34 +1087,17 @@ static int pasemi_mac_phy_init(struct net_device *dev)
 	struct pasemi_mac *mac = netdev_priv(dev);
 	struct device_node *dn, *phy_dn;
 	struct phy_device *phydev;
-	unsigned int phy_id;
-	const phandle *ph;
-	const unsigned int *prop;
-	struct resource r;
-	int ret;
 
 	dn = pci_device_to_OF_node(mac->pdev);
-	ph = of_get_property(dn, "phy-handle", NULL);
-	if (!ph)
-		return -ENODEV;
-	phy_dn = of_find_node_by_phandle(*ph);
-
-	prop = of_get_property(phy_dn, "reg", NULL);
-	ret = of_address_to_resource(phy_dn->parent, 0, &r);
-	if (ret)
-		goto err;
-
-	phy_id = *prop;
-	snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x",
-		 (int)r.start, phy_id);
-
+	phy_dn = of_parse_phandle(dn, "phy-handle", 0);
 	of_node_put(phy_dn);
 
 	mac->link = 0;
 	mac->speed = 0;
 	mac->duplex = -1;
 
-	phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII);
+	phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0,
+				PHY_INTERFACE_MODE_SGMII);
 
 	if (IS_ERR(phydev)) {
 		printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
@@ -1123,10 +1107,6 @@ static int pasemi_mac_phy_init(struct net_device *dev)
 	mac->phydev = phydev;
 
 	return 0;
-
-err:
-	of_node_put(phy_dn);
-	return -ENODEV;
 }
 
 
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index 1a115ec..e2f4efa 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -100,7 +100,6 @@ struct pasemi_mac {
 	int	duplex;
 
 	unsigned int	msg_enable;
-	char	phy_id[BUS_ID_SIZE];
 };
 
 /* Software status descriptor (ring_info) */

^ permalink raw reply related

* [PATCH 12/14] powerpc/82xx: Rework Embedded Planet ep8248e platform to use of_mdio
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch modifies the bitbanged MDIO driver in the ep8248e platform
code to use the common of_mdio infrastructure.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/platforms/82xx/ep8248e.c |    9 +++------
 1 files changed, 3 insertions(+), 6 deletions(-)


diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c
index 0eb6d7f..51fcae4 100644
--- a/arch/powerpc/platforms/82xx/ep8248e.c
+++ b/arch/powerpc/platforms/82xx/ep8248e.c
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/fsl_devices.h>
 #include <linux/mdio-bitbang.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include <asm/io.h>
@@ -115,7 +116,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
 	struct mii_bus *bus;
 	struct resource res;
 	struct device_node *node;
-	int ret, i;
+	int ret;
 
 	node = of_get_parent(ofdev->node);
 	of_node_put(node);
@@ -130,17 +131,13 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
 	if (!bus)
 		return -ENOMEM;
 
-	bus->phy_mask = 0;
 	bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
 
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		bus->irq[i] = -1;
-
 	bus->name = "ep8248e-mdio-bitbang";
 	bus->parent = &ofdev->dev;
 	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 
-	return mdiobus_register(bus);
+	return of_mdiobus_register(bus, ofdev->node);
 }
 
 static int ep8248e_mdio_remove(struct of_device *ofdev)

^ permalink raw reply related

* [PATCH 13/14] net: Rework fs_enet driver to use of_mdio infrastructure
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch simplifies the driver by making use of more common code.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/fs_enet/fs_enet-main.c |   69 ++++++------------------------------
 drivers/net/fs_enet/mii-bitbang.c  |   29 +--------------
 drivers/net/fs_enet/mii-fec.c      |   26 +-------------
 include/linux/fs_enet_pd.h         |    6 +--
 4 files changed, 16 insertions(+), 114 deletions(-)


diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index b037ce9..387e0e9 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -36,6 +36,8 @@
 #include <linux/fs.h>
 #include <linux/platform_device.h>
 #include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
 
@@ -752,9 +754,10 @@ static int fs_init_phy(struct net_device *dev)
 	fep->oldlink = 0;
 	fep->oldspeed = 0;
 	fep->oldduplex = -1;
-	if(fep->fpi->bus_id)
-		phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0,
-				PHY_INTERFACE_MODE_MII);
+	if(fep->fpi->phy_node)
+		phydev = of_phy_connect(dev, fep->fpi->phy_node,
+					&fs_adjust_link, 0,
+					PHY_INTERFACE_MODE_MII);
 	else {
 		printk("No phy bus ID specified in BSP code\n");
 		return -EINVAL;
@@ -962,57 +965,6 @@ static void cleanup_immap(void)
 
 /**************************************************************************************/
 
-static int __devinit find_phy(struct device_node *np,
-                              struct fs_platform_info *fpi)
-{
-	struct device_node *phynode, *mdionode;
-	int ret = 0, len, bus_id;
-	const u32 *data;
-
-	data  = of_get_property(np, "fixed-link", NULL);
-	if (data) {
-		snprintf(fpi->bus_id, 16, "%x:%02x", 0, *data);
-		return 0;
-	}
-
-	data = of_get_property(np, "phy-handle", &len);
-	if (!data || len != 4)
-		return -EINVAL;
-
-	phynode = of_find_node_by_phandle(*data);
-	if (!phynode)
-		return -EINVAL;
-
-	data = of_get_property(phynode, "reg", &len);
-	if (!data || len != 4) {
-		ret = -EINVAL;
-		goto out_put_phy;
-	}
-
-	mdionode = of_get_parent(phynode);
-	if (!mdionode) {
-		ret = -EINVAL;
-		goto out_put_phy;
-	}
-
-	bus_id = of_get_gpio(mdionode, 0);
-	if (bus_id < 0) {
-		struct resource res;
-		ret = of_address_to_resource(mdionode, 0, &res);
-		if (ret)
-			goto out_put_mdio;
-		bus_id = res.start;
-	}
-
-	snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data);
-
-out_put_mdio:
-	of_node_put(mdionode);
-out_put_phy:
-	of_node_put(phynode);
-	return ret;
-}
-
 #ifdef CONFIG_FS_ENET_HAS_FEC
 #define IS_FEC(match) ((match)->data == &fs_fec_ops)
 #else
@@ -1046,9 +998,9 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
 	fpi->rx_copybreak = 240;
 	fpi->use_napi = 1;
 	fpi->napi_weight = 17;
-
-	ret = find_phy(ofdev->node, fpi);
-	if (ret)
+	fpi->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+	if ((!fpi->phy_node) && (!of_get_property(ofdev->node, "fixed-link",
+						  NULL)))
 		goto out_free_fpi;
 
 	privsize = sizeof(*fep) +
@@ -1129,6 +1081,7 @@ out_cleanup_data:
 out_free_dev:
 	free_netdev(ndev);
 	dev_set_drvdata(&ofdev->dev, NULL);
+	of_node_put(fpi->phy_node);
 out_free_fpi:
 	kfree(fpi);
 	return ret;
@@ -1144,7 +1097,7 @@ static int fs_enet_remove(struct of_device *ofdev)
 	fep->ops->free_bd(ndev);
 	fep->ops->cleanup_data(ndev);
 	dev_set_drvdata(fep->dev, NULL);
-
+	of_node_put(fep->fpi->phy_node);
 	free_netdev(ndev);
 	return 0;
 }
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 49b6645..93b481b 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -22,6 +22,7 @@
 #include <linux/mii.h>
 #include <linux/platform_device.h>
 #include <linux/mdio-bitbang.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include "fs_enet.h"
@@ -149,31 +150,12 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
 	return 0;
 }
 
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
-	const u32 *data;
-	int len, id, irq;
-
-	data = of_get_property(np, "reg", &len);
-	if (!data || len != 4)
-		return;
-
-	id = *data;
-	bus->phy_mask &= ~(1 << id);
-
-	irq = of_irq_to_resource(np, 0, NULL);
-	if (irq != NO_IRQ)
-		bus->irq[id] = irq;
-}
-
 static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
                                         const struct of_device_id *match)
 {
-	struct device_node *np = NULL;
 	struct mii_bus *new_bus;
 	struct bb_info *bitbang;
 	int ret = -ENOMEM;
-	int i;
 
 	bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
 	if (!bitbang)
@@ -196,17 +178,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
 	if (!new_bus->irq)
 		goto out_unmap_regs;
 
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		new_bus->irq[i] = -1;
-
-	while ((np = of_get_next_child(ofdev->node, np)))
-		if (!strcmp(np->type, "ethernet-phy"))
-			add_phy(new_bus, np);
-
 	new_bus->parent = &ofdev->dev;
 	dev_set_drvdata(&ofdev->dev, new_bus);
 
-	ret = mdiobus_register(new_bus);
+	ret = of_mdiobus_register(new_bus, ofdev->node);
 	if (ret)
 		goto out_free_irqs;
 
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 28077cc..bdc3160 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -102,23 +102,6 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
 	return 0;
 }
 
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
-	const u32 *data;
-	int len, id, irq;
-
-	data = of_get_property(np, "reg", &len);
-	if (!data || len != 4)
-		return;
-
-	id = *data;
-	bus->phy_mask &= ~(1 << id);
-
-	irq = of_irq_to_resource(np, 0, NULL);
-	if (irq != NO_IRQ)
-		bus->irq[id] = irq;
-}
-
 static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
                                         const struct of_device_id *match)
 {
@@ -165,17 +148,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
 	if (!new_bus->irq)
 		goto out_unmap_regs;
 
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		new_bus->irq[i] = -1;
-
-	while ((np = of_get_next_child(ofdev->node, np)))
-		if (!strcmp(np->type, "ethernet-phy"))
-			add_phy(new_bus, np);
-
 	new_bus->parent = &ofdev->dev;
 	dev_set_drvdata(&ofdev->dev, new_bus);
 
-	ret = mdiobus_register(new_bus);
+	ret = of_mdiobus_register(new_bus, ofdev->node);
 	if (ret)
 		goto out_free_irqs;
 
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 8300cab..51b7934 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -17,6 +17,7 @@
 #define FS_ENET_PD_H
 
 #include <linux/string.h>
+#include <linux/of_mdio.h>
 #include <asm/types.h>
 
 #define FS_ENET_NAME	"fs_enet"
@@ -130,10 +131,7 @@ struct fs_platform_info {
 	
 	u32 device_flags;
 
-	int phy_addr;		/* the phy address (-1 no phy) */
-	char bus_id[16];
-	int phy_irq;		/* the phy irq (if it exists)  */
-
+	struct device_node *phy_node;
 	const struct fs_mii_bus_info *bus_info;
 
 	int rx_ring, tx_ring;	/* number of buffers on rx     */

^ permalink raw reply related

* [PATCH 14/14] net: add Xilinx ll_temac device driver
From: Grant Likely @ 2009-03-31  8:27 UTC (permalink / raw)
  To: netdev, linuxppc-dev; +Cc: olof, afleming, Joakim Tjernlund
In-Reply-To: <20090331075537.1427.7819.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch adds support for the Xilinx ll_temac 10/100/1000 Ethernet
device.  The ll_temac ipcore is typically used on Xilinx Virtex and
Spartan designs attached to either a PowerPC 4xx or Microblaze
processor.

At the present moment, this driver only works with Virtex5 PowerPC
designs because it assumes DCR is used to access the DMA registers.
However, the low level access to DMA registers is abstracted and
it should be easy to adapt for the other implementations.

I'm posting this driver now as an RFC.  There are still some things that
need to be tightened up, but it does appear to be stable.

Derived from driver code written by Yoshio Kashiwagi and David H. Lynch Jr.

CC: Yoshio Kashiwagi <kashiwagi@co-nss.co.jp>
CC: David H. Lynch Jr. <dhlii@dlasys.net>
CC: John Linn <john.linn@xilinx.com>
CC: John Bonesio <john.bonesio@xilinx.com>
CC: David DeBonis <ddeboni@xilinx.com>
CC: Wilson Yang <wyang@xilinx.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/net/Kconfig             |    8 
 drivers/net/Makefile            |    2 
 drivers/net/xilinx_temac.c      |  970 +++++++++++++++++++++++++++++++++++++++
 drivers/net/xilinx_temac.h      |  374 +++++++++++++++
 drivers/net/xilinx_temac_mdio.c |  119 +++++
 5 files changed, 1473 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/xilinx_temac.c
 create mode 100644 drivers/net/xilinx_temac.h
 create mode 100644 drivers/net/xilinx_temac_mdio.c


diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f062b42..9578ee0 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2339,6 +2339,14 @@ config MV643XX_ETH
 	  Some boards that use the Discovery chipset are the Momenco
 	  Ocelot C and Jaguar ATX and Pegasos II.
 
+config XILINX_TEMAC
+	tristate "Xilinx TEMAC 10/100/1000 Ethernet MAC driver"
+	select PHYLIB
+	depends on PPC_DCR_NATIVE
+	help
+	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
+	  device found in Virtex FPGAs
+
 config QLA3XXX
 	tristate "QLogic QLA3XXX Network Driver Support"
 	depends on PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 98409c9..ba98bf5 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -133,6 +133,8 @@ obj-$(CONFIG_AX88796) += ax88796.o
 
 obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+xilinxtemac-objs := xilinx_temac.o xilinx_temac_mdio.o
+obj-$(CONFIG_XILINX_TEMAC) += xilinxtemac.o
 obj-$(CONFIG_QLA3XXX) += qla3xxx.o
 obj-$(CONFIG_QLGE) += qlge/
 
diff --git a/drivers/net/xilinx_temac.c b/drivers/net/xilinx_temac.c
new file mode 100644
index 0000000..d778a55
--- /dev/null
+++ b/drivers/net/xilinx_temac.c
@@ -0,0 +1,970 @@
+/*
+ * Driver for Xilinx TEMAC Ethernet device
+ *
+ * Copyright (c) 2008 Nissin Systems Co., Ltd.,  Yoshio Kashiwagi
+ * Copyright (c) 2005-2008 DLA Systems,  David H. Lynch Jr. <dhlii@dlasys.net>
+ * Copyright (c) 2008-2009 Secret Lab Technologies Ltd.
+ *
+ * This is a driver for the Xilinx ll_temac ipcore which is often used
+ * in the Virtex and Spartan series of chips.
+ *
+ * Notes:
+ * - The ll_temac hardware uses indirect access for many of the TEMAC
+ *   registers, include the MDIO bus.  However, indirect access to MDIO
+ *   registers take considerably more clock cycles than to TEMAC registers.
+ *   MDIO accesses are long, so threads doing them should probably sleep
+ *   rather than busywait.  However, since only one indirect access can be
+ *   in progress at any given time, that means that *all* indirect accesses
+ *   could end up sleeping (to wait for an MDIO access to complete).
+ *   Fortunately none of the indirect accesses are on the 'hot' path for tx
+ *   or rx, so this should be okay.
+ *
+ * TODO:
+ * - Fix driver to work on more than just Virtex5.  Right now the driver
+ *   assumes that the locallink DMA registers are accessed via DCR
+ *   instructions.
+ * - Factor out locallink DMA code into separate driver
+ * - Fix multicast assignment.
+ * - Fix support for hardware checksumming.
+ * - Testing.  Lots and lots of testing.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/tcp.h>      /* needed for sizeof(tcphdr) */
+#include <linux/udp.h>      /* needed for sizeof(udphdr) */
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/in.h>
+#include <linux/io.h>
+#include <linux/ip.h>
+
+#include "xilinx_temac.h"
+
+#define TX_BD_NUM   64
+#define RX_BD_NUM   128
+
+/* ---------------------------------------------------------------------
+ * Low level register access functions
+ */
+
+u32 temac_ior(struct temac_local *lp, int offset)
+{
+	return in_be32((u32 *)(lp->regs + offset));
+}
+
+void temac_iow(struct temac_local *lp, int offset, u32 value)
+{
+	out_be32((u32 *) (lp->regs + offset), value);
+}
+
+int temac_indirect_busywait(struct temac_local *lp)
+{
+	long end = jiffies + 2;
+
+	while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) {
+		if (end - jiffies <= 0) {
+			WARN_ON(1);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+/**
+ * temac_indirect_in32
+ *
+ * lp->indirect_mutex must be held when calling this function
+ */
+u32 temac_indirect_in32(struct temac_local *lp, int reg)
+{
+	u32 val;
+
+	if (temac_indirect_busywait(lp))
+		return -ETIMEDOUT;
+	temac_iow(lp, XTE_CTL0_OFFSET, reg);
+	if (temac_indirect_busywait(lp))
+		return -ETIMEDOUT;
+	val = temac_ior(lp, XTE_LSW0_OFFSET);
+
+	return val;
+}
+
+/**
+ * temac_indirect_out32
+ *
+ * lp->indirect_mutex must be held when calling this function
+ */
+void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
+{
+	if (temac_indirect_busywait(lp))
+		return;
+	temac_iow(lp, XTE_LSW0_OFFSET, value);
+	temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
+}
+
+static u32 temac_dma_in32(struct temac_local *lp, int reg)
+{
+	return dcr_read(lp->sdma_dcrs, reg);
+}
+
+static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
+{
+	dcr_write(lp->sdma_dcrs, reg, value);
+}
+
+/**
+ * temac_dma_bd_init - Setup buffer descriptor rings
+ */
+static int temac_dma_bd_init(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct sk_buff *skb;
+	int i;
+
+	lp->rx_skb = kzalloc(sizeof(struct sk_buff)*RX_BD_NUM, GFP_KERNEL);
+	/* allocate the tx and rx ring buffer descriptors. */
+	/* returns a virtual addres and a physical address. */
+	lp->tx_bd_v = dma_alloc_coherent(NULL, sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+					 &lp->tx_bd_p, GFP_KERNEL);
+	lp->rx_bd_v = dma_alloc_coherent(NULL, sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+					 &lp->rx_bd_p, GFP_KERNEL);
+
+	memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM);
+	for (i = 0; i < TX_BD_NUM; i++) {
+		lp->tx_bd_v[i].next = lp->tx_bd_p +
+				sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM);
+	}
+
+	memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM);
+	for (i = 0; i < RX_BD_NUM; i++) {
+		lp->rx_bd_v[i].next = lp->rx_bd_p +
+				sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
+
+		skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE
+				+ XTE_ALIGN, GFP_ATOMIC);
+		if (skb == 0) {
+			dev_err(&ndev->dev, "alloc_skb error %d\n", i);
+			return -1;
+		}
+		lp->rx_skb[i] = skb;
+		skb_reserve(skb,  BUFFER_ALIGN(skb->data));
+		/* returns physical address of skb->data */
+		lp->rx_bd_v[i].phys = pci_map_single(NULL, skb->data,
+						     XTE_MAX_JUMBO_FRAME_SIZE,
+						     PCI_DMA_FROMDEVICE);
+		lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE;
+		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
+	}
+
+	temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
+					  CHNL_CTRL_IRQ_EN |
+					  CHNL_CTRL_IRQ_DLY_EN |
+					  CHNL_CTRL_IRQ_COAL_EN);
+	/* 0x10220483 */
+	/* 0x00100483 */
+	temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
+					  CHNL_CTRL_IRQ_EN |
+					  CHNL_CTRL_IRQ_DLY_EN |
+					  CHNL_CTRL_IRQ_COAL_EN |
+					  CHNL_CTRL_IRQ_IOE);
+	/* 0xff010283 */
+
+	temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
+	temac_dma_out32(lp, RX_TAILDESC_PTR,
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+	temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * net_device_ops
+ */
+
+static int temac_set_mac_address(struct net_device *ndev, void *address)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+
+	if (address)
+		memcpy(ndev->dev_addr, address, ETH_ALEN);
+
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		random_ether_addr(ndev->dev_addr);
+
+	/* set up unicast MAC address filter set its mac address */
+	mutex_lock(&lp->indirect_mutex);
+	temac_indirect_out32(lp, XTE_UAW0_OFFSET,
+			     (ndev->dev_addr[0]) |
+			     (ndev->dev_addr[1] << 8) |
+			     (ndev->dev_addr[2] << 16) |
+			     (ndev->dev_addr[3] << 24));
+	/* There are reserved bits in EUAW1
+	 * so don't affect them Set MAC bits [47:32] in EUAW1 */
+	temac_indirect_out32(lp, XTE_UAW1_OFFSET,
+			     (ndev->dev_addr[4] & 0x000000ff) |
+			     (ndev->dev_addr[5] << 8));
+	mutex_unlock(&lp->indirect_mutex);
+
+	return 0;
+}
+
+static void temac_set_multicast_list(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	u32 multi_addr_msw, multi_addr_lsw, val;
+	int i;
+
+	mutex_lock(&lp->indirect_mutex);
+	if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC)
+			|| ndev->mc_count > MULTICAST_CAM_TABLE_NUM) {
+		/*
+		 *	We must make the kernel realise we had to move
+		 *	into promisc mode or we start all out war on
+		 *	the cable. If it was a promisc request the
+		 *	flag is already set. If not we assert it.
+		 */
+		ndev->flags |= IFF_PROMISC;
+		temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK);
+		dev_info(&ndev->dev, "Promiscuous mode enabled.\n");
+	} else if (ndev->mc_count) {
+		struct dev_mc_list *mclist = ndev->mc_list;
+		for (i = 0; mclist && i < ndev->mc_count; i++) {
+
+			if (i >= MULTICAST_CAM_TABLE_NUM)
+				break;
+			multi_addr_msw = ((mclist->dmi_addr[3] << 24) |
+					  (mclist->dmi_addr[2] << 16) |
+					  (mclist->dmi_addr[1] << 8) |
+					  (mclist->dmi_addr[0]));
+			temac_indirect_out32(lp, XTE_MAW0_OFFSET,
+					     multi_addr_msw);
+			multi_addr_lsw = ((mclist->dmi_addr[5] << 8) |
+					  (mclist->dmi_addr[4]) | (i << 16));
+			temac_indirect_out32(lp, XTE_MAW1_OFFSET,
+					     multi_addr_lsw);
+			mclist = mclist->next;
+		}
+	} else {
+		val = temac_indirect_in32(lp, XTE_AFM_OFFSET);
+		temac_indirect_out32(lp, XTE_AFM_OFFSET,
+				     val & ~XTE_AFM_EPPRM_MASK);
+		temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0);
+		temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0);
+		dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
+	}
+	mutex_unlock(&lp->indirect_mutex);
+}
+
+struct temac_option {
+	int flg;
+	u32 opt;
+	u32 reg;
+	u32 m_or;
+	u32 m_and;
+} temac_options[] = {
+	/* Turn on jumbo packet support for both Rx and Tx */
+	{
+		.opt = XTE_OPTION_JUMBO,
+		.reg = XTE_TXC_OFFSET,
+		.m_or = XTE_TXC_TXJMBO_MASK,
+	},
+	{
+		.opt = XTE_OPTION_JUMBO,
+		.reg = XTE_RXC1_OFFSET,
+		.m_or =XTE_RXC1_RXJMBO_MASK,
+	},
+	/* Turn on VLAN packet support for both Rx and Tx */
+	{
+		.opt = XTE_OPTION_VLAN,
+		.reg = XTE_TXC_OFFSET,
+		.m_or =XTE_TXC_TXVLAN_MASK,
+	},
+	{
+		.opt = XTE_OPTION_VLAN,
+		.reg = XTE_RXC1_OFFSET,
+		.m_or =XTE_RXC1_RXVLAN_MASK,
+	},
+	/* Turn on FCS stripping on receive packets */
+	{
+		.opt = XTE_OPTION_FCS_STRIP,
+		.reg = XTE_RXC1_OFFSET,
+		.m_or =XTE_RXC1_RXFCS_MASK,
+	},
+	/* Turn on FCS insertion on transmit packets */
+	{
+		.opt = XTE_OPTION_FCS_INSERT,
+		.reg = XTE_TXC_OFFSET,
+		.m_or =XTE_TXC_TXFCS_MASK,
+	},
+	/* Turn on length/type field checking on receive packets */
+	{
+		.opt = XTE_OPTION_LENTYPE_ERR,
+		.reg = XTE_RXC1_OFFSET,
+		.m_or =XTE_RXC1_RXLT_MASK,
+	},
+	/* Turn on flow control */
+	{
+		.opt = XTE_OPTION_FLOW_CONTROL,
+		.reg = XTE_FCC_OFFSET,
+		.m_or =XTE_FCC_RXFLO_MASK,
+	},
+	/* Turn on flow control */
+	{
+		.opt = XTE_OPTION_FLOW_CONTROL,
+		.reg = XTE_FCC_OFFSET,
+		.m_or =XTE_FCC_TXFLO_MASK,
+	},
+	/* Turn on promiscuous frame filtering (all frames are received ) */
+	{
+		.opt = XTE_OPTION_PROMISC,
+		.reg = XTE_AFM_OFFSET,
+		.m_or =XTE_AFM_EPPRM_MASK,
+	},
+	/* Enable transmitter if not already enabled */
+	{
+		.opt = XTE_OPTION_TXEN,
+		.reg = XTE_TXC_OFFSET,
+		.m_or =XTE_TXC_TXEN_MASK,
+	},
+	/* Enable receiver? */
+	{
+		.opt = XTE_OPTION_RXEN,
+		.reg = XTE_RXC1_OFFSET,
+		.m_or =XTE_RXC1_RXEN_MASK,
+	},
+	{}
+};
+
+/**
+ * temac_setoptions
+ */
+static u32 temac_setoptions(struct net_device *ndev, u32 options)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct temac_option *tp = &temac_options[0];
+	int reg;
+
+	mutex_lock(&lp->indirect_mutex);
+	while (tp->opt) {
+		reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or;
+		if (options & tp->opt)
+			reg |= tp->m_or;
+		temac_indirect_out32(lp, tp->reg, reg);
+		tp++;
+	}
+	lp->options |= options;
+	mutex_unlock(&lp->indirect_mutex);
+
+	return (0);
+}
+
+/* Initilize temac */
+static void temac_device_reset(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	u32 timeout;
+	u32 val;
+
+	/* Perform a software reset */
+
+	/* 0x300 host enable bit ? */
+	/* reset PHY through control register ?:1 */
+
+	dev_dbg(&ndev->dev, "%s()\n", __func__);
+
+	mutex_lock(&lp->indirect_mutex);
+	/* Reset the receiver and wait for it to finish reset */
+	temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK);
+	timeout = 1000;
+	while (temac_indirect_in32(lp, XTE_RXC1_OFFSET) & XTE_RXC1_RXRST_MASK) {
+		udelay(1);
+		if (--timeout == 0) {
+			dev_err(&ndev->dev,
+				"temac_device_reset RX reset timeout!!\n");
+			break;
+		}
+	}
+
+	/* Reset the transmitter and wait for it to finish reset */
+	temac_indirect_out32(lp, XTE_TXC_OFFSET, XTE_TXC_TXRST_MASK);
+	timeout = 1000;
+	while (temac_indirect_in32(lp, XTE_TXC_OFFSET) & XTE_TXC_TXRST_MASK) {
+		udelay(1);
+		if (--timeout == 0) {
+			dev_err(&ndev->dev,
+				"temac_device_reset TX reset timeout!!\n");
+			break;
+		}
+	}
+
+	/* Disable the receiver */
+	val = temac_indirect_in32(lp, XTE_RXC1_OFFSET);
+	temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK);
+
+	/* Reset Local Link (DMA) */
+	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
+	timeout = 1000;
+	while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
+		udelay(1);
+		if (--timeout == 0) {
+			dev_err(&ndev->dev,
+				"temac_device_reset DMA reset timeout!!\n");
+			break;
+		}
+	}
+	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
+
+	temac_dma_bd_init(ndev);
+
+	temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0);
+	temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0);
+	temac_indirect_out32(lp, XTE_TXC_OFFSET, 0);
+	temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
+
+	mutex_unlock(&lp->indirect_mutex);
+
+	/* Sync default options with HW
+	 * but leave receiver and transmitter disabled.  */
+	temac_setoptions(ndev,
+			 lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN));
+
+	temac_set_mac_address(ndev, NULL);
+
+	/* Set address filter table */
+	temac_set_multicast_list(ndev);
+	if (temac_setoptions(ndev, lp->options))
+		dev_err(&ndev->dev, "Error setting TEMAC options\n");
+
+	/* Init Driver variable */
+	ndev->trans_start = 0;
+}
+
+void temac_adjust_link(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct phy_device *phy = lp->phy_dev;
+	u32 mii_speed;
+	int link_state;
+
+	/* hash together the state values to decide if something has changed */
+	link_state = phy->speed | (phy->duplex << 1) | phy->link;
+
+	mutex_lock(&lp->indirect_mutex);
+	if (lp->last_link != link_state) {
+		mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET);
+		mii_speed &= ~XTE_EMCFG_LINKSPD_MASK;
+
+		switch (phy->speed) {
+		case SPEED_1000: mii_speed |= XTE_EMCFG_LINKSPD_1000; break;
+		case SPEED_100: mii_speed |= XTE_EMCFG_LINKSPD_100; break;
+		case SPEED_10: mii_speed |= XTE_EMCFG_LINKSPD_10; break;
+		}
+
+		/* Write new speed setting out to TEMAC */
+		temac_indirect_out32(lp, XTE_EMCFG_OFFSET, mii_speed);
+		lp->last_link = link_state;
+		phy_print_status(phy);
+	}
+	mutex_unlock(&lp->indirect_mutex);
+}
+
+static void temac_start_xmit_done(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct cdmac_bd *cur_p;
+	unsigned int stat = 0;
+
+	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
+	stat = cur_p->app0;
+
+	while (stat & STS_CTRL_APP0_CMPLT) {
+		pci_unmap_single(NULL, (unsigned long)cur_p->phys,
+				cur_p->len, PCI_DMA_TODEVICE);
+		if (cur_p->app4)
+			dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
+		cur_p->app0 = 0;
+
+		ndev->stats.tx_packets++;
+		ndev->stats.tx_bytes += cur_p->len;
+
+		lp->tx_bd_ci++;
+		if (lp->tx_bd_ci >= TX_BD_NUM)
+			lp->tx_bd_ci = 0;
+
+		cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
+		stat = cur_p->app0;
+	}
+
+	netif_wake_queue(ndev);
+}
+
+static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct cdmac_bd *cur_p;
+	dma_addr_t start_p, tail_p;
+	int ii;
+	unsigned long num_frag;
+	skb_frag_t *frag;
+
+	num_frag = skb_shinfo(skb)->nr_frags;
+	frag = &skb_shinfo(skb)->frags[0];
+	start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
+	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+
+	if (cur_p->app0 & STS_CTRL_APP0_CMPLT) {
+		if (!netif_queue_stopped(ndev)) {
+			netif_stop_queue(ndev);
+			return NETDEV_TX_BUSY;
+		}
+		return NETDEV_TX_BUSY;
+	}
+
+	cur_p->app0 = 0;
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		const struct iphdr *ip = ip_hdr(skb);
+		int length = 0, start, insert = 0, headlen;
+
+		switch (ip->protocol) {
+		case IPPROTO_TCP:
+			start = sizeof(struct iphdr) + ETH_HLEN;
+			insert = sizeof(struct iphdr) + ETH_HLEN + 16;
+			length = ip->tot_len - sizeof(struct iphdr);
+			headlen = ETH_HLEN + sizeof(struct iphdr) +
+				  sizeof(struct tcphdr);
+			break;
+		case IPPROTO_UDP:
+			start = sizeof(struct iphdr) + ETH_HLEN;
+			insert = sizeof(struct iphdr) + ETH_HLEN + 6;
+			length = ip->tot_len - sizeof(struct iphdr);
+			headlen = ETH_HLEN + sizeof(struct iphdr) +
+				  sizeof(struct udphdr);
+			break;
+		default:
+			break;
+		}
+		cur_p->app1 = ((start << 16) | insert);
+		cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr,
+						length, ip->protocol, 0);
+		skb->data[insert] = 0;
+		skb->data[insert + 1] = 0;
+	}
+	cur_p->app0 |= STS_CTRL_APP0_SOP;
+	cur_p->len = skb_headlen(skb);
+	cur_p->phys = pci_map_single(NULL, skb->data, skb->len,
+				     PCI_DMA_TODEVICE);
+	cur_p->app4 = (unsigned long)skb;
+
+	for (ii = 0; ii < num_frag; ii++) {
+		lp->tx_bd_tail++;
+		if (lp->tx_bd_tail >= TX_BD_NUM)
+			lp->tx_bd_tail = 0;
+
+		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+		cur_p->phys = pci_map_single(NULL,
+				(void *)page_address(frag->page)
+				+ frag->page_offset,
+				frag->size, PCI_DMA_TODEVICE);
+		cur_p->len = frag->size;
+		cur_p->app0 = 0;
+		frag++;
+	}
+	cur_p->app0 |= STS_CTRL_APP0_EOP;
+
+	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
+	lp->tx_bd_tail++;
+	if (lp->tx_bd_tail >= TX_BD_NUM)
+		lp->tx_bd_tail = 0;
+
+	/* Kick off the transfer */
+	temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
+
+	return 0;
+}
+
+
+static void ll_temac_recv(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	struct sk_buff *skb, *new_skb;
+	unsigned int bdstat;
+	struct cdmac_bd *cur_p;
+	dma_addr_t tail_p;
+	int length;
+	unsigned long skb_vaddr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lp->rx_lock, flags);
+
+	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
+	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
+
+	bdstat = cur_p->app0;
+	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
+
+		skb = lp->rx_skb[lp->rx_bd_ci];
+		length = cur_p->app4;
+
+		skb_vaddr = virt_to_bus(skb->data);
+		pci_unmap_single(NULL, skb_vaddr, length, PCI_DMA_FROMDEVICE);
+
+		skb_put(skb, length);
+		skb->dev = ndev;
+		skb->protocol = eth_type_trans(skb, ndev);
+		skb->ip_summed = CHECKSUM_NONE;
+
+		netif_rx(skb);
+
+		ndev->stats.rx_packets++;
+		ndev->stats.rx_bytes += length;
+
+		new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN,
+				GFP_ATOMIC);
+		if (new_skb == 0) {
+			dev_err(&ndev->dev, "no memory for new sk_buff\n");
+			spin_unlock_irqrestore(&lp->rx_lock, flags);
+			return;
+		}
+
+		skb_reserve(new_skb, BUFFER_ALIGN(new_skb->data));
+
+		cur_p->app0 = STS_CTRL_APP0_IRQONEND;
+		cur_p->phys = pci_map_single(NULL, new_skb->data,
+					     XTE_MAX_JUMBO_FRAME_SIZE,
+					     PCI_DMA_FROMDEVICE);
+		cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE;
+		lp->rx_skb[lp->rx_bd_ci] = new_skb;
+
+		lp->rx_bd_ci++;
+		if (lp->rx_bd_ci >= RX_BD_NUM)
+			lp->rx_bd_ci = 0;
+
+		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
+		bdstat = cur_p->app0;
+	}
+	temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
+
+	spin_unlock_irqrestore(&lp->rx_lock, flags);
+}
+
+static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
+{
+	struct net_device *ndev = _ndev;
+	struct temac_local *lp = netdev_priv(ndev);
+	unsigned int status;
+
+	status = temac_dma_in32(lp, TX_IRQ_REG);
+	temac_dma_out32(lp, TX_IRQ_REG, status);
+
+	if (status & (IRQ_COAL | IRQ_DLY))
+		temac_start_xmit_done(lp->ndev);
+	if (status & 0x080)
+		dev_err(&ndev->dev, "DMA error 0x%x\n", status);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)
+{
+	struct net_device *ndev = _ndev;
+	struct temac_local *lp = netdev_priv(ndev);
+	unsigned int status;
+
+	/* Read and clear the status registers */
+	status = temac_dma_in32(lp, RX_IRQ_REG);
+	temac_dma_out32(lp, RX_IRQ_REG, status);
+
+	if (status & (IRQ_COAL | IRQ_DLY))
+		ll_temac_recv(lp->ndev);
+
+	return IRQ_HANDLED;
+}
+
+static int temac_open(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	int rc;
+
+	dev_dbg(&ndev->dev, "temac_open()\n");
+
+	if (lp->phy_node) {
+		lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+					     temac_adjust_link, 0, 0);
+		if (!lp->phy_dev) {
+			dev_err(lp->dev, "of_phy_connect() failed\n");
+			return -ENODEV;
+		}
+
+		phy_start(lp->phy_dev);
+	}
+
+	rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev);
+	if (rc)
+		goto err_tx_irq;
+	rc = request_irq(lp->rx_irq, ll_temac_rx_irq, 0, ndev->name, ndev);
+	if (rc)
+		goto err_rx_irq;
+
+	temac_device_reset(ndev);
+	return 0;
+
+ err_rx_irq:
+	free_irq(lp->tx_irq, ndev);
+ err_tx_irq:
+	if (lp->phy_dev)
+		phy_disconnect(lp->phy_dev);
+	lp->phy_dev = NULL;
+	dev_err(lp->dev, "request_irq() failed\n");
+	return rc;
+}
+
+static int temac_stop(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+
+	dev_dbg(&ndev->dev, "temac_close()\n");
+
+	free_irq(lp->tx_irq, ndev);
+	free_irq(lp->rx_irq, ndev);
+
+	if (lp->phy_dev)
+		phy_disconnect(lp->phy_dev);
+	lp->phy_dev = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+temac_poll_controller(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+
+	disable_irq(lp->tx_irq);
+	disable_irq(lp->rx_irq);
+
+	ll_temac_rx_irq(lp->tx_irq, lp, 0);
+	ll_temac_tx_irq(lp->rx_irq, lp, 0);
+
+	enable_irq(lp->tx_irq);
+	enable_irq(lp->rx_irq);
+}
+#endif
+
+static const struct net_device_ops temac_netdev_ops = {
+	.ndo_open = temac_open,
+	.ndo_stop = temac_stop,
+	.ndo_start_xmit = temac_start_xmit,
+	.ndo_set_mac_address = temac_set_mac_address,
+	//.ndo_set_multicast_list = temac_set_multicast_list,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = temac_poll_controller,
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * SYSFS device attributes
+ */
+static ssize_t temac_show_llink_regs(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct temac_local *lp = netdev_priv(ndev);
+	int i, len = 0;
+
+	for (i = 0; i < 0x11; i++)
+		len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i),
+			       (i % 8) == 7 ? "\n" : " ");
+	len += sprintf(buf + len, "\n");
+
+	return len;
+}
+
+static DEVICE_ATTR(llink_regs, 0440, temac_show_llink_regs, NULL);
+
+static struct attribute *temac_device_attrs[] = {
+	&dev_attr_llink_regs.attr,
+	NULL,
+};
+
+static const struct attribute_group temac_attr_group = {
+	.attrs = temac_device_attrs,
+};
+
+static int __init
+temac_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct device_node *np;
+	struct temac_local *lp;
+	struct net_device *ndev;
+	const void *addr;
+	int size, rc = 0;
+	unsigned int dcrs;
+
+	/* Init network device structure */
+	ndev = alloc_etherdev(sizeof(*lp));
+	if (!ndev) {
+		dev_err(&op->dev, "could not allocate device.\n");
+		return -ENOMEM;
+	}
+	ether_setup(ndev);
+	dev_set_drvdata(&op->dev, ndev);
+	SET_NETDEV_DEV(ndev, &op->dev);
+	ndev->flags &= ~IFF_MULTICAST;  /* clear multicast */
+	ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
+	ndev->netdev_ops = &temac_netdev_ops;
+#if 0
+	ndev->features |= NETIF_F_IP_CSUM; /* Can checksum TCP/UDP over IPv4. */
+	ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */
+	ndev->features |= NETIF_F_IPV6_CSUM; /* Can checksum IPV6 TCP/UDP */
+	ndev->features |= NETIF_F_HIGHDMA; /* Can DMA to high memory. */
+	ndev->features |= NETIF_F_HW_VLAN_TX; /* Transmit VLAN hw accel */
+	ndev->features |= NETIF_F_HW_VLAN_RX; /* Receive VLAN hw acceleration */
+	ndev->features |= NETIF_F_HW_VLAN_FILTER; /* Receive VLAN filtering */
+	ndev->features |= NETIF_F_VLAN_CHALLENGED; /* cannot handle VLAN pkts */
+	ndev->features |= NETIF_F_GSO; /* Enable software GSO. */
+	ndev->features |= NETIF_F_MULTI_QUEUE; /* Has multiple TX/RX queues */
+	ndev->features |= NETIF_F_LRO; /* large receive offload */
+#endif
+
+	/* setup temac private info structure */
+	lp = netdev_priv(ndev);
+	lp->ndev = ndev;
+	lp->dev = &op->dev;
+	lp->options = XTE_OPTION_DEFAULTS;
+	spin_lock_init(&lp->rx_lock);
+	mutex_init(&lp->indirect_mutex);
+
+	/* map device registers */
+	lp->regs = of_iomap(op->node, 0);
+	if (!lp->regs) {
+		dev_err(&op->dev, "could not map temac regs.\n");
+		goto nodev;
+	}
+
+	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
+	np = of_parse_phandle(op->node, "llink-connected", 0);
+	if (!np) {
+		dev_err(&op->dev, "could not find DMA node\n");
+		goto nodev;
+	}
+
+	dcrs = dcr_resource_start(np, 0);
+	if (dcrs == 0) {
+		dev_err(&op->dev, "could not get DMA register address\n");
+		goto nodev;;
+	}
+	lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
+	dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
+
+	lp->rx_irq = irq_of_parse_and_map(np, 0);
+	lp->tx_irq = irq_of_parse_and_map(np, 1);
+	if (!lp->rx_irq || !lp->tx_irq) {
+		dev_err(&op->dev, "could not determine irqs\n");
+		rc = -ENOMEM;
+		goto nodev;
+	}
+
+	of_node_put(np); /* Finished with the DMA node; drop the reference */
+
+	/* Retrieve the MAC address */
+	addr = of_get_property(op->node, "local-mac-address", &size);
+	if ((!addr) || (size != 6)) {
+		dev_err(&op->dev, "could not find MAC address\n");
+		rc = -ENODEV;
+		goto nodev;
+	}
+	temac_set_mac_address(ndev, (void *)addr);
+
+	rc = temac_mdio_setup(lp, op->node);
+	if (rc)
+		dev_warn(&op->dev, "error registering MDIO bus\n");
+
+	lp->phy_node = of_parse_phandle(op->node, "phy-handle", 0);
+	if (lp->phy_node)
+		dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np);
+
+	/* Add the device attributes */
+	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
+	if (rc) {
+		dev_err(lp->dev, "Error creating sysfs files\n");
+		goto nodev;
+	}
+
+	rc = register_netdev(lp->ndev);
+	if (rc) {
+		dev_err(lp->dev, "register_netdev() error (%i)\n", rc);
+		goto err_register_ndev;
+	}
+
+	return 0;
+
+ err_register_ndev:
+	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
+ nodev:
+	free_netdev(ndev);
+	ndev = NULL;
+	return rc;
+}
+
+static int __devexit temac_of_remove(struct of_device *op)
+{
+	struct net_device *ndev = dev_get_drvdata(&op->dev);
+	struct temac_local *lp = netdev_priv(ndev);
+
+	temac_mdio_teardown(lp);
+	unregister_netdev(ndev);
+	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
+	lp->phy_node = NULL;
+	dev_set_drvdata(&op->dev, NULL);
+	free_netdev(ndev);
+	return 0;
+}
+
+static struct of_device_id temac_of_match[] __devinitdata = {
+	{ .compatible = "xlnx,xps-ll-temac-1.01.b", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, temac_of_match);
+
+static struct of_platform_driver temac_of_driver = {
+	.match_table = temac_of_match,
+	.probe = temac_of_probe,
+	.remove = __devexit_p(temac_of_remove),
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "xilinx_temac",
+	},
+};
+
+static int __init temac_init(void)
+{
+	return of_register_platform_driver(&temac_of_driver);
+}
+module_init(temac_init);
+
+static void __exit temac_exit(void)
+{
+	of_unregister_platform_driver(&temac_of_driver);
+}
+module_exit(temac_exit);
+
+MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver");
+MODULE_AUTHOR("Yoshio Kashiwagi");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/xilinx_temac.h b/drivers/net/xilinx_temac.h
new file mode 100644
index 0000000..4bc340c
--- /dev/null
+++ b/drivers/net/xilinx_temac.h
@@ -0,0 +1,374 @@
+
+#ifndef XILINX_TEMAC_H
+#define XILINX_TEMAC_H
+
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+
+/* packet size info */
+#define XTE_HDR_SIZE			14      /* size of Ethernet header */
+#define XTE_TRL_SIZE			4       /* size of Ethernet trailer (FCS) */
+#define XTE_JUMBO_MTU			9000
+#define XTE_MAX_JUMBO_FRAME_SIZE	(XTE_JUMBO_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE)
+
+/*  Configuration options */
+
+/*  Accept all incoming packets.
+ *  This option defaults to disabled (cleared) */
+#define XTE_OPTION_PROMISC                      (1 << 0)
+/*  Jumbo frame support for Tx & Rx.
+ *  This option defaults to disabled (cleared) */
+#define XTE_OPTION_JUMBO                        (1 << 1)
+/*  VLAN Rx & Tx frame support.
+ *  This option defaults to disabled (cleared) */
+#define XTE_OPTION_VLAN                         (1 << 2)
+/*  Enable recognition of flow control frames on Rx
+ *  This option defaults to enabled (set) */
+#define XTE_OPTION_FLOW_CONTROL                 (1 << 4)
+/*  Strip FCS and PAD from incoming frames.
+ *  Note: PAD from VLAN frames is not stripped.
+ *  This option defaults to disabled (set) */
+#define XTE_OPTION_FCS_STRIP                    (1 << 5)
+/*  Generate FCS field and add PAD automatically for outgoing frames.
+ *  This option defaults to enabled (set) */
+#define XTE_OPTION_FCS_INSERT                   (1 << 6)
+/*  Enable Length/Type error checking for incoming frames. When this option is
+set, the MAC will filter frames that have a mismatched type/length field
+and if XTE_OPTION_REPORT_RXERR is set, the user is notified when these
+types of frames are encountered. When this option is cleared, the MAC will
+allow these types of frames to be received.
+This option defaults to enabled (set) */
+#define XTE_OPTION_LENTYPE_ERR                  (1 << 7)
+/*  Enable the transmitter.
+ *  This option defaults to enabled (set) */
+#define XTE_OPTION_TXEN                         (1 << 11)
+/*  Enable the receiver
+*   This option defaults to enabled (set) */
+#define XTE_OPTION_RXEN                         (1 << 12)
+
+/*  Default options set when device is initialized or reset */
+#define XTE_OPTION_DEFAULTS                     \
+	(XTE_OPTION_TXEN |                          \
+	 XTE_OPTION_FLOW_CONTROL |                  \
+	 XTE_OPTION_RXEN)
+
+/* XPS_LL_TEMAC SDMA registers definition */
+
+#define TX_NXTDESC_PTR      0x00            /* r */
+#define TX_CURBUF_ADDR      0x01            /* r */
+#define TX_CURBUF_LENGTH    0x02            /* r */
+#define TX_CURDESC_PTR      0x03            /* rw */
+#define TX_TAILDESC_PTR     0x04            /* rw */
+#define TX_CHNL_CTRL        0x05            /* rw */
+/*
+ 0:7      24:31       IRQTimeout
+ 8:15     16:23       IRQCount
+ 16:20    11:15       Reserved
+ 21       10          0
+ 22       9           UseIntOnEnd
+ 23       8           LdIRQCnt
+ 24       7           IRQEn
+ 25:28    3:6         Reserved
+ 29       2           IrqErrEn
+ 30       1           IrqDlyEn
+ 31       0           IrqCoalEn
+*/
+#define CHNL_CTRL_IRQ_IOE       (1 << 9)
+#define CHNL_CTRL_IRQ_EN        (1 << 7)
+#define CHNL_CTRL_IRQ_ERR_EN    (1 << 2)
+#define CHNL_CTRL_IRQ_DLY_EN    (1 << 1)
+#define CHNL_CTRL_IRQ_COAL_EN   (1 << 0)
+#define TX_IRQ_REG          0x06            /* rw */
+/*
+  0:7      24:31       DltTmrValue
+ 8:15     16:23       ClscCntrValue
+ 16:17    14:15       Reserved
+ 18:21    10:13       ClscCnt
+ 22:23    8:9         DlyCnt
+ 24:28    3::7        Reserved
+ 29       2           ErrIrq
+ 30       1           DlyIrq
+ 31       0           CoalIrq
+ */
+#define TX_CHNL_STS         0x07            /* r */
+/*
+   0:9      22:31   Reserved
+ 10       21      TailPErr
+ 11       20      CmpErr
+ 12       19      AddrErr
+ 13       18      NxtPErr
+ 14       17      CurPErr
+ 15       16      BsyWr
+ 16:23    8:15    Reserved
+ 24       7       Error
+ 25       6       IOE
+ 26       5       SOE
+ 27       4       Cmplt
+ 28       3       SOP
+ 29       2       EOP
+ 30       1       EngBusy
+ 31       0       Reserved
+*/
+
+#define RX_NXTDESC_PTR      0x08            /* r */
+#define RX_CURBUF_ADDR      0x09            /* r */
+#define RX_CURBUF_LENGTH    0x0a            /* r */
+#define RX_CURDESC_PTR      0x0b            /* rw */
+#define RX_TAILDESC_PTR     0x0c            /* rw */
+#define RX_CHNL_CTRL        0x0d            /* rw */
+/*
+ 0:7      24:31       IRQTimeout
+ 8:15     16:23       IRQCount
+ 16:20    11:15       Reserved
+ 21       10          0
+ 22       9           UseIntOnEnd
+ 23       8           LdIRQCnt
+ 24       7           IRQEn
+ 25:28    3:6         Reserved
+ 29       2           IrqErrEn
+ 30       1           IrqDlyEn
+ 31       0           IrqCoalEn
+ */
+#define RX_IRQ_REG          0x0e            /* rw */
+#define IRQ_COAL        (1 << 0)
+#define IRQ_DLY         (1 << 1)
+#define IRQ_ERR         (1 << 2)
+#define IRQ_DMAERR      (1 << 7)            /* this is not documented ??? */
+/*
+ 0:7      24:31       DltTmrValue
+ 8:15     16:23       ClscCntrValue
+ 16:17    14:15       Reserved
+ 18:21    10:13       ClscCnt
+ 22:23    8:9         DlyCnt
+ 24:28    3::7        Reserved
+*/
+#define RX_CHNL_STS         0x0f        /* r */
+#define CHNL_STS_ENGBUSY    (1 << 1)
+#define CHNL_STS_EOP        (1 << 2)
+#define CHNL_STS_SOP        (1 << 3)
+#define CHNL_STS_CMPLT      (1 << 4)
+#define CHNL_STS_SOE        (1 << 5)
+#define CHNL_STS_IOE        (1 << 6)
+#define CHNL_STS_ERR        (1 << 7)
+
+#define CHNL_STS_BSYWR      (1 << 16)
+#define CHNL_STS_CURPERR    (1 << 17)
+#define CHNL_STS_NXTPERR    (1 << 18)
+#define CHNL_STS_ADDRERR    (1 << 19)
+#define CHNL_STS_CMPERR     (1 << 20)
+#define CHNL_STS_TAILERR    (1 << 21)
+/*
+ 0:9      22:31   Reserved
+ 10       21      TailPErr
+ 11       20      CmpErr
+ 12       19      AddrErr
+ 13       18      NxtPErr
+ 14       17      CurPErr
+ 15       16      BsyWr
+ 16:23    8:15    Reserved
+ 24       7       Error
+ 25       6       IOE
+ 26       5       SOE
+ 27       4       Cmplt
+ 28       3       SOP
+ 29       2       EOP
+ 30       1       EngBusy
+ 31       0       Reserved
+*/
+
+#define DMA_CONTROL_REG             0x10            /* rw */
+#define DMA_CONTROL_RST                 (1 << 0)
+#define DMA_TAIL_ENABLE                 (1 << 2)
+
+/* XPS_LL_TEMAC direct registers definition */
+
+#define XTE_RAF0_OFFSET              0x00
+#define RAF0_RST                        (1 << 0)
+#define RAF0_MCSTREJ                    (1 << 1)
+#define RAF0_BCSTREJ                    (1 << 2)
+#define XTE_TPF0_OFFSET              0x04
+#define XTE_IFGP0_OFFSET             0x08
+#define XTE_ISR0_OFFSET              0x0c
+#define ISR0_HARDACSCMPLT               (1 << 0)
+#define ISR0_AUTONEG                    (1 << 1)
+#define ISR0_RXCMPLT                    (1 << 2)
+#define ISR0_RXREJ                      (1 << 3)
+#define ISR0_RXFIFOOVR                  (1 << 4)
+#define ISR0_TXCMPLT                    (1 << 5)
+#define ISR0_RXDCMLCK                   (1 << 6)
+
+#define XTE_IPR0_OFFSET              0x10
+#define XTE_IER0_OFFSET              0x14
+
+#define XTE_MSW0_OFFSET              0x20
+#define XTE_LSW0_OFFSET              0x24
+#define XTE_CTL0_OFFSET              0x28
+#define XTE_RDY0_OFFSET              0x2c
+
+#define XTE_RSE_MIIM_RR_MASK      0x0002
+#define XTE_RSE_MIIM_WR_MASK      0x0004
+#define XTE_RSE_CFG_RR_MASK       0x0020
+#define XTE_RSE_CFG_WR_MASK       0x0040
+#define XTE_RDY0_HARD_ACS_RDY_MASK  (0x10000)
+
+/* XPS_LL_TEMAC indirect registers offset definition */
+
+#define	XTE_RXC0_OFFSET			0x00000200 /* Rx configuration word 0 */
+#define	XTE_RXC1_OFFSET			0x00000240 /* Rx configuration word 1 */
+#define XTE_RXC1_RXRST_MASK		(1 << 31)  /* Receiver reset */
+#define XTE_RXC1_RXJMBO_MASK		(1 << 30)  /* Jumbo frame enable */
+#define XTE_RXC1_RXFCS_MASK		(1 << 29)  /* FCS not stripped */
+#define XTE_RXC1_RXEN_MASK		(1 << 28)  /* Receiver enable */
+#define XTE_RXC1_RXVLAN_MASK		(1 << 27)  /* VLAN enable */
+#define XTE_RXC1_RXHD_MASK		(1 << 26)  /* Half duplex */
+#define XTE_RXC1_RXLT_MASK		(1 << 25)  /* Length/type check disable */
+
+#define XTE_TXC_OFFSET			0x00000280 /*  Tx configuration */
+#define XTE_TXC_TXRST_MASK		(1 << 31)  /* Transmitter reset */
+#define XTE_TXC_TXJMBO_MASK		(1 << 30)  /* Jumbo frame enable */
+#define XTE_TXC_TXFCS_MASK		(1 << 29)  /* Generate FCS */
+#define XTE_TXC_TXEN_MASK		(1 << 28)  /* Transmitter enable */
+#define XTE_TXC_TXVLAN_MASK		(1 << 27)  /* VLAN enable */
+#define XTE_TXC_TXHD_MASK		(1 << 26)  /* Half duplex */
+
+#define XTE_FCC_OFFSET			0x000002C0 /* Flow control config */
+#define XTE_FCC_RXFLO_MASK		(1 << 29)  /* Rx flow control enable */
+#define XTE_FCC_TXFLO_MASK		(1 << 30)  /* Tx flow control enable */
+
+#define XTE_EMCFG_OFFSET		0x00000300 /* EMAC configuration */
+#define XTE_EMCFG_LINKSPD_MASK		0xC0000000 /* Link speed */
+#define XTE_EMCFG_HOSTEN_MASK		(1 << 26)  /* Host interface enable */
+#define XTE_EMCFG_LINKSPD_10		0x00000000 /* 10 Mbit LINKSPD_MASK */
+#define XTE_EMCFG_LINKSPD_100		(1 << 30)  /* 100 Mbit LINKSPD_MASK */
+#define XTE_EMCFG_LINKSPD_1000		(1 << 31)  /* 1000 Mbit LINKSPD_MASK */
+
+#define XTE_GMIC_OFFSET			0x00000320 /* RGMII/SGMII config */
+#define XTE_MC_OFFSET			0x00000340 /* MDIO configuration */
+#define XTE_UAW0_OFFSET			0x00000380 /* Unicast address word 0 */
+#define XTE_UAW1_OFFSET			0x00000384 /* Unicast address word 1 */
+
+#define XTE_MAW0_OFFSET			0x00000388 /* Multicast addr word 0 */
+#define XTE_MAW1_OFFSET			0x0000038C /* Multicast addr word 1 */
+#define XTE_AFM_OFFSET			0x00000390 /* Promiscuous mode */
+#define XTE_AFM_EPPRM_MASK		(1 << 31)  /* Promiscuous mode enable */
+
+/* Interrupt Request status */
+#define XTE_TIS_OFFSET			0x000003A0
+#define TIS_FRIS			(1 << 0)
+#define TIS_MRIS			(1 << 1)
+#define TIS_MWIS			(1 << 2)
+#define TIS_ARIS			(1 << 3)
+#define TIS_AWIS			(1 << 4)
+#define TIS_CRIS			(1 << 5)
+#define TIS_CWIS			(1 << 6)
+
+#define XTE_TIE_OFFSET			0x000003A4 /* Interrupt enable */
+
+/**  MII Mamagement Control register (MGTCR) */
+#define XTE_MGTDR_OFFSET		0x000003B0 /* MII data */
+#define XTE_MIIMAI_OFFSET		0x000003B4 /* MII control */
+
+#define CNTLREG_WRITE_ENABLE_MASK   0x8000
+#define CNTLREG_EMAC1SEL_MASK       0x0400
+#define CNTLREG_ADDRESSCODE_MASK    0x03ff
+
+/* CDMAC descriptor status bit definitions */
+
+#define STS_CTRL_APP0_ERR         (1 << 31)
+#define STS_CTRL_APP0_IRQONEND    (1 << 30)
+/* undoccumented */
+#define STS_CTRL_APP0_STOPONEND   (1 << 29)
+#define STS_CTRL_APP0_CMPLT       (1 << 28)
+#define STS_CTRL_APP0_SOP         (1 << 27)
+#define STS_CTRL_APP0_EOP         (1 << 26)
+#define STS_CTRL_APP0_ENGBUSY     (1 << 25)
+/* undocumented */
+#define STS_CTRL_APP0_ENGRST      (1 << 24)
+
+#define TX_CONTROL_CALC_CSUM_MASK   1
+
+#define XTE_ALIGN       32
+#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
+
+#define MULTICAST_CAM_TABLE_NUM 4
+
+/* TX/RX CURDESC_PTR points to first descriptor */
+/* TX/RX TAILDESC_PTR points to last descriptor in linked list */
+
+/**
+ * struct cdmac_bd - LocalLink buffer descriptor format
+ *
+ * app0 bits:
+ *	0    Error
+ *	1    IrqOnEnd    generate an interrupt at completion of DMA  op
+ *	2    reserved
+ *	3    completed   Current descriptor completed
+ *	4    SOP         TX - marks first desc/ RX marks first desct
+ *	5    EOP         TX marks last desc/RX marks last desc
+ *	6    EngBusy     DMA is processing
+ *	7    reserved
+ *	8:31 application specific
+ */
+struct cdmac_bd {
+	u32 next;	/* Physical address of next buffer descriptor */
+	u32 phys;
+	u32 len;
+	u32 app0;
+	u32 app1;	/* TX start << 16 | insert */
+	u32 app2;	/* TX csum */
+	u32 app3;
+	u32 app4;	/* skb for TX length for RX */
+};
+
+struct temac_local {
+	struct net_device *ndev;
+	struct device *dev;
+
+	/* Connection to PHY device */
+	struct phy_device *phy_dev;	/* Pointer to PHY device */
+	struct device_node *phy_node;
+
+	/* MDIO bus data */
+	struct mii_bus *mii_bus;	/* MII bus reference */
+	int mdio_irqs[PHY_MAX_ADDR];	/* IRQs table for MDIO bus */
+
+	/* IO registers and IRQs */
+	void __iomem *regs;
+	dcr_host_t sdma_dcrs;
+	int tx_irq;
+	int rx_irq;
+	int emac_num;
+
+	struct sk_buff **rx_skb;
+	spinlock_t rx_lock;
+	struct mutex indirect_mutex;
+	u32 options;			/* Current options word */
+	int last_link;
+
+	/* Buffer descriptors */
+	struct cdmac_bd *tx_bd_v;
+	dma_addr_t tx_bd_p;
+	struct cdmac_bd *rx_bd_v;
+	dma_addr_t rx_bd_p;
+	int tx_bd_ci;
+	int tx_bd_next;
+	int tx_bd_tail;
+	int rx_bd_ci;
+};
+
+/* xilinx_temac.c */
+u32 temac_ior(struct temac_local *lp, int offset);
+void temac_iow(struct temac_local *lp, int offset, u32 value);
+int temac_indirect_busywait(struct temac_local *lp);
+u32 temac_indirect_in32(struct temac_local *lp, int reg);
+void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
+
+
+/* xilinx_temac_mdio.c */
+int temac_mdio_setup(struct temac_local *lp, struct device_node *np);
+void temac_mdio_teardown(struct temac_local *lp);
+
+#endif /* XILINX_TEMAC_H */
diff --git a/drivers/net/xilinx_temac_mdio.c b/drivers/net/xilinx_temac_mdio.c
new file mode 100644
index 0000000..eeea61b
--- /dev/null
+++ b/drivers/net/xilinx_temac_mdio.c
@@ -0,0 +1,119 @@
+/*
+ * MDIO bus driver for the Xilinx TEMAC device
+ *
+ * Copyright (c) 2009 Secret Lab Technologies, Ltd.
+ */
+
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include "xilinx_temac.h"
+
+/* ---------------------------------------------------------------------
+ * MDIO Bus functions
+ */
+static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct temac_local *lp = bus->priv;
+	u32 rc;
+
+	/* Write the PHY address to the MIIM Access Initiator register.
+	 * When the transfer completes, the PHY register value will appear
+	 * in the LSW0 register */
+	mutex_lock(&lp->indirect_mutex);
+	temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg);
+	rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET);
+	mutex_unlock(&lp->indirect_mutex);
+
+	dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n",
+		phy_id, reg, rc);
+
+	return rc;
+}
+
+static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+	struct temac_local *lp = bus->priv;
+
+	dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
+		phy_id, reg, val);
+
+	/* First write the desired value into the write data register
+	 * and then write the address into the access initiator register
+	 */
+	mutex_lock(&lp->indirect_mutex);
+	temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val);
+	temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
+	mutex_unlock(&lp->indirect_mutex);
+
+	return 0;
+}
+
+int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
+{
+	struct mii_bus *bus;
+	const u32 *bus_hz;
+	int clk_div;
+	int rc, size;
+	struct resource res;
+
+	/* Calculate a reasonable divisor for the clock rate */
+	clk_div = 0x3f; /* worst-case default setting */
+	bus_hz = of_get_property(np, "clock-frequency", &size);
+	if (bus_hz && size >= sizeof(*bus_hz)) {
+		clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1;
+		if (clk_div < 1)
+			clk_div = 1;
+		if (clk_div > 0x3f)
+			clk_div = 0x3f;
+	}
+
+	/* Enable the MDIO bus by asserting the enable bit and writing
+	 * in the clock config */
+	mutex_lock(&lp->indirect_mutex);
+	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
+	mutex_unlock(&lp->indirect_mutex);
+
+	bus = mdiobus_alloc();
+	if (!bus)
+		return -ENOMEM;
+
+	of_address_to_resource(np, 0, &res);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+		 (unsigned long long)res.start);
+	bus->priv = lp;
+	bus->name = "Xilinx TEMAC MDIO";
+	bus->read = temac_mdio_read;
+	bus->write = temac_mdio_write;
+	bus->parent = lp->dev;
+	bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
+
+	lp->mii_bus = bus;
+
+	rc = of_mdiobus_register(bus, np);
+	if (rc)
+		goto err_register;
+
+	mutex_lock(&lp->indirect_mutex);
+	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
+		temac_indirect_in32(lp, XTE_MC_OFFSET));
+	mutex_unlock(&lp->indirect_mutex);
+	return 0;
+
+ err_register:
+	mdiobus_free(bus);
+	return rc;
+}
+
+void temac_mdio_teardown(struct temac_local *lp)
+{
+	mdiobus_unregister(lp->mii_bus);
+	kfree(lp->mii_bus->irq);
+	mdiobus_free(lp->mii_bus);
+	lp->mii_bus = NULL;
+}
+

^ permalink raw reply related

* Re: [PATCH] ucc_geth: Rework the TX logic.
From: Joakim Tjernlund @ 2009-03-31  9:07 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Li Yang, pku.leo, netdev
In-Reply-To: <49D11E47.8080106@freescale.com>

Scott Wood <scottwood@freescale.com> wrote on 30/03/2009 21:32:23:
> 
> Joakim Tjernlund wrote:
> >> different since descriptors are in MURAM which is ioremap()ed -- 
though 
> >> switching to a cacheable mapping with barriers should be a 
performance 
> >> improvement.
> > 
> > I always thought that MURAM was very fast. The whole reason to have 
BDs in
> > MURAM is that it is faster than normal RAM, at least that is what I 
> > thought.
> 
> Yeah, on second thought it probably wouldn't be worth it.  There's also 
> the question of under what circumstances the QE's MURAM accesses will be 

> cache-coherent.

I am a bit confused, what isn't worth it? Currently MURAM isn't used by 
ucc_geth, but
it is easy to change. Swap MEM_PART_SYSTEM to MEM_PART_MURAM, however, 
just
tried that and the driver stopped working. I known this worked earlier 
because
I tried it and I even think I sent a patch to Leo.

What choices do we have, I see three:

1) MEM_PART_SYSTEM, as today.
2) MEM_PART_MURAM. I guess this should be uncacheable memory?
3) as gianfar, dma_alloc_coherent(). I presume this is uncacheable memory?

My guess would be 2 or 3. Do they have the same synchronization
sematics?

> 
> As for the CPU not reordering guarded+cache inhibited accesses, that 
> initially seemed to be true for the new arch stuff (book3e/book3s, but 
> not really, see below), but the classic arch documentation only 
> guarantees stores to such regions to be in-order (and the 
> explicitly-specified operation of eieio on I+G accesses wouldn't make 
> much sense if they were already guaranteed to be in-order).
> 
> Then I looked at the EREF to see what older book E documents had to say 
> on the issue, and it suggests that when the architecture document says 
> "out of order", it really means "speculative" (and reading the arch 
> doc's definition of "out of order" seems to confirm this -- redefining 
> terms is bad, m'kay?).  So it seems that the simple answer is no, 
> guarded storage is not guaranteed to be in order, unless the only thing 
> that can cause an out-of-order access is speculative execution.

Very informative, thanks.

^ permalink raw reply

* [ppc64] 2.6.29-git7 : offlining a cpu causes an exception
From: Sachin Sant @ 2009-03-31  9:27 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt

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

While executing CPU HotPlug[1] tests i observed that during
every cpu offline process an exception is thrown.

cpu 0x2: Vector: 700 (Program Check) at [c0000000074c7ca0]
    pc: 00000000007b6640
    lr: 000000000079ddc0
    sp: c0000000074c7f20
   msr: 8000000000081002
  current = 0xc0000000fe1c8580
  paca    = 0xc000000000ab2800
    pid   = 0, comm = swapper
2:mon> r
R00 = 0000000000000000   R16 = 0000000000000002
R01 = c0000000074c7f20   R17 = 0000000000000000
R02 = 00000000009e8dc0   R18 = 0000000000000000
R03 = 0000000000008278   R19 = 0000000000000000
R04 = 0000000000008000   R20 = 0000000000000000
R05 = 0000000000000002   R21 = 0000000000000000
R06 = 0000000000000002   R22 = c000000000b33ae0
R07 = 0000000000000000   R23 = 0000000000000000
R08 = 0000000000000000   R24 = 0000000000000002
R09 = 00000000000082fc   R25 = 0000000000000000
R10 = 0000000000000000   R26 = 0000000000000004
R11 = a000000000001002   R27 = c000000000a95bd8
R12 = a000000000000000   R28 = 0000000000000008
R13 = c000000000ab2800   R29 = ffffffffffffffff
R14 = 0000000000000000   R30 = c00000000095e750
R15 = 0000000007531868   R31 = 0000000007d70b20
pc  = 00000000007b6640
lr  = 000000000079ddc0
msr = 8000000000081002   cr  = 22000004
ctr = 0000000000000000   xer = 0000000000000020   trap =  700
2:mon> u
SLB contents of cpu 2
00 c000000008000000 40004f7ca3000500  1T  ESID=   c00000  VSID=       4f7ca3 LLP:100
01 d000000008000000 4000eb71b0000510  1T  ESID=   d00000  VSID=       eb71b0 LLP:110
24 0000000008000000 0000000000000c80 256M ESID=        0  VSID=            0 LLP:  0
2:mon>

I can recreate this problem very easily on power5
as well as power6 box.

2.6.29-git6 did not have this problem. Let me know if there
is any other information i can provide. I have attached the
dmesg log here.

Thanks
-Sachin

[1] -> CPU Hotplug test which is part of LTP.

-- 

---------------------------------
Sachin Sant
IBM Linux Technology Center
India Systems and Technology Labs
Bangalore, India
---------------------------------


[-- Attachment #2: dmesg_cpu_hotplug --]
[-- Type: text/plain, Size: 9380 bytes --]


<6>Phyp-dump disabled at boot time.
<6>Using pSeries machine description.
<7>Page orders: linear mapping = 24, virtual = 16, io = 12.
<6>Using 1TB segments.
<4>Found initrd at 0xc0000000034d0000:0xc000000003c7f14f.
<6>console [udbg0] enabled.
<6>Partition configured for 4 cpus..
<6>CPU maps initialized for 2 threads per core.
<7> (thread shift is 1).
<4>Starting Linux PPC64 #3 SMP Tue Mar 31 14:33:34 IST 2009.
<4>-----------------------------------------------------.
<4>ppc64_pft_size                = 0x1a.
<4>physicalMemorySize            = 0x100000000.
<4>htab_hash_mask                = 0x7ffff.
<4>-----------------------------------------------------.
<6>Initializing cgroup subsys cpuset.
<6>Initializing cgroup subsys cpu.
<5>Linux version 2.6.29-git7 (root@llm62) (gcc version 4.3.2 [gcc-4_3-branch revision 141291] (SUSE Linux) ) #3 SMP Tue Mar 31 14:33:34 IST 2009.
<4>[boot]0012 Setup Arch.
<7>Node 0 Memory: 0x0-0x100000000.
<4>EEH: No capable adapters found.
<6>PPC64 nvram contains 15360 bytes.
<7>Using shared processor idle loop.
<4>Zone PFN ranges:.
<4>  DMA      0x00000000 -> 0x00010000.
<4>  Normal   0x00010000 -> 0x00010000.
<4>Movable zone start PFN for each node.
<4>early_node_map[1] active PFN ranges.
<4>    0: 0x00000000 -> 0x00010000.
<7>On node 0 totalpages: 65536.
<7>  DMA zone: 56 pages used for memmap.
<7>  DMA zone: 0 pages reserved.
<7>  DMA zone: 65480 pages, LIFO batch:1.
<4>[boot]0015 Setup Done.
<4>Built 1 zonelists in Node order, mobility grouping on.  Total pages: 65480.
<4>Policy zone: DMA.
<5>Kernel command line: root=/dev/sda5 sysrq=1 insmod=sym53c8xx insmod=ipr crashkernel=512M-:256M  .
<6>NR_IRQS:512.
<4>[boot]0020 XICS Init.
<4>[boot]0021 XICS Done.
<7>pic: no ISA interrupt controller.
<4>PID hash table entries: 4096 (order: 12, 32768 bytes).
<7>time_init: decrementer frequency = 512.000000 MHz.
<7>time_init: processor frequency   = 4704.000000 MHz.
<6>clocksource: timebase mult[7d0000] shift[22] registered.
<7>clockevent: decrementer mult[8312] shift[16] cpu[0].
<4>Console: colour dummy device 80x25.
<6>console handover: boot [udbg0] -> real [hvc0].
<6>Dentry cache hash table entries: 524288 (order: 6, 4194304 bytes).
<6>Inode-cache hash table entries: 262144 (order: 5, 2097152 bytes).
<6>allocated 2621440 bytes of page_cgroup.
<6>please try cgroup_disable=memory option if you don't want.
<4>freeing bootmem node 0.
<6>Memory: 4119872k/4194304k available (8192k kernel code, 74432k reserved, 1984k data, 4194k bss, 448k init).
<6>Calibrating delay loop... 1022.36 BogoMIPS (lpj=5111808).
<6>Security Framework initialized.
<6>SELinux:  Disabled at boot..
<4>Mount-cache hash table entries: 4096.
<6>Initializing cgroup subsys debug.
<6>Initializing cgroup subsys ns.
<6>Initializing cgroup subsys cpuacct.
<6>Initializing cgroup subsys memory.
<6>Initializing cgroup subsys devices.
<6>Initializing cgroup subsys freezer.
<7>clockevent: decrementer mult[8312] shift[16] cpu[1].
<4>Processor 1 found..
<7>clockevent: decrementer mult[8312] shift[16] cpu[2].
<4>Processor 2 found..
<7>clockevent: decrementer mult[8312] shift[16] cpu[3].
<4>Processor 3 found..
<6>Brought up 4 CPUs.
<7>Node 0 CPUs: 0-3.
<7>CPU0 attaching sched-domain:.
<7> domain 0: span 0-1 level SIBLING.
<7>  groups: 0 1.
<7>  domain 1: span 0-3 level CPU.
<7>   groups: 0-1 2-3.
<7>   domain 2: span 0-3 level NODE.
<7>    groups: 0-3.
<7>CPU1 attaching sched-domain:.
<7> domain 0: span 0-1 level SIBLING.
<7>  groups: 1 0.
<7>  domain 1: span 0-3 level CPU.
<7>   groups: 0-1 2-3.
<7>   domain 2: span 0-3 level NODE.
<7>    groups: 0-3.
<7>CPU2 attaching sched-domain:.
<7> domain 0: span 2-3 level SIBLING.
<7>  groups: 2 3.
<7>  domain 1: span 0-3 level CPU.
<7>   groups: 2-3 0-1.
<7>   domain 2: span 0-3 level NODE.
<7>    groups: 0-3.
<7>CPU3 attaching sched-domain:.
<7> domain 0: span 2-3 level SIBLING.
<7>  groups: 3 2.
<7>  domain 1: span 0-3 level CPU.
<7>   groups: 2-3 0-1.
<7>   domain 2: span 0-3 level NODE.
<7>    groups: 0-3.
<6>net_namespace: 1888 bytes.
<6>NET: Registered protocol family 16.
<6>IBM eBus Device Driver.
<6>PCI: Probing PCI hardware.
<7>PCI: Probing PCI hardware done.
<4>bio: create slab 
<bio-0> at 0.
<6>usbcore: registered new interface driver usbfs.
<6>usbcore: registered new interface driver hub.
<6>usbcore: registered new device driver usb.
<6>NET: Registered protocol family 2.
<7>Switched to high resolution mode on CPU 0.
<7>Switched to high resolution mode on CPU 1.
<7>Switched to high resolution mode on CPU 2.
<7>Switched to high resolution mode on CPU 3.
<6>IP route cache hash table entries: 32768 (order: 2, 262144 bytes).
<6>TCP established hash table entries: 131072 (order: 5, 2097152 bytes).
<6>TCP bind hash table entries: 65536 (order: 4, 1048576 bytes).
<6>TCP: Hash tables configured (established 131072 bind 65536).
<6>TCP reno registered.
<6>NET: Registered protocol family 1.
<6>Unpacking initramfs... done.
<4>Freeing initrd memory: 7868k freed.
<6>IOMMU table initialized, virtual merging enabled.
<7>RTAS daemon started.
<6>audit: initializing netlink socket (disabled).
<5>type=2000 audit(1238490478.637:1): initialized.
<6>Kprobe smoke test started.
<6>Kprobe smoke test passed successfully.
<6>HugeTLB registered 16 MB page size, pre-allocated 0 pages.
<6>HugeTLB registered 16 GB page size, pre-allocated 0 pages.
<5>VFS: Disk quotas dquot_6.5.2.
<4>Dquot-cache hash table entries: 8192 (order 0, 65536 bytes).
<6>msgmni has been set to 8060.
<6>alg: No test for stdrng (krng).
<6>Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254).
<6>io scheduler noop registered.
<6>io scheduler anticipatory registered.
<6>io scheduler deadline registered.
<6>io scheduler cfq registered (default).
<6>pci_hotplug: PCI Hot Plug PCI Core version: 0.5.
<6>rpaphp: RPA HOT Plug PCI Controller Driver version: 0.1.
<7>vio_register_driver: driver hvc_console registering.
<7>HVSI: registered 0 devices.
<6>Generic RTC Driver v1.07.
<6>Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled.
<6>pmac_zilog: 0.6 (Benjamin Herrenschmidt 
<benh@kernel.crashing.org>).
<6>input: Macintosh mouse button emulation as /devices/virtual/input/input0.
<6>Uniform Multi-Platform E-IDE driver.
<6>ide-gd driver 1.18.
<6>IBM eHEA ethernet device driver (Release EHEA_0100).
<6>ehea: eth0: Jumbo frames are disabled.
<6>ehea: eth0 -> logical port id #2.
<6>ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver.
<6>ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver.
<6>mice: PS/2 mouse device common for all mice.
<6>EDAC MC: Ver: 2.1.0 Mar 31 2009.
<6>usbcore: registered new interface driver hiddev.
<6>usbcore: registered new interface driver usbhid.
<6>usbhid: v2.6:USB HID core driver.
<6>TCP cubic registered.
<6>NET: Registered protocol family 15.
<4>registered taskstats version 1.
<4>Freeing unused kernel memory: 448k freed.
<6>SysRq : Changing Loglevel.
<4>Loglevel set to 1.
<5>SCSI subsystem initialized.
<7>vio_register_driver: driver ibmvscsi registering.
<6>ibmvscsi 30000002: SRP_VERSION: 16.a.
<6>scsi0 : IBM POWER Virtual SCSI Adapter 1.5.8.
<6>ibmvscsi 30000002: partner initialization complete.
<6>ibmvscsi 30000002: sent SRP login.
<6>ibmvscsi 30000002: SRP_LOGIN succeeded.
<6>ibmvscsi 30000002: host srp version: 16.a, host partition VIO (1), OS 3, max io 1048576.
<5>scsi 0:0:1:0: Direct-Access     AIX      VDASD            0001 PQ: 0 ANSI: 3.
<6>udevd version 128 started.
<4>Driver 'sd' needs updating - please use bus_type methods.
<5>sd 0:0:1:0: [sda] 167772160 512-byte hardware sectors: (85.8 GB/80.0 GiB).
<5>sd 0:0:1:0: [sda] Write Protect is off.
<7>sd 0:0:1:0: [sda] Mode Sense: 17 00 00 08.
<5>sd 0:0:1:0: [sda] Cache data unavailable.
<3>sd 0:0:1:0: [sda] Assuming drive cache: write through.
<5>sd 0:0:1:0: [sda] Cache data unavailable.
<3>sd 0:0:1:0: [sda] Assuming drive cache: write through.
<6> sda: sda1 sda2 
< sda5 > sda3 sda4.
<5>sd 0:0:1:0: [sda] Attached SCSI disk.
<6>kjournald starting.  Commit interval 5 seconds.
<6>EXT3 FS on sda5, internal journal.
<6>EXT3-fs: mounted filesystem with ordered data mode..
<6>udevd version 128 started.
<5>sd 0:0:1:0: Attached scsi generic sg0 type 0.
<6>Adding 1044096k swap on /dev/sda3.  Priority:-1 extents:1 across:1044096k .
<6>device-mapper: uevent: version 1.0.3.
<6>device-mapper: ioctl: 4.14.0-ioctl (2008-04-23) initialised: dm-devel@redhat.com.
<6>loop: module loaded.
<6>fuse init (API version 7.11).
<6>ehea: eth0: Physical port up.
<6>ehea: External switch port is backup port.
<6>NET: Registered protocol family 10.
<6>lo: Disabled Privacy Extensions.
<7>eth0: no IPv6 routers present.
<4>cpu 2 (hwid 2) Ready to die....
<7>CPU0 attaching NULL sched-domain..
<7>CPU1 attaching NULL sched-domain..
<7>CPU2 attaching NULL sched-domain..
<7>CPU3 attaching NULL sched-domain..
<7>CPU0 attaching sched-domain:.
<7> domain 0: span 0-1 level SIBLING.
<7>  groups: 0 1.
<7>  domain 1: span 0-1,3 level CPU.
<7>   groups: 0-1 3.
<7>   domain 2: span 0-1,3 level NODE.
<7>    groups: 0-1,3.
<7>CPU1 attaching sched-domain:.
<7> domain 0: span 0-1 level SIBLING.
<7>  groups: 1 0.
<7>  domain 1: span 0-1,3 level CPU.
<7>   groups: 0-1 3.
<7>   domain 2: span 0-1,3 level NODE.
<7>    groups: 0-1,3.
<7>CPU3 attaching sched-domain:.
<7> domain 0: span 0-1,3 level CPU.
<7>  groups: 3 0-1.
<7>  domain 1: span 0-1,3 level NODE.
<7>   groups: 0-1,3.....................

^ permalink raw reply

* Re: powerpc/85xx: Add support for the "socrates" board (MPC8544)
From: Wolfgang Grandegger @ 2009-03-31  9:35 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40903192205yed7eb13t45db80a201549f0d@mail.gmail.com>

Grant Likely wrote:
> I agree 100% with David's comments, and I have some additional ones below.
> 
> On Thu, Mar 19, 2009 at 9:26 AM, Wolfgang Grandegger <wg@grandegger.com> wrote:
>> +       soc8544@e0000000 {
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               device_type = "soc";
> 
> Drop device_type here too.

Grrr, I just realized that removing the devices type "soc" has broken
fsl_get_sys_freq(). See:

http://lxr.linux.no/linux+v2.6.29/arch/powerpc/sysdev/fsl_soc.c#L80

We need a quick fix and we could take the occasion to establish a common
function for the MPC52xx as well, but it's not obvious to me how to find
the SOC node without the device type property.

Wolfgang.

^ permalink raw reply

* Re: [PATCH] linux-next remove wmb() from ide-dma-sff.c and scc_pata.c
From: KOBAYASHI Yoshitake @ 2009-03-31  9:33 UTC (permalink / raw)
  To: Geert Uytterhoeven, IDE/ATA Devel
  Cc: Linux/MIPS Development, Bartlomiej Zolnierkiewicz, Atsushi Nemoto,
	Linux/PPC Development, Grant Grundler, LKML
In-Reply-To: <alpine.LRH.2.00.0903310950040.9551@vixen.sonytel.be>

2009/03/31 16:51, Geert Uytterhoeven wrote:
> On Mon, 30 Mar 2009, Grant Grundler wrote:
>> Followup to "[PATCH 03/10] ide: destroy DMA mappings after ending DMA"
>> email on March 14th:
>>     http://lkml.org/lkml/2009/3/14/17
>>
>> No maintainer is listed for "Toshiba CELL Reference Set IDE" (BLK_DEV_CELLEB)
>> or tx4939ide.c in MAINTAINERS. I've CC'd "Ishizaki Kou" @Toshiba (Maintainer for
>> "Spidernet Network Driver for CELL") and linuxppc-dev list in the hope
>> someone else
>> would know or would be able to ACK this patch.
> 
> tx49xx is MIPS, for Nemoto-san.

The patch looks good for Toshiba Cell Reference Set.
I think the patch will be acked by IDE maintainer.

Thank you for informing me of the contribution.

Regards,

-- Yoshi

^ permalink raw reply

* configuring the DMA for using the SCPLC on the MPC5121
From: Jacquemin, Jean-Philippe @ 2009-03-31  9:39 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Loridon, Martin

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

Dear all,
 
I am trying to configure the MPC5121 to perform DMA transfers from the
CPU RAM to the RAM of an FPGA attached on ChipSelect 2.
I have to use the LocalPlus Bus and configure the chipselect2 for bust
mode and non-multiplexed.
I also have to configure a DMA task to copy the content of my buffer to
the local bus Fifo and then kick this content to the wanted address on
chipselect 2.
 
I have some code (thanks to Grant Likely) to implement a LocalPlus Bus
Fifo driver (SCPLC) but have no clue how to configure the DMA for using
the SCPLC... Can someone help me??
 
The 5121 fifo is directly derived from the 5200 fifo, only it is :
* deeper (1024bytes instead of 512), 
* up to 56 bytes can be transfered with one transaction
* increased SCPLC packet size register to 31 bits
 
 
best regards,
 
Jean-Philippe Jacquemin
 


DISCLAIMER:
Unless indicated otherwise, the information contained in this message is privileged and confidential, and is intended only for the use of the addressee(s) named above and others who have been specifically authorized to receive it. If you are not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this message and/or attachments is strictly prohibited. The company accepts no liability for any damage caused by any virus transmitted by this email. Furthermore, the company does not warrant a proper and complete transmission of this information, nor does it accept liability for any delays. If you have received this message in error, please contact the sender and delete the message. Thank you.

[-- Attachment #2: Type: text/html, Size: 3523 bytes --]

^ 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