| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/delay.h>
- #include <linux/skbuff.h>
- #include <linux/switch.h>
- //include from rtl8367c dir
- #include "./rtl8367c/include/rtk_switch.h"
- #include "./rtl8367c/include/vlan.h"
- #include "./rtl8367c/include/stat.h"
- #include "./rtl8367c/include/port.h"
- #define RTL8367C_SW_CPU_PORT 6
- //RTL8367C_PHY_PORT_NUM + ext0 + ext1
- #define RTL8367C_NUM_PORTS 7
- #define RTL8367C_NUM_VIDS 4096
- struct rtl8367_priv {
- struct switch_dev swdev;
- bool global_vlan_enable;
- };
- struct rtl8367_mib_counter {
- const char *name;
- };
- struct rtl8367_vlan_info {
- unsigned short vid;
- unsigned int untag;
- unsigned int member;
- unsigned char fid;
- };
- struct rtl8367_priv rtl8367_priv_data;
- unsigned int rtl8367c_port_id[RTL8367C_NUM_PORTS]={0,1,2,3,4,EXT_PORT1,EXT_PORT0};
- void (*rtl8367_switch_reset_func)(void)=NULL;
- static struct rtl8367_mib_counter rtl8367c_mib_counters[] = {
- {"ifInOctets"},
- {"dot3StatsFCSErrors"},
- {"dot3StatsSymbolErrors"},
- {"dot3InPauseFrames"},
- {"dot3ControlInUnknownOpcodes"},
- {"etherStatsFragments"},
- {"etherStatsJabbers"},
- {"ifInUcastPkts"},
- {"etherStatsDropEvents"},
- {"etherStatsOctets"},
- {"etherStatsUndersizePkts"},
- {"etherStatsOversizePkts"},
- {"etherStatsPkts64Octets"},
- {"etherStatsPkts65to127Octets"},
- {"etherStatsPkts128to255Octets"},
- {"etherStatsPkts256to511Octets"},
- {"etherStatsPkts512to1023Octets"},
- {"etherStatsPkts1024toMaxOctets"},
- {"etherStatsMcastPkts"},
- {"etherStatsBcastPkts"},
- {"ifOutOctets"},
- {"dot3StatsSingleCollisionFrames"},
- {"dot3StatsMultipleCollisionFrames"},
- {"dot3StatsDeferredTransmissions"},
- {"dot3StatsLateCollisions"},
- {"etherStatsCollisions"},
- {"dot3StatsExcessiveCollisions"},
- {"dot3OutPauseFrames"},
- {"dot1dBasePortDelayExceededDiscards"},
- {"dot1dTpPortInDiscards"},
- {"ifOutUcastPkts"},
- {"ifOutMulticastPkts"},
- {"ifOutBrocastPkts"},
- {"outOampduPkts"},
- {"inOampduPkts"},
- {"pktgenPkts"},
- {"inMldChecksumError"},
- {"inIgmpChecksumError"},
- {"inMldSpecificQuery"},
- {"inMldGeneralQuery"},
- {"inIgmpSpecificQuery"},
- {"inIgmpGeneralQuery"},
- {"inMldLeaves"},
- {"inIgmpLeaves"},
- {"inIgmpJoinsSuccess"},
- {"inIgmpJoinsFail"},
- {"inMldJoinsSuccess"},
- {"inMldJoinsFail"},
- {"inReportSuppressionDrop"},
- {"inLeaveSuppressionDrop"},
- {"outIgmpReports"},
- {"outIgmpLeaves"},
- {"outIgmpGeneralQuery"},
- {"outIgmpSpecificQuery"},
- {"outMldReports"},
- {"outMldLeaves"},
- {"outMldGeneralQuery"},
- {"outMldSpecificQuery"},
- {"inKnownMulticastPkts"},
- {"ifInMulticastPkts"},
- {"ifInBroadcastPkts"},
- {"ifOutDiscards"}
- };
- /*rtl8367c proprietary switch API wrapper */
- static inline unsigned int rtl8367c_sw_to_phy_port(int port)
- {
- return rtl8367c_port_id[port];
- }
- static inline unsigned int rtl8367c_portmask_phy_to_sw(rtk_portmask_t phy_portmask)
- {
- int i;
- for (i = 0; i < RTL8367C_NUM_PORTS; i++) {
- if(RTK_PORTMASK_IS_PORT_SET(phy_portmask,rtl8367c_sw_to_phy_port(i))) {
- RTK_PORTMASK_PORT_CLEAR(phy_portmask,rtl8367c_sw_to_phy_port(i));
- RTK_PORTMASK_PORT_SET(phy_portmask,i);
- }
- }
- return (unsigned int)phy_portmask.bits[0];
- }
- static int rtl8367c_reset_mibs(void)
- {
- return rtk_stat_global_reset();
- }
- static int rtl8367c_reset_port_mibs(int port)
- {
- return rtk_stat_port_reset(rtl8367c_sw_to_phy_port(port));
- }
- static int rtl8367c_get_mibs_num(void)
- {
- return ARRAY_SIZE(rtl8367c_mib_counters);
- }
- static const char *rtl8367c_get_mib_name(int idx)
- {
- return rtl8367c_mib_counters[idx].name;
- }
- static int rtl8367c_get_port_mib_counter(int idx, int port, unsigned long long *counter)
- {
- return rtk_stat_port_get(rtl8367c_sw_to_phy_port(port), idx, counter);
- }
- static int rtl8367c_is_vlan_valid(unsigned int vlan)
- {
- unsigned max = RTL8367C_NUM_VIDS;
- if (vlan == 0 || vlan >= max)
- return 0;
- return 1;
- }
- static int rtl8367c_get_vlan( unsigned short vid, struct rtl8367_vlan_info *vlan)
- {
- rtk_vlan_cfg_t vlan_cfg;
- memset(vlan, '\0', sizeof(struct rtl8367_vlan_info));
- if (vid >= RTL8367C_NUM_VIDS)
- return -EINVAL;
- if(rtk_vlan_get(vid,&vlan_cfg))
- return -EINVAL;
- vlan->vid = vid;
- vlan->member = rtl8367c_portmask_phy_to_sw(vlan_cfg.mbr);
- vlan->untag = rtl8367c_portmask_phy_to_sw(vlan_cfg.untag);
- vlan->fid = vlan_cfg.fid_msti;
- return 0;
- }
- static int rtl8367c_set_vlan( unsigned short vid, u32 mbr, u32 untag, u8 fid)
- {
- rtk_vlan_cfg_t vlan_cfg;
- int i;
- memset(&vlan_cfg, 0x00, sizeof(rtk_vlan_cfg_t));
- for (i = 0; i < RTL8367C_NUM_PORTS; i++) {
- if (mbr & (1 << i)) {
- RTK_PORTMASK_PORT_SET(vlan_cfg.mbr, rtl8367c_sw_to_phy_port(i));
- if(untag & (1 << i))
- RTK_PORTMASK_PORT_SET(vlan_cfg.untag, rtl8367c_sw_to_phy_port(i));
- }
- }
- vlan_cfg.fid_msti=fid;
- vlan_cfg.ivl_en = 1;
- return rtk_vlan_set(vid, &vlan_cfg);
- }
- static int rtl8367c_get_pvid( int port, int *pvid)
- {
- u32 prio=0;
- if (port >= RTL8367C_NUM_PORTS)
- return -EINVAL;
- return rtk_vlan_portPvid_get(rtl8367c_sw_to_phy_port(port),pvid,&prio);
- }
- static int rtl8367c_set_pvid( int port, int pvid)
- {
- u32 prio=0;
- if (port >= RTL8367C_NUM_PORTS)
- return -EINVAL;
- return rtk_vlan_portPvid_set(rtl8367c_sw_to_phy_port(port),pvid,prio);
- }
- static int rtl8367c_get_port_link(int port, int *link, int *speed, int *duplex)
- {
- if(rtk_port_phyStatus_get(rtl8367c_sw_to_phy_port(port),(rtk_port_linkStatus_t *)link,
- (rtk_port_speed_t *)speed,(rtk_port_duplex_t *)duplex))
- return -EINVAL;
- return 0;
- }
- /*common rtl8367 swconfig entry API*/
- static int
- rtl8367_sw_set_vlan_enable(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev);
- priv->global_vlan_enable = val->value.i ;
- return 0;
- }
- static int
- rtl8367_sw_get_vlan_enable(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev);
- val->value.i = priv->global_vlan_enable;
- return 0;
- }
- static int rtl8367_sw_reset_mibs(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- return rtl8367c_reset_mibs();
- }
- static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- int port;
- port = val->port_vlan;
- if (port >= RTL8367C_NUM_PORTS)
- return -EINVAL;
- return rtl8367c_reset_port_mibs(port);
- }
- static int rtl8367_sw_get_port_mib(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- int i, len = 0;
- unsigned long long counter = 0;
- static char mib_buf[4096];
- if (val->port_vlan >= RTL8367C_NUM_PORTS)
- return -EINVAL;
- len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
- "Port %d MIB counters\n",
- val->port_vlan);
- for (i = 0; i <rtl8367c_get_mibs_num(); ++i) {
- len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
- "%-36s: ",rtl8367c_get_mib_name(i));
- if (!rtl8367c_get_port_mib_counter(i, val->port_vlan,
- &counter))
- len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
- "%llu\n", counter);
- else
- len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
- "%s\n", "N/A");
- }
- val->value.s = mib_buf;
- val->len = len;
- return 0;
- }
- static int rtl8367_sw_get_vlan_info(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- int i;
- u32 len = 0;
- struct rtl8367_vlan_info vlan;
- static char vlan_buf[256];
- int err;
- if (!rtl8367c_is_vlan_valid(val->port_vlan))
- return -EINVAL;
- memset(vlan_buf, '\0', sizeof(vlan_buf));
- err = rtl8367c_get_vlan(val->port_vlan, &vlan);
- if (err)
- return err;
- len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len,
- "VLAN %d: Ports: '", vlan.vid);
- for (i = 0; i <RTL8367C_NUM_PORTS; i++) {
- if (!(vlan.member & (1 << i)))
- continue;
- len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len, "%d%s", i,
- (vlan.untag & (1 << i)) ? "" : "t");
- }
- len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len,
- "', members=%04x, untag=%04x, fid=%u",
- vlan.member, vlan.untag, vlan.fid);
- val->value.s = vlan_buf;
- val->len = len;
- return 0;
- }
- static int rtl8367_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
- {
- struct switch_port *port;
- struct rtl8367_vlan_info vlan;
- int i;
- if (!rtl8367c_is_vlan_valid(val->port_vlan))
- return -EINVAL;
- if(rtl8367c_get_vlan(val->port_vlan, &vlan))
- return -EINVAL;
- port = &val->value.ports[0];
- val->len = 0;
- for (i = 0; i <RTL8367C_NUM_PORTS ; i++) {
- if (!(vlan.member & BIT(i)))
- continue;
- port->id = i;
- port->flags = (vlan.untag & BIT(i)) ?
- 0 : BIT(SWITCH_PORT_FLAG_TAGGED);
- val->len++;
- port++;
- }
- return 0;
- }
- static int rtl8367_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
- {
- struct switch_port *port;
- u32 member = 0;
- u32 untag = 0;
- u8 fid=0;
- int err;
- int i;
- if (!rtl8367c_is_vlan_valid(val->port_vlan))
- return -EINVAL;
- port = &val->value.ports[0];
- for (i = 0; i < val->len; i++, port++) {
- int pvid = 0;
- member |= BIT(port->id);
- if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED)))
- untag |= BIT(port->id);
- /*
- * To ensure that we have a valid MC entry for this VLAN,
- * initialize the port VLAN ID here.
- */
- err = rtl8367c_get_pvid(port->id, &pvid);
- if (err < 0)
- return err;
- if (pvid == 0) {
- err = rtl8367c_set_pvid(port->id, val->port_vlan);
- if (err < 0)
- return err;
- }
- }
- //pr_info("[%s] vid=%d , mem=%x,untag=%x,fid=%d \n",__func__,val->port_vlan,member,untag,fid);
- return rtl8367c_set_vlan(val->port_vlan, member, untag, fid);
- }
- static int rtl8367_sw_get_port_pvid(struct switch_dev *dev, int port, int *val)
- {
- return rtl8367c_get_pvid(port, val);
- }
- static int rtl8367_sw_set_port_pvid(struct switch_dev *dev, int port, int val)
- {
- return rtl8367c_set_pvid(port, val);
- }
- static int rtl8367_sw_reset_switch(struct switch_dev *dev)
- {
- if(rtl8367_switch_reset_func)
- (*rtl8367_switch_reset_func)();
- else
- printk("rest switch is not supported\n");
- return 0;
- }
- static int rtl8367_sw_get_port_link(struct switch_dev *dev, int port,
- struct switch_port_link *link)
- {
- int speed;
- if (port >= RTL8367C_NUM_PORTS)
- return -EINVAL;
- if(rtl8367c_get_port_link(port,(int *)&link->link,(int *)&speed,(int *)&link->duplex))
- return -EINVAL;
- if (!link->link)
- return 0;
- switch (speed) {
- case 0:
- link->speed = SWITCH_PORT_SPEED_10;
- break;
- case 1:
- link->speed = SWITCH_PORT_SPEED_100;
- break;
- case 2:
- link->speed = SWITCH_PORT_SPEED_1000;
- break;
- default:
- link->speed = SWITCH_PORT_SPEED_UNKNOWN;
- break;
- }
- return 0;
- }
- static struct switch_attr rtl8367_globals[] = {
- {
- .type = SWITCH_TYPE_INT,
- .name = "enable_vlan",
- .description = "Enable VLAN mode",
- .set = rtl8367_sw_set_vlan_enable,
- .get = rtl8367_sw_get_vlan_enable,
- .max = 1,
- }, {
- .type = SWITCH_TYPE_NOVAL,
- .name = "reset_mibs",
- .description = "Reset all MIB counters",
- .set = rtl8367_sw_reset_mibs,
- }
- };
- static struct switch_attr rtl8367_port[] = {
- {
- .type = SWITCH_TYPE_NOVAL,
- .name = "reset_mib",
- .description = "Reset single port MIB counters",
- .set = rtl8367_sw_reset_port_mibs,
- }, {
- .type = SWITCH_TYPE_STRING,
- .name = "mib",
- .description = "Get MIB counters for port",
- //.max = 33,
- .set = NULL,
- .get = rtl8367_sw_get_port_mib,
- },
- };
- static struct switch_attr rtl8367_vlan[] = {
- {
- .type = SWITCH_TYPE_STRING,
- .name = "info",
- .description = "Get vlan information",
- .max = 1,
- .set = NULL,
- .get = rtl8367_sw_get_vlan_info,
- },
- };
- static const struct switch_dev_ops rtl8367_sw_ops = {
- .attr_global = {
- .attr = rtl8367_globals,
- .n_attr = ARRAY_SIZE(rtl8367_globals),
- },
- .attr_port = {
- .attr = rtl8367_port,
- .n_attr = ARRAY_SIZE(rtl8367_port),
- },
- .attr_vlan = {
- .attr = rtl8367_vlan,
- .n_attr = ARRAY_SIZE(rtl8367_vlan),
- },
- .get_vlan_ports = rtl8367_sw_get_vlan_ports,
- .set_vlan_ports = rtl8367_sw_set_vlan_ports,
- .get_port_pvid = rtl8367_sw_get_port_pvid,
- .set_port_pvid = rtl8367_sw_set_port_pvid,
- .reset_switch = rtl8367_sw_reset_switch,
- .get_port_link = rtl8367_sw_get_port_link,
- };
- int rtl8367s_swconfig_init(void (*reset_func)(void))
- {
- struct rtl8367_priv *priv = &rtl8367_priv_data;
- struct switch_dev *dev=&priv->swdev;
- int err=0;
- rtl8367_switch_reset_func = reset_func ;
- memset(priv, 0, sizeof(struct rtl8367_priv));
- priv->global_vlan_enable =0;
- dev->name = "RTL8367C";
- dev->cpu_port = RTL8367C_SW_CPU_PORT;
- dev->ports = RTL8367C_NUM_PORTS;
- dev->vlans = RTL8367C_NUM_VIDS;
- dev->ops = &rtl8367_sw_ops;
- dev->alias = "RTL8367C";
- err = register_switch(dev, NULL);
- pr_info("[%s]\n",__func__);
- return err;
- }
|