linux/drivers/net/dsa/microchip/ksz_common.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Microchip switch driver main logic
 *
 * Copyright (C) 2017-2019 Microchip Technology Inc.
 */

#include <linux/delay.h>
#include <linux/dsa/ksz_common.h>
#include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_data/microchip-ksz.h>
#include <linux/phy.h>
#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>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/micrel_phy.h>
#include <net/dsa.h>
#include <net/ieee8021q.h>
#include <net/pkt_cls.h>
#include <net/switchdev.h>

#include "ksz_common.h"
#include "ksz_dcb.h"
#include "ksz_ptp.h"
#include "ksz8.h"
#include "ksz9477.h"
#include "lan937x.h"

#define MIB_COUNTER_NUM

struct ksz_stats_raw {};

struct ksz88xx_stats_raw {};

static const struct ksz_mib_names ksz88xx_mib_names[] =;

static const struct ksz_mib_names ksz9477_mib_names[] =;

struct ksz_driver_strength_prop {};

enum ksz_driver_strength_type {};

/**
 * struct ksz_drive_strength - drive strength mapping
 * @reg_val:	register value
 * @microamp:	microamp value
 */
struct ksz_drive_strength {};

/* ksz9477_drive_strengths - Drive strength mapping for KSZ9477 variants
 *
 * This values are not documented in KSZ9477 variants but confirmed by
 * Microchip that KSZ9477, KSZ9567, KSZ8567, KSZ9897, KSZ9896, KSZ9563, KSZ9893
 * and KSZ8563 are using same register (drive strength) settings like KSZ8795.
 *
 * Documentation in KSZ8795CLX provides more information with some
 * recommendations:
 * - for high speed signals
 *   1. 4 mA or 8 mA is often used for MII, RMII, and SPI interface with using
 *      2.5V or 3.3V VDDIO.
 *   2. 12 mA or 16 mA is often used for MII, RMII, and SPI interface with
 *      using 1.8V VDDIO.
 *   3. 20 mA or 24 mA is often used for GMII/RGMII interface with using 2.5V
 *      or 3.3V VDDIO.
 *   4. 28 mA is often used for GMII/RGMII interface with using 1.8V VDDIO.
 *   5. In same interface, the heavy loading should use higher one of the
 *      drive current strength.
 * - for low speed signals
 *   1. 3.3V VDDIO, use either 4 mA or 8 mA.
 *   2. 2.5V VDDIO, use either 8 mA or 12 mA.
 *   3. 1.8V VDDIO, use either 12 mA or 16 mA.
 *   4. If it is heavy loading, can use higher drive current strength.
 */
static const struct ksz_drive_strength ksz9477_drive_strengths[] =;

/* ksz8830_drive_strengths - Drive strength mapping for KSZ8830, KSZ8873, ..
 *			     variants.
 * This values are documented in KSZ8873 and KSZ8863 datasheets.
 */
static const struct ksz_drive_strength ksz8830_drive_strengths[] =;

static void ksz8830_phylink_mac_config(struct phylink_config *config,
				       unsigned int mode,
				       const struct phylink_link_state *state);
static void ksz_phylink_mac_config(struct phylink_config *config,
				   unsigned int mode,
				   const struct phylink_link_state *state);
static void ksz_phylink_mac_link_down(struct phylink_config *config,
				      unsigned int mode,
				      phy_interface_t interface);

static const struct phylink_mac_ops ksz8830_phylink_mac_ops =;

static const struct phylink_mac_ops ksz8_phylink_mac_ops =;

static const struct ksz_dev_ops ksz8_dev_ops =;

static void ksz9477_phylink_mac_link_up(struct phylink_config *config,
					struct phy_device *phydev,
					unsigned int mode,
					phy_interface_t interface,
					int speed, int duplex, bool tx_pause,
					bool rx_pause);

static const struct phylink_mac_ops ksz9477_phylink_mac_ops =;

static const struct ksz_dev_ops ksz9477_dev_ops =;

