Skip to contentSkip to conversation

net: Adds Fast Ethernet Controller driver for Armada100

PATCH Superseded Ajay Bhargav 3 participants 5 messages Aug 30, 2011 – Aug 31, 2011

Subsystems (2)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/3 net: Adds Fast Ethernet Controller driver for Armada100

This patch adds support for Fast Ethernet Controller driver for Armada100 series.

---
Changes for v2:
- removed random MAC generation
- driver init function changed to register as per new naming convention
- code cleanup (Thanks to Wolfgang, Marek & Mike for tips)
Changes for v3:
- code cleanup
Changes for v4:
- Debug and Error messages updated
- base_addr param for armada100_fec_register changed to unsigned long

 arch/arm/include/asm/arch-armada100/armada100.h |    1 +
 drivers/net/Makefile                            |    1 +
 drivers/net/armada100_fec.c                     |  762 +++++++++++++++++++++++
 drivers/net/armada100_fec.h                     |  232 +++++++
 include/netdev.h                                |    1 +
 5 files changed, 997 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/armada100_fec.c
 create mode 100644 drivers/net/armada100_fec.h
arch/arm/include/asm/arch-armada100/armada100.h +1 -0
index d5d125a..3d567eb 100644
@@ -59,6 +59,7 @@
 #define ARMD1_MPMU_BASE		0xD4050000
 #define ARMD1_APMU_BASE		0xD4282800
 #define ARMD1_CPU_BASE		0xD4282C00
+#define ARMD1_FEC_BASE		0xC0800000
 
 /*
  * Main Power Management (MPMU) Registers
drivers/net/Makefile +1 -0
index 819b197..34b4322 100644
@@ -28,6 +28,7 @@ LIB	:= $(obj)libnet.o
 COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o
 COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
 COBJS-$(CONFIG_ALTERA_TSE) += altera_tse.o
+COBJS-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
 COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
 COBJS-$(CONFIG_BCM570x) += bcm570x.o
drivers/net/armada100_fec.c new file +762 -0

762 lines not on this page · raw message

drivers/net/armada100_fec.h new file +232 -0

232 lines not on this page · raw message

include/netdev.h +1 -0
index 6f0a971..2ec1e04 100644
@@ -94,6 +94,7 @@ int xilinx_emaclite_initialize (bd_t *bis, int base_addr);
 int sh_eth_initialize(bd_t *bis);
 int dm9000_initialize(bd_t *bis);
 int fecmxc_initialize(bd_t *bis);
+int armada100_fec_register(unsigned long base_addr);
 
 /* Boards with PCI network controllers can call this from their board_eth_init()
  * function to initialize whatever's on board.
Signature · 1 line
1.7.0.4
#1 lore raw

PATCH v4 1/3 net: Adds Fast Ethernet Controller driver for Armada100

Quoted 4 lines · Ajay Bhargav

This patch adds support for Fast Ethernet Controller driver for Armada100 series.

[...]

drivers/net/armada100_fec.c line 85

Quoted 10 lines
drivers/net/armada100_fec.c new file +10 -0
+static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
+			u16 *value)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct armdfec_device *darmdfec = to_darmdfec(dev);
+	struct armdfec_reg *regs = darmdfec->regs;
+	u32 val, reg_data;
+
+	if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
+		reg_data = readl(&regs->phyadr);

You use "reg_data" here and "val" below ... can't you use just one variable?

Quoted 36 lines
drivers/net/armada100_fec.c new file +36 -0
+		*value = reg_data & 0x1f;
+		return 0;
+	}
+
+	/* check parameters */
+	if (phy_addr > PHY_MASK) {
+		printf("ARMD100 FEC: (%s) Invalid phy address: 0x%X\n",
+				__func__, phy_addr);
+		return -EINVAL;
+	}
+	if (phy_reg > PHY_MASK) {
+		printf("ARMD100 FEC: (%s) Invalid register offset: 0x%X\n",
+				__func__, phy_reg);
+		return -EINVAL;
+	}
+
+	/* wait for the SMI register to become available */
+	if (armdfec_phy_timeout(&regs->smi, SMI_BUSY, FALSE)) {
+		printf("ARMD100 FEC: (%s) PHY busy timeout\n",	__func__);
+		return -1;
+	}
+
+	writel((phy_addr << 16) | (phy_reg << 21) | SMI_OP_R, &regs->smi);
+
+	/* now wait for the data to be valid */
+	if (armdfec_phy_timeout(&regs->smi, SMI_R_VALID, TRUE)) {
+		val = readl(&regs->smi);
+		printf("ARMD100 FEC: (%s) PHY Read timeout, val=0x%x\n",
+				__func__, val);
+		return -1;
+	}
+	val = readl(&regs->smi);
+	*value = val & 0xffff;
+
+	return 0;
+}

[...]

