Hallo devs,

currently i porting barebox to ar2313a WiSoC. I know there is redboot, but i do it just for fun. Most basics are working now, including ethernet driver - except there is one issue with it. After RX is enabled, rx ringbuffer starting getting filled. If there is lots of broadcasts and buffer is full, first packet of my transaction can be lost. Are there any way to filter bcasts by hardware? Is it possible to get documentation for this chip? It will be especially interesting then i start to work on bootstrap part.

In attachment is the eth driver for barebox.
--
Regards,
Oleksij
/*
 * ar231x.c: Linux driver for the Atheros AR231x Ethernet device.
 * Based on Linux driver:
 * 		Copyright (C) 2004 by Sameer Dekate <sdek...@arubanetworks.com>
 * 		Copyright (C) 2006 Imre Kaloz <ka...@openwrt.org>
 * 		Copyright (C) 2006-2009 Felix Fietkau <n...@openwrt.org>
 * Ported to Barebox:
 * 		Copyright (C) 2013 Oleksij Rempel <bug-tr...@fisher-privat.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */
/*
 * Known issues:
 * - broadcast packets are not filtered by hardware. On noisy network with
 * lots of bcast packages rx_buffer can be completely filled after. It seems
 * to be OK on transmission (we will clean it), but it is not nice on stand by.
 * In this case we may lose first transmission after stand by.
 */

#include <driver.h>
#include <init.h>
#include <mach/ar231x_platform.h>
#include <common.h>
#include <net.h>
#include "ar231x2.h"
#include <asm/addrspace.h>
#include <asm/io.h>
#include <linux/phy.h>

/* Allocate 64 RX buffers. This will reduce packet loss, until we will start
 * processing them. It is important in noisy network with lots of broadcasts. */
#define AR2313_RXDSC_ENTRIES		64
#define DSC_NEXT(idx)				((idx + 1) & (AR2313_RXDSC_ENTRIES - 1))

/* Use system default buffers size. At the moment of writing it was 1518 */
#define AR2313_RX_BUFSIZE			PKTSIZE
#define CRC_LEN						4

#define virt_to_phys(x) ((u32)(x) & 0x1fffffff)