static const struct phylink_mac_ops lan937x_phylink_mac_ops =;

static const struct ksz_dev_ops lan937x_dev_ops =;

static const u16 ksz8795_regs[] =;

static const u32 ksz8795_masks[] =;

static const u8 ksz8795_xmii_ctrl0[] =;

static const u8 ksz8795_xmii_ctrl1[] =;

static const u8 ksz8795_shifts[] =;

static const u16 ksz8863_regs[] =;

static const u32 ksz8863_masks[] =;

static u8 ksz8863_shifts[] =;

static const u16 ksz9477_regs[] =;

static const u32 ksz9477_masks[] =;

static const u8 ksz9477_shifts[] =;

static const u8 ksz9477_xmii_ctrl0[] =;

static const u8 ksz9477_xmii_ctrl1[] =;

static const u32 lan937x_masks[] =;

static const u8 lan937x_shifts[] =;

static const struct regmap_range ksz8563_valid_regs[] =;

static const struct regmap_access_table ksz8563_register_set =;

static const struct regmap_range ksz9477_valid_regs[] =;

static const struct regmap_access_table ksz9477_register_set =;

static const struct regmap_range ksz9896_valid_regs[] =;

static const struct regmap_access_table ksz9896_register_set =;

static const struct regmap_range ksz8873_valid_regs[] =;

static const struct regmap_access_table ksz8873_register_set =;

const struct ksz_chip_data ksz_switch_chips[] =;
EXPORT_SYMBOL_GPL();

static const struct ksz_chip_data *ksz_lookup_info(unsigned int prod_num)
{}

static int ksz_check_device_id(struct ksz_device *dev)
{}

static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
				 struct phylink_config *config)
{}

void ksz_r_mib_stats64(struct ksz_device *dev, int port)
{}

void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port)
{}

static void ksz_get_stats64(struct dsa_switch *ds, int port,
			    struct rtnl_link_stats64 *s)
{}

static void ksz_get_pause_stats(struct dsa_switch *ds, int port,
				struct ethtool_pause_stats *pause_stats)
{}

static void ksz_get_strings(struct dsa_switch *ds, int port,
			    u32 stringset, uint8_t *buf)
{}

/**
 * ksz_update_port_member - Adjust port forwarding rules based on STP state and
 *			    isolation settings.
 * @dev: A pointer to the struct ksz_device representing the device.
 * @port: The port number to adjust.
 *
 * This function dynamically adjusts the port membership configuration for a
 * specified port and other device ports, based on Spanning Tree Protocol (STP)
 * states and port isolation settings. Each port, including the CPU port, has a
 * membership register, represented as a bitfield, where each bit corresponds
 * to a port number. A set bit indicates permission to forward frames to that
 * port. This function iterates over all ports, updating the membership register
 * to reflect current forwarding permissions:
 *
 * 1. Forwards frames only to ports that are part of the same bridge group and
 *    in the BR_STATE_FORWARDING state.
 * 2. Takes into account the isolation status of ports; ports in the
 *    BR_STATE_FORWARDING state with BR_ISOLATED configuration will not forward
 *    frames to each other, even if they are in the same bridge group.
 * 3. Ensures that the CPU port is included in the membership based on its
 *    upstream port configuration, allowing for management and control traffic
 *    to flow as required.
 */
static void ksz_update_port_member(struct ksz_device *dev, int port)
{}

static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
{}

static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
			     u16 val)
{}

static int ksz_irq_phy_setup(struct ksz_device *dev)
{}

static void ksz_irq_phy_free(struct ksz_device *dev)
{}

static int ksz_mdio_register(struct ksz_device *dev)
{}

static void ksz_irq_mask(struct irq_data *d)
{}

static void ksz_irq_unmask(struct irq_data *d)
{}

static void ksz_irq_bus_lock(struct irq_data *d)
{}

static void ksz_irq_bus_sync_unlock(struct irq_data *d)
{}

static const struct irq_chip ksz_irq_chip =;

