mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
Merge branch 'net-dsa-microchip-remove-unnecessary-dsa_switch_ops-callbacks'
Bastien Curutchet says: ==================== net: dsa: microchip: remove unnecessary dsa_switch_ops callbacks This series continues the rework of the KSZ driver initiated by two previous series (see [1] & [2]). The KSZ driver handles more than 20 switches split in several families. This was previously handled through a common set of dsa_switch_ops operations that used device-specific ksz_dev_ops callbacks. The two previous series have split this common struct dsa_switch_ops into 5 to connect the ksz_dev_ops's implentations directly to the new dsa_swicth ops. This series continues in the same vein and removes the dsa_switch_ops operations that aren't used. On top of this on-going rework I added PTP and periodic output support for the KSZ8463 (which was my first goal). There are still more than 20 patches left for all this so this series will be followed by three others and if you want to see the full picture we can check my github ([3]). FYI, I only have a KSZ8463 so, unfortunately, I can't test other switches. The next series is going to move out of ksz_common.c the last remaining functions that aren't truly common to all KSZ switches. The series after that will add PTP support for the KSZ8463 and the final one will add periodic output support for the KSZ8463. [1]: https://lore.kernel.org/r/20260505-clean-ksz-driver-v1-0-05d70fa42461@bootlin.com [2]: https://lore.kernel.org/r/20260521-clean-ksz-2nd-series-v3-0-75c38971c19a@bootlin.com [3]: https://github.com/bastien-curutchet/linux/tree/ksz_rework ==================== Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-0-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
eee2d0676d
|
|
@ -1562,7 +1562,7 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,
|
|||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev))
|
||||
if (ksz_is_ksz88x3(dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* Discard packets with VID not enabled on the switch */
|
||||
|
|
@ -1599,7 +1599,7 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
|
|||
u16 data, new_pvid = 0;
|
||||
u8 fid, member, valid;
|
||||
|
||||
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev))
|
||||
if (ksz_is_ksz88x3(dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* If a VLAN is added with untagged flag different from the
|
||||
|
|
@ -1669,7 +1669,7 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
|
|||
u8 fid, member, valid;
|
||||
u16 data, pvid;
|
||||
|
||||
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev))
|
||||
if (ksz_is_ksz88x3(dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
|
||||
|
|
@ -2361,6 +2361,24 @@ static int ksz8463_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u32 ksz88xx_get_phy_flags(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ88X3_CHIP_ID:
|
||||
/* Silicon Errata Sheet (DS80000830A):
|
||||
* Port 1 does not work with LinkMD Cable-Testing.
|
||||
* Port 1 does not respond to received PAUSE control frames.
|
||||
*/
|
||||
if (!port)
|
||||
return MICREL_KSZ8_P1_ERRATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz8_switch_init(struct ksz_device *dev)
|
||||
{
|
||||
dev->cpu_port = fls(dev->info->cpu_ports) - 1;
|
||||
|
|
@ -2508,7 +2526,6 @@ const struct ksz_dev_ops ksz88xx_dev_ops = {
|
|||
const struct dsa_switch_ops ksz8463_switch_ops = {
|
||||
.get_tag_protocol = ksz8463_get_tag_protocol,
|
||||
.connect_tag_protocol = ksz8463_connect_tag_protocol,
|
||||
.get_phy_flags = ksz_get_phy_flags,
|
||||
.setup = ksz8_setup,
|
||||
.teardown = ksz_teardown,
|
||||
.phy_read = ksz8463_phy_read16,
|
||||
|
|
@ -2520,17 +2537,11 @@ const struct dsa_switch_ops ksz8463_switch_ops = {
|
|||
.get_sset_count = ksz_sset_count,
|
||||
.port_bridge_join = ksz_port_bridge_join,
|
||||
.port_bridge_leave = ksz_port_bridge_leave,
|
||||
.port_hsr_join = ksz_hsr_join,
|
||||
.port_hsr_leave = ksz_hsr_leave,
|
||||
.port_set_mac_address = ksz_port_set_mac_address,
|
||||
.port_stp_state_set = ksz_port_stp_state_set,
|
||||
.port_teardown = ksz_port_teardown,
|
||||
.port_pre_bridge_flags = ksz_port_pre_bridge_flags,
|
||||
.port_bridge_flags = ksz_port_bridge_flags,
|
||||
.port_fast_age = ksz8_flush_dyn_mac_table,
|
||||
.port_vlan_filtering = ksz8_port_vlan_filtering,
|
||||
.port_vlan_add = ksz8_port_vlan_add,
|
||||
.port_vlan_del = ksz8_port_vlan_del,
|
||||
.port_fdb_dump = ksz8_fdb_dump,
|
||||
.port_fdb_add = ksz8_fdb_add,
|
||||
.port_fdb_del = ksz8_fdb_del,
|
||||
|
|
@ -2542,8 +2553,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = {
|
|||
.get_pause_stats = ksz_get_pause_stats,
|
||||
.port_change_mtu = ksz8_change_mtu,
|
||||
.port_max_mtu = ksz_max_mtu,
|
||||
.get_wol = ksz_get_wol,
|
||||
.set_wol = ksz_set_wol,
|
||||
.suspend = ksz_suspend,
|
||||
.resume = ksz_resume,
|
||||
.get_ts_info = ksz_get_ts_info,
|
||||
|
|
@ -2551,11 +2560,7 @@ const struct dsa_switch_ops ksz8463_switch_ops = {
|
|||
.port_hwtstamp_set = ksz_hwtstamp_set,
|
||||
.port_txtstamp = ksz_port_txtstamp,
|
||||
.port_rxtstamp = ksz_port_rxtstamp,
|
||||
.cls_flower_add = ksz_cls_flower_add,
|
||||
.cls_flower_del = ksz_cls_flower_del,
|
||||
.port_setup_tc = ksz_setup_tc,
|
||||
.support_eee = ksz_support_eee,
|
||||
.set_mac_eee = ksz_set_mac_eee,
|
||||
.port_get_default_prio = ksz_port_get_default_prio,
|
||||
.port_set_default_prio = ksz_port_set_default_prio,
|
||||
.port_get_dscp_prio = ksz_port_get_dscp_prio,
|
||||
|
|
@ -2568,7 +2573,6 @@ const struct dsa_switch_ops ksz8463_switch_ops = {
|
|||
const struct dsa_switch_ops ksz87xx_switch_ops = {
|
||||
.get_tag_protocol = ksz87xx_get_tag_protocol,
|
||||
.connect_tag_protocol = ksz87xx_connect_tag_protocol,
|
||||
.get_phy_flags = ksz_get_phy_flags,
|
||||
.setup = ksz8_setup,
|
||||
.teardown = ksz_teardown,
|
||||
.phy_read = ksz8_phy_read16,
|
||||
|
|
@ -2580,11 +2584,8 @@ const struct dsa_switch_ops ksz87xx_switch_ops = {
|
|||
.get_sset_count = ksz_sset_count,
|
||||
.port_bridge_join = ksz_port_bridge_join,
|
||||
.port_bridge_leave = ksz_port_bridge_leave,
|
||||
.port_hsr_join = ksz_hsr_join,
|
||||
.port_hsr_leave = ksz_hsr_leave,
|
||||
.port_set_mac_address = ksz_port_set_mac_address,
|
||||
.port_stp_state_set = ksz_port_stp_state_set,
|
||||
.port_teardown = ksz_port_teardown,
|
||||
.port_pre_bridge_flags = ksz_port_pre_bridge_flags,
|
||||
.port_bridge_flags = ksz_port_bridge_flags,
|
||||
.port_fast_age = ksz8_flush_dyn_mac_table,
|
||||
|
|
@ -2602,8 +2603,6 @@ const struct dsa_switch_ops ksz87xx_switch_ops = {
|
|||
.get_pause_stats = ksz_get_pause_stats,
|
||||
.port_change_mtu = ksz8_change_mtu,
|
||||
.port_max_mtu = ksz_max_mtu,
|
||||
.get_wol = ksz_get_wol,
|
||||
.set_wol = ksz_set_wol,
|
||||
.suspend = ksz_suspend,
|
||||
.resume = ksz_resume,
|
||||
.get_ts_info = ksz_get_ts_info,
|
||||
|
|
@ -2611,11 +2610,7 @@ const struct dsa_switch_ops ksz87xx_switch_ops = {
|
|||
.port_hwtstamp_set = ksz_hwtstamp_set,
|
||||
.port_txtstamp = ksz_port_txtstamp,
|
||||
.port_rxtstamp = ksz_port_rxtstamp,
|
||||
.cls_flower_add = ksz_cls_flower_add,
|
||||
.cls_flower_del = ksz_cls_flower_del,
|
||||
.port_setup_tc = ksz_setup_tc,
|
||||
.support_eee = ksz_support_eee,
|
||||
.set_mac_eee = ksz_set_mac_eee,
|
||||
.port_get_default_prio = ksz_port_get_default_prio,
|
||||
.port_set_default_prio = ksz_port_set_default_prio,
|
||||
.port_get_dscp_prio = ksz_port_get_dscp_prio,
|
||||
|
|
@ -2628,7 +2623,7 @@ const struct dsa_switch_ops ksz87xx_switch_ops = {
|
|||
const struct dsa_switch_ops ksz88xx_switch_ops = {
|
||||
.get_tag_protocol = ksz88xx_get_tag_protocol,
|
||||
.connect_tag_protocol = ksz88xx_connect_tag_protocol,
|
||||
.get_phy_flags = ksz_get_phy_flags,
|
||||
.get_phy_flags = ksz88xx_get_phy_flags,
|
||||
.setup = ksz8_setup,
|
||||
.teardown = ksz_teardown,
|
||||
.phy_read = ksz8_phy_read16,
|
||||
|
|
@ -2640,11 +2635,8 @@ const struct dsa_switch_ops ksz88xx_switch_ops = {
|
|||
.get_sset_count = ksz_sset_count,
|
||||
.port_bridge_join = ksz_port_bridge_join,
|
||||
.port_bridge_leave = ksz_port_bridge_leave,
|
||||
.port_hsr_join = ksz_hsr_join,
|
||||
.port_hsr_leave = ksz_hsr_leave,
|
||||
.port_set_mac_address = ksz_port_set_mac_address,
|
||||
.port_stp_state_set = ksz_port_stp_state_set,
|
||||
.port_teardown = ksz_port_teardown,
|
||||
.port_pre_bridge_flags = ksz_port_pre_bridge_flags,
|
||||
.port_bridge_flags = ksz_port_bridge_flags,
|
||||
.port_fast_age = ksz8_flush_dyn_mac_table,
|
||||
|
|
@ -2671,11 +2663,7 @@ const struct dsa_switch_ops ksz88xx_switch_ops = {
|
|||
.port_hwtstamp_set = ksz_hwtstamp_set,
|
||||
.port_txtstamp = ksz_port_txtstamp,
|
||||
.port_rxtstamp = ksz_port_rxtstamp,
|
||||
.cls_flower_add = ksz_cls_flower_add,
|
||||
.cls_flower_del = ksz_cls_flower_del,
|
||||
.port_setup_tc = ksz_setup_tc,
|
||||
.support_eee = ksz_support_eee,
|
||||
.set_mac_eee = ksz_set_mac_eee,
|
||||
.port_get_default_prio = ksz_port_get_default_prio,
|
||||
.port_set_default_prio = ksz_port_set_default_prio,
|
||||
.port_get_dscp_prio = ksz_port_get_dscp_prio,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/platform_data/microchip-ksz.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_hsr.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/dsa.h>
|
||||
#include <net/switchdev.h>
|
||||
|
|
@ -1707,12 +1708,52 @@ static int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
|
|||
*/
|
||||
#define KSZ9477_SUPPORTED_HSR_FEATURES (NETIF_F_HW_HSR_DUP | NETIF_F_HW_HSR_FWD)
|
||||
|
||||
void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr)
|
||||
static int ksz9477_hsr_join(struct dsa_switch *ds, int port,
|
||||
struct net_device *hsr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
struct net_device *user;
|
||||
struct dsa_port *hsr_dp;
|
||||
u8 data, hsr_ports = 0;
|
||||
enum hsr_version ver;
|
||||
int ret;
|
||||
|
||||
ret = hsr_get_version(hsr, &ver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->chip_id != KSZ9477_CHIP_ID) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Chip does not support HSR offload");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 can support HW offloading of only 1 HSR device */
|
||||
if (dev->hsr_dev && hsr != dev->hsr_dev) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Offload supported for a single HSR");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 only supports HSR v0 and v1 */
|
||||
if (!(ver == HSR_V0 || ver == HSR_V1)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Only HSR v0 and v1 supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 can only perform HSR offloading for up to two ports */
|
||||
if (hweight8(dev->hsr_ports) >= 2) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Cannot offload more than two ports - using software HSR");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Self MAC address filtering, to avoid frames traversing
|
||||
* the HSR ring more than once.
|
||||
*/
|
||||
ret = ksz_switch_macaddr_get(ds, port, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Program which port(s) shall support HSR */
|
||||
ksz_rmw32(dev, REG_HSR_PORT_MAP__4, BIT(port), BIT(port));
|
||||
|
|
@ -1744,12 +1785,20 @@ void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr)
|
|||
/* Setup HW supported features for lan HSR ports */
|
||||
user = dsa_to_port(ds, port)->user;
|
||||
user->features |= KSZ9477_SUPPORTED_HSR_FEATURES;
|
||||
|
||||
dev->hsr_dev = hsr;
|
||||
dev->hsr_ports |= BIT(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr)
|
||||
static int ksz9477_hsr_leave(struct dsa_switch *ds, int port,
|
||||
struct net_device *hsr)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
WARN_ON(dev->chip_id != KSZ9477_CHIP_ID);
|
||||
|
||||
/* Clear port HSR support */
|
||||
ksz_rmw32(dev, REG_HSR_PORT_MAP__4, BIT(port), 0);
|
||||
|
||||
|
|
@ -1758,6 +1807,14 @@ void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr)
|
|||
|
||||
/* Disable per port self-address filtering */
|
||||
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, PORT_SRC_ADDR_FILTER, false);
|
||||
|
||||
dev->hsr_ports &= ~BIT(port);
|
||||
if (!dev->hsr_ports)
|
||||
dev->hsr_dev = NULL;
|
||||
|
||||
ksz_switch_macaddr_put(ds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz9477_switch_init(struct ksz_device *dev)
|
||||
|
|
@ -1884,6 +1941,14 @@ static void ksz9477_duplex_flowctrl(struct ksz_device *dev, int port, int duplex
|
|||
ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val);
|
||||
}
|
||||
|
||||
static void ksz9477_port_teardown(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
if (dsa_is_user_port(ds, port))
|
||||
ksz9477_port_acl_free(dev, port);
|
||||
}
|
||||
|
||||
void ksz9477_phylink_mac_link_up(struct phylink_config *config,
|
||||
struct phy_device *phydev,
|
||||
unsigned int mode,
|
||||
|
|
@ -1909,6 +1974,54 @@ void ksz9477_phylink_mac_link_up(struct phylink_config *config,
|
|||
ksz9477_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksz9477_support_eee - Determine Energy Efficient Ethernet (EEE) support for a
|
||||
* port
|
||||
* @ds: Pointer to the DSA switch structure
|
||||
* @port: Port number to check
|
||||
*
|
||||
* This function also documents devices where EEE was initially advertised but
|
||||
* later withdrawn due to reliability issues, as described in official errata
|
||||
* documents. These devices are explicitly listed to record known limitations,
|
||||
* even if there is no technical necessity for runtime checks.
|
||||
*
|
||||
* Returns: true if the internal PHY on the given port supports fully
|
||||
* operational EEE, false otherwise.
|
||||
*/
|
||||
static bool ksz9477_support_eee(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
if (!dev->info->internal_phy[port])
|
||||
return false;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ8563_CHIP_ID:
|
||||
case KSZ9563_CHIP_ID:
|
||||
case KSZ9893_CHIP_ID:
|
||||
return true;
|
||||
default:
|
||||
/* KSZ8567R Errata DS80000752C Module 4 */
|
||||
/* KSZ9477S Errata DS80000754A Module 4 */
|
||||
/* KSZ9567S Errata DS80000756A Module 4 */
|
||||
/* KSZ9896C Errata DS80000757A Module 3 */
|
||||
/* KSZ9897R Errata DS80000758C Module 4 */
|
||||
/* Energy Efficient Ethernet (EEE) feature select must be
|
||||
* manually disabled
|
||||
* The EEE feature is enabled by default, but it is not fully
|
||||
* operational. It must be manually disabled through register
|
||||
* controls. If not disabled, the PHY ports can auto-negotiate
|
||||
* to enable EEE, and this feature can cause link drops when
|
||||
* linked to another device supporting EEE.
|
||||
*
|
||||
* The same item appears in the errata for all switches above.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct phylink_pcs *
|
||||
ksz9477_phylink_mac_select_pcs(struct phylink_config *config,
|
||||
phy_interface_t interface)
|
||||
|
|
@ -1952,7 +2065,6 @@ const struct ksz_dev_ops ksz9477_dev_ops = {
|
|||
const struct dsa_switch_ops ksz9477_switch_ops = {
|
||||
.get_tag_protocol = ksz9477_get_tag_protocol,
|
||||
.connect_tag_protocol = ksz9477_connect_tag_protocol,
|
||||
.get_phy_flags = ksz_get_phy_flags,
|
||||
.setup = ksz9477_setup,
|
||||
.teardown = ksz_teardown,
|
||||
.phy_read = ksz9477_phy_read16,
|
||||
|
|
@ -1965,11 +2077,11 @@ const struct dsa_switch_ops ksz9477_switch_ops = {
|
|||
.get_sset_count = ksz_sset_count,
|
||||
.port_bridge_join = ksz_port_bridge_join,
|
||||
.port_bridge_leave = ksz_port_bridge_leave,
|
||||
.port_hsr_join = ksz_hsr_join,
|
||||
.port_hsr_leave = ksz_hsr_leave,
|
||||
.port_hsr_join = ksz9477_hsr_join,
|
||||
.port_hsr_leave = ksz9477_hsr_leave,
|
||||
.port_set_mac_address = ksz_port_set_mac_address,
|
||||
.port_stp_state_set = ksz_port_stp_state_set,
|
||||
.port_teardown = ksz_port_teardown,
|
||||
.port_teardown = ksz9477_port_teardown,
|
||||
.port_pre_bridge_flags = ksz_port_pre_bridge_flags,
|
||||
.port_bridge_flags = ksz_port_bridge_flags,
|
||||
.port_fast_age = ksz9477_flush_dyn_mac_table,
|
||||
|
|
@ -1996,10 +2108,10 @@ const struct dsa_switch_ops ksz9477_switch_ops = {
|
|||
.port_hwtstamp_set = ksz_hwtstamp_set,
|
||||
.port_txtstamp = ksz_port_txtstamp,
|
||||
.port_rxtstamp = ksz_port_rxtstamp,
|
||||
.cls_flower_add = ksz_cls_flower_add,
|
||||
.cls_flower_del = ksz_cls_flower_del,
|
||||
.cls_flower_add = ksz9477_cls_flower_add,
|
||||
.cls_flower_del = ksz9477_cls_flower_del,
|
||||
.port_setup_tc = ksz_setup_tc,
|
||||
.support_eee = ksz_support_eee,
|
||||
.support_eee = ksz9477_support_eee,
|
||||
.set_mac_eee = ksz_set_mac_eee,
|
||||
.port_get_default_prio = ksz_port_get_default_prio,
|
||||
.port_set_default_prio = ksz_port_set_default_prio,
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ int ksz9477_mdb_del(struct dsa_switch *ds, int port,
|
|||
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
|
||||
int ksz9477_enable_stp_addr(struct ksz_device *dev);
|
||||
void ksz9477_port_queue_split(struct ksz_device *dev, int port);
|
||||
void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr);
|
||||
void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr);
|
||||
|
||||
int ksz9477_port_acl_init(struct ksz_device *dev, int port);
|
||||
void ksz9477_port_acl_free(struct ksz_device *dev, int port);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_hsr.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -2257,7 +2256,7 @@ static void ksz_update_port_member(struct ksz_device *dev, int port)
|
|||
dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
|
||||
}
|
||||
|
||||
static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
{
|
||||
struct ksz_device *dev = bus->priv;
|
||||
struct dsa_switch *ds = dev->ds;
|
||||
|
|
@ -2265,8 +2264,7 @@ static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
|||
return ds->ops->phy_read(ds, addr, regnum);
|
||||
}
|
||||
|
||||
static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
|
||||
u16 val)
|
||||
int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
|
||||
{
|
||||
struct ksz_device *dev = bus->priv;
|
||||
struct dsa_switch *ds = dev->ds;
|
||||
|
|
@ -2287,7 +2285,7 @@ static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
|
|||
*
|
||||
* Return: Value of the PHY register, or a negative error code on failure.
|
||||
*/
|
||||
static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
{
|
||||
struct ksz_device *dev = bus->priv;
|
||||
|
||||
|
|
@ -2307,8 +2305,7 @@ static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
|||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum,
|
||||
u16 val)
|
||||
int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
|
||||
{
|
||||
struct ksz_device *dev = bus->priv;
|
||||
|
||||
|
|
@ -2416,8 +2413,8 @@ static void ksz_irq_phy_free(struct ksz_device *dev)
|
|||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
|
||||
struct device_node *mdio_np)
|
||||
int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
|
||||
struct device_node *mdio_np)
|
||||
{
|
||||
struct device_node *phy_node, *phy_parent_node;
|
||||
bool phys_are_valid = true;
|
||||
|
|
@ -2520,20 +2517,8 @@ int ksz_mdio_register(struct ksz_device *dev)
|
|||
goto put_mdio_node;
|
||||
}
|
||||
|
||||
if (dev->dev_ops->mdio_bus_preinit) {
|
||||
ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus);
|
||||
if (ret)
|
||||
goto put_mdio_node;
|
||||
}
|
||||
|
||||
if (dev->dev_ops->create_phy_addr_map) {
|
||||
ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus);
|
||||
if (ret)
|
||||
goto put_mdio_node;
|
||||
} else {
|
||||
for (i = 0; i < dev->info->port_cnt; i++)
|
||||
dev->phy_addr_map[i] = i;
|
||||
}
|
||||
for (i = 0; i < dev->info->port_cnt; i++)
|
||||
dev->phy_addr_map[i] = i;
|
||||
|
||||
bus->priv = dev;
|
||||
if (parent_bus) {
|
||||
|
|
@ -2838,24 +2823,6 @@ void ksz_init_mib_timer(struct ksz_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ88X3_CHIP_ID:
|
||||
/* Silicon Errata Sheet (DS80000830A):
|
||||
* Port 1 does not work with LinkMD Cable-Testing.
|
||||
* Port 1 does not respond to received PAUSE control frames.
|
||||
*/
|
||||
if (!port)
|
||||
return MICREL_KSZ8_P1_ERRATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksz_phylink_mac_link_down(struct phylink_config *config,
|
||||
unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
|
|
@ -2986,25 +2953,6 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
|||
ksz_update_port_member(dev, port);
|
||||
}
|
||||
|
||||
void ksz_port_teardown(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ8563_CHIP_ID:
|
||||
case KSZ8567_CHIP_ID:
|
||||
case KSZ9477_CHIP_ID:
|
||||
case KSZ9563_CHIP_ID:
|
||||
case KSZ9567_CHIP_ID:
|
||||
case KSZ9893_CHIP_ID:
|
||||
case KSZ9896_CHIP_ID:
|
||||
case KSZ9897_CHIP_ID:
|
||||
case LAN9646_CHIP_ID:
|
||||
if (dsa_is_user_port(ds, port))
|
||||
ksz9477_port_acl_free(dev, port);
|
||||
}
|
||||
}
|
||||
|
||||
int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port,
|
||||
struct switchdev_brport_flags flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
|
@ -3070,63 +3018,6 @@ int ksz_max_mtu(struct dsa_switch *ds, int port)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksz_support_eee - Determine Energy Efficient Ethernet (EEE) support for a
|
||||
* port
|
||||
* @ds: Pointer to the DSA switch structure
|
||||
* @port: Port number to check
|
||||
*
|
||||
* This function also documents devices where EEE was initially advertised but
|
||||
* later withdrawn due to reliability issues, as described in official errata
|
||||
* documents. These devices are explicitly listed to record known limitations,
|
||||
* even if there is no technical necessity for runtime checks.
|
||||
*
|
||||
* Returns: true if the internal PHY on the given port supports fully
|
||||
* operational EEE, false otherwise.
|
||||
*/
|
||||
bool ksz_support_eee(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
if (!dev->info->internal_phy[port])
|
||||
return false;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ8563_CHIP_ID:
|
||||
case KSZ9563_CHIP_ID:
|
||||
case KSZ9893_CHIP_ID:
|
||||
return true;
|
||||
case KSZ8567_CHIP_ID:
|
||||
/* KSZ8567R Errata DS80000752C Module 4 */
|
||||
case KSZ8765_CHIP_ID:
|
||||
case KSZ8794_CHIP_ID:
|
||||
case KSZ8795_CHIP_ID:
|
||||
/* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */
|
||||
case KSZ9477_CHIP_ID:
|
||||
/* KSZ9477S Errata DS80000754A Module 4 */
|
||||
case KSZ9567_CHIP_ID:
|
||||
/* KSZ9567S Errata DS80000756A Module 4 */
|
||||
case KSZ9896_CHIP_ID:
|
||||
/* KSZ9896C Errata DS80000757A Module 3 */
|
||||
case KSZ9897_CHIP_ID:
|
||||
case LAN9646_CHIP_ID:
|
||||
/* KSZ9897R Errata DS80000758C Module 4 */
|
||||
/* Energy Efficient Ethernet (EEE) feature select must be
|
||||
* manually disabled
|
||||
* The EEE feature is enabled by default, but it is not fully
|
||||
* operational. It must be manually disabled through register
|
||||
* controls. If not disabled, the PHY ports can auto-negotiate
|
||||
* to enable EEE, and this feature can cause link drops when
|
||||
* linked to another device supporting EEE.
|
||||
*
|
||||
* The same item appears in the errata for all switches above.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ksz_set_mac_eee(struct dsa_switch *ds, int port,
|
||||
struct ethtool_keee *e)
|
||||
{
|
||||
|
|
@ -3145,8 +3036,7 @@ int ksz_set_mac_eee(struct dsa_switch *ds, int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ksz_set_xmii(struct ksz_device *dev, int port,
|
||||
phy_interface_t interface)
|
||||
void ksz_set_xmii(struct ksz_device *dev, int port, phy_interface_t interface)
|
||||
{
|
||||
const u8 *bitval = dev->info->xmii_ctrl1;
|
||||
struct ksz_port *p = &dev->ports[port];
|
||||
|
|
@ -3229,6 +3119,29 @@ phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit)
|
|||
return interface;
|
||||
}
|
||||
|
||||
bool ksz_phylink_need_config(struct phylink_config *config,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||
struct ksz_device *dev = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
|
||||
/* Internal PHYs */
|
||||
if (dev->info->internal_phy[port])
|
||||
return false;
|
||||
|
||||
/* No need to configure XMII control register when using SGMII. */
|
||||
if (ksz_is_sgmii_port(dev, port))
|
||||
return false;
|
||||
|
||||
if (phylink_autoneg_inband(mode)) {
|
||||
dev_err(dev->dev, "In-band AN not supported!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ksz_phylink_mac_config(struct phylink_config *config,
|
||||
unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
|
|
@ -3237,23 +3150,8 @@ void ksz_phylink_mac_config(struct phylink_config *config,
|
|||
struct ksz_device *dev = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
|
||||
/* Internal PHYs */
|
||||
if (dev->info->internal_phy[port])
|
||||
return;
|
||||
|
||||
/* No need to configure XMII control register when using SGMII. */
|
||||
if (ksz_is_sgmii_port(dev, port))
|
||||
return;
|
||||
|
||||
if (phylink_autoneg_inband(mode)) {
|
||||
dev_err(dev->dev, "In-band AN not supported!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ksz_set_xmii(dev, port, state->interface);
|
||||
|
||||
if (dev->dev_ops->setup_rgmii_delay)
|
||||
dev->dev_ops->setup_rgmii_delay(dev, port);
|
||||
if (ksz_phylink_need_config(config, mode))
|
||||
ksz_set_xmii(dev, port, state->interface);
|
||||
}
|
||||
|
||||
bool ksz_get_gbit(struct ksz_device *dev, int port)
|
||||
|
|
@ -3373,48 +3271,6 @@ static int ksz_switch_detect(struct ksz_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ksz_cls_flower_add(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ8563_CHIP_ID:
|
||||
case KSZ8567_CHIP_ID:
|
||||
case KSZ9477_CHIP_ID:
|
||||
case KSZ9563_CHIP_ID:
|
||||
case KSZ9567_CHIP_ID:
|
||||
case KSZ9893_CHIP_ID:
|
||||
case KSZ9896_CHIP_ID:
|
||||
case KSZ9897_CHIP_ID:
|
||||
case LAN9646_CHIP_ID:
|
||||
return ksz9477_cls_flower_add(ds, port, cls, ingress);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int ksz_cls_flower_del(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
switch (dev->chip_id) {
|
||||
case KSZ8563_CHIP_ID:
|
||||
case KSZ8567_CHIP_ID:
|
||||
case KSZ9477_CHIP_ID:
|
||||
case KSZ9563_CHIP_ID:
|
||||
case KSZ9567_CHIP_ID:
|
||||
case KSZ9893_CHIP_ID:
|
||||
case KSZ9896_CHIP_ID:
|
||||
case KSZ9897_CHIP_ID:
|
||||
case LAN9646_CHIP_ID:
|
||||
return ksz9477_cls_flower_del(ds, port, cls, ingress);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Bandwidth is calculated by idle slope/transmission speed. Then the Bandwidth
|
||||
* is converted to Hex-decimal using the successive multiplication method. On
|
||||
* every step, integer part is taken and decimal part is carry forwarded.
|
||||
|
|
@ -3866,9 +3722,6 @@ void ksz_get_wol(struct dsa_switch *ds, int port,
|
|||
u8 pme_ctrl;
|
||||
int ret;
|
||||
|
||||
if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev))
|
||||
return;
|
||||
|
||||
if (!dev->wakeup_source)
|
||||
return;
|
||||
|
||||
|
|
@ -3919,9 +3772,6 @@ int ksz_set_wol(struct dsa_switch *ds, int port,
|
|||
if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!dev->wakeup_source)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -3981,12 +3831,13 @@ static void ksz_wol_pre_shutdown(struct ksz_device *dev)
|
|||
{
|
||||
const struct ksz_dev_ops *ops = dev->dev_ops;
|
||||
const u16 *regs = dev->info->regs;
|
||||
struct dsa_switch *ds = dev->ds;
|
||||
u8 pme_pin_en = PME_ENABLE;
|
||||
bool wol_enabled = false;
|
||||
struct dsa_port *dp;
|
||||
int ret;
|
||||
|
||||
if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev))
|
||||
if (!ds->ops->set_wol)
|
||||
return;
|
||||
|
||||
if (!dev->wakeup_source)
|
||||
|
|
@ -4034,7 +3885,8 @@ int ksz_port_set_mac_address(struct dsa_switch *ds, int port,
|
|||
*/
|
||||
wol.wolopts = 0;
|
||||
|
||||
ksz_get_wol(ds, dp->index, &wol);
|
||||
if (ds->ops->get_wol)
|
||||
ds->ops->get_wol(ds, dp->index, &wol);
|
||||
if (wol.wolopts & WAKE_MAGIC) {
|
||||
dev_err(ds->dev,
|
||||
"Cannot change MAC address on port %d with active Wake on Magic Packet\n",
|
||||
|
|
@ -4169,72 +4021,6 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds)
|
|||
kfree(switch_macaddr);
|
||||
}
|
||||
|
||||
int ksz_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
enum hsr_version ver;
|
||||
int ret;
|
||||
|
||||
ret = hsr_get_version(hsr, &ver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->chip_id != KSZ9477_CHIP_ID) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Chip does not support HSR offload");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 can support HW offloading of only 1 HSR device */
|
||||
if (dev->hsr_dev && hsr != dev->hsr_dev) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Offload supported for a single HSR");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 only supports HSR v0 and v1 */
|
||||
if (!(ver == HSR_V0 || ver == HSR_V1)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Only HSR v0 and v1 supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* KSZ9477 can only perform HSR offloading for up to two ports */
|
||||
if (hweight8(dev->hsr_ports) >= 2) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Cannot offload more than two ports - using software HSR");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Self MAC address filtering, to avoid frames traversing
|
||||
* the HSR ring more than once.
|
||||
*/
|
||||
ret = ksz_switch_macaddr_get(ds, port, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ksz9477_hsr_join(ds, port, hsr);
|
||||
dev->hsr_dev = hsr;
|
||||
dev->hsr_ports |= BIT(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksz_hsr_leave(struct dsa_switch *ds, int port,
|
||||
struct net_device *hsr)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
WARN_ON(dev->chip_id != KSZ9477_CHIP_ID);
|
||||
|
||||
ksz9477_hsr_leave(ds, port, hsr);
|
||||
dev->hsr_ports &= ~BIT(port);
|
||||
if (!dev->hsr_ports)
|
||||
dev->hsr_dev = NULL;
|
||||
|
||||
ksz_switch_macaddr_put(ds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksz_suspend(struct dsa_switch *ds)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
|
|
|||
|
|
@ -366,42 +366,6 @@ struct ksz_dev_ops {
|
|||
u32 (*get_port_addr)(int port, int offset);
|
||||
void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member);
|
||||
|
||||
/**
|
||||
* @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus
|
||||
* for accessing PHYs.
|
||||
* @dev: Pointer to device structure.
|
||||
* @side_mdio: Boolean indicating if the PHYs are accessed over a side
|
||||
* MDIO bus.
|
||||
*
|
||||
* This function pointer is used to configure the MDIO bus for PHY
|
||||
* access before initiating regular PHY operations. It enables either
|
||||
* SPI/I2C or side MDIO access modes by unlocking necessary registers
|
||||
* and setting up access permissions for the selected mode.
|
||||
*
|
||||
* Return:
|
||||
* - 0 on success.
|
||||
* - Negative error code on failure.
|
||||
*/
|
||||
int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio);
|
||||
|
||||
/**
|
||||
* @create_phy_addr_map: Function pointer to create a port-to-PHY
|
||||
* address map.
|
||||
* @dev: Pointer to device structure.
|
||||
* @side_mdio: Boolean indicating if the PHYs are accessed over a side
|
||||
* MDIO bus.
|
||||
*
|
||||
* This function pointer is responsible for mapping switch ports to PHY
|
||||
* addresses according to the configured access mode (SPI or side MDIO)
|
||||
* and the device’s strap configuration. The mapping setup may vary
|
||||
* depending on the chip variant and configuration. Ensures the correct
|
||||
* address mapping for PHY communication.
|
||||
*
|
||||
* Return:
|
||||
* - 0 on success.
|
||||
* - Negative error code on failure (e.g., invalid configuration).
|
||||
*/
|
||||
int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio);
|
||||
void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr,
|
||||
u64 *cnt);
|
||||
void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr,
|
||||
|
|
@ -414,7 +378,6 @@ struct ksz_dev_ops {
|
|||
u8 data);
|
||||
void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze);
|
||||
void (*port_init_cnt)(struct ksz_device *dev, int port);
|
||||
void (*setup_rgmii_delay)(struct ksz_device *dev, int port);
|
||||
int (*tc_cbs_set_cinc)(struct ksz_device *dev, int port, u32 val);
|
||||
int (*init)(struct ksz_device *dev);
|
||||
};
|
||||
|
|
@ -428,7 +391,6 @@ int ksz_switch_suspend(struct device *dev);
|
|||
int ksz_switch_resume(struct device *dev);
|
||||
|
||||
void ksz_teardown(struct dsa_switch *ds);
|
||||
void ksz_port_teardown(struct dsa_switch *ds, int port);
|
||||
|
||||
void ksz_init_mib_timer(struct ksz_device *dev);
|
||||
bool ksz_is_port_mac_global_usable(struct dsa_switch *ds, int port);
|
||||
|
|
@ -444,8 +406,6 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds);
|
|||
void ksz_switch_shutdown(struct ksz_device *dev);
|
||||
int ksz_handle_wake_reason(struct ksz_device *dev, int port);
|
||||
|
||||
u32 ksz_get_phy_flags(struct dsa_switch *ds, int port);
|
||||
|
||||
int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
|
||||
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
uint64_t *buf);
|
||||
|
|
@ -474,6 +434,8 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
|
|||
void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config);
|
||||
int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config,
|
||||
u32 timer, bool tx_clock_stop);
|
||||
void ksz_set_xmii(struct ksz_device *dev, int port, phy_interface_t interface);
|
||||
bool ksz_phylink_need_config(struct phylink_config *config, unsigned int mode);
|
||||
void ksz_phylink_mac_config(struct phylink_config *config,
|
||||
unsigned int mode,
|
||||
const struct phylink_link_state *state);
|
||||
|
|
@ -483,14 +445,9 @@ void ksz_phylink_mac_link_down(struct phylink_config *config,
|
|||
|
||||
int ksz_max_mtu(struct dsa_switch *ds, int port);
|
||||
|
||||
bool ksz_support_eee(struct dsa_switch *ds, int port);
|
||||
int ksz_set_mac_eee(struct dsa_switch *ds, int port,
|
||||
struct ethtool_keee *e);
|
||||
|
||||
int ksz_cls_flower_add(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress);
|
||||
int ksz_cls_flower_del(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress);
|
||||
int ksz_setup_tc(struct dsa_switch *ds, int port,
|
||||
enum tc_setup_type type, void *type_data);
|
||||
|
||||
|
|
@ -500,14 +457,16 @@ int ksz_set_wol(struct dsa_switch *ds, int port,
|
|||
struct ethtool_wolinfo *wol);
|
||||
int ksz_port_set_mac_address(struct dsa_switch *ds, int port,
|
||||
const unsigned char *addr);
|
||||
int ksz_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr,
|
||||
struct netlink_ext_ack *extack);
|
||||
int ksz_hsr_leave(struct dsa_switch *ds, int port,
|
||||
struct net_device *hsr);
|
||||
|
||||
int ksz_suspend(struct dsa_switch *ds);
|
||||
int ksz_resume(struct dsa_switch *ds);
|
||||
|
||||
int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
|
||||
struct device_node *mdio_np);
|
||||
int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum);
|
||||
int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val);
|
||||
int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum);
|
||||
int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val);
|
||||
int ksz_mdio_register(struct ksz_device *dev);
|
||||
int ksz_pirq_setup(struct ksz_device *dev, u8 p);
|
||||
int ksz_girq_setup(struct ksz_device *dev);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_vlan.h>
|
||||
|
|
@ -643,6 +644,20 @@ static void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port)
|
|||
}
|
||||
}
|
||||
|
||||
static void lan937x_phylink_mac_config(struct phylink_config *config,
|
||||
unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||
struct ksz_device *dev = dp->ds->priv;
|
||||
int port = dp->index;
|
||||
|
||||
if (ksz_phylink_need_config(config, mode)) {
|
||||
ksz_set_xmii(dev, port, state->interface);
|
||||
lan937x_setup_rgmii_delay(dev, port);
|
||||
}
|
||||
}
|
||||
|
||||
static int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
|
||||
{
|
||||
return ksz_pwrite32(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);
|
||||
|
|
@ -655,6 +670,101 @@ static int lan937x_switch_init(struct ksz_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lan937x_mdio_register - Register and configure the MDIO bus for the LAN937x.
|
||||
* @dev: Pointer to the KSZ device structure.
|
||||
*
|
||||
* This function sets up and registers an MDIO bus for a LAN937x switch,
|
||||
* allowing access to its internal PHYs. If the device supports side MDIO,
|
||||
* the function will configure the external MDIO controller specified by the
|
||||
* "mdio-parent-bus" device tree property to directly manage internal PHYs.
|
||||
* Otherwise, SPI or I2C access is set up for PHY access.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
static int lan937x_mdio_register(struct ksz_device *dev)
|
||||
{
|
||||
struct device_node *parent_bus_node;
|
||||
struct mii_bus *parent_bus = NULL;
|
||||
struct dsa_switch *ds = dev->ds;
|
||||
struct device_node *mdio_np;
|
||||
struct mii_bus *bus;
|
||||
int ret;
|
||||
|
||||
mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio");
|
||||
if (!mdio_np)
|
||||
return 0;
|
||||
|
||||
parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0);
|
||||
if (parent_bus_node && !dev->info->phy_side_mdio_supported) {
|
||||
dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n");
|
||||
ret = -EINVAL;
|
||||
|
||||
goto put_mdio_node;
|
||||
} else if (parent_bus_node) {
|
||||
parent_bus = of_mdio_find_bus(parent_bus_node);
|
||||
if (!parent_bus) {
|
||||
ret = -EPROBE_DEFER;
|
||||
|
||||
goto put_mdio_node;
|
||||
}
|
||||
|
||||
dev->parent_mdio_bus = parent_bus;
|
||||
}
|
||||
|
||||
bus = devm_mdiobus_alloc(ds->dev);
|
||||
if (!bus) {
|
||||
ret = -ENOMEM;
|
||||
goto put_mdio_node;
|
||||
}
|
||||
|
||||
ret = lan937x_mdio_bus_preinit(dev, !!parent_bus);
|
||||
if (ret)
|
||||
goto put_mdio_node;
|
||||
|
||||
ret = lan937x_create_phy_addr_map(dev, !!parent_bus);
|
||||
if (ret)
|
||||
goto put_mdio_node;
|
||||
|
||||
bus->priv = dev;
|
||||
if (parent_bus) {
|
||||
bus->read = ksz_parent_mdio_read;
|
||||
bus->write = ksz_parent_mdio_write;
|
||||
bus->name = "KSZ side MDIO";
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d",
|
||||
ds->index);
|
||||
} else {
|
||||
bus->read = ksz_sw_mdio_read;
|
||||
bus->write = ksz_sw_mdio_write;
|
||||
bus->name = "ksz user smi";
|
||||
if (ds->dst->index != 0)
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d-%d",
|
||||
ds->dst->index, ds->index);
|
||||
else
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index);
|
||||
}
|
||||
|
||||
ret = ksz_parse_dt_phy_config(dev, bus, mdio_np);
|
||||
if (ret)
|
||||
goto put_mdio_node;
|
||||
|
||||
ds->phys_mii_mask = bus->phy_mask;
|
||||
bus->parent = ds->dev;
|
||||
|
||||
ds->user_mii_bus = bus;
|
||||
|
||||
ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np);
|
||||
if (ret)
|
||||
dev_err(ds->dev, "unable to register MDIO bus %s\n",
|
||||
bus->id);
|
||||
|
||||
put_mdio_node:
|
||||
of_node_put(mdio_np);
|
||||
of_node_put(parent_bus_node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lan937x_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
|
@ -768,7 +878,7 @@ static int lan937x_setup(struct dsa_switch *ds)
|
|||
goto port_release;
|
||||
}
|
||||
|
||||
ret = ksz_mdio_register(dev);
|
||||
ret = lan937x_mdio_register(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "failed to register the mdio");
|
||||
goto out_ptp_clock_unregister;
|
||||
|
|
@ -821,7 +931,7 @@ static int lan937x_connect_tag_protocol(struct dsa_switch *ds,
|
|||
}
|
||||
|
||||
const struct phylink_mac_ops lan937x_phylink_mac_ops = {
|
||||
.mac_config = ksz_phylink_mac_config,
|
||||
.mac_config = lan937x_phylink_mac_config,
|
||||
.mac_link_down = ksz_phylink_mac_link_down,
|
||||
.mac_link_up = ksz9477_phylink_mac_link_up,
|
||||
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
|
||||
|
|
@ -831,14 +941,11 @@ const struct phylink_mac_ops lan937x_phylink_mac_ops = {
|
|||
const struct ksz_dev_ops lan937x_dev_ops = {
|
||||
.get_port_addr = ksz9477_get_port_addr,
|
||||
.cfg_port_member = ksz9477_cfg_port_member,
|
||||
.mdio_bus_preinit = lan937x_mdio_bus_preinit,
|
||||
.create_phy_addr_map = lan937x_create_phy_addr_map,
|
||||
.r_mib_cnt = ksz9477_r_mib_cnt,
|
||||
.r_mib_pkt = ksz9477_r_mib_pkt,
|
||||
.r_mib_stat64 = ksz_r_mib_stats64,
|
||||
.freeze_mib = ksz9477_freeze_mib,
|
||||
.port_init_cnt = ksz9477_port_init_cnt,
|
||||
.setup_rgmii_delay = lan937x_setup_rgmii_delay,
|
||||
.tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc,
|
||||
.init = lan937x_switch_init,
|
||||
};
|
||||
|
|
@ -846,7 +953,6 @@ const struct ksz_dev_ops lan937x_dev_ops = {
|
|||
const struct dsa_switch_ops lan937x_switch_ops = {
|
||||
.get_tag_protocol = lan937x_get_tag_protocol,
|
||||
.connect_tag_protocol = lan937x_connect_tag_protocol,
|
||||
.get_phy_flags = ksz_get_phy_flags,
|
||||
.setup = lan937x_setup,
|
||||
.teardown = ksz_teardown,
|
||||
.phy_read = lan937x_phy_read16,
|
||||
|
|
@ -859,11 +965,8 @@ const struct dsa_switch_ops lan937x_switch_ops = {
|
|||
.get_sset_count = ksz_sset_count,
|
||||
.port_bridge_join = ksz_port_bridge_join,
|
||||
.port_bridge_leave = ksz_port_bridge_leave,
|
||||
.port_hsr_join = ksz_hsr_join,
|
||||
.port_hsr_leave = ksz_hsr_leave,
|
||||
.port_set_mac_address = ksz_port_set_mac_address,
|
||||
.port_stp_state_set = ksz_port_stp_state_set,
|
||||
.port_teardown = ksz_port_teardown,
|
||||
.port_pre_bridge_flags = ksz_port_pre_bridge_flags,
|
||||
.port_bridge_flags = ksz_port_bridge_flags,
|
||||
.port_fast_age = ksz9477_flush_dyn_mac_table,
|
||||
|
|
@ -881,8 +984,6 @@ const struct dsa_switch_ops lan937x_switch_ops = {
|
|||
.get_pause_stats = ksz_get_pause_stats,
|
||||
.port_change_mtu = lan937x_change_mtu,
|
||||
.port_max_mtu = ksz_max_mtu,
|
||||
.get_wol = ksz_get_wol,
|
||||
.set_wol = ksz_set_wol,
|
||||
.suspend = ksz_suspend,
|
||||
.resume = ksz_resume,
|
||||
.get_ts_info = ksz_get_ts_info,
|
||||
|
|
@ -890,11 +991,7 @@ const struct dsa_switch_ops lan937x_switch_ops = {
|
|||
.port_hwtstamp_set = ksz_hwtstamp_set,
|
||||
.port_txtstamp = ksz_port_txtstamp,
|
||||
.port_rxtstamp = ksz_port_rxtstamp,
|
||||
.cls_flower_add = ksz_cls_flower_add,
|
||||
.cls_flower_del = ksz_cls_flower_del,
|
||||
.port_setup_tc = ksz_setup_tc,
|
||||
.support_eee = ksz_support_eee,
|
||||
.set_mac_eee = ksz_set_mac_eee,
|
||||
.port_get_default_prio = ksz_port_get_default_prio,
|
||||
.port_set_default_prio = ksz_port_set_default_prio,
|
||||
.port_get_dscp_prio = ksz_port_get_dscp_prio,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user