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
* Copyright (C) 2006 Imre Kaloz
* Copyright (C) 2006-2009 Felix Fietkau
* Ported to Barebox:
* Copyright (C) 2013 Oleksij Rempel
*
* 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
#include
#include
#include
#include
#include "ar231x2.h"
#include
#include
#include
/* 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) & 0x1fff)
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,