{
struct dsa_priv *priv;
- if (!dev || !dev_get_uclass_priv(dev))
- return -ENODEV;
+ if (!dev)
+ return -EINVAL;
if (headroom + tailroom > DSA_MAX_OVR)
return -EINVAL;
return 0;
}
+ofnode dsa_port_get_ofnode(struct udevice *dev, int port)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
+ struct dsa_port_pdata *port_pdata;
+ struct udevice *pdev;
+
+ if (port == pdata->cpu_port)
+ return pdata->cpu_port_node;
+
+ for (device_find_first_child(dev, &pdev);
+ pdev;
+ device_find_next_child(&pdev)) {
+ port_pdata = dev_get_parent_plat(pdev);
+ if (port_pdata->index == port)
+ return dev_ofnode(pdev);
+ }
+
+ return ofnode_null();
+}
+
/* returns the DSA master Ethernet device */
struct udevice *dsa_get_master(struct udevice *dev)
{
- struct dsa_priv *priv = dev_get_uclass_priv(dev);
+ struct dsa_priv *priv;
- if (!priv)
+ if (!dev)
return NULL;
+ priv = dev_get_uclass_priv(dev);
+
return priv->master_dev;
}
struct dsa_ops *ops = dsa_get_ops(dev);
int err;
- if (!priv)
- return -ENODEV;
-
- if (!master) {
- dev_err(pdev, "DSA master Ethernet device not found!\n");
- return -EINVAL;
- }
-
if (ops->port_enable) {
struct dsa_port_pdata *port_pdata;
struct udevice *master = dsa_get_master(dev);
struct dsa_ops *ops = dsa_get_ops(dev);
- if (!priv)
- return;
-
if (ops->port_disable) {
struct dsa_port_pdata *port_pdata;
port_pdata = dev_get_parent_plat(pdev);
ops->port_disable(dev, port_pdata->index, port_pdata->phy);
- ops->port_disable(dev, priv->cpu_port, NULL);
+ ops->port_disable(dev, priv->cpu_port, priv->cpu_port_fixed_phy);
}
- /*
- * stop master only if it's active, don't probe it otherwise.
- * Under normal usage it would be active because we're using it, but
- * during tear-down it may have been removed ahead of us.
- */
- if (master && device_active(master))
- eth_get_ops(master)->stop(master);
+ eth_get_ops(master)->stop(master);
}
/*
struct dsa_port_pdata *port_pdata;
int err;
- if (!master)
- return -EINVAL;
-
if (length + head + tail > PKTSIZE_ALIGN)
return -EINVAL;
struct dsa_port_pdata *port_pdata;
int length, port_index, err;
- if (!master)
- return -EINVAL;
-
length = eth_get_ops(master)->recv(master, flags, packetp);
if (length <= 0)
return length;
struct udevice *master = dsa_get_master(dev);
struct dsa_priv *priv;
- if (!master)
- return -EINVAL;
-
priv = dev_get_uclass_priv(dev);
if (eth_get_ops(master)->free_pkt) {
/* return the original pointer and length to master Eth */
static int dsa_port_of_to_pdata(struct udevice *pdev)
{
struct dsa_port_pdata *port_pdata;
- struct dsa_pdata *dsa_pdata;
struct eth_pdata *eth_pdata;
- struct udevice *dev;
const char *label;
u32 index;
int err;
if (err)
return err;
- dev = dev_get_parent(pdev);
- dsa_pdata = dev_get_uclass_plat(dev);
-
port_pdata = dev_get_parent_plat(pdev);
port_pdata->index = index;
label = ofnode_read_string(dev_ofnode(pdev), "label");
if (label)
- strncpy(port_pdata->name, label, DSA_PORT_NAME_LENGTH);
+ strlcpy(port_pdata->name, label, DSA_PORT_NAME_LENGTH);
eth_pdata = dev_get_plat(pdev);
eth_pdata->priv_pdata = port_pdata;
.free_pkt = dsa_port_free_pkt,
};
-static int dsa_port_probe(struct udevice *pdev)
+/*
+ * Inherit port's hwaddr from the DSA master, unless the port already has a
+ * unique MAC address specified in the environment.
+ */
+static void dsa_port_set_hwaddr(struct udevice *pdev, struct udevice *master)
{
- struct udevice *dev = dev_get_parent(pdev);
struct eth_pdata *eth_pdata, *master_pdata;
unsigned char env_enetaddr[ARP_HLEN];
+
+ eth_env_get_enetaddr_by_index("eth", dev_seq(pdev), env_enetaddr);
+ if (!is_zero_ethaddr(env_enetaddr)) {
+ /* individual port mac addrs require master to be promisc */
+ struct eth_ops *eth_ops = eth_get_ops(master);
+
+ if (eth_ops->set_promisc)
+ eth_ops->set_promisc(master, true);
+
+ return;
+ }
+
+ master_pdata = dev_get_plat(master);
+ eth_pdata = dev_get_plat(pdev);
+ memcpy(eth_pdata->enetaddr, master_pdata->enetaddr, ARP_HLEN);
+ eth_env_set_enetaddr_by_index("eth", dev_seq(pdev),
+ master_pdata->enetaddr);
+}
+
+static int dsa_port_probe(struct udevice *pdev)
+{
+ struct udevice *dev = dev_get_parent(pdev);
+ struct dsa_ops *ops = dsa_get_ops(dev);
struct dsa_port_pdata *port_pdata;
- struct dsa_priv *dsa_priv;
struct udevice *master;
+ int err;
port_pdata = dev_get_parent_plat(pdev);
- dsa_priv = dev_get_uclass_priv(dev);
port_pdata->phy = dm_eth_phy_connect(pdev);
if (!port_pdata->phy)
return -ENODEV;
/*
- * Inherit port's hwaddr from the DSA master, unless the port already
- * has a unique MAC address specified in the environment.
+ * Probe the master device. We depend on the master device for proper
+ * operation and we also need it for MAC inheritance below.
+ *
+ * TODO: we assume the master device is always there and doesn't get
+ * removed during runtime.
*/
- eth_env_get_enetaddr_by_index("eth", dev_seq(pdev), env_enetaddr);
- if (!is_zero_ethaddr(env_enetaddr))
- return 0;
+ err = device_probe(master);
+ if (err)
+ return err;
- master_pdata = dev_get_plat(master);
- eth_pdata = dev_get_plat(pdev);
- memcpy(eth_pdata->enetaddr, master_pdata->enetaddr, ARP_HLEN);
- eth_env_set_enetaddr_by_index("eth", dev_seq(pdev),
- master_pdata->enetaddr);
+ dsa_port_set_hwaddr(pdev, master);
+
+ if (ops->port_probe) {
+ err = ops->port_probe(dev, port_pdata->index,
+ port_pdata->phy);
+ if (err)
+ return err;
+ }
return 0;
}
static int dsa_port_remove(struct udevice *pdev)
{
- struct udevice *dev = dev_get_parent(pdev);
- struct dsa_port_pdata *port_pdata;
- struct dsa_priv *dsa_priv;
-
- port_pdata = dev_get_parent_plat(pdev);
- dsa_priv = dev_get_uclass_priv(dev);
+ struct dsa_port_pdata *port_pdata = dev_get_parent_plat(pdev);
port_pdata->phy = NULL;
ofnode node = dev_ofnode(dev), pnode;
int i, err, first_err = 0;
- if (!pdata || !ofnode_valid(node))
+ if (!ofnode_valid(node))
return -ENODEV;
pdata->master_node = ofnode_null();
struct dsa_port_pdata *port_pdata;
port_pdata = dev_get_parent_plat(pdev);
- strncpy(port_pdata->name, name, DSA_PORT_NAME_LENGTH);
+ strlcpy(port_pdata->name, name, DSA_PORT_NAME_LENGTH);
pdev->name = port_pdata->name;
}
{
struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
struct dsa_priv *priv = dev_get_uclass_priv(dev);
-
- if (!pdata || !priv)
- return -ENODEV;
+ struct dsa_ops *ops = dsa_get_ops(dev);
+ int err;
priv->num_ports = pdata->num_ports;
priv->cpu_port = pdata->cpu_port;
return -ENODEV;
}
- uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
- &priv->master_dev);
+ err = uclass_get_device_by_ofnode(UCLASS_ETH, pdata->master_node,
+ &priv->master_dev);
+ if (err)
+ return err;
+
+ /* Simulate a probing event for the CPU port */
+ if (ops->port_probe) {
+ err = ops->port_probe(dev, priv->cpu_port,
+ priv->cpu_port_fixed_phy);
+ if (err)
+ return err;
+ }
+
return 0;
}