Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
@@ -123,7 +123,6 @@
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
#define SETUP_FRAME_LEN 192
|
||||
#define ETH_ALEN 6
|
||||
|
||||
struct de4x5_desc {
|
||||
volatile s32 status;
|
||||
|
||||
@@ -193,8 +193,6 @@ struct descriptor { /* A generic descriptor. */
|
||||
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
#define ETH_ALEN 6
|
||||
|
||||
static struct RxFD rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
|
||||
static struct TxFD tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
|
||||
static int rx_next; /* RX descriptor ring pointer */
|
||||
|
||||
@@ -363,8 +363,7 @@ static int mc_fixup_mac_addrs(void *blob, enum mc_fixup_type type)
|
||||
|
||||
for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
|
||||
/* port not enabled */
|
||||
if ((wriop_is_enabled_dpmac(i) != 1) ||
|
||||
(wriop_get_phy_address(i) == -1))
|
||||
if (wriop_is_enabled_dpmac(i) != 1)
|
||||
continue;
|
||||
|
||||
snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s", i,
|
||||
@@ -886,8 +885,7 @@ int fsl_mc_ldpaa_init(bd_t *bis)
|
||||
int i;
|
||||
|
||||
for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++)
|
||||
if ((wriop_is_enabled_dpmac(i) == 1) &&
|
||||
(wriop_get_phy_address(i) != -1))
|
||||
if (wriop_is_enabled_dpmac(i) == 1)
|
||||
ldpaa_eth_init(i, wriop_get_enet_if(i));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,21 +23,43 @@ static int init_phy(struct eth_device *dev)
|
||||
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv;
|
||||
struct phy_device *phydev = NULL;
|
||||
struct mii_dev *bus;
|
||||
int phy_addr, phy_num;
|
||||
int ret = 0;
|
||||
|
||||
bus = wriop_get_mdio(priv->dpmac_id);
|
||||
if (bus == NULL)
|
||||
return 0;
|
||||
|
||||
phydev = phy_connect(bus, wriop_get_phy_address(priv->dpmac_id),
|
||||
dev, wriop_get_enet_if(priv->dpmac_id));
|
||||
if (!phydev) {
|
||||
printf("Failed to connect\n");
|
||||
return -1;
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
phy_addr = wriop_get_phy_address(priv->dpmac_id, phy_num);
|
||||
if (phy_addr < 0)
|
||||
continue;
|
||||
|
||||
phydev = phy_connect(bus, phy_addr, dev,
|
||||
wriop_get_enet_if(priv->dpmac_id));
|
||||
if (!phydev) {
|
||||
printf("Failed to connect\n");
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
wriop_set_phy_dev(priv->dpmac_id, phy_num, phydev);
|
||||
ret = phy_config(phydev);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
priv->phydev = phydev;
|
||||
if (ret) {
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
|
||||
if (!phydev)
|
||||
continue;
|
||||
|
||||
return phy_config(phydev);
|
||||
free(phydev);
|
||||
wriop_set_phy_dev(priv->dpmac_id, phy_num, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -377,6 +399,68 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv,
|
||||
struct dpmac_link_state *state)
|
||||
{
|
||||
struct phy_device *phydev = NULL;
|
||||
phy_interface_t enet_if;
|
||||
int phy_num, phys_detected;
|
||||
int err;
|
||||
|
||||
/* let's start off with maximum capabilities */
|
||||
enet_if = wriop_get_enet_if(priv->dpmac_id);
|
||||
switch (enet_if) {
|
||||
case PHY_INTERFACE_MODE_XGMII:
|
||||
state->rate = SPEED_10000;
|
||||
break;
|
||||
default:
|
||||
state->rate = SPEED_1000;
|
||||
break;
|
||||
}
|
||||
state->up = 1;
|
||||
|
||||
phys_detected = 0;
|
||||
#ifdef CONFIG_PHYLIB
|
||||
state->options |= DPMAC_LINK_OPT_AUTONEG;
|
||||
|
||||
/* start the phy devices one by one and update the dpmac state */
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
|
||||
if (!phydev)
|
||||
continue;
|
||||
|
||||
phys_detected++;
|
||||
err = phy_startup(phydev);
|
||||
if (err) {
|
||||
printf("%s: Could not initialize\n", phydev->dev->name);
|
||||
state->up = 0;
|
||||
break;
|
||||
}
|
||||
if (phydev->link) {
|
||||
state->rate = min(state->rate, (uint32_t)phydev->speed);
|
||||
if (!phydev->duplex)
|
||||
state->options |= DPMAC_LINK_OPT_HALF_DUPLEX;
|
||||
if (!phydev->autoneg)
|
||||
state->options &= ~DPMAC_LINK_OPT_AUTONEG;
|
||||
} else {
|
||||
/* break out of loop even if one phy is down */
|
||||
state->up = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!phys_detected)
|
||||
state->options &= ~DPMAC_LINK_OPT_AUTONEG;
|
||||
|
||||
if (!state->up) {
|
||||
state->rate = 0;
|
||||
state->options = 0;
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
|
||||
{
|
||||
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
|
||||
@@ -385,8 +469,6 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
|
||||
struct dpni_link_state link_state;
|
||||
#endif
|
||||
int err = 0;
|
||||
struct mii_dev *bus;
|
||||
phy_interface_t enet_if;
|
||||
struct dpni_queue d_queue;
|
||||
|
||||
if (net_dev->state == ETH_STATE_ACTIVE)
|
||||
@@ -407,47 +489,14 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
|
||||
if (err < 0)
|
||||
goto err_dpmac_setup;
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
if (priv->phydev) {
|
||||
err = phy_startup(priv->phydev);
|
||||
if (err) {
|
||||
printf("%s: Could not initialize\n",
|
||||
priv->phydev->dev->name);
|
||||
goto err_dpamc_bind;
|
||||
}
|
||||
}
|
||||
#else
|
||||
priv->phydev = (struct phy_device *)malloc(sizeof(struct phy_device));
|
||||
memset(priv->phydev, 0, sizeof(struct phy_device));
|
||||
|
||||
priv->phydev->speed = SPEED_1000;
|
||||
priv->phydev->link = 1;
|
||||
priv->phydev->duplex = DUPLEX_FULL;
|
||||
#endif
|
||||
|
||||
bus = wriop_get_mdio(priv->dpmac_id);
|
||||
enet_if = wriop_get_enet_if(priv->dpmac_id);
|
||||
if ((bus == NULL) &&
|
||||
(enet_if == PHY_INTERFACE_MODE_XGMII)) {
|
||||
priv->phydev = (struct phy_device *)
|
||||
malloc(sizeof(struct phy_device));
|
||||
memset(priv->phydev, 0, sizeof(struct phy_device));
|
||||
|
||||
priv->phydev->speed = SPEED_10000;
|
||||
priv->phydev->link = 1;
|
||||
priv->phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
if (!priv->phydev->link) {
|
||||
printf("%s: No link.\n", priv->phydev->dev->name);
|
||||
err = -1;
|
||||
goto err_dpamc_bind;
|
||||
}
|
||||
err = ldpaa_get_dpmac_state(priv, &dpmac_link_state);
|
||||
if (err < 0)
|
||||
goto err_dpmac_bind;
|
||||
|
||||
/* DPMAC binding DPNI */
|
||||
err = ldpaa_dpmac_bind(priv);
|
||||
if (err)
|
||||
goto err_dpamc_bind;
|
||||
goto err_dpmac_bind;
|
||||
|
||||
/* DPNI initialization */
|
||||
err = ldpaa_dpni_setup(priv);
|
||||
@@ -476,18 +525,6 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
|
||||
return err;
|
||||
}
|
||||
|
||||
dpmac_link_state.rate = priv->phydev->speed;
|
||||
|
||||
if (priv->phydev->autoneg == AUTONEG_DISABLE)
|
||||
dpmac_link_state.options &= ~DPMAC_LINK_OPT_AUTONEG;
|
||||
else
|
||||
dpmac_link_state.options |= DPMAC_LINK_OPT_AUTONEG;
|
||||
|
||||
if (priv->phydev->duplex == DUPLEX_HALF)
|
||||
dpmac_link_state.options |= DPMAC_LINK_OPT_HALF_DUPLEX;
|
||||
|
||||
dpmac_link_state.up = priv->phydev->link;
|
||||
|
||||
err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS,
|
||||
priv->dpmac_handle, &dpmac_link_state);
|
||||
if (err < 0) {
|
||||
@@ -530,7 +567,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
|
||||
goto err_qdid;
|
||||
}
|
||||
|
||||
return priv->phydev->link;
|
||||
return dpmac_link_state.up;
|
||||
|
||||
err_qdid:
|
||||
err_get_queue:
|
||||
@@ -540,7 +577,7 @@ err_dpni_bind:
|
||||
err_dpbp_setup:
|
||||
dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
|
||||
err_dpni_setup:
|
||||
err_dpamc_bind:
|
||||
err_dpmac_bind:
|
||||
dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle);
|
||||
dpmac_destroy(dflt_mc_io,
|
||||
dflt_dprc_handle,
|
||||
@@ -553,9 +590,8 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
|
||||
{
|
||||
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
|
||||
int err = 0;
|
||||
#ifdef CONFIG_PHYLIB
|
||||
struct mii_dev *bus = wriop_get_mdio(priv->dpmac_id);
|
||||
#endif
|
||||
struct phy_device *phydev = NULL;
|
||||
int phy_num;
|
||||
|
||||
if ((net_dev->state == ETH_STATE_PASSIVE) ||
|
||||
(net_dev->state == ETH_STATE_INIT))
|
||||
@@ -588,11 +624,10 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
|
||||
printf("dpni_disable() failed\n");
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
if (priv->phydev && bus != NULL)
|
||||
phy_shutdown(priv->phydev);
|
||||
else {
|
||||
free(priv->phydev);
|
||||
priv->phydev = NULL;
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num);
|
||||
if (phydev)
|
||||
phy_shutdown(phydev);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -127,7 +127,6 @@ struct ldpaa_eth_priv {
|
||||
uint16_t tx_flow_id;
|
||||
|
||||
enum ldpaa_eth_type type; /* 1G or 10G ethernet */
|
||||
struct phy_device *phydev;
|
||||
};
|
||||
|
||||
struct dprc_endpoint dpmac_endpoint;
|
||||
|
||||
@@ -22,10 +22,10 @@ __weak phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtc)
|
||||
void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl)
|
||||
{
|
||||
phy_interface_t enet_if;
|
||||
int phy_num;
|
||||
|
||||
dpmac_info[dpmac_id].enabled = 0;
|
||||
dpmac_info[dpmac_id].id = 0;
|
||||
dpmac_info[dpmac_id].phy_addr = -1;
|
||||
dpmac_info[dpmac_id].enet_if = PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
enet_if = wriop_dpmac_enet_if(dpmac_id, lane_prtcl);
|
||||
@@ -34,14 +34,23 @@ void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl)
|
||||
dpmac_info[dpmac_id].id = dpmac_id;
|
||||
dpmac_info[dpmac_id].enet_if = enet_if;
|
||||
}
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
dpmac_info[dpmac_id].phydev[phy_num] = NULL;
|
||||
dpmac_info[dpmac_id].phy_addr[phy_num] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void wriop_init_dpmac_enet_if(int dpmac_id, phy_interface_t enet_if)
|
||||
{
|
||||
int phy_num;
|
||||
|
||||
dpmac_info[dpmac_id].enabled = 1;
|
||||
dpmac_info[dpmac_id].id = dpmac_id;
|
||||
dpmac_info[dpmac_id].phy_addr = -1;
|
||||
dpmac_info[dpmac_id].enet_if = enet_if;
|
||||
for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
|
||||
dpmac_info[dpmac_id].phydev[phy_num] = NULL;
|
||||
dpmac_info[dpmac_id].phy_addr[phy_num] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,47 +67,53 @@ static int wriop_dpmac_to_index(int dpmac_id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void wriop_disable_dpmac(int dpmac_id)
|
||||
int wriop_disable_dpmac(int dpmac_id)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
dpmac_info[i].enabled = 0;
|
||||
wriop_dpmac_disable(dpmac_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wriop_enable_dpmac(int dpmac_id)
|
||||
int wriop_enable_dpmac(int dpmac_id)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
dpmac_info[i].enabled = 1;
|
||||
wriop_dpmac_enable(dpmac_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 wriop_is_enabled_dpmac(int dpmac_id)
|
||||
int wriop_is_enabled_dpmac(int dpmac_id)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
return dpmac_info[i].enabled;
|
||||
}
|
||||
|
||||
|
||||
void wriop_set_mdio(int dpmac_id, struct mii_dev *bus)
|
||||
int wriop_set_mdio(int dpmac_id, struct mii_dev *bus)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
dpmac_info[i].bus = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mii_dev *wriop_get_mdio(int dpmac_id)
|
||||
@@ -111,44 +126,56 @@ struct mii_dev *wriop_get_mdio(int dpmac_id)
|
||||
return dpmac_info[i].bus;
|
||||
}
|
||||
|
||||
void wriop_set_phy_address(int dpmac_id, int address)
|
||||
int wriop_set_phy_address(int dpmac_id, int phy_num, int address)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
return -ENODEV;
|
||||
if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
dpmac_info[i].phy_addr = address;
|
||||
dpmac_info[i].phy_addr[phy_num] = address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wriop_get_phy_address(int dpmac_id)
|
||||
int wriop_get_phy_address(int dpmac_id, int phy_num)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
return dpmac_info[i].phy_addr;
|
||||
return dpmac_info[i].phy_addr[phy_num];
|
||||
}
|
||||
|
||||
void wriop_set_phy_dev(int dpmac_id, struct phy_device *phydev)
|
||||
int wriop_set_phy_dev(int dpmac_id, int phy_num, struct phy_device *phydev)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
return -ENODEV;
|
||||
if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
dpmac_info[i].phydev = phydev;
|
||||
dpmac_info[i].phydev[phy_num] = phydev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phy_device *wriop_get_phy_dev(int dpmac_id)
|
||||
struct phy_device *wriop_get_phy_dev(int dpmac_id, int phy_num)
|
||||
{
|
||||
int i = wriop_dpmac_to_index(dpmac_id);
|
||||
|
||||
if (i == -1)
|
||||
return NULL;
|
||||
if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM)
|
||||
return NULL;
|
||||
|
||||
return dpmac_info[i].phydev;
|
||||
return dpmac_info[i].phydev[phy_num];
|
||||
}
|
||||
|
||||
phy_interface_t wriop_get_enet_if(int dpmac_id)
|
||||
|
||||
@@ -34,14 +34,6 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
# error Marvell mvneta requires PHYLIB
|
||||
#endif
|
||||
|
||||
/* Some linux -> U-Boot compatibility stuff */
|
||||
#define netdev_err(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
#define netdev_warn(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
#define netdev_info(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
|
||||
#define CONFIG_NR_CPUS 1
|
||||
#define ETH_HLEN 14 /* Total octets in header */
|
||||
|
||||
|
||||
@@ -35,18 +35,6 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Some linux -> U-Boot compatibility stuff */
|
||||
#define netdev_err(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
#define netdev_warn(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
#define netdev_info(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
#define netdev_dbg(dev, fmt, args...) \
|
||||
printf(fmt, ##args)
|
||||
|
||||
#define ETH_ALEN 6 /* Octets in one ethernet addr */
|
||||
|
||||
#define __verify_pcpu_ptr(ptr) \
|
||||
do { \
|
||||
const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \
|
||||
@@ -68,7 +56,6 @@ do { \
|
||||
#define NET_SKB_PAD max(32, MVPP2_CPU_D_CACHE_LINE_SIZE)
|
||||
|
||||
#define CONFIG_NR_CPUS 1
|
||||
#define ETH_HLEN ETHER_HDR_SIZE /* Total octets in header */
|
||||
|
||||
/* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */
|
||||
#define WRAP (2 + ETH_HLEN + 4 + 32)
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/
|
||||
|
||||
#define DSIZE 0x00000FFF
|
||||
#define ETH_ALEN 6
|
||||
#define CRC_SIZE 4
|
||||
#define TOUT_LOOP 500000
|
||||
#define TX_BUF_SIZE 1536
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
|
||||
/* defines */
|
||||
#define DSIZE 0x00000FFF
|
||||
#define ETH_ALEN 6
|
||||
#define CRC_SIZE 4
|
||||
#define TOUT_LOOP 500000
|
||||
#define TX_BUF_SIZE 1536
|
||||
|
||||
@@ -429,7 +429,7 @@ static int pch_gbe_phy_init(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pch_gbe_probe(struct udevice *dev)
|
||||
static int pch_gbe_probe(struct udevice *dev)
|
||||
{
|
||||
struct pch_gbe_priv *priv;
|
||||
struct eth_pdata *plat = dev_get_platdata(dev);
|
||||
@@ -464,7 +464,7 @@ int pch_gbe_probe(struct udevice *dev)
|
||||
return pch_gbe_phy_init(dev);
|
||||
}
|
||||
|
||||
int pch_gbe_remove(struct udevice *dev)
|
||||
static int pch_gbe_remove(struct udevice *dev)
|
||||
{
|
||||
struct pch_gbe_priv *priv = dev_get_priv(dev);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
/* Extended Registers */
|
||||
#define DP83867_CFG4 0x0031
|
||||
#define DP83867_RGMIICTL 0x0032
|
||||
#define DP83867_STRAP_STS1 0x006E
|
||||
#define DP83867_RGMIIDCTL 0x0086
|
||||
#define DP83867_IO_MUX_CFG 0x0170
|
||||
|
||||
@@ -48,8 +49,12 @@
|
||||
#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
|
||||
#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
|
||||
|
||||
/* STRAP_STS1 bits */
|
||||
#define DP83867_STRAP_STS1_RESERVED BIT(11)
|
||||
|
||||
/* PHY CTRL bits */
|
||||
#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
|
||||
#define DP83867_PHYCR_RESERVED_MASK BIT(11)
|
||||
#define DP83867_MDI_CROSSOVER 5
|
||||
#define DP83867_MDI_CROSSOVER_AUTO 2
|
||||
#define DP83867_MDI_CROSSOVER_MDIX 2
|
||||
@@ -88,6 +93,18 @@
|
||||
|
||||
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
|
||||
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
|
||||
#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
|
||||
#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \
|
||||
GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT)
|
||||
|
||||
/* CFG4 bits */
|
||||
#define DP83867_CFG4_PORT_MIRROR_EN BIT(0)
|
||||
|
||||
enum {
|
||||
DP83867_PORT_MIRRORING_KEEP,
|
||||
DP83867_PORT_MIRRORING_EN,
|
||||
DP83867_PORT_MIRRORING_DIS,
|
||||
};
|
||||
|
||||
struct dp83867_private {
|
||||
int rx_id_delay;
|
||||
@@ -95,6 +112,8 @@ struct dp83867_private {
|
||||
int fifo_depth;
|
||||
int io_impedance;
|
||||
bool rxctrl_strap_quirk;
|
||||
int port_mirroring;
|
||||
int clk_output_sel;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -163,6 +182,26 @@ void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
|
||||
phy_write(phydev, addr, MII_MMD_DATA, data);
|
||||
}
|
||||
|
||||
static int dp83867_config_port_mirroring(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867 =
|
||||
(struct dp83867_private *)phydev->priv;
|
||||
u16 val;
|
||||
|
||||
val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
|
||||
phydev->addr);
|
||||
|
||||
if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN)
|
||||
val |= DP83867_CFG4_PORT_MIRROR_EN;
|
||||
else
|
||||
val &= ~DP83867_CFG4_PORT_MIRROR_EN;
|
||||
|
||||
phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
|
||||
phydev->addr, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_ETH)
|
||||
/**
|
||||
* dp83867_data_init - Convenience function for setting PHY specific data
|
||||
@@ -173,6 +212,18 @@ static int dp83867_of_init(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867 = phydev->priv;
|
||||
ofnode node;
|
||||
u16 val;
|
||||
|
||||
/* Optional configuration */
|
||||
|
||||
/*
|
||||
* Keep the default value if ti,clk-output-sel is not set
|
||||
* or to high
|
||||
*/
|
||||
|
||||
dp83867->clk_output_sel =
|
||||
ofnode_read_u32_default(node, "ti,clk-output-sel",
|
||||
DP83867_CLK_O_SEL_REF_CLK);
|
||||
|
||||
node = phy_get_ofnode(phydev);
|
||||
if (!ofnode_valid(node))
|
||||
@@ -197,6 +248,23 @@ static int dp83867_of_init(struct phy_device *phydev)
|
||||
|
||||
dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth",
|
||||
-1);
|
||||
if (ofnode_read_bool(node, "enet-phy-lane-swap"))
|
||||
dp83867->port_mirroring = DP83867_PORT_MIRRORING_EN;
|
||||
|
||||
if (ofnode_read_bool(node, "enet-phy-lane-no-swap"))
|
||||
dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS;
|
||||
|
||||
|
||||
/* Clock output selection if muxing property is set */
|
||||
if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) {
|
||||
val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
|
||||
DP83867_DEVADDR, phydev->addr);
|
||||
val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
|
||||
val |= (dp83867->clk_output_sel <<
|
||||
DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
|
||||
phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
|
||||
DP83867_DEVADDR, phydev->addr, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -218,7 +286,7 @@ static int dp83867_config(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867;
|
||||
unsigned int val, delay, cfg2;
|
||||
int ret;
|
||||
int ret, bs;
|
||||
|
||||
if (!phydev->priv) {
|
||||
dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
|
||||
@@ -253,6 +321,26 @@ static int dp83867_config(struct phy_device *phydev)
|
||||
(dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
/* The code below checks if "port mirroring" N/A MODE4 has been
|
||||
* enabled during power on bootstrap.
|
||||
*
|
||||
* Such N/A mode enabled by mistake can put PHY IC in some
|
||||
* internal testing mode and disable RGMII transmission.
|
||||
*
|
||||
* In this particular case one needs to check STRAP_STS1
|
||||
* register's bit 11 (marked as RESERVED).
|
||||
*/
|
||||
|
||||
bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1,
|
||||
DP83867_DEVADDR, phydev->addr);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL);
|
||||
if (bs & DP83867_STRAP_STS1_RESERVED) {
|
||||
val &= ~DP83867_PHYCR_RESERVED_MASK;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
|
||||
val);
|
||||
}
|
||||
|
||||
} else if (phy_interface_is_sgmii(phydev)) {
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
|
||||
(BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
|
||||
@@ -315,6 +403,9 @@ static int dp83867_config(struct phy_device *phydev)
|
||||
}
|
||||
}
|
||||
|
||||
if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP)
|
||||
dp83867_config_port_mirroring(phydev);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -80,10 +80,6 @@
|
||||
|
||||
#define RTL_TIMEOUT 100000
|
||||
|
||||
#define ETH_FRAME_LEN 1514
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_ZLEN 60
|
||||
|
||||
/* PCI Tuning Parameters
|
||||
Threshold is bytes transferred to chip before transmission starts. */
|
||||
#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
|
||||
|
||||
@@ -102,10 +102,6 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
#define RTL_R16(reg) readw(ioaddr + (reg))
|
||||
#define RTL_R32(reg) readl(ioaddr + (reg))
|
||||
|
||||
#define ETH_FRAME_LEN MAX_ETH_FRAME_SIZE
|
||||
#define ETH_ALEN MAC_ADDR_LEN
|
||||
#define ETH_ZLEN 60
|
||||
|
||||
#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)(unsigned long)dev->priv, \
|
||||
(pci_addr_t)(unsigned long)a)
|
||||
#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)(unsigned long)dev->priv, \
|
||||
|
||||
@@ -10,26 +10,11 @@
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <asm/eth.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/**
|
||||
* struct eth_sandbox_priv - memory for sandbox mock driver
|
||||
*
|
||||
* fake_host_hwaddr: MAC address of mocked machine
|
||||
* fake_host_ipaddr: IP address of mocked machine
|
||||
* recv_packet_buffer: buffer of the packet returned as received
|
||||
* recv_packet_length: length of the packet returned as received
|
||||
*/
|
||||
struct eth_sandbox_priv {
|
||||
uchar fake_host_hwaddr[ARP_HLEN];
|
||||
struct in_addr fake_host_ipaddr;
|
||||
uchar *recv_packet_buffer;
|
||||
int recv_packet_length;
|
||||
};
|
||||
|
||||
static bool disabled[8] = {false};
|
||||
static bool skip_timeout;
|
||||
|
||||
/*
|
||||
@@ -40,7 +25,16 @@ static bool skip_timeout;
|
||||
*/
|
||||
void sandbox_eth_disable_response(int index, bool disable)
|
||||
{
|
||||
disabled[index] = disable;
|
||||
struct udevice *dev;
|
||||
struct eth_sandbox_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device(UCLASS_ETH, index, &dev);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
priv = dev_get_priv(dev);
|
||||
priv->disabled = disable;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -53,13 +47,288 @@ void sandbox_eth_skip_timeout(void)
|
||||
skip_timeout = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_arp_req_to_reply()
|
||||
*
|
||||
* Check for an arp request to be sent. If so, inject a reply
|
||||
*
|
||||
* returns 0 if injected, -EAGAIN if not
|
||||
*/
|
||||
int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet,
|
||||
unsigned int len)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
struct ethernet_hdr *eth = packet;
|
||||
struct arp_hdr *arp;
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct arp_hdr *arp_recv;
|
||||
|
||||
if (ntohs(eth->et_protlen) != PROT_ARP)
|
||||
return -EAGAIN;
|
||||
|
||||
arp = packet + ETHER_HDR_SIZE;
|
||||
|
||||
if (ntohs(arp->ar_op) != ARPOP_REQUEST)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Don't allow the buffer to overrun */
|
||||
if (priv->recv_packets >= PKTBUFSRX)
|
||||
return 0;
|
||||
|
||||
/* store this as the assumed IP of the fake host */
|
||||
priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
|
||||
|
||||
/* Formulate a fake response */
|
||||
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
|
||||
memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
eth_recv->et_protlen = htons(PROT_ARP);
|
||||
|
||||
arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
|
||||
arp_recv->ar_hrd = htons(ARP_ETHER);
|
||||
arp_recv->ar_pro = htons(PROT_IP);
|
||||
arp_recv->ar_hln = ARP_HLEN;
|
||||
arp_recv->ar_pln = ARP_PLEN;
|
||||
arp_recv->ar_op = htons(ARPOP_REPLY);
|
||||
memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
|
||||
memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
|
||||
net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
|
||||
|
||||
priv->recv_packet_length[priv->recv_packets] =
|
||||
ETHER_HDR_SIZE + ARP_HDR_SIZE;
|
||||
++priv->recv_packets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_ping_req_to_reply()
|
||||
*
|
||||
* Check for a ping request to be sent. If so, inject a reply
|
||||
*
|
||||
* returns 0 if injected, -EAGAIN if not
|
||||
*/
|
||||
int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
|
||||
unsigned int len)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
struct ethernet_hdr *eth = packet;
|
||||
struct ip_udp_hdr *ip;
|
||||
struct icmp_hdr *icmp;
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct ip_udp_hdr *ipr;
|
||||
struct icmp_hdr *icmpr;
|
||||
|
||||
if (ntohs(eth->et_protlen) != PROT_IP)
|
||||
return -EAGAIN;
|
||||
|
||||
ip = packet + ETHER_HDR_SIZE;
|
||||
|
||||
if (ip->ip_p != IPPROTO_ICMP)
|
||||
return -EAGAIN;
|
||||
|
||||
icmp = (struct icmp_hdr *)&ip->udp_src;
|
||||
|
||||
if (icmp->type != ICMP_ECHO_REQUEST)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Don't allow the buffer to overrun */
|
||||
if (priv->recv_packets >= PKTBUFSRX)
|
||||
return 0;
|
||||
|
||||
/* reply to the ping */
|
||||
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
|
||||
memcpy(eth_recv, packet, len);
|
||||
ipr = (void *)eth_recv + ETHER_HDR_SIZE;
|
||||
icmpr = (struct icmp_hdr *)&ipr->udp_src;
|
||||
memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
ipr->ip_sum = 0;
|
||||
ipr->ip_off = 0;
|
||||
net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
|
||||
net_write_ip((void *)&ipr->ip_src, priv->fake_host_ipaddr);
|
||||
ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
|
||||
|
||||
icmpr->type = ICMP_ECHO_REPLY;
|
||||
icmpr->checksum = 0;
|
||||
icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
|
||||
|
||||
priv->recv_packet_length[priv->recv_packets] = len;
|
||||
++priv->recv_packets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_recv_arp_req()
|
||||
*
|
||||
* Inject an ARP request for this target
|
||||
*
|
||||
* returns 0 if injected, -EOVERFLOW if not
|
||||
*/
|
||||
int sandbox_eth_recv_arp_req(struct udevice *dev)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct arp_hdr *arp_recv;
|
||||
|
||||
/* Don't allow the buffer to overrun */
|
||||
if (priv->recv_packets >= PKTBUFSRX)
|
||||
return -EOVERFLOW;
|
||||
|
||||
/* Formulate a fake request */
|
||||
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
|
||||
memcpy(eth_recv->et_dest, net_bcast_ethaddr, ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
eth_recv->et_protlen = htons(PROT_ARP);
|
||||
|
||||
arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
|
||||
arp_recv->ar_hrd = htons(ARP_ETHER);
|
||||
arp_recv->ar_pro = htons(PROT_IP);
|
||||
arp_recv->ar_hln = ARP_HLEN;
|
||||
arp_recv->ar_pln = ARP_PLEN;
|
||||
arp_recv->ar_op = htons(ARPOP_REQUEST);
|
||||
memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
|
||||
memcpy(&arp_recv->ar_tha, net_null_ethaddr, ARP_HLEN);
|
||||
net_write_ip(&arp_recv->ar_tpa, net_ip);
|
||||
|
||||
priv->recv_packet_length[priv->recv_packets] =
|
||||
ETHER_HDR_SIZE + ARP_HDR_SIZE;
|
||||
++priv->recv_packets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_recv_ping_req()
|
||||
*
|
||||
* Inject a ping request for this target
|
||||
*
|
||||
* returns 0 if injected, -EOVERFLOW if not
|
||||
*/
|
||||
int sandbox_eth_recv_ping_req(struct udevice *dev)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct ip_udp_hdr *ipr;
|
||||
struct icmp_hdr *icmpr;
|
||||
|
||||
/* Don't allow the buffer to overrun */
|
||||
if (priv->recv_packets >= PKTBUFSRX)
|
||||
return -EOVERFLOW;
|
||||
|
||||
/* Formulate a fake ping */
|
||||
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
|
||||
|
||||
memcpy(eth_recv->et_dest, net_ethaddr, ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
|
||||
eth_recv->et_protlen = htons(PROT_IP);
|
||||
|
||||
ipr = (void *)eth_recv + ETHER_HDR_SIZE;
|
||||
ipr->ip_hl_v = 0x45;
|
||||
ipr->ip_len = htons(IP_ICMP_HDR_SIZE);
|
||||
ipr->ip_off = htons(IP_FLAGS_DFRAG);
|
||||
ipr->ip_p = IPPROTO_ICMP;
|
||||
ipr->ip_sum = 0;
|
||||
net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr);
|
||||
net_write_ip(&ipr->ip_dst, net_ip);
|
||||
ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
|
||||
|
||||
icmpr = (struct icmp_hdr *)&ipr->udp_src;
|
||||
|
||||
icmpr->type = ICMP_ECHO_REQUEST;
|
||||
icmpr->code = 0;
|
||||
icmpr->checksum = 0;
|
||||
icmpr->un.echo.id = 0;
|
||||
icmpr->un.echo.sequence = htons(1);
|
||||
icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
|
||||
|
||||
priv->recv_packet_length[priv->recv_packets] =
|
||||
ETHER_HDR_SIZE + IP_ICMP_HDR_SIZE;
|
||||
++priv->recv_packets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sb_default_handler()
|
||||
*
|
||||
* perform typical responses to simple ping
|
||||
*
|
||||
* dev - device pointer
|
||||
* pkt - "sent" packet buffer
|
||||
* len - length of packet
|
||||
*/
|
||||
static int sb_default_handler(struct udevice *dev, void *packet,
|
||||
unsigned int len)
|
||||
{
|
||||
if (!sandbox_eth_arp_req_to_reply(dev, packet, len))
|
||||
return 0;
|
||||
if (!sandbox_eth_ping_req_to_reply(dev, packet, len))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_set_tx_handler()
|
||||
*
|
||||
* Set a custom response to a packet being sent through the sandbox eth test
|
||||
* driver
|
||||
*
|
||||
* index - interface to set the handler for
|
||||
* handler - The func ptr to call on send. If NULL, set to default handler
|
||||
*/
|
||||
void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct eth_sandbox_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device(UCLASS_ETH, index, &dev);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
priv = dev_get_priv(dev);
|
||||
if (handler)
|
||||
priv->tx_handler = handler;
|
||||
else
|
||||
priv->tx_handler = sb_default_handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set priv ptr
|
||||
*
|
||||
* priv - priv void ptr to store in the device
|
||||
*/
|
||||
void sandbox_eth_set_priv(int index, void *priv)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct eth_sandbox_priv *dev_priv;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device(UCLASS_ETH, index, &dev);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
dev_priv = dev_get_priv(dev);
|
||||
|
||||
dev_priv->priv = priv;
|
||||
}
|
||||
|
||||
static int sb_eth_start(struct udevice *dev)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
debug("eth_sandbox: Start\n");
|
||||
|
||||
priv->recv_packet_buffer = net_rx_packets[0];
|
||||
priv->recv_packets = 0;
|
||||
for (int i = 0; i < PKTBUFSRX; i++) {
|
||||
priv->recv_packet_buffer[i] = net_rx_packets[i];
|
||||
priv->recv_packet_length[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -67,87 +336,13 @@ static int sb_eth_start(struct udevice *dev)
|
||||
static int sb_eth_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
struct ethernet_hdr *eth = packet;
|
||||
|
||||
debug("eth_sandbox: Send packet %d\n", length);
|
||||
|
||||
if (dev->seq >= 0 && dev->seq < ARRAY_SIZE(disabled) &&
|
||||
disabled[dev->seq])
|
||||
if (priv->disabled)
|
||||
return 0;
|
||||
|
||||
if (ntohs(eth->et_protlen) == PROT_ARP) {
|
||||
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
|
||||
|
||||
if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct arp_hdr *arp_recv;
|
||||
|
||||
/* store this as the assumed IP of the fake host */
|
||||
priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
|
||||
/* Formulate a fake response */
|
||||
eth_recv = (void *)priv->recv_packet_buffer;
|
||||
memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
|
||||
ARP_HLEN);
|
||||
eth_recv->et_protlen = htons(PROT_ARP);
|
||||
|
||||
arp_recv = (void *)priv->recv_packet_buffer +
|
||||
ETHER_HDR_SIZE;
|
||||
arp_recv->ar_hrd = htons(ARP_ETHER);
|
||||
arp_recv->ar_pro = htons(PROT_IP);
|
||||
arp_recv->ar_hln = ARP_HLEN;
|
||||
arp_recv->ar_pln = ARP_PLEN;
|
||||
arp_recv->ar_op = htons(ARPOP_REPLY);
|
||||
memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr,
|
||||
ARP_HLEN);
|
||||
net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
|
||||
memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
|
||||
net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
|
||||
|
||||
priv->recv_packet_length = ETHER_HDR_SIZE +
|
||||
ARP_HDR_SIZE;
|
||||
}
|
||||
} else if (ntohs(eth->et_protlen) == PROT_IP) {
|
||||
struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE;
|
||||
|
||||
if (ip->ip_p == IPPROTO_ICMP) {
|
||||
struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src;
|
||||
|
||||
if (icmp->type == ICMP_ECHO_REQUEST) {
|
||||
struct ethernet_hdr *eth_recv;
|
||||
struct ip_udp_hdr *ipr;
|
||||
struct icmp_hdr *icmpr;
|
||||
|
||||
/* reply to the ping */
|
||||
memcpy(priv->recv_packet_buffer, packet,
|
||||
length);
|
||||
eth_recv = (void *)priv->recv_packet_buffer;
|
||||
ipr = (void *)priv->recv_packet_buffer +
|
||||
ETHER_HDR_SIZE;
|
||||
icmpr = (struct icmp_hdr *)&ipr->udp_src;
|
||||
memcpy(eth_recv->et_dest, eth->et_src,
|
||||
ARP_HLEN);
|
||||
memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
|
||||
ARP_HLEN);
|
||||
ipr->ip_sum = 0;
|
||||
ipr->ip_off = 0;
|
||||
net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
|
||||
net_write_ip((void *)&ipr->ip_src,
|
||||
priv->fake_host_ipaddr);
|
||||
ipr->ip_sum = compute_ip_checksum(ipr,
|
||||
IP_HDR_SIZE);
|
||||
|
||||
icmpr->type = ICMP_ECHO_REPLY;
|
||||
icmpr->checksum = 0;
|
||||
icmpr->checksum = compute_ip_checksum(icmpr,
|
||||
ICMP_HDR_SIZE);
|
||||
|
||||
priv->recv_packet_length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return priv->tx_handler(dev, packet, length);
|
||||
}
|
||||
|
||||
static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
@@ -159,18 +354,37 @@ static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
skip_timeout = false;
|
||||
}
|
||||
|
||||
if (priv->recv_packet_length) {
|
||||
int lcl_recv_packet_length = priv->recv_packet_length;
|
||||
if (priv->recv_packets) {
|
||||
int lcl_recv_packet_length = priv->recv_packet_length[0];
|
||||
|
||||
debug("eth_sandbox: received packet %d\n",
|
||||
priv->recv_packet_length);
|
||||
priv->recv_packet_length = 0;
|
||||
*packetp = priv->recv_packet_buffer;
|
||||
debug("eth_sandbox: received packet[%d], %d waiting\n",
|
||||
lcl_recv_packet_length, priv->recv_packets - 1);
|
||||
*packetp = priv->recv_packet_buffer[0];
|
||||
return lcl_recv_packet_length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sb_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
int i;
|
||||
|
||||
if (!priv->recv_packets)
|
||||
return 0;
|
||||
|
||||
--priv->recv_packets;
|
||||
for (i = 0; i < priv->recv_packets; i++) {
|
||||
priv->recv_packet_length[i] = priv->recv_packet_length[i + 1];
|
||||
memcpy(priv->recv_packet_buffer[i],
|
||||
priv->recv_packet_buffer[i + 1],
|
||||
priv->recv_packet_length[i + 1]);
|
||||
}
|
||||
priv->recv_packet_length[priv->recv_packets] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sb_eth_stop(struct udevice *dev)
|
||||
{
|
||||
debug("eth_sandbox: Stop\n");
|
||||
@@ -189,6 +403,7 @@ static const struct eth_ops sb_eth_ops = {
|
||||
.start = sb_eth_start,
|
||||
.send = sb_eth_send,
|
||||
.recv = sb_eth_recv,
|
||||
.free_pkt = sb_eth_free_pkt,
|
||||
.stop = sb_eth_stop,
|
||||
.write_hwaddr = sb_eth_write_hwaddr,
|
||||
};
|
||||
@@ -212,6 +427,8 @@ static int sb_eth_ofdata_to_platdata(struct udevice *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN);
|
||||
priv->disabled = false;
|
||||
priv->tx_handler = sb_default_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
#define LAN7X_MAC_RX_MAX_SIZE(mtu) \
|
||||
((mtu) << 16) /* Max frame size */
|
||||
#define LAN7X_MAC_RX_MAX_SIZE_DEFAULT \
|
||||
LAN7X_MAC_RX_MAX_SIZE(ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */)
|
||||
LAN7X_MAC_RX_MAX_SIZE(PKTSIZE_ALIGN + 4 /* VLAN */ + 4 /* CRC */)
|
||||
|
||||
/* Timeouts */
|
||||
#define USB_CTRL_SET_TIMEOUT_MS 5000
|
||||
|
||||
@@ -71,11 +71,6 @@ unsigned packet_received, packet_sent;
|
||||
* RNDIS specs are ambiguous and appear to be incomplete, and are also
|
||||
* needlessly complex. They borrow more from CDC ACM than CDC ECM.
|
||||
*/
|
||||
#define ETH_ALEN 6 /* Octets in one ethernet addr */
|
||||
#define ETH_HLEN 14 /* Total octets in header. */
|
||||
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
|
||||
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
|
||||
#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
|
||||
|
||||
#define DRIVER_DESC "Ethernet Gadget"
|
||||
/* Based on linux 2.6.27 version */
|
||||
@@ -529,7 +524,7 @@ static const struct usb_cdc_ether_desc ether_desc = {
|
||||
/* this descriptor actually adds value, surprise! */
|
||||
.iMACAddress = STRING_ETHADDR,
|
||||
.bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
|
||||
.wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN),
|
||||
.wMaxSegmentSize = __constant_cpu_to_le16(PKTSIZE_ALIGN),
|
||||
.wNumberMCFilters = __constant_cpu_to_le16(0),
|
||||
.bNumberPowerFilters = 0,
|
||||
};
|
||||
@@ -1575,7 +1570,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
req->length -= length;
|
||||
req->actual -= length;
|
||||
}
|
||||
if (req->actual < ETH_HLEN || ETH_FRAME_LEN < req->actual) {
|
||||
if (req->actual < ETH_HLEN || PKTSIZE_ALIGN < req->actual) {
|
||||
length_err:
|
||||
dev->stats.rx_errors++;
|
||||
dev->stats.rx_length_errors++;
|
||||
|
||||
@@ -35,12 +35,6 @@
|
||||
|
||||
#include "rndis.h"
|
||||
|
||||
#define ETH_ALEN 6 /* Octets in one ethernet addr */
|
||||
#define ETH_HLEN 14 /* Total octets in header. */
|
||||
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
|
||||
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
|
||||
#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
|
||||
|
||||
/*
|
||||
* The driver for your USB chip needs to support ep0 OUT to work with
|
||||
* RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
|
||||
|
||||
Reference in New Issue
Block a user