static int ksz_irq_domain_map(struct irq_domain *d,
			      unsigned int irq, irq_hw_number_t hwirq)
{}

static const struct irq_domain_ops ksz_irq_domain_ops =;

static void ksz_irq_free(struct ksz_irq *kirq)
{}

static irqreturn_t ksz_irq_thread_fn(int irq, void *dev_id)
{}

static int ksz_irq_common_setup(struct ksz_device *dev, struct ksz_irq *kirq)
{}

static int ksz_girq_setup(struct ksz_device *dev)
{}

static int ksz_pirq_setup(struct ksz_device *dev, u8 p)
{}

static int ksz_parse_drive_strength(struct ksz_device *dev);

static int ksz_setup(struct dsa_switch *ds)
{}

static void ksz_teardown(struct dsa_switch *ds)
{}

static void port_r_cnt(struct ksz_device *dev, int port)
{}

static void ksz_mib_read_work(struct work_struct *work)
{}

void ksz_init_mib_timer(struct ksz_device *dev)
{}

static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
{}

static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
{}

static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
{}

static void ksz_phylink_mac_link_down(struct phylink_config *config,
				      unsigned int mode,
				      phy_interface_t interface)
{}

static int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
{}

static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
				  uint64_t *buf)
{}

static int ksz_port_bridge_join(struct dsa_switch *ds, int port,
				struct dsa_bridge bridge,
				bool *tx_fwd_offload,
				struct netlink_ext_ack *extack)
{}

static void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
				  struct dsa_bridge bridge)
{}

static void ksz_port_fast_age(struct dsa_switch *ds, int port)
{}

static int ksz_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
{}

static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
			    const unsigned char *addr, u16 vid,
			    struct dsa_db db)
{}

static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
			    const unsigned char *addr,
			    u16 vid, struct dsa_db db)
{}

static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
			     dsa_fdb_dump_cb_t *cb, void *data)
{}

static int ksz_port_mdb_add(struct dsa_switch *ds, int port,
			    const struct switchdev_obj_port_mdb *mdb,
			    struct dsa_db db)
{}

static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
			    const struct switchdev_obj_port_mdb *mdb,
			    struct dsa_db db)
{}

static int ksz9477_set_default_prio_queue_mapping(struct ksz_device *dev,
						  int port)
{}

static int ksz_port_setup(struct dsa_switch *ds, int port)
{}

void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{}

static void ksz_port_teardown(struct dsa_switch *ds, int port)
{}

static int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port,
				     struct switchdev_brport_flags flags,
				     struct netlink_ext_ack *extack)
{}

static int ksz_port_bridge_flags(struct dsa_switch *ds, int port,
				 struct switchdev_brport_flags flags,
				 struct netlink_ext_ack *extack)
{}

static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
						  int port,
						  enum dsa_tag_protocol mp)
{}

static int ksz_connect_tag_protocol(struct dsa_switch *ds,
				    enum dsa_tag_protocol proto)
{}

static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
				   bool flag, struct netlink_ext_ack *extack)
{}

static int ksz_port_vlan_add(struct dsa_switch *ds, int port,
			     const struct switchdev_obj_port_vlan *vlan,
			     struct netlink_ext_ack *extack)
{}

static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
			     const struct switchdev_obj_port_vlan *vlan)
{}

static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
			       struct dsa_mall_mirror_tc_entry *mirror,
			       bool ingress, struct netlink_ext_ack *extack)
{}

static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
				struct dsa_mall_mirror_tc_entry *mirror)
{}

static int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
{}

static int ksz_max_mtu(struct dsa_switch *ds, int port)
{}

static int ksz_validate_eee(struct dsa_switch *ds, int port)
{}

static int ksz_get_mac_eee(struct dsa_switch *ds, int port,
			   struct ethtool_keee *e)
{}

static int ksz_set_mac_eee(struct dsa_switch *ds, int port,
			   struct ethtool_keee *e)
{}

static void ksz_set_xmii(struct ksz_device *dev, int port,
			 phy_interface_t interface)
{}

phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit)
{}

