1
0
Fork 0

Merge branch 'master' of git://git.denx.de/u-boot-net

utp
Tom Rini 2016-01-28 18:42:10 -05:00
commit 82d72a1b99
32 changed files with 1934 additions and 880 deletions

View File

@ -30,17 +30,13 @@ void ft_fixup_enet_phy_connect_type(void *fdt)
int phy_node;
int i = 0;
uint32_t ph;
char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
while ((dev = eth_get_dev_by_index(i++)) != NULL) {
if (strstr(dev->name, "eTSEC1")) {
strcpy(enet, "ethernet0");
strcpy(phy, "enet0_rgmii_phy");
} else if (strstr(dev->name, "eTSEC2")) {
strcpy(enet, "ethernet1");
strcpy(phy, "enet1_rgmii_phy");
} else if (strstr(dev->name, "eTSEC3")) {
strcpy(enet, "ethernet2");
strcpy(phy, "enet2_rgmii_phy");
for (; i < ARRAY_SIZE(name); i++) {
dev = eth_get_dev_by_name(name[i]);
if (dev) {
sprintf(enet, "ethernet%d", i);
sprintf(phy, "enet%d_rgmii_phy", i);
} else {
continue;
}

View File

@ -227,9 +227,9 @@ int checkboard(void)
return 0;
}
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[4];
int num = 0;
@ -250,6 +250,7 @@ int board_eth_init(bd_t *bis)
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
#endif
#ifdef CONFIG_PCI
pci_eth_init(bis);
@ -257,7 +258,6 @@ int board_eth_init(bd_t *bis)
return 0;
}
#endif
#define USBMUX_SEL_MASK 0xc0
#define USBMUX_SEL_UART2 0xc0

View File

@ -83,9 +83,9 @@ void pci_init_board(void)
}
#endif /* ifdef CONFIG_PCI */
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[2];
int num = 0;
@ -110,10 +110,10 @@ int board_eth_init(bd_t *bis)
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
#endif
return pci_eth_init(bis);
}
#endif
#if defined(CONFIG_OF_BOARD_SETUP)
void fdt_del_sec(void *blob, int offset)

View File

@ -244,9 +244,9 @@ int board_mmc_init(bd_t *bis)
}
#endif
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[4];
int num = 0;
@ -281,10 +281,10 @@ int board_eth_init(bd_t *bis)
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
#endif
return pci_eth_init(bis);
}
#endif
#if !defined(CONFIG_QSPI_BOOT) && !defined(CONFIG_SD_BOOT_QSPI)
int config_serdes_mux(void)

View File

@ -301,9 +301,9 @@ void configure_rgmii(void)
return;
}
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[4];
int num = 0;
@ -345,10 +345,10 @@ int board_eth_init(bd_t *bis)
tsec_eth_init(bis, tsec_info, num);
configure_rgmii();
#endif
return pci_eth_init(bis);
}
#endif
#if defined(CONFIG_OF_BOARD_SETUP)
void ft_pci_setup(void *blob, bd_t *bd)

View File

@ -171,9 +171,9 @@ int board_early_init_r(void)
return 0;
}
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[4];
int num = 0;
@ -226,10 +226,10 @@ int board_eth_init(bd_t *bis)
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
#endif
return pci_eth_init(bis);
}
#endif
#if defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)

View File

@ -326,9 +326,9 @@ int checkboard(void)
return 0;
}
#ifdef CONFIG_TSEC_ENET
int board_eth_init(bd_t *bis)
{
#ifdef CONFIG_TSEC_ENET
struct fsl_pq_mdio_info mdio_info;
struct tsec_info_struct tsec_info[4];
struct cpu_type *cpu;
@ -362,10 +362,10 @@ int board_eth_init(bd_t *bis)
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
#endif
return pci_eth_init(bis);
}
#endif
#if defined(CONFIG_OF_BOARD_SETUP)
void fdt_del_flexcan(void *blob)

View File

@ -71,7 +71,7 @@ static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
"{ [help] | show | all | none | pvid } " \
" - set egress tagging mod for a port"
" - set egress tagging mode for a port"
static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
{
@ -114,6 +114,17 @@ static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
return CMD_RET_SUCCESS;
}
#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
" { [help] | show | <lag_group_no> } " \
"- get/set LAG group for a port"
static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
{
printf(ETHSW_PORT_AGGR_HELP"\n");
return CMD_RET_SUCCESS;
}
static struct keywords_to_function {
enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
int cmd_func_offset;
@ -532,6 +543,39 @@ static struct keywords_to_function {
.cmd_func_offset = offsetof(struct ethsw_command_func,
port_ingr_filt_set),
.keyword_function = NULL,
}, {
.cmd_keyword = {
ethsw_id_aggr,
ethsw_id_key_end,
},
.cmd_func_offset = -1,
.keyword_function = &ethsw_port_aggr_help_key_func,
}, {
.cmd_keyword = {
ethsw_id_aggr,
ethsw_id_help,
ethsw_id_key_end,
},
.cmd_func_offset = -1,
.keyword_function = &ethsw_port_aggr_help_key_func,
}, {
.cmd_keyword = {
ethsw_id_aggr,
ethsw_id_show,
ethsw_id_key_end,
},
.cmd_func_offset = offsetof(struct ethsw_command_func,
port_aggr_show),
.keyword_function = NULL,
}, {
.cmd_keyword = {
ethsw_id_aggr,
ethsw_id_aggr_no,
ethsw_id_key_end,
},
.cmd_func_offset = offsetof(struct ethsw_command_func,
port_aggr_set),
.keyword_function = NULL,
},
};
@ -576,6 +620,9 @@ static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct ethsw_command_def *parsed_cmd);
static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct ethsw_command_def *parsed_cmd);
/*
* Define properties for each keyword;
@ -661,6 +708,9 @@ struct keyword_def {
}, {
.keyword_name = "filtering",
.match = &keyword_match_gen,
}, {
.keyword_name = "aggr",
.match = &keyword_match_aggr,
},
};
@ -826,6 +876,28 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
return 1;
}
/* Function used to match the command's aggregation number */
static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct ethsw_command_def *parsed_cmd)
{
unsigned long val;
if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
return 0;
if (*argc_nr + 1 >= argc)
return 1;
if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
parsed_cmd->aggr_grp = val;
(*argc_nr)++;
parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
}
return 1;
}
/* Finds optional keywords and modifies *argc_va to skip them */
static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
int *argc_val)
@ -984,6 +1056,7 @@ static void command_def_init(struct ethsw_command_def *parsed_cmd)
parsed_cmd->port = ETHSW_CMD_PORT_ALL;
parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
parsed_cmd->cmd_function = NULL;
/* We initialize the MAC address with the Broadcast address */
@ -1010,7 +1083,7 @@ static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
#define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
"- enable/disable a port; show shows a port's configuration"
"- enable/disable a port; show a port's configuration"
U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
"Ethernet l2 switch commands",
@ -1024,4 +1097,5 @@ U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
ETHSW_EGR_VLAN_TAG_HELP"\n"
ETHSW_VLAN_FDB_HELP"\n"
ETHSW_PORT_INGR_FLTR_HELP"\n"
ETHSW_PORT_AGGR_HELP"\n"
);

View File

@ -24,16 +24,31 @@ Switch interfaces:
Commands Overview:
=============
Commands supported
- enable/disable a port
- check a port's link speed, duplexity and status.
- enable/disable a port or show its configuration (speed, duplexity, status, etc.)
- port statistics
- MAC learning
- add/remove FDB entries
- Port-based VLAN
- Private/Shared VLAN learning
- VLAN ingress filtering
- Port LAG
Commands syntax
ethsw port <port_nr> enable|disable - enable/disable an l2 switch port
ethsw port <port_nr> show - show an l2 switch port's configuration
ethsw [port <port_no>] { enable | disable | show } - enable/disable a port; show a port's configuration
ethsw [port <port_no>] statistics { [help] | [clear] } - show an l2 switch port's statistics
ethsw [port <port_no>] learning { [help] | show | auto | disable } - enable/disable/show learning configuration on a port
ethsw [port <port_no>] [vlan <vid>] fdb { [help] | show | flush | { add | del } <mac> } - add/delete a mac entry in FDB; use show to see FDB entries;
if [vlan <vid>] is missing, VID 1 will be used
ethsw [port <port_no>] pvid { [help] | show | <pvid> } - set/show PVID (ingress and egress VLAN tagging) for a port
ethsw [port <port_no>] vlan { [help] | show | add <vid> | del <vid> } - add a VLAN to a port (VLAN members)
ethsw [port <port_no>] untagged { [help] | show | all | none | pvid } - set egress tagging mode for a port
ethsw [port <port_no>] egress tag { [help] | show | pvid | classified } - configure VID source for egress tag.
Tag's VID could be the frame's classified VID or the PVID of the port
ethsw vlan fdb { [help] | show | shared | private } - make VLAN learning shared or private
ethsw [port <port_no>] ingress filtering { [help] | show | enable | disable } - enable/disable VLAN ingress filtering on port
ethsw [port <port_no>] aggr { [help] | show | <lag_group_no> } - get/set LAG group for a port
port_nr=0..9; use "all" for all ports
=> ethsw port all show
=> ethsw show
Port Status Link Speed Duplex
0 enabled down 10 half
1 enabled down 10 half

View File

@ -0,0 +1,64 @@
* TSEC-compatible ethernet nodes
Properties:
- compatible : Should be "fsl,tsec"
- reg : Offset and length of the register set for the device
- phy-handle : See ethernet.txt file in the same directory.
- phy-connection-type : See ethernet.txt file in the same directory. This
property is only really needed if the connection is of type "rgmii-id",
"rgmii-rxid" and "rgmii-txid" as all other connection types are detected
by hardware.
Example:
ethernet@24000 {
compatible = "fsl,tsec";
reg = <0x24000 0x1000>;
phy-handle = <&phy0>;
phy-connection-type = "sgmii";
};
Child nodes of the TSEC controller are typically the individual PHY devices
connected via the MDIO bus (sometimes the MDIO bus controller is separate).
* MDIO IO device
The MDIO is a bus to which the PHY devices are connected. For each
device that exists on this bus, a PHY node should be created.
Required properties:
- compatible : Should define the compatible device type for the
mdio. Currently supported string/device is "fsl,tsec-mdio".
- reg : Offset and length of the register set for the device
Example:
mdio@24520 {
compatible = "fsl,tsec-mdio";
reg = <0x24520 0x20>;
ethernet-phy@0 {
reg = <0>;
};
};
* TBI Internal MDIO bus
As of this writing, every tsec is associated with an internal TBI PHY.
This PHY is accessed through the local MDIO bus. These buses are defined
similarly to the mdio buses. The TBI PHYs underneath them are similar to
normal PHYs, but the reg property is considered instructive, rather than
descriptive. The reg property should be chosen so it doesn't interfere
with other PHYs on the bus. The TBI PHYs are referred to by a "tbi-handle"
property under the tsec node, which has a similar meaning of "phy-handle".
Example:
ethernet@24000 {
phy-handle = <&tbi1>;
};
mdio@24520 {
tbi1: tbi-phy@1f {
reg = <0x1f>;
};
};

