/* * econet.c - implements libethernet functions for Econet switch * * Copyright (C) 2022 iopsys Software Solutions AB. All rights reserved. * * Author: maxim.menshikov@iopsys.eu * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/types.h> #include <net/if.h> #include <stdbool.h> #include <linux/mii.h> #include <easy/easy.h> #include "../ethernet.h" #include "ecnt_prvt.h" int econet_eth_set_link_settings(const char *name, struct eth_link link) { UNUSED(name); UNUSED(link); libethernet_err("%s(): TODO\n", __func__); return 0; } int econet_eth_get_link_settings(const char *ifname, struct eth_link *link) { uint32_t port_num; port_num = ecnt_prvt_get_port_num(ifname); if (port_num == ECNT_PRVT_PORT_NUM_INVALID) { libethernet_err("invalid port name: %s\n", ifname); return -1; } return ecnt_prvt_get_link_settings(port_num, link); } int econet_eth_get_stats(const char *ifname, struct eth_stats *stats) { uint32_t port_num; port_num = ecnt_prvt_get_port_num(ifname); if (port_num == ECNT_PRVT_PORT_NUM_INVALID) { /* Check and fetch stats if the Interface belongs to hsgmii_lan driver */ if (!hsgmii_lan_prvt_get_port_statistics(ifname, stats, NULL)) { return 0; } else if (!strcmp(ifname, "ae_wan")) { /* Check and fetch stats if the Interface belongs to ae_wan driver */ if (!ae_wan_prvt_get_port_statistics(stats, NULL)) { return 0; } } else if (!strcmp(ifname, "pon")) { /* Check and fetch stats if the Interface belongs to PON driver */ if (!pon_prvt_get_port_statistics(stats, NULL)) { return 0; } } libethernet_err("error reading stats for interface %s\n", ifname); return -1; } if (ecnt_prvt_get_port_statistics(port_num, stats, NULL)) { libethernet_err("error reading stats for interface %s\n", ifname); return -1; } return 0; } int econet_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rstats) { uint32_t port_num; port_num = ecnt_prvt_get_port_num(ifname); if (port_num == ECNT_PRVT_PORT_NUM_INVALID) { /* Check and fetch rstats if the Interface belongs to hsgmii_lan driver */ if (!hsgmii_lan_prvt_get_port_statistics(ifname, NULL, rstats)) { return 0; } else if (!strcmp(ifname, "ae_wan")) { /* Check and fetch rstats if the Interface belongs to ae_wan driver */ if (!ae_wan_prvt_get_port_statistics(NULL, rstats)) { return 0; } } else if (!strcmp(ifname, "pon")) { /* Check and fetch rstats if the Interface belongs to PON driver */ if (!pon_prvt_get_port_statistics(NULL, rstats)) { return 0; } } libethernet_err("error reading rmon stats for interface %s\n", ifname); return -1; } if (ecnt_prvt_get_port_statistics(port_num, NULL, rstats)) { libethernet_err("error reading rmon stats for interface %s\n", ifname); return -1; } return 0; } int econet_eth_poweron_phy(const char *ifname, struct eth_phy p) { uint32_t port_num; port_num = ecnt_prvt_get_port_num(ifname); if (port_num == ECNT_PRVT_PORT_NUM_INVALID) { libethernet_err("invalid port name: %s\n", ifname); return -1; } return ecnt_prvt_set_port_state(port_num, true); } int econet_eth_poweroff_phy(const char *ifname, struct eth_phy p) { uint32_t port_num; port_num = ecnt_prvt_get_port_num(ifname); if (port_num == ECNT_PRVT_PORT_NUM_INVALID) { libethernet_err("invalid port name: %s\n", ifname); return -1; } return ecnt_prvt_set_port_state(port_num, false); } int econet_eth_reset_phy(const char *name, int phy_id) { UNUSED(name); UNUSED(phy_id); libethernet_err("%s(): TODO\n", __func__); return 0; } int econet_clear_stats(const char *ifname) { char clear_stats_filename[128] = {0}; FILE *fp = NULL; // clear stats files are named as eth0.1_clear_stats etc. snprintf(clear_stats_filename, sizeof(clear_stats_filename), "/proc/tc3162/%s_clear_stats", ifname); fp = fopen(clear_stats_filename, "w"); if (!fp) { libethernet_err("%s(): fopen() failed for %s\n", __func__, clear_stats_filename); return -1; } else { // just write 1 to clear the stats fprintf(fp, "1"); fclose(fp); } return 0; } /* Declare separate eth ops for all known Econet interfaces */ #define ECNT_ETH_OPS(__name, __interface_name) \ const struct eth_ops __name = { \ .ifname = (__interface_name), \ .set_link_settings = econet_eth_set_link_settings, \ .get_link_settings = econet_eth_get_link_settings, \ .get_stats = econet_eth_get_stats, \ .get_rmon_stats = econet_eth_get_rmon_stats, \ .poweron_phy = econet_eth_poweron_phy, \ .poweroff_phy = econet_eth_poweroff_phy, \ .reset_phy = econet_eth_reset_phy, \ .clear_stats = econet_clear_stats, \ } ECNT_ETH_OPS(econet_gen_eth_ops, "eth"); ECNT_ETH_OPS(econet_nas_wan_eth_ops, "nas"); ECNT_ETH_OPS(econet_ae_wan_eth_ops, "ae_wan"); ECNT_ETH_OPS(econet_pon_ops, "pon"); #undef ECNT_ETH_OPS