static int ar231x_set_ethaddr(struct eth_device *edev, unsigned char *addr);
static void ar231x_reset_regs(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	struct ar231x_eth_platform_data *cfg = priv->cfg;
	u32 flags;

	debug("%s\n", __func__);

	*priv->int_regs |= cfg->reset_mac;
	mdelay(10);
	*priv->int_regs &= ~cfg->reset_mac;
	mdelay(10);
	*priv->int_regs |= cfg->reset_phy;
	mdelay(10);
	*priv->int_regs &= ~cfg->reset_phy;
	mdelay(10);

	priv->dma_regs->bus_mode = DMA_BUS_MODE_SWR;
	mdelay(10);
	priv->dma_regs->bus_mode =
		((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE);

	priv->dma_regs->xmt_base = virt_to_phys(priv->tx_ring);
	priv->dma_regs->rcv_base = virt_to_phys(priv->rx_ring);
	priv->dma_regs->control =
		(DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF);
	priv->eth_regs->flow_control = FLOW_CONTROL_FCE;
	/* TODO: not sure if we need it here. */
	priv->eth_regs->vlan_tag = (0x8100);

	/* Enable Ethernet Interface */
	flags = (MAC_CONTROL_TE |	/* transmit enable */
			/* MAC_CONTROL_PM - pass mcast.
			 * Seems like it makes no difference on some WiSoCs,
			 * for example ar2313. */
			MAC_CONTROL_PM |
			MAC_CONTROL_F  |	/* full duplex */
			MAC_CONTROL_HBD);	/* heart beat disabled */
	priv->eth_regs->mac_control = flags;
}

static void ar231x_flash_rxdsc(ar231x_descr_t *rxdsc)
{
	rxdsc->status = DMA_RX_OWN;
	rxdsc->devcs = ((AR2313_RX_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
			DMA_RX1_CHAINED);
}

static void ar231x_allocate_dma_descriptors(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	u16 ar231x_descr_size = sizeof(ar231x_descr_t);
	u16 i;

	debug("%s\n", __func__);

	priv->tx_ring = xmalloc(ar231x_descr_size);
	dev_dbg(&edev->dev, "allocate tx_ring @ %p\n", priv->tx_ring);

	priv->rx_ring = xmalloc(ar231x_descr_size * AR2313_RXDSC_ENTRIES);
	dev_dbg(&edev->dev, "allocate rx_ring @ %p\n", priv->rx_ring);

	priv->rx_buffer = xmalloc(AR2313_RX_BUFSIZE * AR2313_RXDSC_ENTRIES);
	dev_dbg(&edev->dev, "allocate rx_buffer @ %p\n", priv->rx_buffer);

	/* Initialize the rx Descriptors */
	for (i = 0; i < AR2313_RXDSC_ENTRIES; i++) {
		ar231x_descr_t *rxdsc = &priv->rx_ring[i];
		ar231x_flash_rxdsc(rxdsc);
		rxdsc->buffer_ptr = (uint)(priv->rx_buffer + AR2313_RX_BUFSIZE * i);
		rxdsc->next_dsc_ptr = virt_to_phys(&priv->rx_ring[DSC_NEXT(i)]);
	}
}

static void ar231x_adjust_link(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	u32 mc;

	debug("%s\n", __func__);

	if (edev->phydev->duplex != priv->oldduplex) {
		mc = priv->eth_regs->mac_control;
		mc &= ~(MAC_CONTROL_F | MAC_CONTROL_DRO);
		if (edev->phydev->duplex)
			mc |= MAC_CONTROL_F;
		else
			mc |= MAC_CONTROL_DRO;
		priv->eth_regs->mac_control = mc;
		priv->oldduplex = edev->phydev->duplex;
	}
}

static int ar231x_eth_init(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	debug("%s\n", __func__);

	ar231x_allocate_dma_descriptors(edev);
	ar231x_reset_regs(edev);
	ar231x_set_ethaddr(edev, priv->mac);
	return 0;
}

static int ar231x_eth_open(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	debug("%s\n", __func__);

	/* Enable RX. Now the rx_buffer will be filled.
	 * If it is full we may lose first transmission. In this case
	 * barebox should retry it.
	 * Or TODO: - force HW to filter some how broadcasts
	 *			- disable RX if we do not need it. */
	priv->eth_regs->mac_control |= MAC_CONTROL_RE;

	return phy_device_connect(edev, &priv->miibus, (int)priv->phy_regs,
			ar231x_adjust_link, 0, PHY_INTERFACE_MODE_MII);
}

static int ar231x_eth_send(struct eth_device *edev, void *packet,
		int length)
{
	struct ar231x_eth_priv *priv = edev->priv;
	ar231x_descr_t *txdsc = priv->tx_ring;

	debug("%s\n", __func__);

	/* Setup the transmit descriptor. */
	txdsc->devcs = ((length << DMA_TX1_BSIZE_SHIFT) | DMA_TX1_DEFAULT);
	txdsc->buffer_ptr = (uint)packet;
	txdsc->status = DMA_TX_OWN;

	/* Trigger transmission */
	priv->dma_regs->xmt_poll = 0;

	/* Take enough time to transmit packet. 100 is not enough. */
	wait_on_timeout(2000 * MSECOND,
		!(txdsc->status & DMA_TX_OWN));

	/* We can't do match here. If it is still in progress,
	 * then engine is probably stalled or we wait not enough. */
	if (txdsc->status & DMA_TX_OWN)
		dev_err(&edev->dev, "Frame is still in progress.\n");

	if (txdsc->status & DMA_TX_ERROR)
		dev_err(&edev->dev, "Frame was aborted by engine\n");

	/* Ready or not. Stop it. */
	txdsc->status = 0;
	return 0;
}

static int ar231x_eth_recv(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;
	u16 idx;

	debug("%s\n", __func__);

	idx = priv->rx_ring_idx;

	/* process at most the entire ring and then wait for another interrupt
	 */
	while (1) {
		ar231x_descr_t *rxdsc = &priv->rx_ring[idx];
		u32 status = rxdsc->status;

		/* owned by DMA? */
		if (status & DMA_RX_OWN)
			break;

		/* Pick only packets what we can handle:
		 * - only complete packet per buffer (First and Last at same time)
		 * - drop ERRoneous buffers
		 * - drop multicast */
		if ((status & DMA_RX_FS) && (status & DMA_RX_LS) &&
				!(status & (DMA_RX_MF | DMA_RX_ERROR))) {
			u16 length = ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN;
			net_receive((void *)rxdsc->buffer_ptr, length);
		}
		/* Clean descriptor. now it is owned by DMA. */
		ar231x_flash_rxdsc(rxdsc);
		idx = DSC_NEXT(idx);
	}

	priv->rx_ring_idx = idx;
	return 0;
}

static void ar231x_eth_halt(struct eth_device *edev)
{
	struct ar231x_eth_priv *priv = edev->priv;

	debug("%s\n", __func__);

	/* kill the MAC: disable RX and TX */
	priv->eth_regs->mac_control &= ~(MAC_CONTROL_RE | MAC_CONTROL_TE);
	/* stop DMA */
	priv->dma_regs->control = 0;
	priv->dma_regs->bus_mode = DMA_BUS_MODE_SWR;

	/* place PHY and MAC in reset */
	*priv->int_regs |= (priv->cfg->reset_mac | priv->cfg->reset_phy);
}

static int ar231x_get_ethaddr(struct eth_device *edev, unsigned char *addr)
{
	struct ar231x_eth_priv *priv = edev->priv;

	debug("%s\n", __func__);

	/* MAC address is stored on flash, in some kind of atheros config
	 * area. Platform code should read it and pass to the driver. */
	memcpy(addr, priv->mac, 6);
	return 0;
}

static int ar231x_set_ethaddr(struct eth_device *edev, unsigned char *addr)
{
	struct ar231x_eth_priv *priv = edev->priv;

	debug("%s\n", __func__);

	priv->eth_regs->mac_addr[0] =
			(addr[5] <<  8) | (addr[4]);
	priv->eth_regs->mac_addr[1] =
			(addr[3] << 24) | (addr[2] << 16) |
			(addr[1] <<  8) | addr[0];

	mdelay(10);
	return 0;
}

#define MII_ADDR(phy, reg) \
	((reg << MII_ADDR_REG_SHIFT) | (phy << MII_ADDR_PHY_SHIFT))

static int ar231x_miibus_read(struct mii_bus *bus, int phy_id, int regnum)
{
	struct ar231x_eth_priv *priv = bus->priv;
	volatile ETHERNET_STRUCT *ethernet = priv->phy_regs;

	debug("%s\n", __func__);

	ethernet->mii_addr = MII_ADDR(phy_id, regnum);
	while (ethernet->mii_addr & MII_ADDR_BUSY);
	return (ethernet->mii_data >> MII_DATA_SHIFT);
}

static int ar231x_miibus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
{
	struct ar231x_eth_priv *priv = bus->priv;
	volatile ETHERNET_STRUCT *ethernet = priv->phy_regs;

	debug("%s\n", __func__);

	while (ethernet->mii_addr & MII_ADDR_BUSY);
	ethernet->mii_data = val << MII_DATA_SHIFT;
	ethernet->mii_addr = MII_ADDR(phy_id, regnum) | MII_ADDR_WRITE;

	return 0;
}

static int ar231x_mdiibus_reset(struct mii_bus *bus)
{
	struct ar231x_eth_priv *priv = bus->priv;

	debug("%s\n", __func__);

	ar231x_reset_regs(&priv->edev);
	return 0;
}

static int ar231x_eth_probe(struct device_d *dev)
{
	struct ar231x_eth_priv *priv;
	struct eth_device *edev;
	struct mii_bus *miibus;
	struct ar231x_eth_platform_data *pdata;

	debug("%s\n", __func__);

	if (!dev->platform_data) {
		dev_err(dev, "no platform data\n");
		return -ENODEV;
	}

	pdata = dev->platform_data;

	priv = xzalloc(sizeof(struct ar231x_eth_priv));
	edev = &priv->edev;
	miibus = &priv->miibus;
	edev->priv = priv;

	/* link all platform depended regs */
	priv->mac = pdata->mac;

	if (!pdata->base_eth) {
		dev_err(dev, "no eth base defined\n");
		return -ENODEV;
	}
	priv->eth_regs = (ETHERNET_STRUCT *)pdata->base_eth;
	priv->dma_regs = (DMA *)(pdata->base_eth + 0x1000);

	if (!pdata->base_phy) {
		dev_err(dev, "no phy base defined\n");
		return -ENODEV;
	}
	priv->phy_regs = (ETHERNET_STRUCT *)pdata->base_phy;

	if (!pdata->base_reset) {
		dev_err(dev, "no reset base defined\n");
		return -ENODEV;
	}
	priv->int_regs = (u32 *)pdata->base_reset;
	priv->cfg = pdata;

	edev->init = ar231x_eth_init;
	edev->open = ar231x_eth_open;
	edev->send = ar231x_eth_send;
	edev->recv = ar231x_eth_recv;
	edev->halt = ar231x_eth_halt;
	edev->get_ethaddr = ar231x_get_ethaddr;
	edev->set_ethaddr = ar231x_set_ethaddr;

	priv->miibus.read = ar231x_miibus_read;
	priv->miibus.write = ar231x_miibus_write;
	priv->miibus.reset = ar231x_mdiibus_reset;
	priv->miibus.priv = priv;
	priv->miibus.parent = dev;

	mdiobus_register(miibus);
	eth_register(edev);

	return 0;
}

static void ar231x_eth_remove(struct device_d *dev)
{
	debug("%s\n", __func__);
}

static struct driver_d ar231x_eth_driver = {
        .name = "ar231x_eth",
        .probe = ar231x_eth_probe,
        .remove = ar231x_eth_remove,
};

static int ar231x_eth_driver_init(void)
{
	debug("%s\n", __func__);

	platform_driver_register(&ar231x_eth_driver);
	return 0;
}
device_initcall(ar231x_eth_driver_init);
_______________________________________________
ath9k-devel mailing list
ath9k-devel@lists.ath9k.org
https://lists.ath9k.org/mailman/listinfo/ath9k-devel

Reply via email to