From: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] sh: sh_eth: Change new network API
Date: Fri, 21 Nov 2008 12:04:18 +0900 [thread overview]
Message-ID: <49262532.3000900@renesas.com> (raw)
sh_eth used old network API. This patch changed new API.
Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
---
cpu/sh4/cpu.c | 8 +
drivers/net/sh_eth.c | 355 ++++++++++++++++++++++++++++++++------------------
drivers/net/sh_eth.h | 10 +-
include/netdev.h | 1 +
4 files changed, 240 insertions(+), 134 deletions(-)
diff --git a/cpu/sh4/cpu.c b/cpu/sh4/cpu.c
index d94e139..52b6cfd 100644
--- a/cpu/sh4/cpu.c
+++ b/cpu/sh4/cpu.c
@@ -82,3 +82,11 @@ int dcache_status (void)
{
return 0;
}
+
+int cpu_eth_init(bd_t *bis)
+{
+#ifdef CONFIG_SH_ETHER
+ sh_eth_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 9e3cf98..ebe8588 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -24,6 +24,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -36,12 +37,7 @@
# error "Please define CONFIG_SH_ETHER_PHY_ADDR"
#endif
-extern int eth_init(bd_t *bd);
-extern void eth_halt(void);
-extern int eth_rx(void);
-extern int eth_send(volatile void *packet, int length);
-
-static struct dev_info_s *dev;
+#define SH_ETH_PHY_DELAY 50000
/*
* Bits are written to the PHY serially using the
@@ -89,7 +85,7 @@ static void sh_eth_mii_ind_bus_release(int port)
udelay(1);
}
-static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len)
+static void sh_eth_mii_read_phy_bits(int port, u32 *val, int len)
{
int i;
u32 pir;
@@ -106,8 +102,6 @@ static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len)
outl(0, PIR(port));
udelay(1);
}
-
- return 0;
}
#define PHY_INIT 0xFFFFFFFF
@@ -183,26 +177,23 @@ static void sh_eth_mii_write_phy_reg(int port, u8 phy_addr, int reg, u16 val)
sh_eth_mii_ind_bus_release(port);
}
-void eth_halt(void)
-{
-}
-
-int eth_send(volatile void *packet, int len)
+int sh_eth_send(struct eth_device *dev, volatile void *packet, int len)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
- int timeout;
- int rc = 0;
+ struct sh_eth_dev *eth = dev->priv;
+ int port = eth->port, ret = 0, timeout;
+ struct sh_eth_info *port_info = ð->port_info[port];
if (!packet || len > 0xffff) {
- printf("eth_send: Invalid argument\n");
- return -EINVAL;
+ printf(SHETHER_NAME ": %s: Invalid argument\n", __func__);
+ ret = -EINVAL;
+ goto err;
}
/* packet must be a 4 byte boundary */
if ((int)packet & (4 - 1)) {
- printf("eth_send: packet not 4 byte alligned\n");
- return -EFAULT;
+ printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n", __func__);
+ ret = -EFAULT;
+ goto err;
}
/* Update tx descriptor */
@@ -224,24 +215,25 @@ int eth_send(volatile void *packet, int len)
udelay(100);
if (timeout < 0) {
- printf("eth_send: transmit timeout\n");
- rc = -1;
+ printf(SHETHER_NAME ": transmit timeout\n");
+ ret = -ETIMEDOUT;
goto err;
}
-err:
port_info->tx_desc_cur++;
if (port_info->tx_desc_cur >= port_info->tx_desc_base + NUM_TX_DESC)
port_info->tx_desc_cur = port_info->tx_desc_base;
- return rc;
+ return ret;
+err:
+ return ret;
}
-int eth_rx(void)
+int sh_eth_recv(struct eth_device *dev)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
- int len = 0;
+ struct sh_eth_dev *eth = dev->priv;
+ int port = eth->port, len = 0;
+ struct sh_eth_info *port_info = ð->port_info[port];
volatile u8 *packet;
/* Check if the rx descriptor is ready */
@@ -275,10 +267,10 @@ int eth_rx(void)
}
#define EDMR_INIT_CNT 1000
-static int sh_eth_reset(struct dev_info_s *dev)
+static int sh_eth_reset(struct sh_eth_dev *eth)
{
- int port = dev->port;
- int i;
+ int port = eth->port;
+ int ret = 0, i;
/* Start e-dmac transmitter and receiver */
outl(EDSR_ENALL, EDSR(port));
@@ -292,33 +284,36 @@ static int sh_eth_reset(struct dev_info_s *dev)
}
if (i == EDMR_INIT_CNT) {
- printf("Error: Software reset timeout\n");
- return -1;
+ printf(SHETHER_NAME ": Software reset timeout\n");
+ ret = -EIO;
}
- return 0;
+
+ return ret;
}
-static int sh_eth_tx_desc_init(struct dev_info_s *dev)
+static int sh_eth_tx_desc_init(struct sh_eth_dev *eth)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
+ int port = eth->port, i, ret = 0;
u32 tmp_addr;
+ struct sh_eth_info *port_info = ð->port_info[port];
struct tx_desc_s *cur_tx_desc;
- int i;
- /* Allocate tx descriptors. They must be TX_DESC_SIZE bytes
- aligned */
- if (!(port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
+ /*
+ * Allocate tx descriptors. They must be TX_DESC_SIZE bytes aligned
+ */
+ port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
sizeof(struct tx_desc_s) +
- TX_DESC_SIZE - 1))) {
- printf("Error: malloc failed\n");
- return -ENOMEM;
+ TX_DESC_SIZE - 1);
+ if (!port_info->tx_desc_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err;
}
+
tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) &
~(TX_DESC_SIZE - 1));
/* Make sure we use a P2 address (non-cacheable) */
port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr);
-
port_info->tx_desc_cur = port_info->tx_desc_base;
/* Initialize all descriptors */
@@ -340,26 +335,30 @@ static int sh_eth_tx_desc_init(struct dev_info_s *dev)
outl(ADDR_TO_PHY(cur_tx_desc), TDFXR(port));
outl(0x01, TDFFR(port));/* Last discriptor bit */
- return 0;
+err:
+ return ret;
}
-static int sh_eth_rx_desc_init(struct dev_info_s *dev)
+static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
- u32 tmp_addr;
+ int port = eth->port, i , ret = 0;
+ struct sh_eth_info *port_info = ð->port_info[port];
struct rx_desc_s *cur_rx_desc;
+ u32 tmp_addr;
u8 *rx_buf;
- int i;
- /* Allocate rx descriptors. They must be RX_DESC_SIZE bytes
- aligned */
- if (!(port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
+ /*
+ * Allocate rx descriptors. They must be RX_DESC_SIZE bytes aligned
+ */
+ port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
sizeof(struct rx_desc_s) +
- RX_DESC_SIZE - 1))) {
- printf("Error: malloc failed\n");
- return -ENOMEM;
+ RX_DESC_SIZE - 1);
+ if (!port_info->rx_desc_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err;
}
+
tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) &
~(RX_DESC_SIZE - 1));
/* Make sure we use a P2 address (non-cacheable) */
@@ -367,15 +366,17 @@ static int sh_eth_rx_desc_init(struct dev_info_s *dev)
port_info->rx_desc_cur = port_info->rx_desc_base;
- /* Allocate rx data buffers. They must be 32 bytes aligned and in
- P2 area */
- if (!(port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE +
- 31))) {
- printf("Error: malloc failed\n");
- free(port_info->rx_desc_malloc);
- port_info->rx_desc_malloc = NULL;
- return -ENOMEM;
+ /*
+ * Allocate rx data buffers. They must be 32 bytes aligned and in
+ * P2 area
+ */
+ port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE + 31);
+ if (!port_info->rx_buf_malloc) {
+ printf(SHETHER_NAME ": malloc failed\n");
+ ret = -ENOMEM;
+ goto err_buf_malloc;
}
+
tmp_addr = (u32)(((int)port_info->rx_buf_malloc + (32 - 1)) &
~(32 - 1));
port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr);
@@ -399,18 +400,31 @@ static int sh_eth_rx_desc_init(struct dev_info_s *dev)
outl(ADDR_TO_PHY(cur_rx_desc), RDFXR(port));
outl(RDFFR_RDLF, RDFFR(port));
- return 0;
+ return ret;
+
+err_buf_malloc:
+ free(port_info->rx_desc_malloc);
+ port_info->rx_desc_malloc = NULL;
+
+err:
+ return ret;
}
-static void sh_eth_desc_free(struct dev_info_s *dev)
+static void sh_eth_tx_desc_free(struct sh_eth_dev *eth)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
+ int port = eth->port;
+ struct sh_eth_info *port_info = ð->port_info[port];
if (port_info->tx_desc_malloc) {
free(port_info->tx_desc_malloc);
port_info->tx_desc_malloc = NULL;
}
+}
+
+static void sh_eth_rx_desc_free(struct sh_eth_dev *eth)
+{
+ int port = eth->port;
+ struct sh_eth_info *port_info = ð->port_info[port];
if (port_info->rx_desc_malloc) {
free(port_info->rx_desc_malloc);
@@ -423,36 +437,48 @@ static void sh_eth_desc_free(struct dev_info_s *dev)
}
}
-static int sh_eth_desc_init(struct dev_info_s *dev)
+static int sh_eth_desc_init(struct sh_eth_dev *eth)
{
- int rc;
+ int ret = 0;
- if ((rc = sh_eth_tx_desc_init(dev)) || (rc = sh_eth_rx_desc_init(dev))) {
- sh_eth_desc_free(dev);
- return rc;
- }
+ ret = sh_eth_tx_desc_init(eth);
+ if (ret)
+ goto err_tx_init;
- return 0;
+ ret = sh_eth_rx_desc_init(eth);
+ if (ret)
+ goto err_rx_init;
+
+ return ret;
+err_rx_init:
+ sh_eth_tx_desc_free(eth);
+
+err_tx_init:
+ return ret;
}
-static int sh_eth_phy_config(struct dev_info_s *dev)
+static int sh_eth_phy_config(struct sh_eth_dev *eth)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
- int timeout;
+ int port = eth->port, timeout, ret = 0;
+ struct sh_eth_info *port_info = ð->port_info[port];
u32 val;
+
/* Reset phy */
- sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_CTRL, PHY_C_RESET);
+ sh_eth_mii_write_phy_reg
+ (port, port_info->phy_addr, PHY_CTRL, PHY_C_RESET);
timeout = 10;
while (timeout--) {
- val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, PHY_CTRL);
+ val = sh_eth_mii_read_phy_reg(port,
+ port_info->phy_addr, PHY_CTRL);
if (!(val & PHY_C_RESET))
break;
- udelay(50000);
+ udelay(SH_ETH_PHY_DELAY);
}
+
if (timeout < 0) {
- printf("%s phy reset timeout\n", __func__);
- return -1;
+ printf(SHETHER_NAME ": phy reset timeout\n");
+ ret = -EIO;
+ goto err_tout;
}
/* Advertise 100/10 baseT full/half duplex */
@@ -467,23 +493,27 @@ static int sh_eth_phy_config(struct dev_info_s *dev)
val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1);
if (val & PHY_S_ANEGC)
break;
- udelay(50000);
+
+ udelay(SH_ETH_PHY_DELAY);
}
+
if (timeout < 0) {
- printf("sh_eth_phy_config() phy auto-negotiation failed\n");
- return -1;
+ printf(SHETHER_NAME ": phy auto-negotiation failed\n");
+ ret = -ETIMEDOUT;
+ goto err_tout;
}
- return 0;
+ return ret;
+
+err_tout:
+ return ret;
}
-static int sh_eth_config(struct dev_info_s *dev, bd_t * bd)
+static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
{
- int port = dev->port;
- struct port_info_s *port_info = &dev->port_info[port];
- u32 val;
- u32 phy_status;
- int rc;
+ int port = eth->port, ret = 0;
+ u32 val, phy_status;
+ struct sh_eth_info *port_info = ð->port_info[port];
/* Configure e-dmac registers */
outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port));
@@ -513,20 +543,20 @@ static int sh_eth_config(struct dev_info_s *dev, bd_t * bd)
outl(TPAUSER_TPAUSE, TPAUSER(port));
/* Configure phy */
- if ((rc = sh_eth_phy_config(dev)))
- return rc;
-
+ ret = sh_eth_phy_config(eth);
+ if (ret) {
+ printf(SHETHER_NAME ":i phy config timeout\n");
+ goto err_phy_cfg;
+ }
/* Read phy status to finish configuring the e-mac */
- phy_status = sh_eth_mii_read_phy_reg(dev->port,
- dev->port_info[dev->port].phy_addr,
- 1);
+ phy_status = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1);
/* Set the transfer speed */
if (phy_status & (PHY_S_100X_F|PHY_S_100X_H)) {
- printf("100Base/");
+ printf(SHETHER_NAME ": 100Base/");
outl(GECMR_100B, GECMR(port));
} else {
- printf("10Base/");
+ printf(SHETHER_NAME ": 10Base/");
outl(GECMR_10B, GECMR(port));
}
@@ -538,27 +568,34 @@ static int sh_eth_config(struct dev_info_s *dev, bd_t * bd)
printf("Half\n");
outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR(port));
}
- return 0;
+
+ return ret;
+
+err_phy_cfg:
+ return ret;
}
-static int sh_eth_start(struct dev_info_s *dev)
+static void sh_eth_start(struct sh_eth_dev *eth)
{
/*
* Enable the e-dmac receiver only. The transmitter will be enabled when
* we have something to transmit
*/
- outl(EDRRR_R, EDRRR(dev->port));
+ outl(EDRRR_R, EDRRR(eth->port));
+}
- return 0;
+static void sh_eth_stop(struct sh_eth_dev *eth)
+{
+ outl(~EDRRR_R, EDRRR(eth->port));
}
static int sh_eth_get_mac(bd_t *bd)
{
char *s, *e;
- int i;
s = getenv("ethaddr");
if (s != NULL) {
+ int i;
for (i = 0; i < 6; ++i) {
bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
if (s)
@@ -570,34 +607,92 @@ static int sh_eth_get_mac(bd_t *bd)
return 0;
}
-int eth_init(bd_t *bd)
+int sh_eth_init(struct eth_device *dev, bd_t *bd)
{
- int rc;
- /* Allocate main device information structure */
- if (!(dev = malloc(sizeof(*dev)))) {
- printf("eth_init: malloc failed\n");
- return -ENOMEM;
- }
+ int ret = 0;
+ struct sh_eth_dev *eth = dev->priv;
- memset(dev, 0, sizeof(*dev));
+ ret = sh_eth_reset(eth);
+ if (ret)
+ goto err;
- dev->port = CONFIG_SH_ETHER_USE_PORT;
- dev->port_info[dev->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;
+ ret = sh_eth_desc_init(eth);
+ if (ret)
+ goto err;
- sh_eth_get_mac(bd);
+ ret = sh_eth_config(eth, bd);
+ if (ret)
+ goto err_config;
+
+ sh_eth_start(eth);
+
+ return ret;
- if ((rc = sh_eth_reset(dev)) || (rc = sh_eth_desc_init(dev)))
+err_config:
+ sh_eth_tx_desc_free(eth);
+ sh_eth_rx_desc_free(eth);
+
+err:
+ return ret;
+}
+
+void sh_eth_halt(struct eth_device *dev)
+{
+ struct sh_eth_dev *eth = dev->priv;
+
+ sh_eth_reset(eth);
+ sh_eth_stop(eth);
+}
+
+int sh_eth_initialize(bd_t *bd)
+{
+ int ret = 0;
+ struct sh_eth_dev *eth = NULL;
+ struct eth_device *dev = NULL;
+
+ eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev));
+ if (!eth) {
+ printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
+ ret = -ENOMEM;
goto err;
+ }
- if ((rc = sh_eth_config(dev, bd)) || (rc = sh_eth_start(dev)))
- goto err_desc;
+ dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!dev) {
+ printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ memset(dev, 0, sizeof(struct eth_device));
+ memset(eth, 0, sizeof(struct sh_eth_dev));
- return 0;
+ eth->port = CONFIG_SH_ETHER_USE_PORT;
+ eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;
+
+ dev->priv = (void *)eth;
+ dev->iobase = 0;
+ dev->init = sh_eth_init;
+ dev->halt = sh_eth_halt;
+ dev->send = sh_eth_send;
+ dev->recv = sh_eth_recv;
+ eth->port_info[eth->port].dev = dev;
+
+ sprintf(dev->name, SHETHER_NAME);
+
+ /* Register Device to EtherNet subsystem */
+ eth_register(dev);
+
+ sh_eth_get_mac(bd);
+
+ return ret;
-err_desc:
- sh_eth_desc_free(dev);
err:
- free(dev);
- printf("eth_init: Failed\n");
- return rc;
+ if (dev)
+ free(dev);
+
+ if (eth)
+ free(eth);
+
+ printf(SHETHER_NAME ": Failed\n");
+ return ret;
}
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 9cf0ea0..a13fff0 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -20,6 +20,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <netdev.h>
#include <asm/types.h>
#define SHETHER_NAME "sh_eth"
@@ -48,7 +49,7 @@
#define TX_DESC_PADDING 4
#define TX_DESC_SIZE (12 + TX_DESC_PADDING)
-/* Tx descriptor. We always use 4 bytes of padding */
+/* Tx descriptor. We always use 3 bytes of padding */
struct tx_desc_s {
volatile u32 td0;
u32 td1;
@@ -72,7 +73,7 @@ struct rx_desc_s {
u32 padding;
};
-struct port_info_s {
+struct sh_eth_info {
struct tx_desc_s *tx_desc_malloc;
struct tx_desc_s *tx_desc_base;
struct tx_desc_s *tx_desc_cur;
@@ -83,11 +84,12 @@ struct port_info_s {
u8 *rx_buf_base;
u8 mac_addr[6];
u8 phy_addr;
+ struct eth_device *dev;
};
-struct dev_info_s {
+struct sh_eth_dev {
int port;
- struct port_info_s port_info[MAX_PORT_NUM];
+ struct sh_eth_info port_info[MAX_PORT_NUM];
};
/* Register Address */
diff --git a/include/netdev.h b/include/netdev.h
index 751f0da..a7d662d 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -70,6 +70,7 @@ int skge_initialize(bd_t *bis);
int tsi108_eth_initialize(bd_t *bis);
int uec_initialize(int index);
int uli526x_initialize(bd_t *bis);
+int sh_eth_initialize(bd_t *bis);
/* Boards with PCI network controllers can call this from their board_eth_init()
* function to initialize whatever's on board.
--
1.5.6.5
next reply other threads:[~2008-11-21 3:04 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-11-21 3:04 Nobuhiro Iwamatsu [this message]
2008-11-21 6:56 ` [U-Boot] [PATCH] sh: sh_eth: Change new network API Ben Warren
2008-11-25 7:48 ` Ben Warren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49262532.3000900@renesas.com \
--to=iwamatsu.nobuhiro@renesas.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.