static void ksz8830_phylink_mac_config(struct phylink_config *config,
				       unsigned int mode,
				       const struct phylink_link_state *state)
{}

static void ksz_phylink_mac_config(struct phylink_config *config,
				   unsigned int mode,
				   const struct phylink_link_state *state)
{}

bool ksz_get_gbit(struct ksz_device *dev, int port)
{}

static void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit)
{}

static void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed)
{}

static void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed)
{}

static void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex,
				bool tx_pause, bool rx_pause)
{}

static void ksz9477_phylink_mac_link_up(struct phylink_config *config,
					struct phy_device *phydev,
					unsigned int mode,
					phy_interface_t interface,
					int speed, int duplex, bool tx_pause,
					bool rx_pause)
{}

static int ksz_switch_detect(struct ksz_device *dev)
{}

static int ksz_cls_flower_add(struct dsa_switch *ds, int port,
			      struct flow_cls_offload *cls, bool ingress)
{}

static int ksz_cls_flower_del(struct dsa_switch *ds, int port,
			      struct flow_cls_offload *cls, bool ingress)
{}

/* 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.
 */
static int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw)
{}

static int ksz_setup_tc_mode(struct ksz_device *dev, int port, u8 scheduler,
			     u8 shaper)
{}

static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
			    struct tc_cbs_qopt_offload *qopt)
{}

static int ksz_disable_egress_rate_limit(struct ksz_device *dev, int port)
{}

static int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p,
				 int band)
{}

static int ksz_queue_set_strict(struct ksz_device *dev, int port, int queue)
{}

static int ksz_queue_set_wrr(struct ksz_device *dev, int port, int queue,
			     int weight)
{}

static int ksz_tc_ets_add(struct ksz_device *dev, int port,
			  struct tc_ets_qopt_offload_replace_params *p)
{}

static int ksz_tc_ets_del(struct ksz_device *dev, int port)
{}

static int ksz_tc_ets_validate(struct ksz_device *dev, int port,
			       struct tc_ets_qopt_offload_replace_params *p)
{}

static int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port,
				  struct tc_ets_qopt_offload *qopt)
{}

static int ksz_setup_tc(struct dsa_switch *ds, int port,
			enum tc_setup_type type, void *type_data)
{}

static void ksz_get_wol(struct dsa_switch *ds, int port,
			struct ethtool_wolinfo *wol)
{}

static int ksz_set_wol(struct dsa_switch *ds, int port,
		       struct ethtool_wolinfo *wol)
{}

static int ksz_port_set_mac_address(struct dsa_switch *ds, int port,
				    const unsigned char *addr)
{}

/**
 * ksz_is_port_mac_global_usable - Check if the MAC address on a given port
 *                                 can be used as a global address.
 * @ds: Pointer to the DSA switch structure.
 * @port: The port number on which the MAC address is to be checked.
 *
 * This function examines the MAC address set on the specified port and
 * determines if it can be used as a global address for the switch.
 *
 * Return: true if the port's MAC address can be used as a global address, false
 * otherwise.
 */
bool ksz_is_port_mac_global_usable(struct dsa_switch *ds, int port)
{}

/**
 * ksz_switch_macaddr_get - Program the switch's MAC address register.
 * @ds: DSA switch instance.
 * @port: Port number.
 * @extack: Netlink extended acknowledgment.
 *
 * This function programs the switch's MAC address register with the MAC address
 * of the requesting user port. This single address is used by the switch for
 * multiple features like HSR self-address filtering and WoL. Other user ports
 * can share ownership of this address as long as their MAC address is the same.
 * The MAC addresses of user ports must not change while they have ownership of
 * the switch MAC address.
 *
 * Return: 0 on success, or other error codes on failure.
 */
int ksz_switch_macaddr_get(struct dsa_switch *ds, int port,
			   struct netlink_ext_ack *extack)
{}

void ksz_switch_macaddr_put(struct dsa_switch *ds)
{}

static int ksz_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr,
			struct netlink_ext_ack *extack)
{}