Quoted 30 lines
drivers/net/armada100_fec.c new file +30 -0
+static int add_del_hash_entry(struct armdfec_device *darmdfec, u32 mach,
+			      u32 macl, u32 rd, u32 skip, int del)
+{
+	struct addr_table_entry_t *entry, *start;
+	u32 newhi;
+	u32 newlo;
+	u32 i;
+
+	newlo = (((mach >> 4) & 0xf) << 15)
+		| (((mach >> 0) & 0xf) << 11)
+		| (((mach >> 12) & 0xf) << 7)
+		| (((mach >> 8) & 0xf) << 3)
+		| (((macl >> 20) & 0x1) << 31)
+		| (((macl >> 16) & 0xf) << 27)
+		| (((macl >> 28) & 0xf) << 23)
+		| (((macl >> 24) & 0xf) << 19)
+		| (skip << HTESKIP) | (rd << HTERDBIT)
+		| HTEVALID;
+
+	newhi = (((macl >> 4) & 0xf) << 15)
+		| (((macl >> 0) & 0xf) << 11)
+		| (((macl >> 12) & 0xf) << 7)
+		| (((macl >> 8) & 0xf) << 3)
+		| (((macl >> 21) & 0x7) << 0);
+
+	/*
+	 * Pick the appropriate table, start scanning for free/reusable
+	 * entries at the index obtained by hashing the specified MAC address
+	 */
+	start = (struct addr_table_entry_t *) (darmdfec->htpr);

drivers/net/armada100_fec.c line 307

Quoted 10 lines
drivers/net/armada100_fec.c new file +10 -0
+	entry = start + hash_function(mach, macl);
+	for (i = 0; i < HOP_NUMBER; i++) {
+		if (!(entry->lo & HTEVALID)) {
+			break;
+		} else {
+			/* if same address put in same position */
+			if (((entry->lo & 0xfffffff8) == (newlo & 0xfffffff8))
+					&& (entry->hi == newhi))
+				break;
+		}

What about

if (!(entry->lo & HTEVALID))

	break;

if (((entry->lo & 0xfffffff8) == (newlo & 0xfffffff8))

		&& (entry->hi == newhi)) {
	break;
}

? :-)

drivers/net/armada100_fec.c line 316

Quoted 9 lines
drivers/net/armada100_fec.c new file +9 -0
+		if (entry == start + 0x7ff)
+			entry = start;
+		else
+			entry++;
+	}
+
+	if (((entry->lo & 0xfffffff8) != (newlo & 0xfffffff8)) &&
+		(entry->hi != newhi) && del)
+		return 0;

Now thinking of it, are you sure about this condition ? Shouldn't the first && be || instead ? And there should be parenthesis around that ?

Quoted 10 lines
drivers/net/armada100_fec.c new file +10 -0
+
+	if (i == HOP_NUMBER) {
+		if (!del) {
+			printf("ARMD100 FEC: (%s) table section is full\n",
+					__func__);
+			return -ENOSPC;
+		} else {
+			return 0;
+		}
+	}

[...]

drivers/net/armada100_fec.c line 384

Quoted 2 lines
drivers/net/armada100_fec.c new file +2 -0
+
+	/* 64 should work but does not -- dhcp packets NEVER get transmitted. */

What's this about ?

Quoted 2 lines
drivers/net/armada100_fec.c new file +2 -0
+	if ((mtu > MAX_PKT_SIZE) || (mtu < 64))
+		return -EINVAL;

[...]

drivers/net/armada100_fec.c line 589

Quoted 7 lines
drivers/net/armada100_fec.c new file +7 -0
+static int armdfec_send(struct eth_device *dev, volatile void *dataptr,
+		    int datasize)
+{
+	struct armdfec_device *darmdfec = to_darmdfec(dev);
+	struct armdfec_reg *regs = darmdfec->regs;
+	struct tx_desc *p_txdesc = darmdfec->p_txdesc;
+	void *p = (void *) dataptr;

Is this needed?

drivers/net/armada100_fec.c line 594

Quoted 5 lines
drivers/net/armada100_fec.c new file +5 -0
+	int retry = PHY_WAIT_ITERATIONS * PHY_WAIT_MICRO_SECONDS;
+	u32 cmd_sts;
+
+	/* Copy buffer if it's misaligned */
+	if ((u32) dataptr & 0x07) {

Space after typecast. Please fix globally.

drivers/net/armada100_fec.c line 602

Quoted 8 lines
drivers/net/armada100_fec.c new file +8 -0
+		if (datasize > PKTSIZE_ALIGN) {
+			printf("ARMD100 FEC: Non-aligned data too large (%d)\n",
+					datasize);
+			return -1;
+		}
+		memcpy(darmdfec->p_aligned_txbuf, p, datasize);
+		p = darmdfec->p_aligned_txbuf;
+	}

The rest is really good !

Thanks!

Cheers

#2 lore raw

PATCH v4 1/3 net: Adds Fast Ethernet Controller driver for Armada100

In reply to Ajay Bhargav
Quoted 14 lines · On Tuesday, August 30, 2011 01:44:40 Ajay Bhargav wrote:
drivers/net/armada100_fec.c new file +14 -0
+static void update_hash_table_mac_address(struct armdfec_device *darmdfec,
+					  u8 *oaddr, u8 *addr)
+{
+	u32 mach;
+	u32 macl;
+
+	/* Delete old entry */
+	if (oaddr) {
+		mach = (oaddr[0] << 8) | oaddr[1];
+		macl = (oaddr[2] << 24) | (oaddr[3] << 16) |
+			(oaddr[4] << 8) | oaddr[5];
+		add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_DELETE);
+	}
+

drivers/net/armada100_fec.c

Quoted 10 lines
drivers/net/armada100_fec.c new file +8 -0
+	/* Add new entry */
+	mach = (addr[0] << 8) | addr[1];
+	macl = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+	add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_ADD);
+}
...
+static int armdfec_init(struct eth_device *dev, bd_t *bd)
+{
...
+	update_hash_table_mac_address(darmdfec, dev->enetaddr, dev->enetaddr);

i think something got lost along the way here :)