View File

@ -0,0 +1,165 @@
Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY
Some boards require special tuning values, particularly when it comes to
clock delays. You can specify clock delay values by adding
micrel-specific properties to an Ethernet OF device node.
Note that these settings are applied after any phy-specific fixup from
phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c),
and therefore may overwrite them.
KSZ9021:
All skew control options are specified in picoseconds. The minimum
value is 0, the maximum value is 1800, and it is incremented by 120ps
steps.
Optional properties:
- rxc-skew-ps : Skew control of RXC pad
- rxdv-skew-ps : Skew control of RX CTL pad
- txc-skew-ps : Skew control of TXC pad
- txen-skew-ps : Skew control of TX CTL pad
- rxd0-skew-ps : Skew control of RX data 0 pad
- rxd1-skew-ps : Skew control of RX data 1 pad
- rxd2-skew-ps : Skew control of RX data 2 pad
- rxd3-skew-ps : Skew control of RX data 3 pad
- txd0-skew-ps : Skew control of TX data 0 pad
- txd1-skew-ps : Skew control of TX data 1 pad
- txd2-skew-ps : Skew control of TX data 2 pad
- txd3-skew-ps : Skew control of TX data 3 pad
KSZ9031:
All skew control options are specified in picoseconds. The minimum
value is 0, and the maximum is property-dependent. The increment
step is 60ps.
The KSZ9031 hardware supports a range of skew values from negative to
positive, where the specific range is property dependent. All values
specified in the devicetree are offset by the minimum value so they
can be represented as positive integers in the devicetree since it's
difficult to represent a negative number in the devictree.
The following 5-bit values table apply to rxc-skew-ps and txc-skew-ps.
Pad Skew Value Delay (ps) Devicetree Value
------------------------------------------------------
0_0000 -900ps 0
0_0001 -840ps 60
0_0010 -780ps 120
0_0011 -720ps 180
0_0100 -660ps 240
0_0101 -600ps 300
0_0110 -540ps 360
0_0111 -480ps 420
0_1000 -420ps 480
0_1001 -360ps 540
0_1010 -300ps 600
0_1011 -240ps 660
0_1100 -180ps 720
0_1101 -120ps 780
0_1110 -60ps 840
0_1111 0ps 900
1_0000 60ps 960
1_0001 120ps 1020
1_0010 180ps 1080
1_0011 240ps 1140
1_0100 300ps 1200
1_0101 360ps 1260
1_0110 420ps 1320
1_0111 480ps 1380
1_1000 540ps 1440
1_1001 600ps 1500
1_1010 660ps 1560
1_1011 720ps 1620
1_1100 780ps 1680
1_1101 840ps 1740
1_1110 900ps 1800
1_1111 960ps 1860
The following 4-bit values table apply to the txdX-skew-ps, rxdX-skew-ps
data pads, and the rxdv-skew-ps, txen-skew-ps control pads.
Pad Skew Value Delay (ps) Devicetree Value
------------------------------------------------------
0000 -420ps 0
0001 -360ps 60
0010 -300ps 120
0011 -240ps 180
0100 -180ps 240
0101 -120ps 300
0110 -60ps 360
0111 0ps 420
1000 60ps 480
1001 120ps 540
1010 180ps 600
1011 240ps 660
1100 300ps 720
1101 360ps 780
1110 420ps 840
1111 480ps 900
Optional properties:
Maximum value of 1860:
- rxc-skew-ps : Skew control of RX clock pad
- txc-skew-ps : Skew control of TX clock pad
Maximum value of 900:
- rxdv-skew-ps : Skew control of RX CTL pad
- txen-skew-ps : Skew control of TX CTL pad
- rxd0-skew-ps : Skew control of RX data 0 pad
- rxd1-skew-ps : Skew control of RX data 1 pad
- rxd2-skew-ps : Skew control of RX data 2 pad
- rxd3-skew-ps : Skew control of RX data 3 pad
- txd0-skew-ps : Skew control of TX data 0 pad
- txd1-skew-ps : Skew control of TX data 1 pad
- txd2-skew-ps : Skew control of TX data 2 pad
- txd3-skew-ps : Skew control of TX data 3 pad
Examples:
/* Attach to an Ethernet device with autodetected PHY */
&enet {
rxc-skew-ps = <1800>;
rxdv-skew-ps = <0>;
txc-skew-ps = <1800>;
txen-skew-ps = <0>;
status = "okay";
};
/* Attach to an explicitly-specified PHY */
mdio {
phy0: ethernet-phy@0 {
rxc-skew-ps = <1800>;
rxdv-skew-ps = <0>;
txc-skew-ps = <1800>;
txen-skew-ps = <0>;
reg = <0>;
};
};
ethernet@70000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
References
Micrel ksz9021rl/rn Data Sheet, Revision 1.2. Dated 2/13/2014.
http://www.micrel.com/_PDF/Ethernet/datasheets/ksz9021rl-rn_ds.pdf
Micrel ksz9031rnx Data Sheet, Revision 2.1. Dated 11/20/2014.
http://www.micrel.com/_PDF/Ethernet/datasheets/KSZ9031RNX.pdf
Notes:
Note that a previous version of the Micrel ksz9021rl/rn Data Sheet
was missing extended register 106 (transmit data pad skews), and
incorrectly specified the ps per step as 200ps/step instead of
120ps/step. The latest update to this document reflects the latest
revision of the Micrel specification even though usage in the kernel
still reflects that incorrect document.

View File

@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
if (phydev->speed != 1000)
conf |= MII_PORTSELECT;
else
conf &= ~MII_PORTSELECT;
if (phydev->speed == 100)
conf |= FES_100;
@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
int mask = 0xffffffff;
int mask = 0xffffffff, ret;
#ifdef CONFIG_PHY_ADDR
mask = 1 << CONFIG_PHY_ADDR;
@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
phy_connect_dev(phydev, dev);
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
if (ret)
return ret;
}
phydev->advertising = phydev->supported;
priv->phydev = phydev;
@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
priv->mac_regs_p = (struct eth_mac_regs *)iobase;
priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
dw_mdio_init(dev->name, priv->mac_regs_p);
priv->bus = miiphy_get_dev_by_name(dev->name);
@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
const fdt32_t *cell;
pdata->iobase = dev_get_addr(dev);
pdata->phy_interface = -1;
@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
return -EINVAL;
}
pdata->max_speed = 0;
cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
if (cell)
pdata->max_speed = fdt32_to_cpu(*cell);
return 0;
}

View File

@ -223,6 +223,7 @@ struct dw_eth_dev {
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
u32 interface;
u32 max_speed;
u32 tx_currdescnum;
u32 rx_currdescnum;

View File

@ -5,6 +5,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <miiphy.h>
#include <phy.h>
@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
int value;
int timeout = 1000000;
/* Put the address of the phy, and the register
* number into MIIMADD */
/* Put the address of the phy, and the register number into MIIMADD */
out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
/* Clear the command register, and wait */

View File

@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
return 0;
}
int cs4340_probe(struct phy_device *phydev)
{
phydev->flags = PHY_FLAG_BROKEN_RESET;
return 0;
}
int cs4340_startup(struct phy_device *phydev)
{
phydev->link = 1;
@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
.config = &cs4340_config,
.probe = &cs4340_probe,
.startup = &cs4340_startup,
.shutdown = &gen10g_shutdown,
};

View File

