diff options
author | Mugunthan V N | 2014-09-02 08:04:21 -0500 |
---|---|---|
committer | Sekhar Nori | 2014-09-02 08:06:58 -0500 |
commit | 088f0226367a0f04d055080878a5c4c8a0ebf05b (patch) | |
tree | 751bf70be47e2918d575b2d24e397a5132b84b60 | |
parent | fd012d03d17b38c5350ff814583b2f2f0fc0723f (diff) | |
download | kernel-video-088f0226367a0f04d055080878a5c4c8a0ebf05b.tar.gz kernel-video-088f0226367a0f04d055080878a5c4c8a0ebf05b.tar.xz kernel-video-088f0226367a0f04d055080878a5c4c8a0ebf05b.zip |
drivers: net: cpsw: switch-config: set/get port state
Configuring port states handling of the packet switching to the slave port
like disabling packet forwarding/learning.
Note: Using this interface an user can disable all the slave ports which
will bring down the Ethernet interface.
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 51 | ||||
-rw-r--r-- | include/uapi/linux/net_switch_config.h | 10 |
2 files changed, 59 insertions, 2 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d8ff8237af3..5a7717ee83b 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -398,6 +398,7 @@ struct cpsw_priv { | |||
398 | struct cpdma_ctlr *dma; | 398 | struct cpdma_ctlr *dma; |
399 | struct cpdma_chan *txch, *rxch; | 399 | struct cpdma_chan *txch, *rxch; |
400 | struct cpsw_ale *ale; | 400 | struct cpsw_ale *ale; |
401 | u8 port_state[3]; | ||
401 | /* snapshot of IRQ numbers */ | 402 | /* snapshot of IRQ numbers */ |
402 | u32 irqs_table[4]; | 403 | u32 irqs_table[4]; |
403 | u32 num_irqs; | 404 | u32 num_irqs; |
@@ -842,7 +843,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave, | |||
842 | 843 | ||
843 | /* enable forwarding */ | 844 | /* enable forwarding */ |
844 | cpsw_ale_control_set(priv->ale, slave_port, | 845 | cpsw_ale_control_set(priv->ale, slave_port, |
845 | ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); | 846 | ALE_PORT_STATE, |
847 | priv->port_state[slave_port]); | ||
846 | 848 | ||
847 | if (phy->speed == 1000) | 849 | if (phy->speed == 1000) |
848 | mac_control |= BIT(7); /* GIGABITEN */ | 850 | mac_control |= BIT(7); /* GIGABITEN */ |
@@ -860,7 +862,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave, | |||
860 | mac_control = 0; | 862 | mac_control = 0; |
861 | /* disable forwarding */ | 863 | /* disable forwarding */ |
862 | cpsw_ale_control_set(priv->ale, slave_port, | 864 | cpsw_ale_control_set(priv->ale, slave_port, |
863 | ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); | 865 | ALE_PORT_STATE, |
866 | priv->port_state[slave_port]); | ||
864 | } | 867 | } |
865 | 868 | ||
866 | if (mac_control != slave->mac_control) { | 869 | if (mac_control != slave->mac_control) { |
@@ -1181,6 +1184,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) | |||
1181 | slave->mac_control = 0; /* no link yet */ | 1184 | slave->mac_control = 0; /* no link yet */ |
1182 | 1185 | ||
1183 | slave_port = cpsw_get_slave_port(priv, slave->slave_num); | 1186 | slave_port = cpsw_get_slave_port(priv, slave->slave_num); |
1187 | priv->port_state[slave_port] = ALE_PORT_STATE_FORWARD; | ||
1184 | 1188 | ||
1185 | if (priv->data.dual_emac) | 1189 | if (priv->data.dual_emac) |
1186 | cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port); | 1190 | cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port); |
@@ -1597,6 +1601,30 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) | |||
1597 | 1601 | ||
1598 | #endif /*CONFIG_TI_CPTS*/ | 1602 | #endif /*CONFIG_TI_CPTS*/ |
1599 | 1603 | ||
1604 | static int cpsw_set_port_state(struct cpsw_priv *priv, int port, | ||
1605 | int port_state) | ||
1606 | { | ||
1607 | switch (port_state) { | ||
1608 | case PORT_STATE_DISABLED: | ||
1609 | priv->port_state[port] = ALE_PORT_STATE_DISABLE; | ||
1610 | break; | ||
1611 | case PORT_STATE_BLOCKED: | ||
1612 | priv->port_state[port] = ALE_PORT_STATE_BLOCK; | ||
1613 | break; | ||
1614 | case PORT_STATE_LEARN: | ||
1615 | priv->port_state[port] = ALE_PORT_STATE_LEARN; | ||
1616 | break; | ||
1617 | case PORT_STATE_FORWARD: | ||
1618 | priv->port_state[port] = ALE_PORT_STATE_FORWARD; | ||
1619 | break; | ||
1620 | default: | ||
1621 | dev_err(priv->dev, "Switch config: Invalid port state\n"); | ||
1622 | return -EFAULT; | ||
1623 | } | ||
1624 | return cpsw_ale_control_set(priv->ale, port, ALE_PORT_STATE, | ||
1625 | priv->port_state[port]); | ||
1626 | } | ||
1627 | |||
1600 | static int cpsw_switch_config_ioctl(struct net_device *ndev, | 1628 | static int cpsw_switch_config_ioctl(struct net_device *ndev, |
1601 | struct ifreq *ifrq, int cmd) | 1629 | struct ifreq *ifrq, int cmd) |
1602 | { | 1630 | { |
@@ -1721,6 +1749,25 @@ static int cpsw_switch_config_ioctl(struct net_device *ndev, | |||
1721 | ret = -EINVAL; | 1749 | ret = -EINVAL; |
1722 | } | 1750 | } |
1723 | break; | 1751 | break; |
1752 | case CONFIG_SWITCH_GET_PORT_STATE: | ||
1753 | if ((config.port == 1) || (config.port == 2)) { | ||
1754 | config.port_state = priv->port_state[config.port]; | ||
1755 | ret = copy_to_user(ifrq->ifr_data, &config, | ||
1756 | sizeof(config)); | ||
1757 | } else { | ||
1758 | dev_err(priv->dev, "Invalid Arguments\n"); | ||
1759 | ret = -EINVAL; | ||
1760 | } | ||
1761 | break; | ||
1762 | case CONFIG_SWITCH_SET_PORT_STATE: | ||
1763 | if ((config.port == 1) || (config.port == 2)) { | ||
1764 | ret = cpsw_set_port_state(priv, config.port, | ||
1765 | config.port_state); | ||
1766 | } else { | ||
1767 | dev_err(priv->dev, "Invalid Arguments\n"); | ||
1768 | ret = -EINVAL; | ||
1769 | } | ||
1770 | break; | ||
1724 | 1771 | ||
1725 | default: | 1772 | default: |
1726 | ret = -EOPNOTSUPP; | 1773 | ret = -EOPNOTSUPP; |
diff --git a/include/uapi/linux/net_switch_config.h b/include/uapi/linux/net_switch_config.h index afc64d9ceb5..149fcdc0680 100644 --- a/include/uapi/linux/net_switch_config.h +++ b/include/uapi/linux/net_switch_config.h | |||
@@ -29,6 +29,15 @@ enum { | |||
29 | CONFIG_SWITCH_SET_PORT_CONFIG, | 29 | CONFIG_SWITCH_SET_PORT_CONFIG, |
30 | CONFIG_SWITCH_GET_PORT_CONFIG, | 30 | CONFIG_SWITCH_GET_PORT_CONFIG, |
31 | CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO, | 31 | CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO, |
32 | CONFIG_SWITCH_GET_PORT_STATE, | ||
33 | CONFIG_SWITCH_SET_PORT_STATE, | ||
34 | }; | ||
35 | |||
36 | enum { | ||
37 | PORT_STATE_DISABLED = 0, | ||
38 | PORT_STATE_BLOCKED, | ||
39 | PORT_STATE_LEARN, | ||
40 | PORT_STATE_FORWARD, | ||
32 | }; | 41 | }; |
33 | 42 | ||
34 | struct net_switch_config { | 43 | struct net_switch_config { |
@@ -45,6 +54,7 @@ struct net_switch_config { | |||
45 | unsigned char unknown_vlan_untag; | 54 | unsigned char unknown_vlan_untag; |
46 | unsigned int unknown_vlan_unreg_multi; | 55 | unsigned int unknown_vlan_unreg_multi; |
47 | unsigned int unknown_vlan_reg_multi; | 56 | unsigned int unknown_vlan_reg_multi; |
57 | unsigned int port_state; | ||
48 | struct ethtool_cmd ecmd; | 58 | struct ethtool_cmd ecmd; |
49 | 59 | ||
50 | unsigned int ret_type; /* Return Success/Failure */ | 60 | unsigned int ret_type; /* Return Success/Failure */ |