you'll probably want to have oaddr[] be a static local in update_hash_table_mac_address and use that to delete the old one when it differs from the new one, and then copy the new one into the static local. -mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110830/c5636d6f/attachment.pgp

#3 lore raw

PATCH v4 1/3 net: Adds Fast Ethernet Controller driver for Armada100

Quoted 29 lines · ----- "Mike Frysinger
Quoted 1 line · On Tuesday, August 30, 2011 01:44:40 Ajay Bhargav wrote:

+static void update_hash_table_mac_address(struct armdfec_device

*darmdfec,

Quoted 6 lines
drivers/net/armada100_fec.c new file +6 -0
+					  u8 *oaddr, u8 *addr)
+{
+	u32 mach;
+	u32 macl;
+
+	/* Delete old entry */

drivers/net/armada100_fec.c

Quoted 10 lines
drivers/net/armada100_fec.c new file +10 -0
+	if (oaddr) {
+		mach = (oaddr[0] << 8) | oaddr[1];
+		macl = (oaddr[2] << 24) | (oaddr[3] << 16) |
+			(oaddr[4] << 8) | oaddr[5];
+		add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_DELETE);
+	}
+
+	/* Add new entry */
+	mach = (addr[0] << 8) | addr[1];
+	macl = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |

addr[5];

drivers/net/armada100_fec.c

Quoted 7 lines
drivers/net/armada100_fec.c new file +5 -0
+	add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_ADD);
+}
...
+static int armdfec_init(struct eth_device *dev, bd_t *bd)
+{
...
+	update_hash_table_mac_address(darmdfec, dev->enetaddr,

dev->enetaddr);

Quoted 8 lines

i think something got lost along the way here :)

you'll probably want to have oaddr[] be a static local in update_hash_table_mac_address and use that to delete the old one when it
differs from the new one, and then copy the new one into the static local.
-mike

You can have multiple entries in Hash table for different MAC addresses. The reason old entry is deleted because it may be possible that hash entry in the list is skipped but not invalidated so the same entry is made valid in the list after removing the old one and updating list with new entry. The calculated has for a particular MAC address is going to be same.

Thanks,
Ajay Bhargav

#4 lore raw

PATCH v4 1/3 net: Adds Fast Ethernet Controller driver for Armada100

Quoted 51 lines · ----- "Ajay Bhargav
Quoted 29 lines · ----- "Mike Frysinger
Quoted 1 line · On Tuesday, August 30, 2011 01:44:40 Ajay Bhargav wrote:

+static void update_hash_table_mac_address(struct armdfec_device

*darmdfec,

Quoted 6 lines
drivers/net/armada100_fec.c new file +6 -0
+					  u8 *oaddr, u8 *addr)
+{
+	u32 mach;
+	u32 macl;
+
+	/* Delete old entry */

drivers/net/armada100_fec.c

Quoted 10 lines
drivers/net/armada100_fec.c new file +10 -0
+	if (oaddr) {
+		mach = (oaddr[0] << 8) | oaddr[1];
+		macl = (oaddr[2] << 24) | (oaddr[3] << 16) |
+			(oaddr[4] << 8) | oaddr[5];
+		add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_DELETE);
+	}
+
+	/* Add new entry */
+	mach = (addr[0] << 8) | addr[1];
+	macl = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |

addr[5];

drivers/net/armada100_fec.c

Quoted 7 lines
drivers/net/armada100_fec.c new file +5 -0
+	add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_ADD);
+}
...
+static int armdfec_init(struct eth_device *dev, bd_t *bd)
+{
...
+	update_hash_table_mac_address(darmdfec, dev->enetaddr,

dev->enetaddr);

Quoted 4 lines

i think something got lost along the way here :)

you'll probably want to have oaddr[] be a static local in update_hash_table_mac_address and use that to delete the old one

when

Quoted 4 lines

it
differs from the new one, and then copy the new one into the static local.
-mike

You can have multiple entries in Hash table for different MAC addresses.
The reason old entry is deleted because it may be possible that hash entry
in the list is skipped but not invalidated so the same entry is made valid
in the list after removing the old one and updating list with new entry.
The calculated has for a particular MAC address is going to be same.

Quoted 2 lines

Thanks,
Ajay Bhargav

Adding to this.. In my case, its the first entry in hash table so I do not need to delete it, I can simply pass NULL in place of oaddr. That change I will make in the updated patch I am going to submit.

Thanks,
Ajay Bhargav