@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
.shutdown = &genphy_shutdown,
};
#define MII_KSZPHY_OMSO 0x16
#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
static int ksz_genconfig_bcastoff(struct phy_device *phydev)
{
int ret;
ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
if (ret < 0)
return ret;
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
ret | KSZPHY_OMSO_B_CAST_OFF);
if (ret < 0)
return ret;
return genphy_config(phydev);
}
static struct phy_driver KSZ8031_driver = {
.name = "Micrel KSZ8021/KSZ8031",
.uid = 0x221550,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
.config = &genphy_config,
.config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
.config = &genphy_config,
.config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
{
struct udevice *dev = phydev->dev;
struct phy_driver *drv = phydev->drv;
const int ps_to_regval = 200;
const int ps_to_regval = 60;
int val[4];
int i, changed = 0, offset, max;
u16 regval = 0;

View File

@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
int oldadv, adv;
int oldadv, adv, bmsr;
int err, changed = 0;
/* Only allow advertising what
* this PHY supports */
/* Only allow advertising what this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
oldadv = adv;
if (adv < 0)
return adv;
@ -79,30 +79,41 @@ static int genphy_config_advert(struct phy_device *phydev)
changed = 1;
}
bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
if (bmsr < 0)
return bmsr;
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
* 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
* logical 1.
*/
if (!(bmsr & BMSR_ESTATEN))
return changed;
/* Configure gigabit if it's supported */
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
oldadv = adv;
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) {
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (advertise & SUPPORTED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
if (adv != oldadv) {
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
adv);
if (err < 0)
return err;
changed = 1;
}
}
if (adv != oldadv)
changed = 1;
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
if (err < 0)
return err;
return changed;
}
@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
static int genphy_setup_forced(struct phy_device *phydev)
{
int err;
int ctl = 0;
int ctl = BMCR_ANRESTART;
phydev->pause = phydev->asym_pause = 0;
@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
if (phydev->link && mii_reg & BMSR_LSTATUS)
return 0;
if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
if ((phydev->autoneg == AUTONEG_ENABLE) &&
!(mii_reg & BMSR_ANEGCOMPLETE)) {
int i = 0;
printf("%s Waiting for PHY auto negotiation to complete",
@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
/* We're using autonegotiation */
if (phydev->supported & SUPPORTED_Autoneg) {
if (phydev->autoneg == AUTONEG_ENABLE) {
u32 lpa = 0;
int gblpa = 0;
u32 estatus = 0;
@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
int val;
u32 features;
/* For now, I'll claim that the generic driver supports
* all possible port types */
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC);
@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
features |= SUPPORTED_1000baseX_Half;
}
phydev->supported = features;
phydev->advertising = features;
phydev->supported &= features;
phydev->advertising &= features;
genphy_config_aneg(phydev);
@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
.uid = 0xffffffff,
.mask = 0xffffffff,
.name = "Generic PHY",
.features = 0,
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC,
.config = genphy_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
return 0;
}
int phy_set_supported(struct phy_device *phydev, u32 max_speed)
{
/* The default values for phydev->supported are provided by the PHY
* driver "features" member, we want to reset to sane defaults first
* before supporting higher speeds.
*/
phydev->supported &= PHY_DEFAULT_FEATURES;
switch (max_speed) {
default:
return -ENOTSUPP;
case SPEED_1000:
phydev->supported |= PHY_1000BT_FEATURES;
/* fall through */
case SPEED_100:
phydev->supported |= PHY_100BT_FEATURES;
/* fall through */
case SPEED_10:
phydev->supported |= PHY_10BT_FEATURES;
}
return 0;
}
static int phy_probe(struct phy_device *phydev)
{
int err = 0;
@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
int timeout = 500;
int devad = MDIO_DEVAD_NONE;
if (phydev->flags & PHY_FLAG_BROKEN_RESET)
return 0;
#ifdef CONFIG_PHYLIB_10G
/* If it's 10G, we need to issue reset through one of the MMDs */
if (is_10g_interface(phydev->interface)) {
@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
}
#endif
reg = phy_read(phydev, devad, MII_BMCR);
if (reg < 0) {
debug("PHY status read failed\n");
return -1;
}
reg |= BMCR_RESET;
if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
debug("PHY reset failed\n");
return -1;
}
@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
* auto-clearing). This should happen within 0.5 seconds per the
* IEEE spec.
*/
reg = phy_read(phydev, devad, MII_BMCR);
while ((reg & BMCR_RESET) && timeout--) {
reg = phy_read(phydev, devad, MII_BMCR);

View File

@ -1,18 +1,16 @@
/*
* Freescale Three Speed Ethernet Controller driver
*
* This software may be used and distributed according to the
* terms of the GNU Public License, Version 2, incorporated
* herein by reference.
*
* Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
* (C) Copyright 2003, Motorola, Inc.
* author Andy Fleming
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
@ -24,21 +22,7 @@
DECLARE_GLOBAL_DATA_PTR;
#define TX_BUF_CNT 2
static uint rx_idx; /* index of the current RX buffer */
static uint tx_idx; /* index of the current TX buffer */
#ifdef __GNUC__
static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
#else
#error "rtx must be 64-bit aligned"
#endif
static int tsec_send(struct eth_device *dev, void *packet, int length);
#ifndef CONFIG_DM_ETH
/* Default initializations for TSEC controllers. */
static struct tsec_info_struct tsec_info[] = {
@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
STD_TSEC_INFO(4), /* TSEC4 */
#endif
};
#endif /* CONFIG_DM_ETH */
#define TBIANA_SETTINGS ( \
TBIANA_ASYMMETRIC_PAUSE \
@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
/* Configure the TBI for SGMII operation */
static void tsec_configure_serdes(struct tsec_private *priv)
{
/* Access TBI PHY registers at given TSEC register offset as opposed
* to the register offset used for external PHY accesses */
/*
* Access TBI PHY registers at given TSEC register offset as opposed
* to the register offset used for external PHY accesses
*/
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
0, TBI_ANA, TBIANA_SETTINGS);
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
/* Set the appropriate hash bit for the given addr */
/* The algorithm works like so:
/*
* The algorithm works like so:
* 1) Take the Destination Address (ie the multicast address), and
* do a CRC on it (little endian), and reverse the bits of the
* result.
@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
* hash index which gaddr register to use, and the 5 other bits
* indicate which bit (assuming an IBM numbering scheme, which
* for PowerPC (tm) is usually the case) in the register holds
* the entry. */
static int
tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
* the entry.
*/
#ifndef CONFIG_DM_ETH
static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
#else
static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
}
#endif /* Multicast TFTP ? */
/* Initialized required registers to appropriate values, zeroing
/*
* Initialized required registers to appropriate values, zeroing
* those we don't care about (unless zero is bad, in which case,
* choose a more appropriate value)
*/
@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
}
/* Configure maccfg2 based on negotiated speed and duplex
/*
* Configure maccfg2 based on negotiated speed and duplex
* reported by PHY handling code
*/
static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
case 10:
maccfg2 |= MACCFG2_MII;
/* Set R100 bit in all modes although
/*
* Set R100 bit in all modes although
* it is only used in RGMII mode
*/
if (phydev->speed == 100)
@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
}
/*
* This returns the status bits of the device. The return value
* is never checked, and this is what the 8260 driver did, so we
* do the same. Presumably, this would be zero if there were no
* errors
*/
#ifndef CONFIG_DM_ETH
static int tsec_send(struct eth_device *dev, void *packet, int length)
#else
static int tsec_send(struct udevice *dev, void *packet, int length)
#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
uint16_t status;
int result = 0;
int i;
/* Find an empty buffer descriptor */
for (i = 0;
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
debug("%s: tsec: tx buffers full\n", dev->name);
return result;
}
}
out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
out_be16(&priv->txbd[priv->tx_idx].length, length);
status = in_be16(&priv->txbd[priv->tx_idx].status);
out_be16(&priv->txbd[priv->tx_idx].status, status |
(TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
/* Tell the DMA to go */
out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
/* Wait for buffer to be transmitted */
for (i = 0;
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
debug("%s: tsec: tx error\n", dev->name);
return result;
}
}
priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
return result;
}
#ifndef CONFIG_DM_ETH
static int tsec_recv(struct eth_device *dev)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
int length = in_be16(&priv->rxbd[priv->rx_idx].length);
uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
uchar *packet = net_rx_packets[priv->rx_idx];
/* Send the packet up if there were no errors */
if (!(status & RXBD_STATS))
net_process_received_packet(packet, length - 4);
else
printf("Got error %x\n", (status & RXBD_STATS));
out_be16(&priv->rxbd[priv->rx_idx].length, 0);
status = RXBD_EMPTY;
/* Set the wrap bit if this is the last element in the list */
if ((priv->rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
out_be16(&priv->rxbd[priv->rx_idx].status, status);
priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
}
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
}
return -1;
}
#else
static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
int ret = -1;
if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
int length = in_be16(&priv->rxbd[priv->rx_idx].length);
uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
uint32_t buf;
/* Send the packet up if there were no errors */
if (!(status & RXBD_STATS)) {
buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
*packetp = (uchar *)buf;
ret = length - 4;
} else {
printf("Got error %x\n", (status & RXBD_STATS));
}
}
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
}
return ret;
}
static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
uint16_t status;
out_be16(&priv->rxbd[priv->rx_idx].length, 0);
status = RXBD_EMPTY;
/* Set the wrap bit if this is the last element in the list */
if ((priv->rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
out_be16(&priv->rxbd[priv->rx_idx].status, status);
priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
return 0;
}
#endif
/* Stop the interface */
#ifndef CONFIG_DM_ETH
static void tsec_halt(struct eth_device *dev)
#else
static void tsec_halt(struct udevice *dev)
#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
!= (IEVENT_GRSC | IEVENT_GTSC))
;
clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
/* Shut down the PHY, as needed */
phy_shutdown(priv->phydev);
}
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
/*
* When MACCFG1[Rx_EN] is enabled during system boot as part
* of the eTSEC port initialization sequence,
* the eTSEC Rx logic may not be properly initialized.
*/
void redundant_init(struct eth_device *dev)
void redundant_init(struct tsec_private *priv)
{
struct tsec_private *priv = dev->priv;
struct tsec __iomem *regs = priv->regs;
uint t, count = 0;
int fail = 1;
@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
do {
uint16_t status;
tsec_send(dev, (void *)pkt, sizeof(pkt));
tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
/* Wait for buffer to be received */
for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
for (t = 0;
in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
t++) {
if (t >= 10 * TOUT_LOOP) {
printf("%s: tsec: rx error\n", dev->name);
printf("%s: tsec: rx error\n", priv->dev->name);
break;
}
}
if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
fail = 0;
out_be16(&rxbd[rx_idx].length, 0);
out_be16(&priv->rxbd[priv->rx_idx].length, 0);
status = RXBD_EMPTY;
if ((rx_idx + 1) == PKTBUFSRX)
if ((priv->rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
out_be16(&rxbd[rx_idx].status, status);
rx_idx = (rx_idx + 1) % PKTBUFSRX;
out_be16(&priv->rxbd[priv->rx_idx].status, status);
priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
}
#endif
/* Set up the buffers and their descriptors, and bring up the
/*
* Set up the buffers and their descriptors, and bring up the
* interface
*/
static void startup_tsec(struct eth_device *dev)
static void startup_tsec(struct tsec_private *priv)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
uint16_t status;
int i;
/* reset the indices to zero */
rx_idx = 0;
tx_idx = 0;
priv->rx_idx = 0;
priv->tx_idx = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
uint svr;
#endif
/* Point to the buffer descriptors */
out_be32(&regs->tbase, (u32)&txbd[0]);
out_be32(&regs->rbase, (u32)&rxbd[0]);
out_be32(&regs->tbase, (u32)&priv->txbd[0]);
out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
/* Initialize the Rx Buffer descriptors */
for (i = 0; i < PKTBUFSRX; i++) {
out_be16(&rxbd[i].status, RXBD_EMPTY);
out_be16(&rxbd[i].length, 0);
out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
out_be16(&priv->rxbd[i].length, 0);
out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
}
status = in_be16(&rxbd[PKTBUFSRX - 1].status);
out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
/* Initialize the TX Buffer Descriptors */
for (i = 0; i < TX_BUF_CNT; i++) {
out_be16(&txbd[i].status, 0);
out_be16(&txbd[i].length, 0);
out_be32(&txbd[i].bufptr, 0);
out_be16(&priv->txbd[i].status, 0);
out_be16(&priv->txbd[i].length, 0);
out_be32(&priv->txbd[i].bufptr, 0);
}
status = in_be16(&txbd[TX_BUF_CNT - 1].status);
out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
svr = get_svr();
if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
redundant_init(dev);
redundant_init(priv);
#endif
/* Enable Transmit and Receive */
setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
}
/* This returns the status bits of the device. The return value
* is never checked, and this is what the 8260 driver did, so we
* do the same. Presumably, this would be zero if there were no
* errors
*/
static int tsec_send(struct eth_device *dev, void *packet, int length)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
uint16_t status;
int result = 0;
int i;
/* Find an empty buffer descriptor */
for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
if (i >= TOUT_LOOP) {
debug("%s: tsec: tx buffers full\n", dev->name);
return result;
}
}
out_be32(&txbd[tx_idx].bufptr, (u32)packet);
out_be16(&txbd[tx_idx].length, length);
status = in_be16(&txbd[tx_idx].status);
out_be16(&txbd[tx_idx].status, status |
(TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
/* Tell the DMA to go */
out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
/* Wait for buffer to be transmitted */
for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
if (i >= TOUT_LOOP) {
debug("%s: tsec: tx error\n", dev->name);
return result;
}
}
tx_idx = (tx_idx + 1) % TX_BUF_CNT;
result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
return result;
}
static int tsec_recv(struct eth_device *dev)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
int length = in_be16(&rxbd[rx_idx].length);
uint16_t status = in_be16(&rxbd[rx_idx].status);
/* Send the packet up if there were no errors */
if (!(status & RXBD_STATS))
net_process_received_packet(net_rx_packets[rx_idx],
length - 4);
else
printf("Got error %x\n", (status & RXBD_STATS));
out_be16(&rxbd[rx_idx].length, 0);
status = RXBD_EMPTY;
/* Set the wrap bit if this is the last element in the list */
if ((rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
out_be16(&rxbd[rx_idx].status, status);
rx_idx = (rx_idx + 1) % PKTBUFSRX;
}
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
}
return -1;
}
/* Stop the interface */
static void tsec_halt(struct eth_device *dev)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
!= (IEVENT_GRSC | IEVENT_GTSC))
;
clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
/* Shut down the PHY, as needed */
phy_shutdown(priv->phydev);
}
/* Initializes data structures and registers for the controller,
* and brings the interface up. Returns the link status, meaning
/*
* Initializes data structures and registers for the controller,
* and brings the interface up. Returns the link status, meaning
* that it returns success if the link is up, failure otherwise.
* This allows u-boot to find the first active controller.
* This allows U-Boot to find the first active controller.
*/
#ifndef CONFIG_DM_ETH
static int tsec_init(struct eth_device *dev, bd_t * bd)
#else
static int tsec_init(struct udevice *dev)
#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
#ifdef CONFIG_DM_ETH
struct eth_pdata *pdata = dev_get_platdata(dev);
#endif
struct tsec __iomem *regs = priv->regs;
u32 tempval;
int ret;
@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
/* Init ECNTRL */
out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
/* Copy the station address into the address registers.
/*
* Copy the station address into the address registers.
* For a station address of 0x12345678ABCD in transmission
* order (BE), MACnADDR1 is set to 0xCDAB7856 and
* MACnADDR2 is set to 0x34120000.
*/
#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
(dev->enetaddr[3] << 8) | dev->enetaddr[2];
#else
tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
(pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
#endif
out_be32(&regs->macstnaddr1, tempval);
#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
#else
tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
#endif
out_be32(&regs->macstnaddr2, tempval);
@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
init_registers(regs);
/* Ready the device for tx/rx */
startup_tsec(dev);
startup_tsec(priv);
/* Start up the PHY */
ret = phy_startup(priv->phydev);
@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
* be set by the platform code.
*/
if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
(interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
(interface == PHY_INTERFACE_MODE_RGMII_RXID))
(interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
(interface == PHY_INTERFACE_MODE_RGMII_RXID))
return interface;
return PHY_INTERFACE_MODE_RGMII;
@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
return PHY_INTERFACE_MODE_MII;
}
/* Discover which PHY is attached to the device, and configure it
/*
* Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0
* (failure). Otherwise, return 1
*/
static int init_phy(struct eth_device *dev)
static int init_phy(struct tsec_private *priv)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct phy_device *phydev;
struct tsec __iomem *regs = priv->regs;
u32 supported = (SUPPORTED_10baseT_Half |
@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
supported |= SUPPORTED_1000baseT_Full;
/* Assign a Physical address to the TBI */
out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
out_be32(&regs->tbipa, priv->tbiaddr);
priv->interface = tsec_get_interface(priv);
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
tsec_configure_serdes(priv);
phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
priv->interface);
if (!phydev)
return 0;
@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
return 1;
}
/* Initialize device structure. Returns success if PHY
#ifndef CONFIG_DM_ETH
/*
* Initialize device structure. Returns success if PHY
* initialization succeeded (i.e. if it recognizes the PHY)
*/
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
priv->phyaddr = tsec_info->phyaddr;
priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
priv->flags = tsec_info->flags;
strcpy(dev->name, tsec_info->devname);
priv->interface = tsec_info->interface;
priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
priv->dev = dev;
dev->iobase = 0;
dev->priv = priv;
dev->init = tsec_init;
@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
dev->mcast = tsec_mcast_addr;
#endif
/* Tell u-boot to get the addr from the env */
/* Tell U-Boot to get the addr from the env */
for (i = 0; i < 6; i++)
dev->enetaddr[i] = 0;
@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
/* Try to initialize PHY here, and return */
return init_phy(dev);
return init_phy(priv);
}
/*
@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
}
#else /* CONFIG_DM_ETH */
int tsec_probe(struct udevice *dev)
{
struct tsec_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
struct fsl_pq_mdio_info mdio_info;
int offset = 0;
int reg;
const char *phy_mode;
int ret;
pdata->iobase = (phys_addr_t)dev_get_addr(dev);
priv->regs = (struct tsec *)pdata->iobase;
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
"phy-handle");
if (offset > 0) {
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
priv->phyaddr = reg;
} else {
debug("phy-handle does not exist under tsec %s\n", dev->name);
return -ENOENT;
}
offset = fdt_parent_offset(gd->fdt_blob, offset);
if (offset > 0) {
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
} else {
debug("No parent node for PHY?\n");
return -ENOENT;
}
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
"tbi-handle");
if (offset > 0) {
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
CONFIG_SYS_TBIPA_VALUE);
priv->tbiaddr = reg;
} else {
priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
}
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
"phy-connection-type", NULL);
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
debug("Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
priv->interface = pdata->phy_interface;
/* Initialize flags */
priv->flags = TSEC_GIGABIT;
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
priv->flags |= TSEC_SGMII;
mdio_info.regs = priv->phyregs_sgmii;
mdio_info.name = (char *)dev->name;
ret = fsl_pq_mdio_init(NULL, &mdio_info);
if (ret)
return ret;
/* Reset the MAC */
setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
priv->dev = dev;
priv->bus = miiphy_get_dev_by_name(dev->name);
/* Try to initialize PHY here, and return */
return !init_phy(priv);
}
int tsec_remove(struct udevice *dev)
{
struct tsec_private *priv = dev->priv;
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
return 0;
}
static const struct eth_ops tsec_ops = {
.start = tsec_init,
.send = tsec_send,
.recv = tsec_recv,
.free_pkt = tsec_free_pkt,
.stop = tsec_halt,
#ifdef CONFIG_MCAST_TFTP
.mcast = tsec_mcast_addr,
#endif
};
static const struct udevice_id tsec_ids[] = {
{ .compatible = "fsl,tsec" },
{ }
};
U_BOOT_DRIVER(eth_tsec) = {
.name = "tsec",
.id = UCLASS_ETH,
.of_match = tsec_ids,
.probe = tsec_probe,
.remove = tsec_remove,
.ops = &tsec_ops,
.priv_auto_alloc_size = sizeof(struct tsec_private),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
#endif /* CONFIG_DM_ETH */

View File

@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
}
enum aggr_code_mode {
AGGR_CODE_RAND = 0,
AGGR_CODE_ALL, /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
};
/* Set aggregation code generation mode */
static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
{
int rc;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
switch (ac) {
case AGGR_CODE_RAND:
clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
VSC9953_AC_IP6_LBL_ENA |
VSC9953_AC_IP6_TCPUDP_ENA |
VSC9953_AC_IP4_SIPDIP_ENA |
VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
rc = 0;
break;
case AGGR_CODE_ALL:
clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
VSC9953_AC_IP6_LBL_ENA |
VSC9953_AC_IP6_TCPUDP_ENA |
VSC9953_AC_IP4_SIPDIP_ENA |
VSC9953_AC_IP4_TCPUDP_ENA);
rc = 0;
break;
default:
/* unknown mode for aggregation code */
rc = -EINVAL;
}
return rc;
}
/* Egress untag modes of a VSC9953 port */
enum egress_untag_mode {
EGRESS_UNTAG_ALL = 0,
@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
vsc9953_port_vlan_egr_untag_set(i, mode);
}
static int vsc9953_autoage_time_set(int age_period)
{
u32 autoage;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
return -EINVAL;
autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
VSC9953_AUTOAGE_PERIOD_MASK,
age_period);
out_le32(&l2ana_reg->ana.auto_age, autoage);
return 0;
}
#ifdef CONFIG_CMD_ETHSW
/* Enable/disable status of a VSC9953 port */
@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
return !!(val & (1 << port_no));
}
/* Get the aggregation group of a port */
static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
{
u32 val;
struct vsc9953_analyzer *l2ana_reg;
if (!VSC9953_PORT_CHECK(port_no))
return -EINVAL;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
val = in_le32(&l2ana_reg->port[port_no].port_cfg);
*aggr_grp = bitfield_extract_by_mask(val,
VSC9953_PORT_CFG_PORTID_MASK);
return 0;
}
static void vsc9953_aggr_grp_members_get(int aggr_grp,
u8 aggr_membr[VSC9953_MAX_PORTS])
{
int port_no;
int aggr_membr_grp;
for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
aggr_membr[port_no] = 0;
if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
continue;
if (aggr_grp == aggr_membr_grp)
aggr_membr[port_no] = 1;
}
}
static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
u32 membr_bitfld_new)
{
int i;
u32 pgid;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
/*
* NOTE: Only the unicast destination masks are updated, since
* we do not support for now Layer-2 multicast entries
*/
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
if (i == port_no) {
clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
VSC9953_PGID_PORT_MASK,
membr_bitfld_new);
continue;
}
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
pgid &= ~((u32)(1 << port_no));
if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
pgid |= ((u32)(1 << port_no));
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
}
}
static void vsc9953_update_source_members_masks(int port_no,
u32 membr_bitfld_old,
u32 membr_bitfld_new)
{
int i;
int index;
u32 pgid;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
index = PGID_SRC_START + i;
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
if (i == port_no) {
pgid = (pgid | VSC9953_PGID_PORT_MASK) &
~membr_bitfld_new;
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
pgid);
continue;
}
if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
pgid |= (u32)(1 << port_no);
if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
pgid &= ~(u32)(1 << port_no);
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
}
}
static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
{
if (!member_bitfield)
return 0;
if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
aggr_mask = 1;
else
aggr_mask <<= 1;
while (!(aggr_mask & member_bitfield)) {
aggr_mask <<= 1;
if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
aggr_mask = 1;
}
return aggr_mask;
}
static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
u32 membr_bitfld_new)
{
int i;
u32 pgid;
u32 aggr_mask_old = 0;
u32 aggr_mask_new = 0;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
/* Update all the PGID aggregation masks */
for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
membr_bitfld_old);
pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
membr_bitfld_new);
pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
}
}
static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
{
int i;
u32 member_bitfield = 0;
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
if (member[i])
member_bitfield |= 1 << i;
}
member_bitfield &= VSC9953_PGID_PORT_MASK;
return member_bitfield;
}
static void vsc9953_update_members_masks(int port_no,
u8 member_old[VSC9953_MAX_PORTS],
u8 member_new[VSC9953_MAX_PORTS])
{
u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
membr_bitfld_new);
vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
membr_bitfld_new);
vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
membr_bitfld_new);
}
/* Set the aggregation group of a port */
static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
{
u8 aggr_membr_old[VSC9953_MAX_PORTS];
u8 aggr_membr_new[VSC9953_MAX_PORTS];
int rc;
int aggr_grp_old;
u32 val;
struct vsc9953_analyzer *l2ana_reg;
if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
return -EINVAL;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
if (rc)
return rc;
/* get all the members of the old aggregation group */
vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
/* get all the members of the same aggregation group */
vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
/* add current port as member to the new aggregation group */
aggr_membr_old[port_no] = 0;
aggr_membr_new[port_no] = 1;
/* update masks */
vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
/* Change logical port number */
val = in_le32(&l2ana_reg->port[port_no].port_cfg);
val = bitfield_replace_by_mask(val,
VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
out_le32(&l2ana_reg->port[port_no].port_cfg, val);
return 0;
}
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
return CMD_RET_SUCCESS;
}
static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
int aggr_grp;
if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
printf("Invalid port number: %d\n", parsed_cmd->port);
return CMD_RET_FAILURE;
}
if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
return CMD_RET_FAILURE;
printf("%7s %10s\n", "Port", "Aggr grp");
printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
} else {
printf("%7s %10s\n", "Port", "Aggr grp");
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
continue;
printf("%7d %10d\n", i, aggr_grp);
}
}
return CMD_RET_SUCCESS;
}
static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
/* Aggregation group number should be set in parsed_cmd->aggr_grp */
if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
printf("Please set an aggregation group value\n");
return CMD_RET_FAILURE;
}
if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
printf("Invalid aggregation group number: %d\n",
parsed_cmd->aggr_grp);
return CMD_RET_FAILURE;
}
if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
printf("Invalid port number: %d\n", parsed_cmd->port);
return CMD_RET_FAILURE;
}
if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
parsed_cmd->aggr_grp)) {
printf("Port %d: failed to set aggr group %d\n",
parsed_cmd->port, parsed_cmd->aggr_grp);
}
} else {
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
if (vsc9953_port_aggr_grp_set(i,
parsed_cmd->aggr_grp)) {
printf("Port %d: failed to set aggr group %d\n",
i, parsed_cmd->aggr_grp);
}
}
}
return CMD_RET_SUCCESS;
}
static struct ethsw_command_func vsc9953_cmd_func = {
.ethsw_name = "L2 Switch VSC9953",
.port_enable = &vsc9953_port_status_key_func,
@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
.port_aggr_show = &vsc9953_port_aggr_show_key_func,
.port_aggr_set = &vsc9953_port_aggr_set_key_func,
};
#endif /* CONFIG_CMD_ETHSW */
@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
{
int i;
if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
debug("VSC9953: failed to set AGE time to %d\n",
VSC9953_DEFAULT_AGE_TIME);
for (i = 0; i < VSC9953_MAX_VLAN; i++)
vsc9953_vlan_table_membership_all_set(i, 0);
vsc9953_port_all_vlan_aware_set(1);
@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
vsc9953_vlan_table_membership_all_set(1, 1);
vsc9953_vlan_ingr_fltr_learn_drop(1);
vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
debug("VSC9953: failed to set default aggregation code mode\n");
}
void vsc9953_init(bd_t *bis)

