summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: efd468c)
raw | patch | inline | side by side (parent: efd468c)
author | WingMan Kwok <w-kwok2@ti.com> | |
Fri, 27 Feb 2015 21:53:19 +0000 (16:53 -0500) | ||
committer | WingMan Kwok <w-kwok2@ti.com> | |
Tue, 10 Mar 2015 14:20:34 +0000 (10:20 -0400) |
This patch adds support of setting hw address live.
When doing so, the netcp needs to update the lower
modules cpsw and pa to update their database accordingly,
i.e. setting up their receive filters.
Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
When doing so, the netcp needs to update the lower
modules cpsw and pa to update their database accordingly,
i.e. setting up their receive filters.
Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
index 51a5bd7038efd967d12501f1f8ffb8855729893f..dc0ed03df540012c13ae55c7093194a821d5c78d 100644 (file)
u32 num_serdes;
u32 serdes_lanes;
struct serdes serdes;
+ u32 opened;
};
/* slave_port: 0-based (currently relevant only in multi_if mode)
struct cpsw_intf *cpsw_intf = intf_priv;
struct cpsw_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "ethss adding address %pM, type %d\n",
naddr->addr, naddr->type);
struct cpsw_intf *cpsw_intf = intf_priv;
struct cpsw_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "ethss deleting address %pM, type %d\n",
naddr->addr, naddr->type);
PSTREAM_ROUTE_DMA);
cpsw_register_cpts(cpsw_dev);
+ cpsw_dev->opened = 1;
return 0;
ale_fail:
clk_put(cpsw_dev->cpgmac);
cpsw_unregister_cpts(cpsw_dev);
+ cpsw_dev->opened = 0;
return 0;
}
index e5fadee8c0f4a0f8d8c944aa313ba39676eee3fa..feaf3b82840c72199fbfde3a67673a4bdf1040c8 100644 (file)
#define IS_SGMII_MAC_PHY(i) \
(((i) == SGMII_LINK_MAC_PHY) || ((i) == SGMII_LINK_MAC_PHY_MASTER))
+
/* CPSW Statistics register map size */
#define CPSW2_STATS_REGS_SIZE 0x200
u32 num_serdes;
u32 serdes_lanes;
struct serdes serdes;
+ u32 opened;
};
/* slave_port: 0-based (currently relevant only in multi_if mode)
struct cpsw2_intf *cpsw_intf = intf_priv;
struct cpsw2_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "ethss adding address %pM, type %d\n",
naddr->addr, naddr->type);
struct cpsw2_intf *cpsw_intf = intf_priv;
struct cpsw2_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "ethss deleting address %pM, type %d\n",
naddr->addr, naddr->type);
PSTREAM_ROUTE_GLOBAL_DMA);
cpsw2_register_cpts(cpsw_dev);
+ cpsw_dev->opened = 1;
return 0;
ale_fail:
clk_put(cpsw_dev->cpgmac);
cpsw2_unregister_cpts(cpsw_dev);
+ cpsw_dev->opened = 0;
return 0;
}
diff --git a/drivers/net/ethernet/ti/keystone_net_core.c b/drivers/net/ethernet/ti/keystone_net_core.c
index ae5098aa09c6feb97d5841ad747e6c0eaad82ca9..4d53d59ef8af05ee433284429e2bfc227a1fdd0e 100644 (file)
naddr->flags = 0;
}
-static void netcp_addr_add_mark(struct netcp_priv *netcp, const u8 *addr,
- enum netcp_addr_type type)
+static struct netcp_addr *
+netcp_addr_add_mark(struct netcp_priv *netcp, const u8 *addr,
+ enum netcp_addr_type type)
{
struct netcp_addr *naddr;
naddr = netcp_addr_find(netcp, addr, type);
if (naddr) {
naddr->flags |= ADDR_VALID;
- return;
+ return naddr;
}
naddr = netcp_addr_add(netcp, addr, type);
if (!WARN_ON(!naddr))
naddr->flags |= ADDR_NEW;
+
+ return naddr;
}
-static void netcp_addr_sweep_del(struct netcp_priv *netcp)
+static void netcp_mod_del_addr(struct netcp_priv *netcp,
+ struct netcp_addr *naddr)
{
- struct netcp_addr *naddr, *tmp;
struct netcp_intf_modpriv *priv;
struct netcp_module *module;
- int error;
+
+ dev_dbg(netcp->dev, "deleting address %pM, type %x\n",
+ naddr->addr, naddr->type);
+ for_each_module(netcp, priv) {
+ module = priv->netcp_module;
+ if (!module->del_addr)
+ continue;
+ module->del_addr(priv->module_priv, naddr);
+ }
+}
+
+static void netcp_addr_sweep_del(struct netcp_priv *netcp)
+{
+ struct netcp_addr *naddr, *tmp;
list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) {
if (naddr->flags & (ADDR_VALID | ADDR_NEW))
continue;
- dev_dbg(netcp->dev, "deleting address %pM, type %x\n",
- naddr->addr, naddr->type);
- for_each_module(netcp, priv) {
- module = priv->netcp_module;
- if (!module->del_addr)
- continue;
- error = module->del_addr(priv->module_priv,
- naddr);
- WARN_ON(error);
- }
+ netcp_mod_del_addr(netcp, naddr);
netcp_addr_del(naddr);
}
}
-static void netcp_addr_sweep_add(struct netcp_priv *netcp)
+static int netcp_mod_add_addr(struct netcp_priv *netcp,
+ struct netcp_addr *naddr)
{
- struct netcp_addr *naddr, *tmp;
struct netcp_intf_modpriv *priv;
struct netcp_module *module;
int error;
+ dev_dbg(netcp->dev, "adding address %pM, type %x\n",
+ naddr->addr, naddr->type);
+ for_each_module(netcp, priv) {
+ module = priv->netcp_module;
+ if (!module->add_addr)
+ continue;
+ error = module->add_addr(priv->module_priv, naddr);
+ if (error)
+ break;
+ }
+
+ if (error)
+ netcp_mod_del_addr(netcp, naddr);
+
+ return error;
+}
+
+static void netcp_addr_sweep_add(struct netcp_priv *netcp)
+{
+ struct netcp_addr *naddr, *tmp;
+
list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) {
if (!(naddr->flags & ADDR_NEW))
continue;
- dev_dbg(netcp->dev, "adding address %pM, type %x\n",
- naddr->addr, naddr->type);
- for_each_module(netcp, priv) {
- module = priv->netcp_module;
- if (!module->add_addr)
- continue;
- error = module->add_addr(priv->module_priv, naddr);
- WARN_ON(error);
- }
+ netcp_mod_add_addr(netcp, naddr);
}
}
return 0;
}
+static int netcp_ndo_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct netcp_priv *netcp = netdev_priv(ndev);
+ struct netcp_addr *naddr;
+ int ret;
+
+ ret = eth_mac_addr(ndev, p);
+ if (ret) {
+ dev_info(netcp->dev, "set mac addr %pM failed (%d).\n",
+ ((struct sockaddr *)p)->sa_data, ret);
+ goto done;
+ }
+
+ naddr = netcp_addr_add_mark(netcp, ndev->dev_addr, ADDR_DEV);
+ if (!naddr) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (naddr->flags & ADDR_VALID)
+ goto done;
+
+ ret = netcp_mod_add_addr(netcp, naddr);
+ if (ret) {
+ /* lower modules are not ready yet */
+ netcp_addr_del(naddr);
+ ret = 0;
+ }
+
+done:
+ return ret;
+}
+
static void netcp_ndo_tx_timeout(struct net_device *ndev)
{
struct netcp_priv *netcp = netdev_priv(ndev);
.ndo_do_ioctl = netcp_ndo_ioctl,
.ndo_get_stats64 = netcp_get_stats,
.ndo_change_mtu = netcp_ndo_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = netcp_ndo_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = netcp_rx_add_vid,
.ndo_vlan_rx_kill_vid = netcp_rx_kill_vid,
NETIF_F_SG|
NETIF_F_FRAGLIST;
+ ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
netcp = netdev_priv(ndev);
spin_lock_init(&netcp->lock);
INIT_LIST_HEAD(&netcp->module_head);
index 5b4875f3e7891f7b2de7419c5ff761bede94bf5a..620ed16a0534b15d530362842af02e2eb956425f 100644 (file)
u32 ip_lut_size;
netdev_features_t netif_features;
const char *pdsp_fw[DEVICE_PA_NUM_PDSPS];
+ u32 opened;
};
#define pa_from_module(data) container_of(data, struct pa_device, module)
pa_dev->clk = NULL;
}
+ pa_dev->opened = 0;
mutex_unlock(&pa_modules_lock);
return 0;
}
netcp_register_rxhook(netcp_priv, pa_dev->rxhook_order,
pa_rx_hook, intf_priv);
+ pa_dev->opened = 1;
return 0;
fail:
int idx, error;
const u8 *addr;
+ if (!pa_dev->opened)
+ return -ENXIO;
+
for (idx = 0; idx < count; idx++) {
entries[idx] = pa_lut_alloc(pa_dev, PA_LUT_MAC,
naddr->type == ADDR_ANY);
struct pa_lut_entry *entry;
int idx;
+ if (!pa_dev->opened)
+ return -ENXIO;
+
for (idx = 0; idx < pa_dev->lut_size; idx++) {
entry = pa_dev->lut + idx;
if (!entry->valid || !entry->in_use || entry->u.naddr != naddr)
index caca6ff3006008c2b3a30490e1a6dfef35f11650..3d642714ec9622eebb824c034ae7f6d16233a375 100644 (file)
u32 lut_size;
const char *pdsp_fw[PA2_NUM_PDSPS];
+ u32 opened;
};
#define pa2_from_module(data) container_of(data, struct pa2_device, module)
pa_dev->clk = NULL;
}
+ pa_dev->opened = 0;
mutex_unlock(&pa2_modules_lock);
return 0;
}
netcp_register_txhook(netcp_priv, pa_dev->txhook_softcsum,
pa2_txhook_softcsum, intf_priv);
+ pa_dev->opened = 1;
return 0;
fail:
int idx, error;
const u8 *addr;
+ if (!pa_dev->opened)
+ return -ENXIO;
+
for (idx = 0; idx < count; idx++) {
entries[idx] = pa2_lut_alloc(pa_dev, naddr->type == ADDR_ANY);
if (!entries[idx])
struct pa2_lut_entry *entry;
int idx;
+ if (!pa_dev->opened)
+ return -ENXIO;
+
for (idx = 0; idx < pa_dev->lut_size; idx++) {
entry = pa_dev->lut + idx;
if (!entry->valid || !entry->in_use || entry->naddr != naddr)
index 0af8126a11ef86c453f5a3841045c05e448453a2..a84d5d78623cbc00359701fd96efcf59e40f574d 100644 (file)
struct kobject stats_kobj;
spinlock_t hw_stats_lock;
struct device_node *serdes;
+ u32 opened;
};
/* slave_port: 0-based (currently relevant only in multi_if mode)
struct cpswx_intf *cpsw_intf = intf_priv;
struct cpswx_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "xgess adding address %pM, type %d\n",
naddr->addr, naddr->type);
struct cpswx_intf *cpsw_intf = intf_priv;
struct cpswx_priv *cpsw_dev = cpsw_intf->cpsw_priv;
+ if (!cpsw_dev->opened)
+ return -ENXIO;
+
dev_dbg(cpsw_dev->dev, "xgess deleting address %pM, type %d\n",
naddr->addr, naddr->type);
PSTREAM_ROUTE_DMA);
#endif
+ cpsw_dev->opened = 1;
return 0;
ale_fail:
clk_disable_unprepare(cpsw_dev->clk);
clk_put(cpsw_dev->clk);
+ cpsw_dev->opened = 0;
return 0;
}