static int ksz_hsr_leave(struct dsa_switch *ds, int port,
			 struct net_device *hsr)
{}

static const struct dsa_switch_ops ksz_switch_ops =;

struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
{}
EXPORT_SYMBOL();

/**
 * ksz_switch_shutdown - Shutdown routine for the switch device.
 * @dev: The switch device structure.
 *
 * This function is responsible for initiating a shutdown sequence for the
 * switch device. It invokes the reset operation defined in the device
 * operations, if available, to reset the switch. Subsequently, it calls the
 * DSA framework's shutdown function to ensure a proper shutdown of the DSA
 * switch.
 */
void ksz_switch_shutdown(struct ksz_device *dev)
{}
EXPORT_SYMBOL();

static void ksz_parse_rgmii_delay(struct ksz_device *dev, int port_num,
				  struct device_node *port_dn)
{}

/**
 * ksz_drive_strength_to_reg() - Convert drive strength value to corresponding
 *				 register value.
 * @array:	The array of drive strength values to search.
 * @array_size:	The size of the array.
 * @microamp:	The drive strength value in microamp to be converted.
 *
 * This function searches the array of drive strength values for the given
 * microamp value and returns the corresponding register value for that drive.
 *
 * Returns: If found, the corresponding register value for that drive strength
 * is returned. Otherwise, -EINVAL is returned indicating an invalid value.
 */
static int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
				     size_t array_size, int microamp)
{}

/**
 * ksz_drive_strength_error() - Report invalid drive strength value
 * @dev:	ksz device
 * @array:	The array of drive strength values to search.
 * @array_size:	The size of the array.
 * @microamp:	Invalid drive strength value in microamp
 *
 * This function logs an error message when an unsupported drive strength value
 * is detected. It lists out all the supported drive strength values for
 * reference in the error message.
 */
static void ksz_drive_strength_error(struct ksz_device *dev,
				     const struct ksz_drive_strength *array,
				     size_t array_size, int microamp)
{}

/**
 * ksz9477_drive_strength_write() - Set the drive strength for specific KSZ9477
 *				    chip variants.
 * @dev:       ksz device
 * @props:     Array of drive strength properties to be applied
 * @num_props: Number of properties in the array
 *
 * This function configures the drive strength for various KSZ9477 chip variants
 * based on the provided properties. It handles chip-specific nuances and
 * ensures only valid drive strengths are written to the respective chip.
 *
 * Return: 0 on successful configuration, a negative error code on failure.
 */
static int ksz9477_drive_strength_write(struct ksz_device *dev,
					struct ksz_driver_strength_prop *props,
					int num_props)
{}

/**
 * ksz8830_drive_strength_write() - Set the drive strength configuration for
 *				    KSZ8830 compatible chip variants.
 * @dev:       ksz device
 * @props:     Array of drive strength properties to be set
 * @num_props: Number of properties in the array
 *
 * This function applies the specified drive strength settings to KSZ8830 chip
 * variants (KSZ8873, KSZ8863).
 * It ensures the configurations align with what the chip variant supports and
 * warns or errors out on unsupported settings.
 *
 * Return: 0 on success, error code otherwise
 */
static int ksz8830_drive_strength_write(struct ksz_device *dev,
					struct ksz_driver_strength_prop *props,
					int num_props)
{}

/**
 * ksz_parse_drive_strength() - Extract and apply drive strength configurations
 *				from device tree properties.
 * @dev:	ksz device
 *
 * This function reads the specified drive strength properties from the
 * device tree, validates against the supported chip variants, and sets
 * them accordingly. An error should be critical here, as the drive strength
 * settings are crucial for EMI compliance.
 *
 * Return: 0 on success, error code otherwise
 */
static int ksz_parse_drive_strength(struct ksz_device *dev)
{}

int ksz_switch_register(struct ksz_device *dev)
{}
EXPORT_SYMBOL();

void ksz_switch_remove(struct ksz_device *dev)
{}
EXPORT_SYMBOL();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();