View File

@ -465,7 +465,11 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return err;
}
tegra_pcie_board_init();
err = tegra_pcie_board_init();
if (err < 0) {
error("tegra_pcie_board_init() failed: err=%d", err);
return err;
}
pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
if (pcie->phy) {

View File

@ -12,6 +12,7 @@
#define ETHSW_MAX_CMD_PARAMS 20
#define ETHSW_CMD_PORT_ALL -1
#define ETHSW_CMD_VLAN_ALL -1
#define ETHSW_CMD_AGGR_GRP_NONE -1
/* IDs used to track keywords in a command */
enum ethsw_keyword_id {
@ -41,6 +42,7 @@ enum ethsw_keyword_id {
ethsw_id_private,
ethsw_id_ingress,
ethsw_id_filtering,
ethsw_id_aggr,
ethsw_id_count, /* keep last */
};
@ -50,6 +52,7 @@ enum ethsw_keyword_opt_id {
ethsw_id_pvid_no,
ethsw_id_add_del_no,
ethsw_id_add_del_mac,
ethsw_id_aggr_no,
ethsw_id_count_all, /* keep last */
};
@ -58,6 +61,7 @@ struct ethsw_command_def {
int cmd_keywords_nr;
int port;
int vid;
int aggr_grp;
uchar ethaddr[6];
int (*cmd_function)(struct ethsw_command_def *parsed_cmd);
};
@ -88,6 +92,8 @@ struct ethsw_command_func {
int (*vlan_learn_set)(struct ethsw_command_def *parsed_cmd);
int (*port_ingr_filt_show)(struct ethsw_command_def *parsed_cmd);
int (*port_ingr_filt_set)(struct ethsw_command_def *parsed_cmd);
int (*port_aggr_show)(struct ethsw_command_def *parsed_cmd);
int (*port_aggr_set)(struct ethsw_command_def *parsed_cmd);
};
int ethsw_define_functions(const struct ethsw_command_func *cmd_func);

View File

@ -5,6 +5,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __FSL_PHY_H__
#define __FSL_PHY_H__
@ -27,9 +28,9 @@ int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc);
#define PHY_EXT_PAGE_ACCESS 0x1f
/* MII Management Configuration Register */
#define MIIMCFG_RESET_MGMT 0x80000000
#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007
#define MIIMCFG_INIT_VALUE 0x00000003
#define MIIMCFG_RESET_MGMT 0x80000000
#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007
#define MIIMCFG_INIT_VALUE 0x00000003
/* MII Management Command Register */
#define MIIMCOM_READ_CYCLE 0x00000001

View File

@ -86,11 +86,13 @@ enum eth_state_t {
* @iobase: The base address of the hardware registers
* @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
* @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
* @max_speed: Maximum speed of Ethernet connection supported by MAC
*/
struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
int phy_interface;
int max_speed;
};
enum eth_recv_flags {

View File

@ -17,18 +17,28 @@
#define PHY_MAX_ADDR 32
#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | \
SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg | \
#define PHY_FLAG_BROKEN_RESET (1 << 0) /* soft reset not supported */
#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
SUPPORTED_TP | \
SUPPORTED_MII)
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
SUPPORTED_1000baseT_Half | \
#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \
SUPPORTED_10baseT_Full)
#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \
SUPPORTED_100baseT_Full)
#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \
SUPPORTED_1000baseT_Full)
#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \
PHY_100BT_FEATURES | \
PHY_DEFAULT_FEATURES)
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
PHY_1000BT_FEATURES)
#define PHY_10G_FEATURES (PHY_GBIT_FEATURES | \
SUPPORTED_10000baseT_Full)
@ -226,6 +236,7 @@ int phy_startup(struct phy_device *phydev);
int phy_config(struct phy_device *phydev);
int phy_shutdown(struct phy_device *phydev);
int phy_register(struct phy_driver *drv);
int phy_set_supported(struct phy_device *phydev, u32 max_speed);
int genphy_config_aneg(struct phy_device *phydev);
int genphy_restart_aneg(struct phy_device *phydev);
int genphy_update_link(struct phy_device *phydev);

