diff options
author | Reece R. Pollack | 2013-08-15 17:13:12 -0500 |
---|---|---|
committer | Murali Karicheri | 2014-12-03 10:29:33 -0600 |
commit | 2953d2c9838a779b08c9a2eceac6279bd7ec4b3f (patch) | |
tree | 393dcef356e341e15615549193506351c6c4caa6 /drivers/net/ethernet/ti/cpsw_ale.c | |
parent | e1d4fc9f5555671662456197de5bbfc31823c502 (diff) | |
download | linux-2953d2c9838a779b08c9a2eceac6279bd7ec4b3f.tar.gz linux-2953d2c9838a779b08c9a2eceac6279bd7ec4b3f.tar.xz linux-2953d2c9838a779b08c9a2eceac6279bd7ec4b3f.zip |
drivers: net: cpsw: Add sysfs attributes "ale_control" and "ale_table"
Add support for two new sysfs attributes "ale_control" and "ale_table"
to allow visibility into the contents of the Address Lookup Engine.
This is a forward port of code originally written by Sandeep Paulraj
and committed under ID 26368250396825790ee31745f7d277d3890f4dcd.
Signed-off-by: Reece R. Pollack <x0183204@ti.com>
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw_ale.c')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 7fa60d6092e..bb50893c2c9 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c | |||
@@ -25,6 +25,9 @@ | |||
25 | #include "cpsw_ale.h" | 25 | #include "cpsw_ale.h" |
26 | 26 | ||
27 | #define BITMASK(bits) (BIT(bits) - 1) | 27 | #define BITMASK(bits) (BIT(bits) - 1) |
28 | #define ADDR_FMT_STR "%02x:%02x:%02x:%02x:%02x:%02x" | ||
29 | #define ADDR_FMT_ARGS(addr) (addr)[0], (addr)[1], (addr)[2], \ | ||
30 | (addr)[3], (addr)[4], (addr)[5] | ||
28 | #define ALE_ENTRY_BITS 68 | 31 | #define ALE_ENTRY_BITS 68 |
29 | #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) | 32 | #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) |
30 | 33 | ||
@@ -677,6 +680,170 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) | |||
677 | return tmp & BITMASK(info->bits); | 680 | return tmp & BITMASK(info->bits); |
678 | } | 681 | } |
679 | 682 | ||
683 | static int cpsw_ale_dump_mcast(u32 *ale_entry, char *buf, int len) | ||
684 | { | ||
685 | int outlen = 0; | ||
686 | static const char * const str_mcast_state[] = {"f", "blf", "lf", "f"}; | ||
687 | int mcast_state = cpsw_ale_get_mcast_state(ale_entry); | ||
688 | int port_mask = cpsw_ale_get_port_mask(ale_entry); | ||
689 | int super = cpsw_ale_get_super(ale_entry); | ||
690 | |||
691 | outlen += snprintf(buf + outlen, len - outlen, | ||
692 | "mcstate: %s(%d), ", str_mcast_state[mcast_state], | ||
693 | mcast_state); | ||
694 | outlen += snprintf(buf + outlen, len - outlen, | ||
695 | "port mask: %x, %ssuper\n", port_mask, | ||
696 | super ? "" : "no "); | ||
697 | return outlen; | ||
698 | } | ||
699 | |||
700 | static int cpsw_ale_dump_ucast(u32 *ale_entry, char *buf, int len) | ||
701 | { | ||
702 | int outlen = 0; | ||
703 | static const char * const str_ucast_type[] = {"persistant", "untouched", | ||
704 | "oui", "touched"}; | ||
705 | int ucast_type = cpsw_ale_get_ucast_type(ale_entry); | ||
706 | int port_num = cpsw_ale_get_port_num(ale_entry); | ||
707 | int secure = cpsw_ale_get_secure(ale_entry); | ||
708 | int blocked = cpsw_ale_get_blocked(ale_entry); | ||
709 | |||
710 | outlen += snprintf(buf + outlen, len - outlen, | ||
711 | "uctype: %s(%d), ", str_ucast_type[ucast_type], | ||
712 | ucast_type); | ||
713 | outlen += snprintf(buf + outlen, len - outlen, | ||
714 | "port: %d%s%s\n", port_num, secure ? ", Secure" : "", | ||
715 | blocked ? ", Blocked" : ""); | ||
716 | return outlen; | ||
717 | } | ||
718 | |||
719 | static int cpsw_ale_dump_entry(int idx, u32 *ale_entry, char *buf, int len) | ||
720 | { | ||
721 | int type, outlen = 0; | ||
722 | u8 addr[6]; | ||
723 | static const char * const str_type[] = {"free", "addr", | ||
724 | "vlan", "vlan+addr"}; | ||
725 | |||
726 | type = cpsw_ale_get_entry_type(ale_entry); | ||
727 | if (type == ALE_TYPE_FREE) | ||
728 | return outlen; | ||
729 | |||
730 | if (idx >= 0) { | ||
731 | outlen += snprintf(buf + outlen, len - outlen, | ||
732 | "index %d, ", idx); | ||
733 | } | ||
734 | |||
735 | outlen += snprintf(buf + outlen, len - outlen, "raw: %08x %08x %08x, ", | ||
736 | ale_entry[0], ale_entry[1], ale_entry[2]); | ||
737 | |||
738 | outlen += snprintf(buf + outlen, len - outlen, | ||
739 | "type: %s(%d), ", str_type[type], type); | ||
740 | |||
741 | cpsw_ale_get_addr(ale_entry, addr); | ||
742 | outlen += snprintf(buf + outlen, len - outlen, | ||
743 | "addr: " ADDR_FMT_STR ", ", ADDR_FMT_ARGS(addr)); | ||
744 | |||
745 | if (type == ALE_TYPE_VLAN || type == ALE_TYPE_VLAN_ADDR) { | ||
746 | outlen += snprintf(buf + outlen, len - outlen, "vlan: %d, ", | ||
747 | cpsw_ale_get_vlan_id(ale_entry)); | ||
748 | } | ||
749 | |||
750 | outlen += cpsw_ale_get_mcast(ale_entry) ? | ||
751 | cpsw_ale_dump_mcast(ale_entry, buf + outlen, len - outlen) : | ||
752 | cpsw_ale_dump_ucast(ale_entry, buf + outlen, len - outlen); | ||
753 | |||
754 | return outlen; | ||
755 | } | ||
756 | |||
757 | static ssize_t cpsw_ale_control_show(struct device *dev, | ||
758 | struct device_attribute *attr, | ||
759 | char *buf) | ||
760 | { | ||
761 | int i, port, len = 0; | ||
762 | const struct ale_control_info *info; | ||
763 | struct cpsw_ale *ale = control_attr_to_ale(attr); | ||
764 | |||
765 | for (i = 0, info = ale_controls; i < ALE_NUM_CONTROLS; i++, info++) { | ||
766 | /* global controls */ | ||
767 | if (info->port_shift == 0 && info->port_offset == 0) { | ||
768 | len += snprintf(buf + len, SZ_4K - len, | ||
769 | "%s=%d\n", info->name, | ||
770 | cpsw_ale_control_get(ale, 0, i)); | ||
771 | continue; | ||
772 | } | ||
773 | |||
774 | /* port specific controls */ | ||
775 | for (port = 0; port < ale->params.ale_ports; port++) { | ||
776 | len += snprintf(buf + len, SZ_4K - len, | ||
777 | "%s.%d=%d\n", info->name, port, | ||
778 | cpsw_ale_control_get(ale, port, i)); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | return len; | ||
783 | } | ||
784 | |||
785 | static ssize_t cpsw_ale_control_store(struct device *dev, | ||
786 | struct device_attribute *attr, | ||
787 | const char *buf, size_t count) | ||
788 | { | ||
789 | char ctrl_str[33]; | ||
790 | int port = 0, value, len, ret, control; | ||
791 | unsigned long end; | ||
792 | struct cpsw_ale *ale = control_attr_to_ale(attr); | ||
793 | |||
794 | len = strcspn(buf, ".="); | ||
795 | if (len >= 32) | ||
796 | return -ENOMEM; | ||
797 | |||
798 | strncpy(ctrl_str, buf, len); | ||
799 | ctrl_str[len] = '\0'; | ||
800 | buf += len; | ||
801 | |||
802 | if (*buf == '.') | ||
803 | port = kstrtoul(buf + 1, 0, &end); | ||
804 | |||
805 | if (*buf != '=') | ||
806 | return -EINVAL; | ||
807 | |||
808 | value = kstrtoul(buf + 1, 0, NULL); | ||
809 | |||
810 | for (control = 0; control < ALE_NUM_CONTROLS; control++) | ||
811 | if (strcmp(ctrl_str, ale_controls[control].name) == 0) | ||
812 | break; | ||
813 | |||
814 | if (control >= ALE_NUM_CONTROLS) | ||
815 | return -ENOENT; | ||
816 | |||
817 | dev_dbg(ale->params.dev, "processing command %s.%d=%d\n", | ||
818 | ale_controls[control].name, port, value); | ||
819 | |||
820 | ret = cpsw_ale_control_set(ale, port, control, value); | ||
821 | if (ret < 0) | ||
822 | return ret; | ||
823 | |||
824 | return count; | ||
825 | } | ||
826 | DEVICE_ATTR(ale_control, S_IRUGO | S_IWUSR, cpsw_ale_control_show, | ||
827 | cpsw_ale_control_store); | ||
828 | |||
829 | static ssize_t cpsw_ale_table_show(struct device *dev, | ||
830 | struct device_attribute *attr, | ||
831 | char *buf) | ||
832 | { | ||
833 | int len = SZ_4K, outlen = 0, idx; | ||
834 | u32 ale_entry[ALE_ENTRY_WORDS]; | ||
835 | struct cpsw_ale *ale = table_attr_to_ale(attr); | ||
836 | |||
837 | for (idx = 0; idx < ale->params.ale_entries; idx++) { | ||
838 | cpsw_ale_read(ale, idx, ale_entry); | ||
839 | outlen += cpsw_ale_dump_entry(idx, ale_entry, buf + outlen, | ||
840 | len - outlen); | ||
841 | } | ||
842 | |||
843 | return outlen; | ||
844 | } | ||
845 | DEVICE_ATTR(ale_table, S_IRUGO, cpsw_ale_table_show, NULL); | ||
846 | |||
680 | static void cpsw_ale_timer(unsigned long arg) | 847 | static void cpsw_ale_timer(unsigned long arg) |
681 | { | 848 | { |
682 | struct cpsw_ale *ale = (struct cpsw_ale *)arg; | 849 | struct cpsw_ale *ale = (struct cpsw_ale *)arg; |
@@ -703,6 +870,7 @@ int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) | |||
703 | void cpsw_ale_start(struct cpsw_ale *ale) | 870 | void cpsw_ale_start(struct cpsw_ale *ale) |
704 | { | 871 | { |
705 | u32 rev; | 872 | u32 rev; |
873 | int ret; | ||
706 | 874 | ||
707 | rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); | 875 | rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); |
708 | dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", | 876 | dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", |
@@ -710,6 +878,14 @@ void cpsw_ale_start(struct cpsw_ale *ale) | |||
710 | cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); | 878 | cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); |
711 | cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); | 879 | cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); |
712 | 880 | ||
881 | ale->ale_control_attr = dev_attr_ale_control; | ||
882 | ret = device_create_file(ale->params.dev, &ale->ale_control_attr); | ||
883 | WARN_ON(ret < 0); | ||
884 | |||
885 | ale->ale_table_attr = dev_attr_ale_table; | ||
886 | ret = device_create_file(ale->params.dev, &ale->ale_table_attr); | ||
887 | WARN_ON(ret < 0); | ||
888 | |||
713 | init_timer(&ale->timer); | 889 | init_timer(&ale->timer); |
714 | ale->timer.data = (unsigned long)ale; | 890 | ale->timer.data = (unsigned long)ale; |
715 | ale->timer.function = cpsw_ale_timer; | 891 | ale->timer.function = cpsw_ale_timer; |
@@ -722,6 +898,8 @@ void cpsw_ale_start(struct cpsw_ale *ale) | |||
722 | void cpsw_ale_stop(struct cpsw_ale *ale) | 898 | void cpsw_ale_stop(struct cpsw_ale *ale) |
723 | { | 899 | { |
724 | del_timer_sync(&ale->timer); | 900 | del_timer_sync(&ale->timer); |
901 | device_remove_file(ale->params.dev, &ale->ale_table_attr); | ||
902 | device_remove_file(ale->params.dev, &ale->ale_control_attr); | ||
725 | } | 903 | } |
726 | 904 | ||
727 | struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) | 905 | struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) |