[U-Boot] [PATCH] ftgmac100: support of gigabit eth ftgmac100

Wolfgang Denk wd at denx.de
Sun Dec 12 22:13:55 CET 2010


Dear Macpaul Lin,

In message <1291969229-3884-1-git-send-email-macpaul at andestech.com> you wrote:
> Add Faraday's ftgmac100 (gigabit ethernet)
> MAC controller's driver.
> 
> Sub configuration in this driver:
> 
> CONFIG_FTGMAC100_EGIGA:
>   Support GE link update with gigabit PHY.

This needs to be documented in the README.

> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index b605eea..faeab32 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -48,6 +48,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
>  COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
>  COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
>  COBJS-$(CONFIG_FTMAC100) += ftmac100.o
> +COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
>  COBJS-$(CONFIG_GRETH) += greth.o
>  COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
>  COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o

Please keep list sorted.

> diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
> new file mode 100644
> index 0000000..7616fcd
> --- /dev/null
> +++ b/drivers/net/ftgmac100.c
> @@ -0,0 +1,598 @@
...

> +struct ftgmac100_data {
> +	volatile struct ftgmac100_txdes txdes[PKTBUFSTX];	/* must be power of 2 */
> +	volatile struct ftgmac100_rxdes rxdes[PKTBUFSRX];	/* must be power of 2 */

Please re-read Documentation/volatile-considered-harmful.txt and then
explain why this volatile here is needed.

...
> +	for (i = 0; i < 10; i++) {
> +		phycr = readl(&ftgmac100->phycr);
> +
> +		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
> +			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: phy_addr: %x\n", phy_addr);

Line too long.  Please fix globally (consider running checkpatch.pl).

> +static int ftgmac100_mdiobus_reset(struct eth_device *dev)
> +{
> +	return 0;
> +}

Why do we need this function?

> +int ftgmac100_phy_read(struct eth_device *dev, int addr,
> +		int reg, u16 *value)
> +{
> +	*value = ftgmac100_mdiobus_read(dev , addr, reg);
> +	return 0;
> +}

Error handling missing.

> +int  ftgmac100_phy_write(struct eth_device *dev, int addr,
> +		int reg, u16 value)
> +{
> +	ftgmac100_mdiobus_write(dev, addr, reg, value);
> +	return 0;
> +}

Error handling missing.  Please check and fix globally.


> +static int ftgmac100_phy_reset(struct eth_device *dev)
> +{
...
> +	for (i = 0; i < 100000 / 100; i++) {
> +		ftgmac100_phy_read(dev, priv->phy_addr,
> +			MII_BMSR, &status);
> +		if (status & BMSR_ANEGCOMPLETE)
> +			break;
> +		udelay(100);

Are you sure that autonegotiation will always complete within 100
milliseconds or less?

> +	/* Check if the PHY is up to snuff... */
> +
> +	for (phy_addr=0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
> +		ftgmac100_phy_read(dev, phy_addr,
> +			MII_PHYSID1, &phy_id);

See note above about error handling.  You need to reqork all your
code.

> +		/* When it is unable to found PHY, the interface usually return 0xffff or 0x0000 */

Ditto for line too long.


> +		for (i = 0; i < 100000 / 100; i++) {
> +			ftgmac100_phy_read(dev, priv->phy_addr,
> +				MII_BMSR, &status);
> +			if (status & BMSR_LSTATUS)
> +				break;
> +			udelay(100);

See note above - are 100 milliseconds always sufficient?

> +	}
> +	if (!(status & BMSR_LSTATUS)) {
> +		printf("%s: link down\n", dev->name);
> +		return 3;
> +	} else {

No "else" needed after a "return".

> +#ifdef CONFIG_FTGMAC100_EGIGA
> +		ftgmac100_phy_read(dev, priv->phy_addr,
> +			MII_STAT1000, &stat_ge);	/* 1000 Base-T Status Register */
> +
> +		speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
> +			 ? 1 : 0);
> +
> +		duplex = ((stat_ge & LPA_1000FULL)
> +			 ? 1 : 0);
> +
> +		if (speed) { /* Speed is 1000 */
> +			printf("%s: link up, %sMbps %s-duplex\n",
> +				dev->name,
> +				speed ? "1000" : "10/100",

This makes no sense. You tested "speed" 4 lines above, so we know
it's always true.

> +				duplex ? "full" : "half");
> +			return 0;
> +		}
> +#endif
> +
> +		ftgmac100_phy_read(dev, priv->phy_addr,
> +			MII_ADVERTISE, &adv);
> +		ftgmac100_phy_read(dev, priv->phy_addr,
> +			MII_LPA, &lpa);
> +		media = mii_nway_result(lpa & adv);
> +		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
> +			 ? 1 : 0);
> +		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
> +		printf("%s: link up, %sMbps %s-duplex\n",
> +		       dev->name,
> +		       speed ? "100" : "10",
> +		       duplex ? "full" : "half");
> +	}
> +	return 0;
> +}
> +
> +int ftgmac100_update_link_speed(struct eth_device *dev)
> +{
> +	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
> +	struct ftgmac100_data *priv = dev->priv;
> +
> +	unsigned short stat_fe;
> +	unsigned short stat_ge;
> +
> +#ifdef CONFIG_FTGMAC100_EGIGA
> +	ftgmac100_phy_read(dev, priv->phy_addr,
> +		MII_STAT1000, &stat_ge);	/* 1000 Base-T Status Register */
> +#endif
> +
> +	ftgmac100_phy_read(dev, priv->phy_addr,
> +		MII_BMSR, &stat_fe);
> +
> +	if (!(stat_fe & BMSR_LSTATUS))	/* link status up? */
> +		return 1;
> +
> +#ifdef CONFIG_FTGMAC100_EGIGA
> +	if (stat_ge & LPA_1000FULL) {
> +		/*set Emac for 1000BaseTX and Full Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
> +			) | FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP,
> +			&ftgmac100->maccr);
> +		return 0;
> +	}
> +
> +	if (stat_ge & LPA_1000HALF) {
> +		/*set Emac for 1000BaseTX and Half Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
> +			) | FTGMAC100_MACCR_GIGA_MODE,
> +			&ftgmac100->maccr);
> +		return 0;
> +	}
> +#endif
> +
> +	if (stat_fe & BMSR_100FULL) {
> +		/*set Emac for 100BaseTX and Full Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
> +			) | FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP,
> +			&ftgmac100->maccr);
> +		return 0;
> +	}
> +
> +	if (stat_fe & BMSR_10FULL) {
> +		/*set MII for 10BaseT and Full Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
> +			) | FTGMAC100_MACCR_FULLDUP,
> +			&ftgmac100->maccr);
> +		return 0;
> +	}
> +
> +	if (stat_fe & BMSR_100HALF) {
> +		/*set MII for 100BaseTX and Half Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
> +			) | FTGMAC100_MACCR_FAST_MODE,
> +			&ftgmac100->maccr);
> +		return 0;
> +	}
> +
> +	if (stat_fe & BMSR_10HALF) {
> +		/*set MII for 10BaseT and Half Duplex  */
> +		writel((readl(&ftgmac100->maccr) &
> +			~(FTGMAC100_MACCR_GIGA_MODE |
> +			  FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)),
> +			&ftgmac100->maccr);
> +		return 0;

Instead of repeating this code fragment again and again, can you not
make the code data driven, i. e. use a table to look up the mask?

> +	/* pass the packet up to the protocol layers. */
> +
> +	NetReceive ((void *)curr_des->rxdes3, rxlen);
> +
> +	/* release buffer to DMA */
> +
> +	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;

Please remove the blank lines between these on-line comments and the
code.  Please do globally.

> +ftgmac100_send (struct eth_device *dev, volatile void *packet, int length)
> +{
> +	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
> +	struct ftgmac100_data *priv = dev->priv;
> +	volatile struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];

Please explain why this volatile is needed.


> +	tmo = get_timer (0) + 5 * CONFIG_SYS_HZ;
> +	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
> +		if (get_timer (0) >= tmo) {

This is bound to fail when the timer wraps around.

> +#define FTGMAC100_OFFSET_ISR		0x00
> +#define FTGMAC100_OFFSET_IER		0x04
> +#define FTGMAC100_OFFSET_MAC_MADR	0x08
> +#define FTGMAC100_OFFSET_MAC_LADR	0x0c
> +#define FTGMAC100_OFFSET_MAHT0		0x10
> +#define FTGMAC100_OFFSET_MAHT1		0x14
> +#define FTGMAC100_OFFSET_NPTXPD		0x18
> +#define FTGMAC100_OFFSET_RXPD		0x1c
> +#define FTGMAC100_OFFSET_NPTXR_BADR	0x20
> +#define FTGMAC100_OFFSET_RXR_BADR	0x24
> +#define FTGMAC100_OFFSET_HPTXPD		0x28
> +#define FTGMAC100_OFFSET_HPTXR_BADR	0x2c
...

Ouch.

> +struct ftgmac100 {
> +	unsigned int	isr;		/* 0x00 */
> +	unsigned int	ier;		/* 0x04 */
> +	unsigned int	mac_madr;	/* 0x08 */
> +	unsigned int	mac_ladr;	/* 0x0c */
> +	unsigned int	maht0;		/* 0x10 */
> +	unsigned int	maht1;		/* 0x14 */
> +	unsigned int	txpd;		/* 0x18 */
> +	unsigned int	rxpd;		/* 0x1c */
> +	unsigned int	txr_badr;	/* 0x20 */
> +	unsigned int	rxr_badr;	/* 0x24 */
> +	unsigned int	hptxpd;		/* 0x28 */
> +	unsigned int	hptxpd_badr;	/* 0x2c */

Um.... We don't need both offset tables and C structs, do we?

Please dump the offset table.


> --- a/include/netdev.h
> +++ b/include/netdev.h
> @@ -62,6 +62,7 @@ int eth_3com_initialize (bd_t * bis);
>  int fec_initialize (bd_t *bis);
>  int fecmxc_initialize (bd_t *bis);
>  int ftmac100_initialize(bd_t *bits);
> +int ftgmac100_initialize(bd_t *bits);
>  int greth_initialize(bd_t *bis);
>  void gt6426x_eth_initialize(bd_t *bis);
>  int inca_switch_initialize(bd_t *bis);

Please keep  list sorted.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"Have you lived in this village all your life?"        "No, not yet."


More information about the U-Boot mailing list