View File

@ -3,15 +3,12 @@
*
* Driver for the Motorola Triple Speed Ethernet Controller
*
* This software may be used and distributed according to the
* terms of the GNU Public License, Version 2, incorporated
* herein by reference.
*
* Copyright 2004, 2007, 2009, 2011, 2013 Freescale Semiconductor, Inc.
* (C) Copyright 2003, Motorola, Inc.
* maintained by Xianghua Xiao (x.xiao@motorola.com)
* author Andy Fleming
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __TSEC_H
@ -21,6 +18,8 @@
#include <config.h>
#include <phy.h>
#ifndef CONFIG_DM_ETH
#ifdef CONFIG_LS102XA
#define TSEC_SIZE 0x40000
#define TSEC_MDIO_OFFSET 0x40000
@ -67,11 +66,13 @@
x.mii_devname = DEFAULT_MII_NAME;\
}
#define MAC_ADDR_LEN 6
#endif /* CONFIG_DM_ETH */
#define MAC_ADDR_LEN 6
/* #define TSEC_TIMEOUT 1000000 */
#define TSEC_TIMEOUT 1000
#define TOUT_LOOP 1000000
#define TSEC_TIMEOUT 1000
#define TOUT_LOOP 1000000
/* TBI register addresses */
#define TBI_CR 0x00
@ -83,8 +84,8 @@
/* TBI MDIO register bit fields*/
#define TBICON_CLK_SELECT 0x0020
#define TBIANA_ASYMMETRIC_PAUSE 0x0100
#define TBIANA_SYMMETRIC_PAUSE 0x0080
#define TBIANA_ASYMMETRIC_PAUSE 0x0100
#define TBIANA_SYMMETRIC_PAUSE 0x0080
#define TBIANA_HALF_DUPLEX 0x0040
#define TBIANA_FULL_DUPLEX 0x0020
#define TBICR_PHY_RESET 0x8000
@ -93,13 +94,12 @@
#define TBICR_FULL_DUPLEX 0x0100
#define TBICR_SPEED1_SET 0x0040
/* MAC register bits */
#define MACCFG1_SOFT_RESET 0x80000000
#define MACCFG1_RESET_RX_MC 0x00080000
#define MACCFG1_RESET_TX_MC 0x00040000
#define MACCFG1_RESET_RX_FUN 0x00020000
#define MACCFG1_RESET_TX_FUN 0x00010000
#define MACCFG1_RESET_TX_FUN 0x00010000
#define MACCFG1_LOOPBACK 0x00000100
#define MACCFG1_RX_FLOW 0x00000020
#define MACCFG1_TX_FLOW 0x00000010
@ -122,7 +122,7 @@
#define ECNTRL_SGMII_MODE 0x00000002
#ifndef CONFIG_SYS_TBIPA_VALUE
#define CONFIG_SYS_TBIPA_VALUE 0x1f
# define CONFIG_SYS_TBIPA_VALUE 0x1f
#endif
#define MRBLR_INIT_SETTINGS PKTSIZE_ALIGN
@ -137,7 +137,6 @@
#define TSTAT_CLEAR_THALT 0x80000000
#define RSTAT_CLEAR_RHALT 0x00800000
#define IEVENT_INIT_CLEAR 0xffffffff
#define IEVENT_BABR 0x80000000
#define IEVENT_RXC 0x40000000
@ -164,11 +163,9 @@
#define IMASK_TXFEN 0x00100000
#define IMASK_RXFEN0 0x00000080
/* Default Attribute fields */
#define ATTR_INIT_SETTINGS 0x000000c0
#define ATTRELI_INIT_SETTINGS 0x00000000
#define ATTR_INIT_SETTINGS 0x000000c0
#define ATTRELI_INIT_SETTINGS 0x00000000
/* TxBD status field bits */
#define TXBD_READY 0x8000
@ -181,7 +178,7 @@
#define TXBD_HUGEFRAME 0x0080
#define TXBD_LATECOLLISION 0x0080
#define TXBD_RETRYLIMIT 0x0040
#define TXBD_RETRYCOUNTMASK 0x003c
#define TXBD_RETRYCOUNTMASK 0x003c
#define TXBD_UNDERRUN 0x0002
#define TXBD_STATS 0x03ff
@ -204,15 +201,15 @@
#define RXBD_STATS 0x003f
struct txbd8 {
uint16_t status; /* Status Fields */
uint16_t length; /* Buffer length */
uint32_t bufptr; /* Buffer Pointer */
uint16_t status; /* Status Fields */
uint16_t length; /* Buffer length */
uint32_t bufptr; /* Buffer Pointer */
};
struct rxbd8 {
uint16_t status; /* Status Fields */
uint16_t length; /* Buffer Length */
uint32_t bufptr; /* Buffer Pointer */
uint16_t status; /* Status Fields */
uint16_t length; /* Buffer Length */
uint32_t bufptr; /* Buffer Pointer */
};
struct tsec_rmon_mib {
@ -336,15 +333,15 @@ struct tsec {
u32 rbdlen; /* RxBD Data Length */
u32 res310[4];
u32 res320;
u32 crbptr; /* Current Receive Buffer Pointer */
u32 crbptr; /* Current Receive Buffer Pointer */
u32 res328[6];
u32 mrblr; /* Maximum Receive Buffer Length */
u32 mrblr; /* Maximum Receive Buffer Length */
u32 res344[16];
u32 rbptr; /* RxBD Pointer */
u32 rbptr; /* RxBD Pointer */
u32 res388[30];
/* (0x2_n400) */
u32 res400;
u32 rbase; /* RxBD Base Address */
u32 rbase; /* RxBD Base Address */
u32 res408[62];
/* MAC Registers (0x2_n500) */
@ -388,21 +385,33 @@ struct tsec {
u32 resc00[256];
};
#define TSEC_GIGABIT (1 << 0)
#define TSEC_GIGABIT (1 << 0)
/* These flags currently only have meaning if we're using the eTSEC */
#define TSEC_REDUCED (1 << 1) /* MAC-PHY interface uses RGMII */
#define TSEC_SGMII (1 << 2) /* MAC-PHY interface uses SGMII */
#define TX_BUF_CNT 2
struct tsec_private {
struct txbd8 __iomem txbd[TX_BUF_CNT];
struct rxbd8 __iomem rxbd[PKTBUFSRX];
struct tsec __iomem *regs;
struct tsec_mii_mng __iomem *phyregs_sgmii;
struct phy_device *phydev;
phy_interface_t interface;
struct mii_dev *bus;
uint phyaddr;
uint tbiaddr;
char mii_devname[16];
u32 flags;
uint rx_idx; /* index of the current RX buffer */
uint tx_idx; /* index of the current TX buffer */
#ifndef CONFIG_DM_ETH
struct eth_device *dev;
#else
struct udevice *dev;
#endif
};
struct tsec_info_struct {
@ -415,7 +424,9 @@ struct tsec_info_struct {
u32 flags;
};
#ifndef CONFIG_DM_ETH
int tsec_standard_init(bd_t *bis);
int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num);
#endif
#endif /* __TSEC_H */

View File

@ -126,6 +126,7 @@
#define VSC9953_PORT_CFG_LEARN_AUTO 0x00000100
#define VSC9953_PORT_CFG_LEARN_CPU 0x00000200
#define VSC9953_PORT_CFG_LEARN_DROP 0x00000400
#define VSC9953_PORT_CFG_PORTID_MASK 0x0000003c
/* Macros for vsc9953_qsys_sys.switch_port_mode register */
#define VSC9953_PORT_ENA 0x00002000
@ -136,6 +137,9 @@
/* Macros for vsc9953_ana_ana.adv_learn register */
#define VSC9953_VLAN_CHK 0x00000400
/* Macros for vsc9953_ana_ana.auto_age register */
#define VSC9953_AUTOAGE_PERIOD_MASK 0x001ffffe
/* Macros for vsc9953_rew_port.port_tag_cfg register */
#define VSC9953_TAG_CFG_MASK 0x00000180
#define VSC9953_TAG_CFG_NONE 0x00000000
@ -153,6 +157,19 @@
/* Macros for vsc9953_ana_ana_tables.mach_data register */
#define VSC9953_MACHDATA_VID_MASK 0x1fff0000
/* Macros for vsc9953_ana_common.aggr_cfg register */
#define VSC9953_AC_RND_ENA 0x00000080
#define VSC9953_AC_DMAC_ENA 0x00000040
#define VSC9953_AC_SMAC_ENA 0x00000020
#define VSC9953_AC_IP6_LBL_ENA 0x00000010
#define VSC9953_AC_IP6_TCPUDP_ENA 0x00000008
#define VSC9953_AC_IP4_SIPDIP_ENA 0x00000004
#define VSC9953_AC_IP4_TCPUDP_ENA 0x00000002
#define VSC9953_AC_MASK 0x000000fe
/* Macros for vsc9953_ana_pgid.port_grp_id[] registers */
#define VSC9953_PGID_PORT_MASK 0x000003ff
#define VSC9953_MAX_PORTS 10
#define VSC9953_PORT_CHECK(port) \
(((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
@ -164,6 +181,7 @@
#define VSC9953_MAX_VLAN 4096
#define VSC9953_VLAN_CHECK(vid) \
(((vid) < 0 || (vid) >= VSC9953_MAX_VLAN) ? 0 : 1)
#define VSC9953_DEFAULT_AGE_TIME 300
#define DEFAULT_VSC9953_MDIO_NAME "VSC9953_MDIO0"
@ -235,6 +253,10 @@ struct vsc9953_ana_ana {
u32 port_mode[12];
};
#define PGID_DST_START 0
#define PGID_AGGR_START 64
#define PGID_SRC_START 80
struct vsc9953_ana_pgid {
u32 port_grp_id[91];
};
@ -269,7 +291,7 @@ struct vsc9953_analyzer {
struct vsc9953_ana_ana_tables ana_tables;
u32 reserved2[14];
struct vsc9953_ana_ana ana;
u32 reserved3[22];
u32 reserved3[21];
struct vsc9953_ana_pgid port_id_tbl;
u32 reserved4[549];
struct vsc9953_ana_pfc pfc[10];

View File

@ -12,7 +12,12 @@ obj-$(CONFIG_CMD_NET) += arp.o
obj-$(CONFIG_CMD_NET) += bootp.o
obj-$(CONFIG_CMD_CDP) += cdp.o
obj-$(CONFIG_CMD_DNS) += dns.o
obj-$(CONFIG_CMD_NET) += eth.o
ifdef CONFIG_DM_ETH
obj-$(CONFIG_CMD_NET) += eth-uclass.o
else
obj-$(CONFIG_CMD_NET) += eth_legacy.o
endif
obj-$(CONFIG_CMD_NET) += eth_common.o
obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
obj-$(CONFIG_CMD_NET) += net.o
obj-$(CONFIG_CMD_NFS) += nfs.o

View File

@ -949,6 +949,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
net_write_ip(&bp->bp_giaddr, zero_ip);
memcpy(bp->bp_chaddr, net_ethaddr, 6);
copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
/*
* ID is the id of the OFFER packet
@ -995,6 +996,9 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
"%d\n", src, dest, len, dhcp_state);
if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
return;
switch (dhcp_state) {
case SELECTING:
/*

View File

@ -7,113 +7,13 @@
*/
#include <common.h>
#include <command.h>
#include <dm.h>
#include <environment.h>
#include <net.h>
#include <miiphy.h>
#include <phy.h>
#include <asm/errno.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
#include "eth_internal.h"
DECLARE_GLOBAL_DATA_PTR;
void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
{
char *end;
int i;
for (i = 0; i < 6; ++i) {
enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
if (addr)
addr = (*end) ? end + 1 : end;
}
}
int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
{
eth_parse_enetaddr(getenv(name), enetaddr);
return is_valid_ethaddr(enetaddr);
}
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
{
char buf[20];
sprintf(buf, "%pM", enetaddr);
return setenv(name, buf);
}
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr)
{
char enetvar[32];
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
return eth_getenv_enetaddr(enetvar, enetaddr);
}
static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr)
{
char enetvar[32];
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
return eth_setenv_enetaddr(enetvar, enetaddr);
}
static int eth_mac_skip(int index)
{
char enetvar[15];
char *skip_state;
sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
skip_state = getenv(enetvar);
return skip_state != NULL;
}
static void eth_current_changed(void);
/*
* CPU and board-specific Ethernet initializations. Aliased function
* signals caller to move on
*/
static int __def_eth_init(bd_t *bis)
{
return -1;
}
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
static void eth_common_init(void)
{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
miiphy_init();
#endif
#ifdef CONFIG_PHYLIB
phy_init();
#endif
/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
*/
if (board_eth_init != __def_eth_init) {
if (board_eth_init(gd->bd) < 0)
printf("Board Net Initialization Failed\n");
} else if (cpu_eth_init != __def_eth_init) {
if (cpu_eth_init(gd->bd) < 0)
printf("CPU Net Initialization Failed\n");
} else {
#ifndef CONFIG_DM_ETH
printf("Net Initialization Skipped\n");
#endif
}
}
#ifdef CONFIG_DM_ETH
/**
* struct eth_device_priv - private structure for each Ethernet device
*
@ -144,7 +44,7 @@ static struct eth_uclass_priv *eth_get_uclass_priv(void)
return uc->priv;
}
static void eth_set_current_to_next(void)
void eth_set_current_to_next(void)
{
struct eth_uclass_priv *uc_priv;
@ -177,7 +77,7 @@ struct udevice *eth_get_dev(void)
* In case it was not probed, we will attempt to do so.
* dev may be NULL to unset the active device.
*/
static void eth_set_dev(struct udevice *dev)
void eth_set_dev(struct udevice *dev)
{
if (dev && !device_active(dev)) {
eth_errno = device_probe(dev);
@ -647,493 +547,3 @@ UCLASS_DRIVER(eth) = {
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
};
#endif /* #ifdef CONFIG_DM_ETH */
#ifndef CONFIG_DM_ETH
#ifdef CONFIG_API
static struct {
uchar data[PKTSIZE];
int length;
} eth_rcv_bufs[PKTBUFSRX];
static unsigned int eth_rcv_current, eth_rcv_last;
#endif
static struct eth_device *eth_devices;
struct eth_device *eth_current;
static void eth_set_current_to_next(void)
{
eth_current = eth_current->next;
}
static void eth_set_dev(struct eth_device *dev)
{
eth_current = dev;
}
struct eth_device *eth_get_dev_by_name(const char *devname)
{
struct eth_device *dev, *target_dev;
BUG_ON(devname == NULL);
if (!eth_devices)
return NULL;
dev = eth_devices;
target_dev = NULL;
do {
if (strcmp(devname, dev->name) == 0) {
target_dev = dev;
break;
}
dev = dev->next;
} while (dev != eth_devices);
return target_dev;
}
struct eth_device *eth_get_dev_by_index(int index)
{
struct eth_device *dev, *target_dev;
if (!eth_devices)
return NULL;
dev = eth_devices;
target_dev = NULL;
do {
if (dev->index == index) {
target_dev = dev;
break;
}
dev = dev->next;
} while (dev != eth_devices);
return target_dev;
}
int eth_get_dev_index(void)
{
if (!eth_current)
return -1;
return eth_current->index;
}
static int on_ethaddr(const char *name, const char *value, enum env_op op,
int flags)
{
int index;
struct eth_device *dev;
if (!eth_devices)
return 0;
/* look for an index after "eth" */
index = simple_strtoul(name + 3, NULL, 10);
dev = eth_devices;
do {
if (dev->index == index) {
switch (op) {
case env_op_create:
case env_op_overwrite:
eth_parse_enetaddr(value, dev->enetaddr);
break;
case env_op_delete:
memset(dev->enetaddr, 0, 6);
}
}
dev = dev->next;
} while (dev != eth_devices);
return 0;
}
U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int eth_number)
{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
if (!is_zero_ethaddr(env_enetaddr)) {
if (!is_zero_ethaddr(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
dev->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(dev->enetaddr, env_enetaddr, 6);
} else if (is_valid_ethaddr(dev->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
dev->enetaddr);
} else if (is_zero_ethaddr(dev->enetaddr)) {
#ifdef CONFIG_NET_RANDOM_ETHADDR
net_random_ethaddr(dev->enetaddr);
printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
dev->name, eth_number, dev->enetaddr);
#else
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
#endif
}
if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ethaddr(dev->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, dev->enetaddr);
return -EINVAL;
}
ret = dev->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
return ret;
}
int eth_register(struct eth_device *dev)
{
struct eth_device *d;
static int index;
assert(strlen(dev->name) < sizeof(dev->name));
if (!eth_devices) {
eth_devices = dev;
eth_current = dev;
eth_current_changed();
} else {
for (d = eth_devices; d->next != eth_devices; d = d->next)
;
d->next = dev;
}
dev->state = ETH_STATE_INIT;
dev->next = eth_devices;
dev->index = index++;
return 0;
}
int eth_unregister(struct eth_device *dev)
{
struct eth_device *cur;
/* No device */
if (!eth_devices)
return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
cur = cur->next)
;
/* Device not found */
if (cur->next != dev)
return -ENODEV;
cur->next = dev->next;
if (eth_devices == dev)
eth_devices = dev->next == eth_devices ? NULL : dev->next;
if (eth_current == dev) {
eth_current = eth_devices;
eth_current_changed();
}
return 0;
}
int eth_initialize(void)
{
int num_devices = 0;
eth_devices = NULL;
eth_current = NULL;
eth_common_init();
if (!eth_devices) {
puts("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
struct eth_device *dev = eth_devices;
char *ethprime = getenv("ethprime");
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
if (dev->index)
puts(", ");
printf("%s", dev->name);
if (ethprime && strcmp(dev->name, ethprime) == 0) {
eth_current = dev;
puts(" [PRIME]");
}
if (strchr(dev->name, ' '))
puts("\nWarning: eth device name has a space!"
"\n");
eth_write_hwaddr(dev, "eth", dev->index);
dev = dev->next;
num_devices++;
} while (dev != eth_devices);
eth_current_changed();
putc('\n');
}
return num_devices;
}
#ifdef CONFIG_MCAST_TFTP
/* Multicast.
* mcast_addr: multicast ipaddr from which multicast Mac is made
* join: 1=join, 0=leave.
*/
int eth_mcast_join(struct in_addr mcast_ip, int join)
{
u8 mcast_mac[6];
if (!eth_current || !eth_current->mcast)
return -1;
mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
mcast_mac[2] = 0x5e;
mcast_mac[1] = 0x0;
mcast_mac[0] = 0x1;
return eth_current->mcast(eth_current, mcast_mac, join);
}
/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
* and this is the ethernet-crc method needed for TSEC -- and perhaps
* some other adapter -- hash tables
*/
#define CRCPOLY_LE 0xedb88320
u32 ether_crc(size_t len, unsigned char const *p)
{
int i;
u32 crc;
crc = ~0;
while (len--) {
crc ^= *p++;
for (i = 0; i < 8; i++)
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
}
/* an reverse the bits, cuz of way they arrive -- last-first */
crc = (crc >> 16) | (crc << 16);
crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
return crc;
}
#endif
int eth_init(void)
{
struct eth_device *old_current;
if (!eth_current) {
puts("No ethernet found.\n");
return -ENODEV;
}
old_current = eth_current;
do {
debug("Trying %s\n", eth_current->name);
if (eth_current->init(eth_current, gd->bd) >= 0) {
eth_current->state = ETH_STATE_ACTIVE;
return 0;
}
debug("FAIL\n");
eth_try_another(0);
} while (old_current != eth_current);
return -ETIMEDOUT;
}
void eth_halt(void)
{
if (!eth_current)
return;
eth_current->halt(eth_current);
eth_current->state = ETH_STATE_PASSIVE;
}
int eth_is_active(struct eth_device *dev)
{
return dev && dev->state == ETH_STATE_ACTIVE;
}
int eth_send(void *packet, int length)
{
if (!eth_current)
return -ENODEV;
return eth_current->send(eth_current, packet, length);
}
int eth_rx(void)
{
if (!eth_current)
return -ENODEV;
return eth_current->recv(eth_current);
}
#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API
static void eth_save_packet(void *packet, int length)
{
char *p = packet;
int i;
if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
return;
if (PKTSIZE < length)
return;
for (i = 0; i < length; i++)
eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
eth_rcv_bufs[eth_rcv_last].length = length;
eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
}
int eth_receive(void *packet, int length)
{
char *p = packet;
void *pp = push_packet;
int i;
if (eth_rcv_current == eth_rcv_last) {
push_packet = eth_save_packet;
eth_rx();
push_packet = pp;
if (eth_rcv_current == eth_rcv_last)
return -1;
}
length = min(eth_rcv_bufs[eth_rcv_current].length, length);
for (i = 0; i < length; i++)
p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
return length;
}
#endif /* CONFIG_API */
static void eth_current_changed(void)
{
char *act = getenv("ethact");
char *ethrotate;
/*
* The call to eth_get_dev() below has a side effect of rotating
* ethernet device if uc_priv->current == NULL. This is not what
* we want when 'ethrotate' variable is 'no'.
*/
ethrotate = getenv("ethrotate");
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
return;
/* update current ethernet name */
if (eth_get_dev()) {
if (act == NULL || strcmp(act, eth_get_name()) != 0)
setenv("ethact", eth_get_name());
}
/*
* remove the variable completely if there is no active
* interface
*/
else if (act != NULL)
setenv("ethact", NULL);
}
void eth_try_another(int first_restart)
{
static void *first_failed;
char *ethrotate;
/*
* Do not rotate between network interfaces when
* 'ethrotate' variable is set to 'no'.
*/
ethrotate = getenv("ethrotate");
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
return;
if (!eth_get_dev())
return;
if (first_restart)
first_failed = eth_get_dev();
eth_set_current_to_next();
eth_current_changed();
if (first_failed == eth_get_dev())
net_restart_wrap = 1;
}
void eth_set_current(void)
{
static char *act;
static int env_changed_id;
int env_id;
env_id = get_env_id();
if ((act == NULL) || (env_changed_id != env_id)) {
act = getenv("ethact");
env_changed_id = env_id;
}
if (act == NULL) {
char *ethprime = getenv("ethprime");
void *dev = NULL;
if (ethprime)
dev = eth_get_dev_by_name(ethprime);
if (dev)
eth_set_dev(dev);
else
eth_set_dev(NULL);
} else {
eth_set_dev(eth_get_dev_by_name(act));
}
eth_current_changed();
}
const char *eth_get_name(void)
{
return eth_get_dev() ? eth_get_dev()->name : "unknown";
}

166
net/eth_common.c 100644
View File

@ -0,0 +1,166 @@
/*
* (C) Copyright 2001-2015
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* Joe Hershberger, National Instruments
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <miiphy.h>
#include <net.h>
#include "eth_internal.h"
void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
{
char *end;
int i;
for (i = 0; i < 6; ++i) {
enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
if (addr)
addr = (*end) ? end + 1 : end;
}
}
int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
{
eth_parse_enetaddr(getenv(name), enetaddr);
return is_valid_ethaddr(enetaddr);
}
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
{
char buf[20];
sprintf(buf, "%pM", enetaddr);
return setenv(name, buf);
}
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr)
{
char enetvar[32];
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
return eth_getenv_enetaddr(enetvar, enetaddr);
}
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr)
{
char enetvar[32];
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
return eth_setenv_enetaddr(enetvar, enetaddr);
}
void eth_common_init(void)
{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
miiphy_init();
#endif
#ifdef CONFIG_PHYLIB
phy_init();
#endif
}
int eth_mac_skip(int index)
{
char enetvar[15];
char *skip_state;
sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
skip_state = getenv(enetvar);
return skip_state != NULL;
}
void eth_current_changed(void)
{
char *act = getenv("ethact");
char *ethrotate;
/*
* The call to eth_get_dev() below has a side effect of rotating
* ethernet device if uc_priv->current == NULL. This is not what
* we want when 'ethrotate' variable is 'no'.
*/
ethrotate = getenv("ethrotate");
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
return;
/* update current ethernet name */
if (eth_get_dev()) {
if (act == NULL || strcmp(act, eth_get_name()) != 0)
setenv("ethact", eth_get_name());
}
/*
* remove the variable completely if there is no active
* interface
*/
else if (act != NULL)
setenv("ethact", NULL);
}
void eth_try_another(int first_restart)
{
static void *first_failed;
char *ethrotate;
/*
* Do not rotate between network interfaces when
* 'ethrotate' variable is set to 'no'.
*/
ethrotate = getenv("ethrotate");
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
return;
if (!eth_get_dev())
return;
if (first_restart)
first_failed = eth_get_dev();
eth_set_current_to_next();
eth_current_changed();
if (first_failed == eth_get_dev())
net_restart_wrap = 1;
}
void eth_set_current(void)
{
static char *act;
static int env_changed_id;
int env_id;
env_id = get_env_id();
if ((act == NULL) || (env_changed_id != env_id)) {
act = getenv("ethact");
env_changed_id = env_id;
}
if (act == NULL) {
char *ethprime = getenv("ethprime");
void *dev = NULL;
if (ethprime)
dev = eth_get_dev_by_name(ethprime);
if (dev)
eth_set_dev(dev);
else
eth_set_dev(NULL);
} else {
eth_set_dev(eth_get_dev_by_name(act));
}
eth_current_changed();
}
const char *eth_get_name(void)
{
return eth_get_dev() ? eth_get_dev()->name : "unknown";
}

40
net/eth_internal.h 100644
View File

@ -0,0 +1,40 @@
/*
* (C) Copyright 2001-2015
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* Joe Hershberger, National Instruments
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ETH_INTERNAL_H
#define __ETH_INTERNAL_H
/* Do init that is common to driver model and legacy networking */
void eth_common_init(void);
/**
* eth_setenv_enetaddr_by_index() - set the MAC address envrionment variable
*
* This sets up an environment variable with the given MAC address (@enetaddr).
* The environment variable to be set is defined by <@base_name><@index>addr.
* If @index is 0 it is omitted. For common Ethernet this means ethaddr,
* eth1addr, etc.
*
* @base_name: Base name for variable, typically "eth"
* @index: Index of interface being updated (>=0)
* @enetaddr: Pointer to MAC address to put into the variable
* @return 0 if OK, other value on error
*/
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
int eth_mac_skip(int index);
void eth_current_changed(void);
#ifdef CONFIG_DM_ETH
void eth_set_dev(struct udevice *dev);
#else
void eth_set_dev(struct eth_device *dev);
#endif
void eth_set_current_to_next(void);
#endif

439
net/eth_legacy.c 100644
View File

@ -0,0 +1,439 @@
/*
* (C) Copyright 2001-2015
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* Joe Hershberger, National Instruments
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <environment.h>
#include <net.h>
#include <phy.h>
#include <asm/errno.h>
#include "eth_internal.h"
DECLARE_GLOBAL_DATA_PTR;
/*
* CPU and board-specific Ethernet initializations. Aliased function
* signals caller to move on
*/
static int __def_eth_init(bd_t *bis)
{
return -1;
}
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
#ifdef CONFIG_API
static struct {
uchar data[PKTSIZE];
int length;
} eth_rcv_bufs[PKTBUFSRX];
static unsigned int eth_rcv_current, eth_rcv_last;
#endif
static struct eth_device *eth_devices;
struct eth_device *eth_current;
void eth_set_current_to_next(void)
{
eth_current = eth_current->next;
}
void eth_set_dev(struct eth_device *dev)
{
eth_current = dev;
}
struct eth_device *eth_get_dev_by_name(const char *devname)
{
struct eth_device *dev, *target_dev;
BUG_ON(devname == NULL);
if (!eth_devices)
return NULL;
dev = eth_devices;
target_dev = NULL;
do {
if (strcmp(devname, dev->name) == 0) {
target_dev = dev;
break;
}
dev = dev->next;
} while (dev != eth_devices);
return target_dev;
}
struct eth_device *eth_get_dev_by_index(int index)
{
struct eth_device *dev, *target_dev;
if (!eth_devices)
return NULL;
dev = eth_devices;
target_dev = NULL;
do {
if (dev->index == index) {
target_dev = dev;
break;
}
dev = dev->next;
} while (dev != eth_devices);
return target_dev;
}
int eth_get_dev_index(void)
{
if (!eth_current)
return -1;
return eth_current->index;
}
static int on_ethaddr(const char *name, const char *value, enum env_op op,
int flags)
{
int index;
struct eth_device *dev;
if (!eth_devices)
return 0;
/* look for an index after "eth" */
index = simple_strtoul(name + 3, NULL, 10);
dev = eth_devices;
do {
if (dev->index == index) {
switch (op) {
case env_op_create:
case env_op_overwrite:
eth_parse_enetaddr(value, dev->enetaddr);
break;
case env_op_delete:
memset(dev->enetaddr, 0, 6);
}
}
dev = dev->next;
} while (dev != eth_devices);
return 0;
}
U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int eth_number)
{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
if (!is_zero_ethaddr(env_enetaddr)) {
if (!is_zero_ethaddr(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
dev->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(dev->enetaddr, env_enetaddr, 6);
} else if (is_valid_ethaddr(dev->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
dev->enetaddr);
} else if (is_zero_ethaddr(dev->enetaddr)) {
#ifdef CONFIG_NET_RANDOM_ETHADDR
net_random_ethaddr(dev->enetaddr);
printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
dev->name, eth_number, dev->enetaddr);
#else
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
#endif
}
if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ethaddr(dev->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, dev->enetaddr);
return -EINVAL;
}
ret = dev->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
return ret;
}
int eth_register(struct eth_device *dev)
{
struct eth_device *d;
static int index;
assert(strlen(dev->name) < sizeof(dev->name));
if (!eth_devices) {
eth_devices = dev;
eth_current = dev;
eth_current_changed();
} else {
for (d = eth_devices; d->next != eth_devices; d = d->next)
;
d->next = dev;
}
dev->state = ETH_STATE_INIT;
dev->next = eth_devices;
dev->index = index++;
return 0;
}
int eth_unregister(struct eth_device *dev)
{
struct eth_device *cur;
/* No device */
if (!eth_devices)
return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
cur = cur->next)
;
/* Device not found */
if (cur->next != dev)
return -ENODEV;
cur->next = dev->next;
if (eth_devices == dev)
eth_devices = dev->next == eth_devices ? NULL : dev->next;
if (eth_current == dev) {
eth_current = eth_devices;
eth_current_changed();
}
return 0;
}
int eth_initialize(void)
{
int num_devices = 0;
eth_devices = NULL;
eth_current = NULL;
eth_common_init();
/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
*/
if (board_eth_init != __def_eth_init) {
if (board_eth_init(gd->bd) < 0)
printf("Board Net Initialization Failed\n");
} else if (cpu_eth_init != __def_eth_init) {
if (cpu_eth_init(gd->bd) < 0)
printf("CPU Net Initialization Failed\n");
} else {
printf("Net Initialization Skipped\n");
}
if (!eth_devices) {
puts("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
struct eth_device *dev = eth_devices;
char *ethprime = getenv("ethprime");
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
if (dev->index)
puts(", ");
printf("%s", dev->name);
if (ethprime && strcmp(dev->name, ethprime) == 0) {
eth_current = dev;
puts(" [PRIME]");
}
if (strchr(dev->name, ' '))
puts("\nWarning: eth device name has a space!"
"\n");
eth_write_hwaddr(dev, "eth", dev->index);
dev = dev->next;
num_devices++;
} while (dev != eth_devices);
eth_current_changed();
putc('\n');
}
return num_devices;
}
#ifdef CONFIG_MCAST_TFTP
/* Multicast.
* mcast_addr: multicast ipaddr from which multicast Mac is made
* join: 1=join, 0=leave.
*/
int eth_mcast_join(struct in_addr mcast_ip, int join)
{
u8 mcast_mac[6];
if (!eth_current || !eth_current->mcast)
return -1;
mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
mcast_mac[2] = 0x5e;
mcast_mac[1] = 0x0;
mcast_mac[0] = 0x1;
return eth_current->mcast(eth_current, mcast_mac, join);
}
/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
* and this is the ethernet-crc method needed for TSEC -- and perhaps
* some other adapter -- hash tables
*/
#define CRCPOLY_LE 0xedb88320
u32 ether_crc(size_t len, unsigned char const *p)
{
int i;
u32 crc;
crc = ~0;
while (len--) {
crc ^= *p++;
for (i = 0; i < 8; i++)
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
}
/* an reverse the bits, cuz of way they arrive -- last-first */
crc = (crc >> 16) | (crc << 16);
crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
return crc;
}
#endif
int eth_init(void)
{
struct eth_device *old_current;
if (!eth_current) {
puts("No ethernet found.\n");
return -ENODEV;
}
old_current = eth_current;
do {
debug("Trying %s\n", eth_current->name);
if (eth_current->init(eth_current, gd->bd) >= 0) {
eth_current->state = ETH_STATE_ACTIVE;
return 0;
}
debug("FAIL\n");
eth_try_another(0);
} while (old_current != eth_current);
return -ETIMEDOUT;
}
void eth_halt(void)
{
if (!eth_current)
return;
eth_current->halt(eth_current);
eth_current->state = ETH_STATE_PASSIVE;
}
int eth_is_active(struct eth_device *dev)
{
return dev && dev->state == ETH_STATE_ACTIVE;
}
int eth_send(void *packet, int length)
{
if (!eth_current)
return -ENODEV;
return eth_current->send(eth_current, packet, length);
}
int eth_rx(void)
{
if (!eth_current)
return -ENODEV;
return eth_current->recv(eth_current);
}
#ifdef CONFIG_API
static void eth_save_packet(void *packet, int length)
{
char *p = packet;
int i;
if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
return;
if (PKTSIZE < length)
return;
for (i = 0; i < length; i++)
eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
eth_rcv_bufs[eth_rcv_last].length = length;
eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
}
int eth_receive(void *packet, int length)
{
char *p = packet;
void *pp = push_packet;
int i;
if (eth_rcv_current == eth_rcv_last) {
push_packet = eth_save_packet;
eth_rx();
push_packet = pp;
if (eth_rcv_current == eth_rcv_last)
return -1;
}
length = min(eth_rcv_bufs[eth_rcv_current].length, length);
for (i = 0; i < length; i++)
p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
return length;
}
#endif /* CONFIG_API */