diff --git a/Makefile b/Makefile index a0582e8176adc5a40c726caa1e3510dbde5ac748..66e7f0d33ca88a4679bd8bd5318abd31e9c9ad31 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,15 @@ CC = gcc CFLAGS = -O2 -Wall -g +LIBETH_CFLAGS += -I. -I../libeasy +LIBETH_LDFLAGS += -L../libeasy +LIBS += -lnl-3 -lnl-route-3 -lnl-genl-3 +LIBS += -leasy + objs_lib = ethernet.o ifeq ($(PLATFORM),BROADCOM) -objs_lib += bcm.o +objs_lib += bcm/bcm.o else ifeq ($(PLATFORM),MEDIATEK) objs_lib += ethsw.o XXFLAGS += -Wl,-whole-archive -lsw -Wl,-no-whole-archive @@ -13,10 +18,12 @@ endif all: libethernet.so %.o: %.c - $(CC) $(CFLAGS) -fPIC -c -o $@ $< + $(CC) $(CFLAGS) $(LIBETH_CFLAGS) -fPIC -c -o $@ $< libethernet.so: $(objs_lib) - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(LDFLAGS) -shared -o $@ $^ $(XXFLAGS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(LDFLAGS) $(LIBETH_LDFLAGS) \ + -shared -o $@ $^ $(XXFLAGS) $(LIBS) clean: + rm -f bcm/*.o rm -f *.o *.so diff --git a/bcm.c b/bcm.c deleted file mode 100644 index 4812a92fb3c391f327768874e03b0bd2c6248928..0000000000000000000000000000000000000000 --- a/bcm.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * bcm.c - implements for Broadcom eth switch - * - * Copyright (C) 2018 iopsys Software Solutions AB. All rights reserved. - * - * Author: anjan.chanda@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 "ethernet.h" -#include "bcmswapitypes.h" -#include "bcmnet.h" - -#define UNUSED(var) (void)(var) - -#define PHYID_2_MII_IOCTL(phy_id, mii_ioctl_data) \ - {mii_ioctl_data->val_out = (phy_id >> 24 ) & 0xff; \ - mii_ioctl_data->phy_id = phy_id & 0x1f;} - -int bcm_eth_get_link_settings(char *name, struct eth_link *link) -{ - int port = ETH_PORT_UNDEFINED; - int portmap = 0; - int ret; - int num_ports = 0; - int pos = 0; - int phy_id = 0; - struct ethswctl_data data; - - ret = eth_ioctl(name, SIOCGQUERYNUMPORTS, - &portmap, sizeof(portmap)); - if (ret < 0) - return -1; - - while (portmap && pos < sizeof(portmap) * 8) { - if ((portmap & (1 << pos++))) - num_ports++; - } - - if (link && link->portid != ETH_PORT_UNDEFINED) - port = link->portid; - - if (!num_ports) { - if (port >= 0) - return -ETH_EINVAL; - } - else { - if (port == ETH_PORT_UNDEFINED) { - if (num_ports > 1) { - return -ETH_EINVAL; - } else { - for (port = 0; port < 32; port++) - if ((portmap & (1 << port))) - break; - } - } - - if ((portmap & (1 << port)) == 0) - return -ETH_EINVAL; - } - - eth_get_phy_id(name, port, &phy_id); - - memset(&data, 0, sizeof(struct ethswctl_data)); - data.op = ETHSWPHYMODE; - data.type = TYPE_GET; - data.addressing_flag = ETHSW_ADDRESSING_DEV; - if (port != ETH_PORT_UNDEFINED) { - data.sub_unit = -1; - data.sub_port = port; - data.addressing_flag |= ETHSW_ADDRESSING_SUBPORT; - } - - if (eth_ioctl(name, SIOCETHSWCTLOPS, &data, - sizeof(struct ethswctl_data)) < 0) - return -1; - - link->autoneg = !!(data.phycfg & PHY_CFG_AUTO_NEGO); - link->fullduplex = !!(data.phycfg & (PHY_CFG_10000FD | - PHY_CFG_5000FD | - PHY_CFG_2500FD | - PHY_CFG_1000FD | - PHY_CFG_100FD | - PHY_CFG_10FD)); - link->speed = data.speed; - link->down = data.speed == 0 ? 1 : 0; - - if (data.phycfg & PHY_CFG_1000FD) - link->capability |= ETH_1000_Full; - - if (data.phycfg & PHY_CFG_1000HD) - link->capability |= ETH_1000_Half; - - if (data.phycfg & PHY_CFG_100FD) - link->capability |= ETH_100_Full; - - if (data.phycfg & PHY_CFG_100HD) - link->capability |= ETH_100_Half; - - if (data.phycfg & PHY_CFG_10FD) - link->capability |= ETH_10_Full; - - if (data.phycfg & PHY_CFG_10HD) - link->capability |= ETH_10_Half; - - if (data.phycfg & PHY_CFG_5000FD) - link->capability |= ETH_5000_Full; - - if (data.phycfg & PHY_CFG_10000FD) - link->capability |= ETH_10000_Full; - - return 0; -} - -int bcm_eth_set_link_settings(char *name, struct eth_link link) -{ - fprintf(stderr, "%s(): name = %s\n", __func__, name); - return 0; -} - -int bcm_eth_poweron_phy(char *name, struct eth_phy p) -{ - struct ethctl_data data; - - memset(&data, 0, sizeof(struct ethctl_data)); - data.op = ETHSETSPOWERUP; - - if (eth_ioctl(name, SIOCETHSWCTLOPS, &data, - sizeof(struct ethswctl_data)) < 0) - return -1; - - return 0; -} - -int bcm_eth_poweroff_phy(char *name, struct eth_phy p) -{ - struct ethctl_data data; - - memset(&data, 0, sizeof(struct ethctl_data)); - data.op = ETHSETSPOWERDOWN; - - if (eth_ioctl(name, SIOCETHSWCTLOPS, &data, - sizeof(struct ethswctl_data)) < 0) - return -1; - - return 0; -} - -int bcm_eth_reset_phy(char *name, int phy_id) -{ - return eth_mii_reset_phy(name, phy_id & 0x1f); -} - -const struct eth_ops bcm_eth_ops = { - .name = "eth", - //.up = bcm_eth_up, - //.down = bcm_eth_down, - .set_link_settings = bcm_eth_set_link_settings, - .get_link_settings = bcm_eth_get_link_settings, - //.get_stats = bcm_eth_get_stats, - .poweron_phy = bcm_eth_poweron_phy, - .poweroff_phy = bcm_eth_poweroff_phy, - .reset_phy = bcm_eth_reset_phy, -}; diff --git a/bcm/bcm.c b/bcm/bcm.c new file mode 100644 index 0000000000000000000000000000000000000000..643e6f85c649cbac669a5f9dbffe9c79bd27f890 --- /dev/null +++ b/bcm/bcm.c @@ -0,0 +1,287 @@ +/* + * bcm.c - implements for Broadcom eth switch + * + * Copyright (C) 2018 iopsys Software Solutions AB. All rights reserved. + * + * Author: anjan.chanda@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.h" +#include "ethernet.h" +#include "bcmswapitypes.h" +#include "bcmnet.h" + +#define PHYID_2_MII_IOCTL(phy_id, mii_ioctl_data) \ + {mii_ioctl_data->val_out = (phy_id >> 24 ) & 0xff; \ + mii_ioctl_data->phy_id = phy_id & 0x1f;} + +static int bcm_eth_get_unit_port(const char *ifname, int *unit, int *port) +{ + struct ethswctl_data data; + int ret; + int i; + + memset(&data, 0, sizeof(struct ethswctl_data)); + + data.op = ETHSWUNITPORT; + data.type = TYPE_GET; + strncpy(data.ifname, ifname, 16); + + ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)); + if (ret != 0) { + fprintf(stderr, "ioctl failed! ret = %d\n", ret); + return -1; + } + + *unit = data.unit; + *port = data.port; + + if (!data.port && data.port_map) { + unsigned int portmap = data.port_map; + + for (i = 0; i < sizeof(portmap); i++) { + if (!!(portmap & (1 << i))) { + *port = i; + break; + } + } + } + + /* fprintf(stderr, "[%s] unit = %d port = %d portmap = 0x%x " + "phyportmap = 0x%x\n", + ifname, *unit, *port, data.port_map, + data.phy_portmap); */ + + return 0; +} + +int bcm_eth_get_link_settings(const char *ifname, struct eth_link *link) +{ + struct ethswctl_data data; + int unit = -1; + int port = -1; + int ret; + + memset(&data, 0, sizeof(struct ethswctl_data)); + ret = bcm_eth_get_unit_port(ifname, &unit, &port); + if (ret) + return -1; + + data.op = ETHSWPHYMODE; + data.port = port; + data.unit = unit; + data.type = TYPE_GET; + + ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)); + if (ret != 0) { + fprintf(stderr, "ioctl failed!\n"); + return -1; + } + + link->portid = port; + link->speed = data.speed; + link->fullduplex = data.duplex == 1 ? false : true; + + /* fprintf(stderr, "port: %d speed = %d fullduplex = %d\n", + link->portid, link->speed, link->fullduplex); */ + + if (!!(data.phycfg & PHY_CFG_1000FD)) + link->capability |= ETH_1000_Full; + + if (!!(data.phycfg & PHY_CFG_1000HD)) + link->capability |= ETH_1000_Half; + + if (!!(data.phycfg & PHY_CFG_100FD)) + link->capability |= ETH_100_Full; + + if (!!(data.phycfg & PHY_CFG_100HD)) + link->capability |= ETH_100_Half; + + if (!!(data.phycfg & PHY_CFG_10FD)) + link->capability |= ETH_10_Full; + + if (!!(data.phycfg & PHY_CFG_10HD)) + link->capability |= ETH_10_Half; + + if (!!(data.phycfg & PHY_CFG_5000FD)) + link->capability |= ETH_5000_Full; + + if (!!(data.phycfg & PHY_CFG_10000FD)) + link->capability |= ETH_10000_Full; + + + memset(&data, 0, sizeof(struct ethswctl_data)); + data.op = ETHSWPHYAUTONEG; + data.port = port; + data.unit = unit; + data.type = TYPE_GET; + + ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)); + if (ret != 0) { + fprintf(stderr, "ioctl failed! ret = %d\n", ret); + return -1; + } + + link->autoneg = data.autoneg_info == 0 ? false : true; + /* fprintf(stderr, "autoneg = %d\n", link->autoneg); */ + + memset(&data, 0, sizeof(struct ethswctl_data)); + data.op = ETHSWLINKSTATUS; + data.port = port; + data.unit = unit; + data.type = TYPE_GET; + + ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)); + if (ret != 0) { + fprintf(stderr, "ioctl failed!\n"); + return -1; + } + + link->down = data.status == 0 ? true : false; + + return 0; +} + +int bcm_eth_set_link_settings(const char *name, struct eth_link link) +{ + fprintf(stderr, "%s(): TODO\n", __func__); + return 0; +} + +int bcm_eth_poweron_phy(const char *name, struct eth_phy p) +{ + struct ethctl_data data; + + memset(&data, 0, sizeof(struct ethctl_data)); + data.op = ETHSETSPOWERUP; + + if (eth_ioctl(name, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)) < 0) + return -1; + + return 0; +} + +int bcm_eth_poweroff_phy(const char *name, struct eth_phy p) +{ + struct ethctl_data data; + + memset(&data, 0, sizeof(struct ethctl_data)); + data.op = ETHSETSPOWERDOWN; + + if (eth_ioctl(name, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)) < 0) + return -1; + + return 0; +} + +int bcm_eth_reset_phy(const char *name, int phy_id) +{ + return eth_mii_reset_phy(name, phy_id & 0x1f); +} + + +int bcm_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *tx, + struct eth_rmon_stats *rx) +{ + struct ethswctl_data data; + int ret; + int unit = -1; + int port = -1; + + memset(&data, 0, sizeof(struct ethswctl_data)); + ret = bcm_eth_get_unit_port(ifname, &unit, &port); + if (ret) + return -1; + + //data.op = ETHSWDUMPMIB; + data.op = ETHSWEMACGET; + data.port = port; + data.unit = unit; + data.queue = -1; /* prio_q = -1 */ + + ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data, + sizeof(struct ethswctl_data)); + if (ret != 0) { + fprintf(stderr, "ioctl failed! ret = %d\n", ret); + return -1; + } + + tx->all_q = true; + tx->bytes = data.emac_stats_s.tx_byte; + tx->packets = data.emac_stats_s.tx_packet; + tx->bcast_packets = data.emac_stats_s.tx_broadcast_packet; + tx->mcast_packets = data.emac_stats_s.tx_multicast_packet; + tx->crc_err_packets = data.emac_stats_s.tx_fcs_error; + tx->under_sz_packets = data.emac_stats_s.tx_undersize_frame; + tx->over_sz_packets = data.emac_stats_s.tx_oversize_frame; + tx->packets_64bytes = data.emac_stats_s.tx_frame_64; + tx->packets_65to127bytes = data.emac_stats_s.tx_frame_65_127; + tx->packets_128to255bytes = data.emac_stats_s.tx_frame_128_255; + tx->packets_256to511bytes = data.emac_stats_s.tx_frame_256_511; + tx->packets_512to1023bytes = data.emac_stats_s.tx_frame_512_1023; + tx->packets_1024to1518bytes = data.emac_stats_s.tx_frame_1024_1518; + + + rx->all_q = true; + rx->bytes = data.emac_stats_s.rx_byte; + rx->packets = data.emac_stats_s.rx_packet; + rx->bcast_packets = data.emac_stats_s.rx_broadcast_packet; + rx->mcast_packets = data.emac_stats_s.rx_multicast_packet; + rx->crc_err_packets = data.emac_stats_s.rx_fcs_error; + rx->under_sz_packets = data.emac_stats_s.rx_undersize_packet; + rx->over_sz_packets = data.emac_stats_s.rx_oversize_packet; + rx->packets_64bytes = data.emac_stats_s.rx_frame_64; + rx->packets_65to127bytes = data.emac_stats_s.rx_frame_65_127; + rx->packets_128to255bytes = data.emac_stats_s.rx_frame_128_255; + rx->packets_256to511bytes = data.emac_stats_s.rx_frame_256_511; + rx->packets_512to1023bytes = data.emac_stats_s.rx_frame_512_1023; + rx->packets_1024to1518bytes = data.emac_stats_s.rx_frame_1024_1518; + + return 0; +} + +const struct eth_ops bcm_eth_ops = { + .ifname = "eth", + //.up = bcm_eth_up, + //.down = bcm_eth_down, + .set_link_settings = bcm_eth_set_link_settings, + .get_link_settings = bcm_eth_get_link_settings, + //.get_stats = bcm_eth_get_stats, + .get_rmon_stats = bcm_eth_get_rmon_stats, + .poweron_phy = bcm_eth_poweron_phy, + .poweroff_phy = bcm_eth_poweroff_phy, + .reset_phy = bcm_eth_reset_phy, +}; diff --git a/bcmnet.h b/bcm/bcmnet.h similarity index 100% rename from bcmnet.h rename to bcm/bcmnet.h diff --git a/bcmswapitypes.h b/bcm/bcmswapitypes.h similarity index 93% rename from bcmswapitypes.h rename to bcm/bcmswapitypes.h index 99e0fe9c01950534ffee7e2c4a14c844355f304d..bd5c9444aa2e17ea035d26938d43645707acc056 100644 --- a/bcmswapitypes.h +++ b/bcm/bcmswapitypes.h @@ -32,6 +32,7 @@ #define __BCM_SWAPI_TYPES_H__ #include "bcmtypes.h" +#include "net_port.h" /* * BCM API error codes. @@ -158,13 +159,16 @@ enum { ETHSWPHYAPD, ETHSWPHYEEE, ETHSWDEEPGREENMODE, /* 80 */ - ETHSWSTATPORTGET, ETHSWPHYAUTONEGCAPADV, ETHSWQUEMON, ETHSWQUEMAP, ETHSWPORTSTORMCTRL, ETHSWOAMIDXMAPPING, ETHSWCFP, + ETHSWSWITCHFLAG, + ETHSWAUTOMDIX, + ETHSWIFSTP, + ETHSWMACLMT, /* 90 */ }; typedef struct cfpArg_s { @@ -306,6 +310,7 @@ enum { #define OPT_UDF_MASK = (CFP_ARG_DA_M | CFP_ARG_SA_M) #define BMCR_SPEED2500 0x0080 /* Command Parameter definition */ +#define BMCR_SPEED10000 0x0020 /* Command Parameter definition */ /************************************************* * Flow Control Diagnosis Definitions * @@ -329,8 +334,22 @@ enum { QUE_MON_MAX_TYPES, }; +enum { + PORT_LIMIT_EN, + PORT_LIMIT, + PORT_ACTION, + PORT_LEARNED_COUNT, + PORT_OVER_LIMIT_PKT_COUNT, + PORT_RST_OVER_LIMIT_PKT_COUNT, + GLOBAL_LIMIT, + GLOBAL_LEARNED_COUNT, + GLOBAL_RST_OVER_LIMIT_PKT_COUNT, + + MACLMT_MAX_TYPES, +}; -#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CHIP_63138) || defined(CHIP_63148) || defined(CHIP_4908) +#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CONFIG_BCM963158) || defined(CONFIG_BCM963178) || defined(CONFIG_BCM947622) || \ + defined(CHIP_63138) || defined(CHIP_63148) || defined(CHIP_4908) || defined(CHIP_63158) || defined(CHIP_63178) || defined(CHIP_47622) #define BCM_COS_COUNT 8 #else #define BCM_COS_COUNT 4 @@ -428,7 +447,10 @@ struct ethswctl_data int ret_val; int val; int max_pkts_per_iter; + int rx_queues; int weights[BCM_COS_COUNT]; +#define MAX_WRR_WEIGHTS 16 + int weight_pkts[BCM_COS_COUNT]; unsigned char qos_egrq_sched_cap[BCM_COS_COUNT]; int priority; int sw_port_type; @@ -460,6 +482,9 @@ struct ethswctl_data int duplex; unsigned int port_map; unsigned int phy_portmap; + int cfgSpeed; + int cfgDuplex; + int phyCap; int phycfg; int epon_port; char ifname[IFNAMSIZ]; @@ -472,6 +497,7 @@ struct ethswctl_data }; struct dos_ctrl_params { + unsigned char da_eq_sa_drop_en; unsigned char ip_lan_drop_en; unsigned char tcp_blat_drop_en; unsigned char udp_blat_drop_en; @@ -596,28 +622,6 @@ struct ethswctl_data { unsigned int link_change; }mdk_kernel_poll; - /** Port statistics */ - struct rdpa_port_stats - { - uint64 rx_valid_pkt; /**< Valid Received packets */ - uint64 rx_crc_error_pkt; /**< Received packets with CRC error */ - uint64 rx_discard_1; /**< RX discard 1 */ - uint64 rx_discard_2; /**< RX discard 2 */ - uint64 bbh_drop_1; /**< BBH drop 1 */ - uint64 bbh_drop_2; /**< BBH drop 2 */ - uint64 bbh_drop_3; /**< BBH drop 3 */ - uint64 rx_discard_max_length; /**< Packets discarded due to size bigger than MTU */ - uint64 rx_discard_min_length; /**< Packets discarded due to size smaller than 64 */ - uint64 tx_valid_pkt; /**< Valid transmitted packets */ - uint64 tx_discard; /**< TX discarded packets (TX FIFO full) */ - uint64 discard_pkt; /**< Dropped filtered Packets */ - uint64 rx_valid_bytes; - uint64 tx_valid_bytes; - uint64 rx_broadcast_pkt; - uint64 tx_broadcast_pkt; - uint64 rx_multicast_pkt; - uint64 tx_multicast_pkt; - } rdpa_port_stats_s; struct oam_idx_str { #define OAM_MAP_SUB_TYPE_TO_UNIT_PORT 0 @@ -630,6 +634,12 @@ struct ethswctl_data }; }oam_idx_str; + struct + { + int pfc_ret; + int pfc_timer[8]; + }; + net_port_t net_port; }; /* Union */ }; @@ -679,6 +689,8 @@ typedef enum bcm_switch_control_e { bcmSwitchLinkUpLanPorts, /* COnfigure TxQ Configuration Mode */ bcmSwitchLinkUpWanPorts, /* COnfigure TxQ Configuration Mode */ bcmSwitchMaxStreams, /* Configure Queue Max Streams */ + bcmSwitchCurStreams, /* Current streams used to compute threshold */ + bcmSwitchActQuePerPort, /* Active Queue per poert */ bcmSwitch__Count, } bcm_switch_control_t; @@ -773,7 +785,8 @@ typedef struct { #define BCM_COSQ_COMBO 2 #define BCM_COSQ_SP 0 -#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CHIP_63138) || defined(CHIP_63148) || defined(CHIP_4908) +#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CONFIG_BCM963158) || defined(CONFIG_BCM963178) \ + || defined(CHIP_63138) || defined(CHIP_63148) || defined(CHIP_4908) || defined(CHIP_63158) || defined(CHIP_63178) #define NUM_EGRESS_QUEUES 8 #else #define NUM_EGRESS_QUEUES 4 @@ -791,8 +804,11 @@ typedef struct { #define PAUSE_FLOW_CTRL_BOTH 2 #define PAUSE_FLOW_CTRL_TX 3 #define PAUSE_FLOW_CTRL_RX 4 -#define PAUSE_FLOW_CTRL_BCMSWITCH_OFF 5 -#define PAUSE_FLOW_CTRL_BCMSWITCH_ON 6 +#define PAUSE_FLOW_PFC_BOTH 5 +#define PAUSE_FLOW_PFC_TX 6 +#define PAUSE_FLOW_PFC_RX 7 +#define PAUSE_FLOW_CTRL_BCMSWITCH_OFF 8 +#define PAUSE_FLOW_CTRL_BCMSWITCH_ON 9 #define SWITCH_PORTS_ALL_PHYS 255 /* For ETHSWCOSTXQSEL */ @@ -811,6 +827,7 @@ typedef struct { #define IMP_PORT_ID 8 #define P4_PORT_ID 4 #define P5_PORT_ID 5 +#define P7_PORT_ID 7 #define TC_ZERO_QOS 4 #define SWAP_TYPE_MASK (0xff<<24) #define PORT_RXDISABLE 0x1 @@ -830,6 +847,16 @@ typedef struct { /* Link Handling */ #define ETHSW_LINK_MIGHT_CHANGED (1<<0) #define ETHSW_LINK_FORCE_CHECK (1<<1) +#define ETHSW_LINK_CHANGED (1<<2) + +/* Spanning Tree states */ +enum { + STP_DISABLED, + STP_LISTENING, + STP_LEARNING, + STP_FORWARDING, + STP_BLOCKING, +}; /* DMA Dump */ #define ETHSW_DMA_RX 1 diff --git a/bcmtypes.h b/bcm/bcmtypes.h similarity index 100% rename from bcmtypes.h rename to bcm/bcmtypes.h diff --git a/bcm/net_port.h b/bcm/net_port.h new file mode 100644 index 0000000000000000000000000000000000000000..fe9d26fe3c7a6e2ccae71ed51ecfe212f210ea60 --- /dev/null +++ b/bcm/net_port.h @@ -0,0 +1,101 @@ +/* + Copyright 2007-2015 Broadcom Corporation + + <:label-BRCM:2015:DUAL/GPL:standard + + Unless you and Broadcom execute a separate written software license + agreement governing use of this software, this software is licensed + to you under the terms of the GNU General Public License version 2 + (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, + with the following added to such license: + + As a special exception, the copyright holders of this software give + you permission to link this software with independent modules, and + to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent + module, the terms and conditions of the license of that module. + An independent module is a module which is not derived from this + software. The special exception does not apply to any modifications + of the software. + + Not withstanding the above, under no circumstances may you combine + this software in any way with any other Broadcom software provided + under a license other than the GPL, without Broadcom's express prior + written consent. + + :> +*/ + +/***********************************************************************/ +/* */ +/* MODULE: net_port.h */ +/* PURPOSE: Generic port name interface. */ +/* */ +/***********************************************************************/ +#ifndef _NET_PORT_H +#define _NET_PORT_H + +typedef struct net_port_t +{ + int port; + int sub_type; + int is_wan; + int speed; + char ifname[32]; +} net_port_t; + +#define _FOREACH_NET_PORT_TYPE(TYPE, TYPE0) \ + TYPE0(NET_PORT_LAN_0) \ + TYPE(NET_PORT_LAN_1) \ + TYPE(NET_PORT_LAN_2) \ + TYPE(NET_PORT_LAN_3) \ + TYPE(NET_PORT_LAN_4) \ + TYPE(NET_PORT_LAN_5) \ + TYPE(NET_PORT_LAN_6) \ + TYPE(NET_PORT_LAN_7) \ + TYPE(NET_PORT_EPON_AE) \ + TYPE(NET_PORT_EPON) \ + TYPE(NET_PORT_GPON) \ + TYPE(NET_PORT_LAST) \ + TYPE(NET_PORT_NONE) + +#define _FOREACH_NET_PORT_SUBTYPE_TYPE(TYPE, TYPE0) \ + TYPE0(NET_PORT_SUBTYPE_GPON) \ + TYPE(NET_PORT_SUBTYPE_XGPON) \ + TYPE(NET_PORT_SUBTYPE_XGS) \ + TYPE(NET_PORT_SUBTYPE_NGPON) \ + TYPE(NET_PORT_SUBTYPE_LAST) \ + TYPE(NET_PORT_SUBTYPE_NONE) + +#define _FOREACH_NET_PORT_SPEED_TYPE(TYPE, TYPE0) \ + TYPE0(NET_PORT_SPEED_0101) \ + TYPE(NET_PORT_SPEED_0201) \ + TYPE(NET_PORT_SPEED_0202) \ + TYPE(NET_PORT_SPEED_2501) \ + TYPE(NET_PORT_SPEED_1001) \ + TYPE(NET_PORT_SPEED_1025) \ + TYPE(NET_PORT_SPEED_1010) \ + TYPE(NET_PORT_SPEED_LAST) \ + TYPE(NET_PORT_SPEED_NONE) + +#define FOREACH_NET_PORT_ENUM \ + _FOREACH_NET_PORT_TYPE(GENERATE_ENUM, GENERATE_ENUM0) \ + _FOREACH_NET_PORT_SUBTYPE_TYPE(GENERATE_ENUM, GENERATE_ENUM0) \ + _FOREACH_NET_PORT_SPEED_TYPE(GENERATE_ENUM, GENERATE_ENUM0) + +#define FOREACH_NET_PORT_STRING \ + _FOREACH_NET_PORT_TYPE(GENERATE_STRING, GENERATE_STRING) \ + _FOREACH_NET_PORT_SUBTYPE_TYPE(GENERATE_STRING, GENERATE_STRING) \ + _FOREACH_NET_PORT_SPEED_TYPE(GENERATE_STRING, GENERATE_STRING) + +#define GENERATE_ENUM(ENUM) ENUM, +#define GENERATE_ENUM0(ENUM) ENUM = 0, +#define GENERATE_STRING(STRING) #STRING, + +enum +{ + FOREACH_NET_PORT_ENUM +}; + +#endif + diff --git a/ethernet.c b/ethernet.c index 9cbc6231d5d69efe6deca27626ae86a6ec5dc925..7e4ddcb6f554c01af3fa3cf202af235a5cd6f543 100644 --- a/ethernet.c +++ b/ethernet.c @@ -1,7 +1,7 @@ /* * ethernet.c - file implements library APIs * - * Copyright (C) 2018 iopsys Software Solutions AB. All rights reserved. + * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved. * * Author: anjan.chanda@iopsys.eu * @@ -34,6 +34,7 @@ #include <linux/sockios.h> #include <linux/mii.h> +#include "easy.h" #include "ethernet.h" #ifdef IOPSYS_BROADCOM @@ -46,139 +47,140 @@ const struct eth_ops *eth_ops[] = { #ifdef IOPSYS_BROADCOM &bcm_eth_ops, #else - ðsw_ops, + ðsw_ops, /* FIXME */ #endif }; -const struct eth_ops *get_eth_driver(char *name) +const struct eth_ops *get_eth_driver(const char *ifname) { int i; for (i = 0; i < sizeof(eth_ops)/sizeof(eth_ops[0]); i++) - if (!strncmp(eth_ops[i]->name, name, - strlen(eth_ops[i]->name))) + if (!strncmp(eth_ops[i]->ifname, ifname, + strlen(eth_ops[i]->ifname))) return eth_ops[i]; return NULL; } -int eth_up(char *name) +int eth_up(const char *ifname) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->up) - return eth->up(name); + return eth->up(ifname); return -1; } -int eth_down(char *name) +int eth_down(const char *ifname) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->down) - return eth->down(name); + return eth->down(ifname); return -1; } -int eth_get_link_settings(char *name, struct eth_link *link) +int eth_get_link_settings(const char *ifname, struct eth_link *link) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->get_link_settings) - return eth->get_link_settings(name, link); + return eth->get_link_settings(ifname, link); return -1; } -int eth_set_link_settings(char *name, struct eth_link link) +int eth_set_link_settings(const char *ifname, struct eth_link link) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->set_link_settings) - return eth->set_link_settings(name, link); + return eth->set_link_settings(ifname, link); return -1; } -int eth_get_operstate(char *name, enum eth_operstate *op) +int eth_get_operstate(const char *ifname, ifopstatus_t *s) { - const struct eth_ops *eth = get_eth_driver(name); - - if (eth && eth->get_operstate) - return eth->get_operstate(name, op); + return get_ifoperstatus(ifname, s); +} +int eth_set_operstate(const char *ifname, ifopstatus_t s) +{ + /* return set_ifoperstatus(ifname, s); */ //TODO return -1; } -int eth_set_operstate(char *name, enum eth_operstate op) +int eth_get_stats(const char *ifname, struct eth_stats *s) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); - if (eth && eth->set_operstate) - return eth->set_operstate(name, op); + if (eth && eth->get_stats) + return eth->get_stats(ifname, s); return -1; } -int eth_get_stats(char *name, struct eth_counters *c) +int eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *tx, + struct eth_rmon_stats *rx) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); - if (eth && eth->get_stats) - return eth->get_stats(name, c); + if (eth && eth->get_rmon_stats) + return eth->get_rmon_stats(ifname, tx, rx); return -1; } -int eth_poweron_phy(char *name, struct eth_phy p) +int eth_poweron_phy(const char *ifname, struct eth_phy p) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->poweron_phy) - return eth->poweron_phy(name, p); + return eth->poweron_phy(ifname, p); return -1; } -int eth_poweroff_phy(char *name, struct eth_phy p) +int eth_poweroff_phy(const char *ifname, struct eth_phy p) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->poweroff_phy) - return eth->poweroff_phy(name, p); + return eth->poweroff_phy(ifname, p); return -1; } - -int eth_reset_phy(char *name, int phy_id) +int eth_reset_phy(const char *ifname, int phy_id) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->reset_phy) - return eth->reset_phy(name, phy_id); + return eth->reset_phy(ifname, phy_id); else - return eth_mii_reset_phy(name, phy_id); + return eth_mii_reset_phy(ifname, phy_id); } -int eth_get_phy_id(char *name, int port, int *phy_id) +int eth_get_phy_id(const char *ifname, int port, int *phy_id) { - const struct eth_ops *eth = get_eth_driver(name); + const struct eth_ops *eth = get_eth_driver(ifname); if (eth && eth->get_phy_id) - return eth->get_phy_id(name, port, phy_id); + return eth->get_phy_id(ifname, port, phy_id); else - return eth_mii_get_phy_id(name, port, phy_id); + return eth_mii_get_phy_id(ifname, port, phy_id); } -int eth_ioctl(char *name, int cmd, void *in, int len) +int eth_ioctl(const char *ifname, int cmd, void *in, int len) { struct ifreq ifr; int s; - strncpy(ifr.ifr_name, name, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) return -1; @@ -201,7 +203,7 @@ int eth_ioctl(char *name, int cmd, void *in, int len) return 0; } -int eth_mii_get_phy_id(char *ifname, int port, int *phy_id) +int eth_mii_get_phy_id(const char *ifname, int port, int *phy_id) { struct mii_ioctl_data *mii; struct ifreq ifr; @@ -237,7 +239,7 @@ int eth_mii_get_phy_id(char *ifname, int port, int *phy_id) return 0; } -static int eth_mii_ioctl(char *name, int cmd, int phy_id, int reg, +static int eth_mii_ioctl(const char *ifname, int cmd, int phy_id, int reg, int in, int *out) { struct mii_ioctl_data *mii; @@ -249,7 +251,7 @@ static int eth_mii_ioctl(char *name, int cmd, int phy_id, int reg, return -1; memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifr.ifr_name, name, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { fprintf(stderr, "SIOCGIFINDEX failed!\n"); close(s); @@ -277,18 +279,18 @@ static int eth_mii_ioctl(char *name, int cmd, int phy_id, int reg, return 0; } -int eth_mii_read(char *name, int phy_id, int reg, int *out) +int eth_mii_read(const char *ifname, int phy_id, int reg, int *out) { - return eth_mii_ioctl(name, SIOCGMIIREG, phy_id, reg, 0, out); + return eth_mii_ioctl(ifname, SIOCGMIIREG, phy_id, reg, 0, out); } -int eth_mii_write(char *name, int phy_id, int reg, int in) +int eth_mii_write(const char *ifname, int phy_id, int reg, int in) { - return eth_mii_ioctl(name, SIOCGMIIREG, phy_id, reg, in, NULL); + return eth_mii_ioctl(ifname, SIOCGMIIREG, phy_id, reg, in, NULL); } -int eth_mii_reset_phy(char *name, int phy_id) +int eth_mii_reset_phy(const char *ifname, int phy_id) { - return eth_mii_ioctl(name, SIOCSMIIREG, phy_id, + return eth_mii_ioctl(ifname, SIOCSMIIREG, phy_id, MII_BMCR, BMCR_RESET, NULL); } diff --git a/ethernet.h b/ethernet.h index d51d3646b01794e185c8e73db17442f8de6c5ff1..3cf3cf3f93a24c55448f8dc565b3a96c26885b6c 100644 --- a/ethernet.h +++ b/ethernet.h @@ -1,7 +1,7 @@ /* - * ethernet.h - library header file + * ethernet.h - libethernet header file * - * Copyright (C) 2018 iopsys Software Solutions AB. All rights reserved. + * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved. * * Author: anjan.chanda@iopsys.eu * @@ -24,37 +24,49 @@ #include <stdint.h> #include <stdbool.h> +#include <linux/types.h> #ifdef __cplusplus extern "C" { #endif -/** enum eth_operstate - maps to operational state of interface */ -enum eth_operstate { - IF_UP, - IF_DOWN, - IF_UKNOWN, - IF_DORMANT, - IF_NOTPRESENT, - IF_LLDOWN, - IF_ERROR, +/* enum eth_duplex - duplex modes */ +enum eth_duplex { + AUTO_DUPLEX, + HALF_DUPLEX, + FULL_DUPLEX, }; -struct eth_counters { - unsigned long tx_bytes; - unsigned long rx_bytes; - unsigned long tx_packets; - unsigned long rx_packets; - - /** packets dropped due to errors */ - unsigned long tx_error_packets; - unsigned long rx_error_packets; +/* enum eth_rmon_status - rmon status */ +enum rmon_status { + RMON_STATUS_DISABLED, + RMON_STATUS_ENABLED, + RMON_STATUS_ERR_MISCONF, + RMON_STATUS_ERR, +}; - /** no-error packets dropped due to other factors */ - unsigned long tx_dropped_packets; - unsigned long rx_dropped_pcakets; +/* struct eth_rmon_stats - ethernet rmon counters */ +struct eth_rmon_stats { + enum rmon_status status; + uint16_t vlanid; /* 0..4094 */ + bool all_q; + uint32_t drop_events; + unsigned long bytes; + unsigned long packets; + unsigned long bcast_packets; + unsigned long mcast_packets; + uint32_t crc_err_packets; + uint32_t under_sz_packets; + uint32_t over_sz_packets; + unsigned long packets_64bytes; + unsigned long packets_65to127bytes; + unsigned long packets_128to255bytes; + unsigned long packets_256to511bytes; + unsigned long packets_512to1023bytes; + unsigned long packets_1024to1518bytes; }; + #define ETH_PORT_UNDEFINED -1 enum eth_speed { @@ -75,15 +87,6 @@ struct eth_phy { int portidx; }; -struct eth_link { - int portid; - uint32_t capability; - bool autoneg; - uint32_t speed; - bool fullduplex; - bool down; -}; - struct eth_info { int phy_portmap; int phy_numports; @@ -97,6 +100,74 @@ enum eth_callstatus { ETH_EUNKNOWN }; +struct eth_stats { + unsigned long tx_bytes; + unsigned long rx_bytes; + unsigned long tx_packets; + unsigned long rx_packets; + uint32_t tx_errors; /* error packets */ + uint32_t rx_errors; + unsigned long tx_ucast_packets; /* unicast packets */ + unsigned long rx_ucast_packets; + unsigned long tx_mcast_packets; /* multicast packets */ + unsigned long rx_mcast_packets; + unsigned long tx_bcast_packets; /* broadcast packets */ + unsigned long rx_bcast_packets; + uint32_t tx_discard_packets; /* no error packets dropped */ + uint32_t rx_discard_packets; /* no error packets dropped */ + uint32_t rx_unknown_packets; /* unknown protocol packets */ +}; + +/* struct eth_vlan - vlan over eth_link */ +struct eth_vlan { + ifopstatus_t status; + uint16_t id; /* vlan id [1..4094] */ + uint16_t tpid; /* tag protocol id, t.x. 0x8100 */ + struct eth_stats stats; +}; + +//TODO: revisit +/* struct eth_link - logical link per ethernet port */ +struct eth_link { + int portid; + uint32_t capability; + bool autoneg; + uint32_t speed; + bool fullduplex; + bool down; + bool prio_tagged; + struct eth_stats stats; +}; + +/* struct eth_iface - ethernet interface */ +struct eth_iface { + ifopstatus_t status; + uint32_t lastchange; /* in secs */ + bool is_upstream; + uint8_t macaddr[6]; + uint32_t max_bitrate; /* in Mbps */ + uint32_t curr_bitrate; /* in Mbps */ + enum eth_duplex duplex; + bool eee_supported; + bool eee_enabled; + struct eth_stats stats; +}; + +/* struct eth_device - ethernet device */ +struct eth_device { + bool wol_supported; + uint32_t num_ifaces; + uint32_t num_links; + uint32_t num_vlans; + struct eth_rmon_stats tx, + rx; + struct eth_iface *ifs; + struct eth_link *links; + struct eth_vlan *vlans; +}; + + + #ifndef if_mii static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) { @@ -105,50 +176,56 @@ static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) #endif +/* TODO: eth_device/sw_ops, eth_iface_ops, eth_link_ops */ + struct eth_ops { /** interface name/prefix to match */ - const char *name; + const char *ifname; - int (*up)(char *name); - int (*down)(char *name); + int (*up)(const char *ifname); + int (*down)(const char *ifname); - int (*get_link_settings)(char *name, struct eth_link *link); - int (*set_link_settings)(char *name, struct eth_link link); + int (*get_link_settings)(const char *ifname, struct eth_link *link); + int (*set_link_settings)(const char *ifname, struct eth_link link); - int (*get_operstate)(char *name, enum eth_operstate *s); - int (*set_operstate)(char *name, enum eth_operstate s); + int (*get_operstate)(const char *ifname, ifopstatus_t *s); + int (*set_operstate)(const char *ifname, ifopstatus_t s); - int (*reset_phy)(char *name, int phy_id); - int (*poweroff_phy)(char *name, struct eth_phy p); - int (*poweron_phy)(char *name, struct eth_phy p); - int (*get_phy_id)(char *name, int port, int *phy_id); + int (*reset_phy)(const char *ifname, int phy_id); + int (*poweroff_phy)(const char *ifname, struct eth_phy p); + int (*poweron_phy)(const char *ifname, struct eth_phy p); + int (*get_phy_id)(const char *ifname, int port, int *phy_id); - int (*get_stats)(char *name, struct eth_counters *s); - int (*get_info)(char *name, struct eth_info *info); + int (*get_stats)(const char *ifname, struct eth_stats *s); + int (*get_info)(const char *ifname, struct eth_info *info); + int (*get_rmon_stats)(const char *ifname, struct eth_rmon_stats *tx, + struct eth_rmon_stats *rx); }; /* API list */ -int eth_up(char *name); -int eth_down(char *name); -int eth_get_link_settings(char *name, struct eth_link *link); -int eth_set_link_settings(char *name, struct eth_link link); -int eth_get_operstate(char *name, enum eth_operstate *s); -int eth_set_operstate(char *name, enum eth_operstate s); -int eth_get_stats(char *name, struct eth_counters *c); -int eth_get_info(char *name, struct eth_info *info); - -int eth_reset_phy(char *name, int phy_id); -int eth_poweroff_phy(char *name, struct eth_phy p); -int eth_poweron_phy(char *name, struct eth_phy p); - -int eth_get_phy_id(char *name, int port, int *phy_id); - -int eth_ioctl(char *name, int cmd, void *in, int len); -int eth_mii_read(char *name, int phy_id, int reg, int *out); -int eth_mii_write(char *name, int phy_id, int reg, int in); -int eth_mii_get_phy_id(char *ifname, int port, int *phy_id); -int eth_mii_reset_phy(char *name, int phy_id); +int eth_up(const char *ifname); +int eth_down(const char *ifname); +int eth_get_link_settings(const char *ifname, struct eth_link *link); +int eth_set_link_settings(const char *ifname, struct eth_link link); +int eth_get_operstate(const char *ifname, ifopstatus_t *s); +int eth_set_operstate(const char *ifname, ifopstatus_t s); +int eth_get_stats(const char *ifname, struct eth_stats *c); +int eth_get_info(const char *ifname, struct eth_info *info); +int eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *tx, + struct eth_rmon_stats *rx); + +int eth_reset_phy(const char *ifname, int phy_id); +int eth_poweroff_phy(const char *ifname, struct eth_phy p); +int eth_poweron_phy(const char *ifname, struct eth_phy p); + +int eth_get_phy_id(const char *ifname, int port, int *phy_id); + +int eth_ioctl(const char *ifname, int cmd, void *in, int len); +int eth_mii_read(const char *ifname, int phy_id, int reg, int *out); +int eth_mii_write(const char *ifname, int phy_id, int reg, int in); +int eth_mii_get_phy_id(const char *ifname, int port, int *phy_id); +int eth_mii_reset_phy(const char *ifname, int phy_id); #ifdef __cplusplus }