diff options
author | Santwona Behera <santwona.behera@sun.com> | 2009-02-20 03:58:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-20 03:58:45 -0500 |
commit | 2d96cf8cdfd625da51e5d237d564cd75d3147547 (patch) | |
tree | 2acc376af0acebc752f563051ace6a90571c7680 /drivers/net/niu.c | |
parent | 59089d8d162ddcb5c434672e915331964d38a754 (diff) |
niu: Add TCAM classification configuration
Signed-off-by: Santwona Behera <santwona.behera@sun.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 699 |
1 files changed, 675 insertions, 24 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 75991eb761cf..50c11126a3db 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -2981,7 +2981,6 @@ static int tcam_user_ip_class_enable(struct niu *np, unsigned long class, | |||
2981 | return 0; | 2981 | return 0; |
2982 | } | 2982 | } |
2983 | 2983 | ||
2984 | #if 0 | ||
2985 | static int tcam_user_ip_class_set(struct niu *np, unsigned long class, | 2984 | static int tcam_user_ip_class_set(struct niu *np, unsigned long class, |
2986 | int ipv6, u64 protocol_id, | 2985 | int ipv6, u64 protocol_id, |
2987 | u64 tos_mask, u64 tos_val) | 2986 | u64 tos_mask, u64 tos_val) |
@@ -3009,7 +3008,6 @@ static int tcam_user_ip_class_set(struct niu *np, unsigned long class, | |||
3009 | 3008 | ||
3010 | return 0; | 3009 | return 0; |
3011 | } | 3010 | } |
3012 | #endif | ||
3013 | 3011 | ||
3014 | static int tcam_early_init(struct niu *np) | 3012 | static int tcam_early_init(struct niu *np) |
3015 | { | 3013 | { |
@@ -3276,6 +3274,27 @@ static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key) | |||
3276 | return 0; | 3274 | return 0; |
3277 | } | 3275 | } |
3278 | 3276 | ||
3277 | /* Entries for the ports are interleaved in the TCAM */ | ||
3278 | static u16 tcam_get_index(struct niu *np, u16 idx) | ||
3279 | { | ||
3280 | /* One entry reserved for IP fragment rule */ | ||
3281 | if (idx >= (np->clas.tcam_sz - 1)) | ||
3282 | idx = 0; | ||
3283 | return (np->clas.tcam_top + ((idx+1) * np->parent->num_ports)); | ||
3284 | } | ||
3285 | |||
3286 | static u16 tcam_get_size(struct niu *np) | ||
3287 | { | ||
3288 | /* One entry reserved for IP fragment rule */ | ||
3289 | return np->clas.tcam_sz - 1; | ||
3290 | } | ||
3291 | |||
3292 | static u16 tcam_get_valid_entry_cnt(struct niu *np) | ||
3293 | { | ||
3294 | /* One entry reserved for IP fragment rule */ | ||
3295 | return np->clas.tcam_valid_entries - 1; | ||
3296 | } | ||
3297 | |||
3279 | static void niu_rx_skb_append(struct sk_buff *skb, struct page *page, | 3298 | static void niu_rx_skb_append(struct sk_buff *skb, struct page *page, |
3280 | u32 offset, u32 size) | 3299 | u32 offset, u32 size) |
3281 | { | 3300 | { |
@@ -4999,8 +5018,7 @@ static int niu_set_ip_frag_rule(struct niu *np) | |||
4999 | struct niu_tcam_entry *tp; | 5018 | struct niu_tcam_entry *tp; |
5000 | int index, err; | 5019 | int index, err; |
5001 | 5020 | ||
5002 | /* XXX fix this allocation scheme XXX */ | 5021 | index = cp->tcam_top; |
5003 | index = cp->tcam_index; | ||
5004 | tp = &parent->tcam[index]; | 5022 | tp = &parent->tcam[index]; |
5005 | 5023 | ||
5006 | /* Note that the noport bit is the same in both ipv4 and | 5024 | /* Note that the noport bit is the same in both ipv4 and |
@@ -5017,6 +5035,8 @@ static int niu_set_ip_frag_rule(struct niu *np) | |||
5017 | err = tcam_assoc_write(np, index, tp->assoc_data); | 5035 | err = tcam_assoc_write(np, index, tp->assoc_data); |
5018 | if (err) | 5036 | if (err) |
5019 | return err; | 5037 | return err; |
5038 | tp->valid = 1; | ||
5039 | cp->tcam_valid_entries++; | ||
5020 | 5040 | ||
5021 | return 0; | 5041 | return 0; |
5022 | } | 5042 | } |
@@ -6907,6 +6927,75 @@ static int niu_get_eeprom(struct net_device *dev, | |||
6907 | return 0; | 6927 | return 0; |
6908 | } | 6928 | } |
6909 | 6929 | ||
6930 | static void niu_ethflow_to_l3proto(int flow_type, u8 *pid) | ||
6931 | { | ||
6932 | switch (flow_type) { | ||
6933 | case TCP_V4_FLOW: | ||
6934 | case TCP_V6_FLOW: | ||
6935 | *pid = IPPROTO_TCP; | ||
6936 | break; | ||
6937 | case UDP_V4_FLOW: | ||
6938 | case UDP_V6_FLOW: | ||
6939 | *pid = IPPROTO_UDP; | ||
6940 | break; | ||
6941 | case SCTP_V4_FLOW: | ||
6942 | case SCTP_V6_FLOW: | ||
6943 | *pid = IPPROTO_SCTP; | ||
6944 | break; | ||
6945 | case AH_V4_FLOW: | ||
6946 | case AH_V6_FLOW: | ||
6947 | *pid = IPPROTO_AH; | ||
6948 | break; | ||
6949 | case ESP_V4_FLOW: | ||
6950 | case ESP_V6_FLOW: | ||
6951 | *pid = IPPROTO_ESP; | ||
6952 | break; | ||
6953 | default: | ||
6954 | *pid = 0; | ||
6955 | break; | ||
6956 | } | ||
6957 | } | ||
6958 | |||
6959 | static int niu_class_to_ethflow(u64 class, int *flow_type) | ||
6960 | { | ||
6961 | switch (class) { | ||
6962 | case CLASS_CODE_TCP_IPV4: | ||
6963 | *flow_type = TCP_V4_FLOW; | ||
6964 | break; | ||
6965 | case CLASS_CODE_UDP_IPV4: | ||
6966 | *flow_type = UDP_V4_FLOW; | ||
6967 | break; | ||
6968 | case CLASS_CODE_AH_ESP_IPV4: | ||
6969 | *flow_type = AH_V4_FLOW; | ||
6970 | break; | ||
6971 | case CLASS_CODE_SCTP_IPV4: | ||
6972 | *flow_type = SCTP_V4_FLOW; | ||
6973 | break; | ||
6974 | case CLASS_CODE_TCP_IPV6: | ||
6975 | *flow_type = TCP_V6_FLOW; | ||
6976 | break; | ||
6977 | case CLASS_CODE_UDP_IPV6: | ||
6978 | *flow_type = UDP_V6_FLOW; | ||
6979 | break; | ||
6980 | case CLASS_CODE_AH_ESP_IPV6: | ||
6981 | *flow_type = AH_V6_FLOW; | ||
6982 | break; | ||
6983 | case CLASS_CODE_SCTP_IPV6: | ||
6984 | *flow_type = SCTP_V6_FLOW; | ||
6985 | break; | ||
6986 | case CLASS_CODE_USER_PROG1: | ||
6987 | case CLASS_CODE_USER_PROG2: | ||
6988 | case CLASS_CODE_USER_PROG3: | ||
6989 | case CLASS_CODE_USER_PROG4: | ||
6990 | *flow_type = IP_USER_FLOW; | ||
6991 | break; | ||
6992 | default: | ||
6993 | return 0; | ||
6994 | } | ||
6995 | |||
6996 | return 1; | ||
6997 | } | ||
6998 | |||
6910 | static int niu_ethflow_to_class(int flow_type, u64 *class) | 6999 | static int niu_ethflow_to_class(int flow_type, u64 *class) |
6911 | { | 7000 | { |
6912 | switch (flow_type) { | 7001 | switch (flow_type) { |
@@ -6916,7 +7005,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) | |||
6916 | case UDP_V4_FLOW: | 7005 | case UDP_V4_FLOW: |
6917 | *class = CLASS_CODE_UDP_IPV4; | 7006 | *class = CLASS_CODE_UDP_IPV4; |
6918 | break; | 7007 | break; |
6919 | case AH_ESP_V4_FLOW: | 7008 | case AH_V4_FLOW: |
7009 | case ESP_V4_FLOW: | ||
6920 | *class = CLASS_CODE_AH_ESP_IPV4; | 7010 | *class = CLASS_CODE_AH_ESP_IPV4; |
6921 | break; | 7011 | break; |
6922 | case SCTP_V4_FLOW: | 7012 | case SCTP_V4_FLOW: |
@@ -6928,7 +7018,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) | |||
6928 | case UDP_V6_FLOW: | 7018 | case UDP_V6_FLOW: |
6929 | *class = CLASS_CODE_UDP_IPV6; | 7019 | *class = CLASS_CODE_UDP_IPV6; |
6930 | break; | 7020 | break; |
6931 | case AH_ESP_V6_FLOW: | 7021 | case AH_V6_FLOW: |
7022 | case ESP_V6_FLOW: | ||
6932 | *class = CLASS_CODE_AH_ESP_IPV6; | 7023 | *class = CLASS_CODE_AH_ESP_IPV6; |
6933 | break; | 7024 | break; |
6934 | case SCTP_V6_FLOW: | 7025 | case SCTP_V6_FLOW: |
@@ -6945,8 +7036,6 @@ static u64 niu_flowkey_to_ethflow(u64 flow_key) | |||
6945 | { | 7036 | { |
6946 | u64 ethflow = 0; | 7037 | u64 ethflow = 0; |
6947 | 7038 | ||
6948 | if (flow_key & FLOW_KEY_PORT) | ||
6949 | ethflow |= RXH_DEV_PORT; | ||
6950 | if (flow_key & FLOW_KEY_L2DA) | 7039 | if (flow_key & FLOW_KEY_L2DA) |
6951 | ethflow |= RXH_L2DA; | 7040 | ethflow |= RXH_L2DA; |
6952 | if (flow_key & FLOW_KEY_VLAN) | 7041 | if (flow_key & FLOW_KEY_VLAN) |
@@ -6970,8 +7059,6 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key) | |||
6970 | { | 7059 | { |
6971 | u64 key = 0; | 7060 | u64 key = 0; |
6972 | 7061 | ||
6973 | if (ethflow & RXH_DEV_PORT) | ||
6974 | key |= FLOW_KEY_PORT; | ||
6975 | if (ethflow & RXH_L2DA) | 7062 | if (ethflow & RXH_L2DA) |
6976 | key |= FLOW_KEY_L2DA; | 7063 | key |= FLOW_KEY_L2DA; |
6977 | if (ethflow & RXH_VLAN) | 7064 | if (ethflow & RXH_VLAN) |
@@ -6993,41 +7080,279 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key) | |||
6993 | 7080 | ||
6994 | } | 7081 | } |
6995 | 7082 | ||
6996 | static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | 7083 | static int niu_get_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc) |
6997 | { | 7084 | { |
6998 | struct niu *np = netdev_priv(dev); | ||
6999 | u64 class; | 7085 | u64 class; |
7000 | 7086 | ||
7001 | cmd->data = 0; | 7087 | nfc->data = 0; |
7002 | 7088 | ||
7003 | if (!niu_ethflow_to_class(cmd->flow_type, &class)) | 7089 | if (!niu_ethflow_to_class(nfc->flow_type, &class)) |
7004 | return -EINVAL; | 7090 | return -EINVAL; |
7005 | 7091 | ||
7006 | if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & | 7092 | if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & |
7007 | TCAM_KEY_DISC) | 7093 | TCAM_KEY_DISC) |
7008 | cmd->data = RXH_DISCARD; | 7094 | nfc->data = RXH_DISCARD; |
7009 | else | 7095 | else |
7010 | 7096 | nfc->data = niu_flowkey_to_ethflow(np->parent->flow_key[class - | |
7011 | cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class - | ||
7012 | CLASS_CODE_USER_PROG1]); | 7097 | CLASS_CODE_USER_PROG1]); |
7013 | return 0; | 7098 | return 0; |
7014 | } | 7099 | } |
7015 | 7100 | ||
7016 | static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | 7101 | static void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp, |
7102 | struct ethtool_rx_flow_spec *fsp) | ||
7103 | { | ||
7104 | |||
7105 | fsp->h_u.tcp_ip4_spec.ip4src = (tp->key[3] & TCAM_V4KEY3_SADDR) >> | ||
7106 | TCAM_V4KEY3_SADDR_SHIFT; | ||
7107 | fsp->h_u.tcp_ip4_spec.ip4dst = (tp->key[3] & TCAM_V4KEY3_DADDR) >> | ||
7108 | TCAM_V4KEY3_DADDR_SHIFT; | ||
7109 | fsp->m_u.tcp_ip4_spec.ip4src = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >> | ||
7110 | TCAM_V4KEY3_SADDR_SHIFT; | ||
7111 | fsp->m_u.tcp_ip4_spec.ip4dst = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >> | ||
7112 | TCAM_V4KEY3_DADDR_SHIFT; | ||
7113 | |||
7114 | fsp->h_u.tcp_ip4_spec.ip4src = | ||
7115 | cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4src); | ||
7116 | fsp->m_u.tcp_ip4_spec.ip4src = | ||
7117 | cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4src); | ||
7118 | fsp->h_u.tcp_ip4_spec.ip4dst = | ||
7119 | cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4dst); | ||
7120 | fsp->m_u.tcp_ip4_spec.ip4dst = | ||
7121 | cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4dst); | ||
7122 | |||
7123 | fsp->h_u.tcp_ip4_spec.tos = (tp->key[2] & TCAM_V4KEY2_TOS) >> | ||
7124 | TCAM_V4KEY2_TOS_SHIFT; | ||
7125 | fsp->m_u.tcp_ip4_spec.tos = (tp->key_mask[2] & TCAM_V4KEY2_TOS) >> | ||
7126 | TCAM_V4KEY2_TOS_SHIFT; | ||
7127 | |||
7128 | switch (fsp->flow_type) { | ||
7129 | case TCP_V4_FLOW: | ||
7130 | case UDP_V4_FLOW: | ||
7131 | case SCTP_V4_FLOW: | ||
7132 | fsp->h_u.tcp_ip4_spec.psrc = | ||
7133 | ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7134 | TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16; | ||
7135 | fsp->h_u.tcp_ip4_spec.pdst = | ||
7136 | ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7137 | TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff; | ||
7138 | fsp->m_u.tcp_ip4_spec.psrc = | ||
7139 | ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7140 | TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16; | ||
7141 | fsp->m_u.tcp_ip4_spec.pdst = | ||
7142 | ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7143 | TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff; | ||
7144 | |||
7145 | fsp->h_u.tcp_ip4_spec.psrc = | ||
7146 | cpu_to_be16(fsp->h_u.tcp_ip4_spec.psrc); | ||
7147 | fsp->h_u.tcp_ip4_spec.pdst = | ||
7148 | cpu_to_be16(fsp->h_u.tcp_ip4_spec.pdst); | ||
7149 | fsp->m_u.tcp_ip4_spec.psrc = | ||
7150 | cpu_to_be16(fsp->m_u.tcp_ip4_spec.psrc); | ||
7151 | fsp->m_u.tcp_ip4_spec.pdst = | ||
7152 | cpu_to_be16(fsp->m_u.tcp_ip4_spec.pdst); | ||
7153 | break; | ||
7154 | case AH_V4_FLOW: | ||
7155 | case ESP_V4_FLOW: | ||
7156 | fsp->h_u.ah_ip4_spec.spi = | ||
7157 | (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7158 | TCAM_V4KEY2_PORT_SPI_SHIFT; | ||
7159 | fsp->m_u.ah_ip4_spec.spi = | ||
7160 | (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7161 | TCAM_V4KEY2_PORT_SPI_SHIFT; | ||
7162 | |||
7163 | fsp->h_u.ah_ip4_spec.spi = | ||
7164 | cpu_to_be32(fsp->h_u.ah_ip4_spec.spi); | ||
7165 | fsp->m_u.ah_ip4_spec.spi = | ||
7166 | cpu_to_be32(fsp->m_u.ah_ip4_spec.spi); | ||
7167 | break; | ||
7168 | case IP_USER_FLOW: | ||
7169 | fsp->h_u.usr_ip4_spec.l4_4_bytes = | ||
7170 | (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7171 | TCAM_V4KEY2_PORT_SPI_SHIFT; | ||
7172 | fsp->m_u.usr_ip4_spec.l4_4_bytes = | ||
7173 | (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >> | ||
7174 | TCAM_V4KEY2_PORT_SPI_SHIFT; | ||
7175 | |||
7176 | fsp->h_u.usr_ip4_spec.l4_4_bytes = | ||
7177 | cpu_to_be32(fsp->h_u.usr_ip4_spec.l4_4_bytes); | ||
7178 | fsp->m_u.usr_ip4_spec.l4_4_bytes = | ||
7179 | cpu_to_be32(fsp->m_u.usr_ip4_spec.l4_4_bytes); | ||
7180 | |||
7181 | fsp->h_u.usr_ip4_spec.proto = | ||
7182 | (tp->key[2] & TCAM_V4KEY2_PROTO) >> | ||
7183 | TCAM_V4KEY2_PROTO_SHIFT; | ||
7184 | fsp->m_u.usr_ip4_spec.proto = | ||
7185 | (tp->key_mask[2] & TCAM_V4KEY2_PROTO) >> | ||
7186 | TCAM_V4KEY2_PROTO_SHIFT; | ||
7187 | |||
7188 | fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; | ||
7189 | break; | ||
7190 | default: | ||
7191 | break; | ||
7192 | } | ||
7193 | } | ||
7194 | |||
7195 | static int niu_get_ethtool_tcam_entry(struct niu *np, | ||
7196 | struct ethtool_rxnfc *nfc) | ||
7197 | { | ||
7198 | struct niu_parent *parent = np->parent; | ||
7199 | struct niu_tcam_entry *tp; | ||
7200 | struct ethtool_rx_flow_spec *fsp = &nfc->fs; | ||
7201 | u16 idx; | ||
7202 | u64 class; | ||
7203 | int ret = 0; | ||
7204 | |||
7205 | idx = tcam_get_index(np, (u16)nfc->fs.location); | ||
7206 | |||
7207 | tp = &parent->tcam[idx]; | ||
7208 | if (!tp->valid) { | ||
7209 | pr_info(PFX "niu%d: %s entry [%d] invalid for idx[%d]\n", | ||
7210 | parent->index, np->dev->name, (u16)nfc->fs.location, idx); | ||
7211 | return -EINVAL; | ||
7212 | } | ||
7213 | |||
7214 | /* fill the flow spec entry */ | ||
7215 | class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >> | ||
7216 | TCAM_V4KEY0_CLASS_CODE_SHIFT; | ||
7217 | ret = niu_class_to_ethflow(class, &fsp->flow_type); | ||
7218 | |||
7219 | if (ret < 0) { | ||
7220 | pr_info(PFX "niu%d: %s niu_class_to_ethflow failed\n", | ||
7221 | parent->index, np->dev->name); | ||
7222 | ret = -EINVAL; | ||
7223 | goto out; | ||
7224 | } | ||
7225 | |||
7226 | if (fsp->flow_type == AH_V4_FLOW || fsp->flow_type == AH_V6_FLOW) { | ||
7227 | u32 proto = (tp->key[2] & TCAM_V4KEY2_PROTO) >> | ||
7228 | TCAM_V4KEY2_PROTO_SHIFT; | ||
7229 | if (proto == IPPROTO_ESP) { | ||
7230 | if (fsp->flow_type == AH_V4_FLOW) | ||
7231 | fsp->flow_type = ESP_V4_FLOW; | ||
7232 | else | ||
7233 | fsp->flow_type = ESP_V6_FLOW; | ||
7234 | } | ||
7235 | } | ||
7236 | |||
7237 | switch (fsp->flow_type) { | ||
7238 | case TCP_V4_FLOW: | ||
7239 | case UDP_V4_FLOW: | ||
7240 | case SCTP_V4_FLOW: | ||
7241 | case AH_V4_FLOW: | ||
7242 | case ESP_V4_FLOW: | ||
7243 | niu_get_ip4fs_from_tcam_key(tp, fsp); | ||
7244 | break; | ||
7245 | case TCP_V6_FLOW: | ||
7246 | case UDP_V6_FLOW: | ||
7247 | case SCTP_V6_FLOW: | ||
7248 | case AH_V6_FLOW: | ||
7249 | case ESP_V6_FLOW: | ||
7250 | /* Not yet implemented */ | ||
7251 | ret = -EINVAL; | ||
7252 | break; | ||
7253 | case IP_USER_FLOW: | ||
7254 | niu_get_ip4fs_from_tcam_key(tp, fsp); | ||
7255 | break; | ||
7256 | default: | ||
7257 | ret = -EINVAL; | ||
7258 | break; | ||
7259 | } | ||
7260 | |||
7261 | if (ret < 0) | ||
7262 | goto out; | ||
7263 | |||
7264 | if (tp->assoc_data & TCAM_ASSOCDATA_DISC) | ||
7265 | fsp->ring_cookie = RX_CLS_FLOW_DISC; | ||
7266 | else | ||
7267 | fsp->ring_cookie = (tp->assoc_data & TCAM_ASSOCDATA_OFFSET) >> | ||
7268 | TCAM_ASSOCDATA_OFFSET_SHIFT; | ||
7269 | |||
7270 | /* put the tcam size here */ | ||
7271 | nfc->data = tcam_get_size(np); | ||
7272 | out: | ||
7273 | return ret; | ||
7274 | } | ||
7275 | |||
7276 | static int niu_get_ethtool_tcam_all(struct niu *np, | ||
7277 | struct ethtool_rxnfc *nfc, | ||
7278 | u32 *rule_locs) | ||
7279 | { | ||
7280 | struct niu_parent *parent = np->parent; | ||
7281 | struct niu_tcam_entry *tp; | ||
7282 | int i, idx, cnt; | ||
7283 | u16 n_entries; | ||
7284 | unsigned long flags; | ||
7285 | |||
7286 | |||
7287 | /* put the tcam size here */ | ||
7288 | nfc->data = tcam_get_size(np); | ||
7289 | |||
7290 | niu_lock_parent(np, flags); | ||
7291 | n_entries = nfc->rule_cnt; | ||
7292 | for (cnt = 0, i = 0; i < nfc->data; i++) { | ||
7293 | idx = tcam_get_index(np, i); | ||
7294 | tp = &parent->tcam[idx]; | ||
7295 | if (!tp->valid) | ||
7296 | continue; | ||
7297 | rule_locs[cnt] = i; | ||
7298 | cnt++; | ||
7299 | } | ||
7300 | niu_unlock_parent(np, flags); | ||
7301 | |||
7302 | if (n_entries != cnt) { | ||
7303 | /* print warning, this should not happen */ | ||
7304 | pr_info(PFX "niu%d: %s In niu_get_ethtool_tcam_all, " | ||
7305 | "n_entries[%d] != cnt[%d]!!!\n\n", | ||
7306 | np->parent->index, np->dev->name, n_entries, cnt); | ||
7307 | } | ||
7308 | |||
7309 | return 0; | ||
7310 | } | ||
7311 | |||
7312 | static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd, | ||
7313 | void *rule_locs) | ||
7017 | { | 7314 | { |
7018 | struct niu *np = netdev_priv(dev); | 7315 | struct niu *np = netdev_priv(dev); |
7316 | int ret = 0; | ||
7317 | |||
7318 | switch (cmd->cmd) { | ||
7319 | case ETHTOOL_GRXFH: | ||
7320 | ret = niu_get_hash_opts(np, cmd); | ||
7321 | break; | ||
7322 | case ETHTOOL_GRXRINGS: | ||
7323 | cmd->data = np->num_rx_rings; | ||
7324 | break; | ||
7325 | case ETHTOOL_GRXCLSRLCNT: | ||
7326 | cmd->rule_cnt = tcam_get_valid_entry_cnt(np); | ||
7327 | break; | ||
7328 | case ETHTOOL_GRXCLSRULE: | ||
7329 | ret = niu_get_ethtool_tcam_entry(np, cmd); | ||
7330 | break; | ||
7331 | case ETHTOOL_GRXCLSRLALL: | ||
7332 | ret = niu_get_ethtool_tcam_all(np, cmd, (u32 *)rule_locs); | ||
7333 | break; | ||
7334 | default: | ||
7335 | ret = -EINVAL; | ||
7336 | break; | ||
7337 | } | ||
7338 | |||
7339 | return ret; | ||
7340 | } | ||
7341 | |||
7342 | static int niu_set_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc) | ||
7343 | { | ||
7019 | u64 class; | 7344 | u64 class; |
7020 | u64 flow_key = 0; | 7345 | u64 flow_key = 0; |
7021 | unsigned long flags; | 7346 | unsigned long flags; |
7022 | 7347 | ||
7023 | if (!niu_ethflow_to_class(cmd->flow_type, &class)) | 7348 | if (!niu_ethflow_to_class(nfc->flow_type, &class)) |
7024 | return -EINVAL; | 7349 | return -EINVAL; |
7025 | 7350 | ||
7026 | if (class < CLASS_CODE_USER_PROG1 || | 7351 | if (class < CLASS_CODE_USER_PROG1 || |
7027 | class > CLASS_CODE_SCTP_IPV6) | 7352 | class > CLASS_CODE_SCTP_IPV6) |
7028 | return -EINVAL; | 7353 | return -EINVAL; |
7029 | 7354 | ||
7030 | if (cmd->data & RXH_DISCARD) { | 7355 | if (nfc->data & RXH_DISCARD) { |
7031 | niu_lock_parent(np, flags); | 7356 | niu_lock_parent(np, flags); |
7032 | flow_key = np->parent->tcam_key[class - | 7357 | flow_key = np->parent->tcam_key[class - |
7033 | CLASS_CODE_USER_PROG1]; | 7358 | CLASS_CODE_USER_PROG1]; |
@@ -7052,7 +7377,7 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | |||
7052 | } | 7377 | } |
7053 | } | 7378 | } |
7054 | 7379 | ||
7055 | if (!niu_ethflow_to_flowkey(cmd->data, &flow_key)) | 7380 | if (!niu_ethflow_to_flowkey(nfc->data, &flow_key)) |
7056 | return -EINVAL; | 7381 | return -EINVAL; |
7057 | 7382 | ||
7058 | niu_lock_parent(np, flags); | 7383 | niu_lock_parent(np, flags); |
@@ -7063,6 +7388,331 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | |||
7063 | return 0; | 7388 | return 0; |
7064 | } | 7389 | } |
7065 | 7390 | ||
7391 | static void niu_get_tcamkey_from_ip4fs(struct ethtool_rx_flow_spec *fsp, | ||
7392 | struct niu_tcam_entry *tp, | ||
7393 | int l2_rdc_tab, u64 class) | ||
7394 | { | ||
7395 | u8 pid = 0; | ||
7396 | u32 sip, dip, sipm, dipm, spi, spim; | ||
7397 | u16 sport, dport, spm, dpm; | ||
7398 | |||
7399 | sip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4src); | ||
7400 | sipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4src); | ||
7401 | dip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4dst); | ||
7402 | dipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4dst); | ||
7403 | |||
7404 | tp->key[0] = class << TCAM_V4KEY0_CLASS_CODE_SHIFT; | ||
7405 | tp->key_mask[0] = TCAM_V4KEY0_CLASS_CODE; | ||
7406 | tp->key[1] = (u64)l2_rdc_tab << TCAM_V4KEY1_L2RDCNUM_SHIFT; | ||
7407 | tp->key_mask[1] = TCAM_V4KEY1_L2RDCNUM; | ||
7408 | |||
7409 | tp->key[3] = (u64)sip << TCAM_V4KEY3_SADDR_SHIFT; | ||
7410 | tp->key[3] |= dip; | ||
7411 | |||
7412 | tp->key_mask[3] = (u64)sipm << TCAM_V4KEY3_SADDR_SHIFT; | ||
7413 | tp->key_mask[3] |= dipm; | ||
7414 | |||
7415 | tp->key[2] |= ((u64)fsp->h_u.tcp_ip4_spec.tos << | ||
7416 | TCAM_V4KEY2_TOS_SHIFT); | ||
7417 | tp->key_mask[2] |= ((u64)fsp->m_u.tcp_ip4_spec.tos << | ||
7418 | TCAM_V4KEY2_TOS_SHIFT); | ||
7419 | switch (fsp->flow_type) { | ||
7420 | case TCP_V4_FLOW: | ||
7421 | case UDP_V4_FLOW: | ||
7422 | case SCTP_V4_FLOW: | ||
7423 | sport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.psrc); | ||
7424 | spm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.psrc); | ||
7425 | dport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.pdst); | ||
7426 | dpm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.pdst); | ||
7427 | |||
7428 | tp->key[2] |= (((u64)sport << 16) | dport); | ||
7429 | tp->key_mask[2] |= (((u64)spm << 16) | dpm); | ||
7430 | niu_ethflow_to_l3proto(fsp->flow_type, &pid); | ||
7431 | break; | ||
7432 | case AH_V4_FLOW: | ||
7433 | case ESP_V4_FLOW: | ||
7434 | spi = be32_to_cpu(fsp->h_u.ah_ip4_spec.spi); | ||
7435 | spim = be32_to_cpu(fsp->m_u.ah_ip4_spec.spi); | ||
7436 | |||
7437 | tp->key[2] |= spi; | ||
7438 | tp->key_mask[2] |= spim; | ||
7439 | niu_ethflow_to_l3proto(fsp->flow_type, &pid); | ||
7440 | break; | ||
7441 | case IP_USER_FLOW: | ||
7442 | spi = be32_to_cpu(fsp->h_u.usr_ip4_spec.l4_4_bytes); | ||
7443 | spim = be32_to_cpu(fsp->m_u.usr_ip4_spec.l4_4_bytes); | ||
7444 | |||
7445 | tp->key[2] |= spi; | ||
7446 | tp->key_mask[2] |= spim; | ||
7447 | pid = fsp->h_u.usr_ip4_spec.proto; | ||
7448 | break; | ||
7449 | default: | ||
7450 | break; | ||
7451 | } | ||
7452 | |||
7453 | tp->key[2] |= ((u64)pid << TCAM_V4KEY2_PROTO_SHIFT); | ||
7454 | if (pid) { | ||
7455 | tp->key_mask[2] |= TCAM_V4KEY2_PROTO; | ||
7456 | } | ||
7457 | } | ||
7458 | |||
7459 | static int niu_add_ethtool_tcam_entry(struct niu *np, | ||
7460 | struct ethtool_rxnfc *nfc) | ||
7461 | { | ||
7462 | struct niu_parent *parent = np->parent; | ||
7463 | struct niu_tcam_entry *tp; | ||
7464 | struct ethtool_rx_flow_spec *fsp = &nfc->fs; | ||
7465 | struct niu_rdc_tables *rdc_table = &parent->rdc_group_cfg[np->port]; | ||
7466 | int l2_rdc_table = rdc_table->first_table_num; | ||
7467 | u16 idx; | ||
7468 | u64 class; | ||
7469 | unsigned long flags; | ||
7470 | int err, ret; | ||
7471 | |||
7472 | ret = 0; | ||
7473 | |||
7474 | idx = nfc->fs.location; | ||
7475 | if (idx >= tcam_get_size(np)) | ||
7476 | return -EINVAL; | ||
7477 | |||
7478 | if (fsp->flow_type == IP_USER_FLOW) { | ||
7479 | int i; | ||
7480 | int add_usr_cls = 0; | ||
7481 | int ipv6 = 0; | ||
7482 | struct ethtool_usrip4_spec *uspec = &fsp->h_u.usr_ip4_spec; | ||
7483 | struct ethtool_usrip4_spec *umask = &fsp->m_u.usr_ip4_spec; | ||
7484 | |||
7485 | niu_lock_parent(np, flags); | ||
7486 | |||
7487 | for (i = 0; i < NIU_L3_PROG_CLS; i++) { | ||
7488 | if (parent->l3_cls[i]) { | ||
7489 | if (uspec->proto == parent->l3_cls_pid[i]) { | ||
7490 | class = parent->l3_cls[i]; | ||
7491 | parent->l3_cls_refcnt[i]++; | ||
7492 | add_usr_cls = 1; | ||
7493 | break; | ||
7494 | } | ||
7495 | } else { | ||
7496 | /* Program new user IP class */ | ||
7497 | switch (i) { | ||
7498 | case 0: | ||
7499 | class = CLASS_CODE_USER_PROG1; | ||
7500 | break; | ||
7501 | case 1: | ||
7502 | class = CLASS_CODE_USER_PROG2; | ||
7503 | break; | ||
7504 | case 2: | ||
7505 | class = CLASS_CODE_USER_PROG3; | ||
7506 | break; | ||
7507 | case 3: | ||
7508 | class = CLASS_CODE_USER_PROG4; | ||
7509 | break; | ||
7510 | default: | ||
7511 | break; | ||
7512 | } | ||
7513 | if (uspec->ip_ver == ETH_RX_NFC_IP6) | ||
7514 | ipv6 = 1; | ||
7515 | ret = tcam_user_ip_class_set(np, class, ipv6, | ||
7516 | uspec->proto, | ||
7517 | uspec->tos, | ||
7518 | umask->tos); | ||
7519 | if (ret) | ||
7520 | goto out; | ||
7521 | |||
7522 | ret = tcam_user_ip_class_enable(np, class, 1); | ||
7523 | if (ret) | ||
7524 | goto out; | ||
7525 | parent->l3_cls[i] = class; | ||
7526 | parent->l3_cls_pid[i] = uspec->proto; | ||
7527 | parent->l3_cls_refcnt[i]++; | ||
7528 | add_usr_cls = 1; | ||
7529 | break; | ||
7530 | } | ||
7531 | } | ||
7532 | if (!add_usr_cls) { | ||
7533 | pr_info(PFX "niu%d: %s niu_add_ethtool_tcam_entry: " | ||
7534 | "Could not find/insert class for pid %d\n", | ||
7535 | parent->index, np->dev->name, uspec->proto); | ||
7536 | ret = -EINVAL; | ||
7537 | goto out; | ||
7538 | } | ||
7539 | niu_unlock_parent(np, flags); | ||
7540 | } else { | ||
7541 | if (!niu_ethflow_to_class(fsp->flow_type, &class)) { | ||
7542 | return -EINVAL; | ||
7543 | } | ||
7544 | } | ||
7545 | |||
7546 | niu_lock_parent(np, flags); | ||
7547 | |||
7548 | idx = tcam_get_index(np, idx); | ||
7549 | tp = &parent->tcam[idx]; | ||
7550 | |||
7551 | memset(tp, 0, sizeof(*tp)); | ||
7552 | |||
7553 | /* fill in the tcam key and mask */ | ||
7554 | switch (fsp->flow_type) { | ||
7555 | case TCP_V4_FLOW: | ||
7556 | case UDP_V4_FLOW: | ||
7557 | case SCTP_V4_FLOW: | ||
7558 | case AH_V4_FLOW: | ||
7559 | case ESP_V4_FLOW: | ||
7560 | niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class); | ||
7561 | break; | ||
7562 | case TCP_V6_FLOW: | ||
7563 | case UDP_V6_FLOW: | ||
7564 | case SCTP_V6_FLOW: | ||
7565 | case AH_V6_FLOW: | ||
7566 | case ESP_V6_FLOW: | ||
7567 | /* Not yet implemented */ | ||
7568 | pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " | ||
7569 | "flow %d for IPv6 not implemented\n\n", | ||
7570 | parent->index, np->dev->name, fsp->flow_type); | ||
7571 | ret = -EINVAL; | ||
7572 | goto out; | ||
7573 | case IP_USER_FLOW: | ||
7574 | if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) { | ||
7575 | niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, | ||
7576 | class); | ||
7577 | } else { | ||
7578 | /* Not yet implemented */ | ||
7579 | pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " | ||
7580 | "usr flow for IPv6 not implemented\n\n", | ||
7581 | parent->index, np->dev->name); | ||
7582 | ret = -EINVAL; | ||
7583 | goto out; | ||
7584 | } | ||
7585 | break; | ||
7586 | default: | ||
7587 | pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " | ||
7588 | "Unknown flow type %d\n\n", | ||
7589 | parent->index, np->dev->name, fsp->flow_type); | ||
7590 | ret = -EINVAL; | ||
7591 | goto out; | ||
7592 | } | ||
7593 | |||
7594 | /* fill in the assoc data */ | ||
7595 | if (fsp->ring_cookie == RX_CLS_FLOW_DISC) { | ||
7596 | tp->assoc_data = TCAM_ASSOCDATA_DISC; | ||
7597 | } else { | ||
7598 | if (fsp->ring_cookie >= np->num_rx_rings) { | ||
7599 | pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " | ||
7600 | "Invalid RX ring %lld\n\n", | ||
7601 | parent->index, np->dev->name, | ||
7602 | (long long) fsp->ring_cookie); | ||
7603 | ret = -EINVAL; | ||
7604 | goto out; | ||
7605 | } | ||
7606 | tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET | | ||
7607 | (fsp->ring_cookie << | ||
7608 | TCAM_ASSOCDATA_OFFSET_SHIFT)); | ||
7609 | } | ||
7610 | |||
7611 | err = tcam_write(np, idx, tp->key, tp->key_mask); | ||
7612 | if (err) { | ||
7613 | ret = -EINVAL; | ||
7614 | goto out; | ||
7615 | } | ||
7616 | err = tcam_assoc_write(np, idx, tp->assoc_data); | ||
7617 | if (err) { | ||
7618 | ret = -EINVAL; | ||
7619 | goto out; | ||
7620 | } | ||
7621 | |||
7622 | /* validate the entry */ | ||
7623 | tp->valid = 1; | ||
7624 | np->clas.tcam_valid_entries++; | ||
7625 | out: | ||
7626 | niu_unlock_parent(np, flags); | ||
7627 | |||
7628 | return ret; | ||
7629 | } | ||
7630 | |||
7631 | static int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc) | ||
7632 | { | ||
7633 | struct niu_parent *parent = np->parent; | ||
7634 | struct niu_tcam_entry *tp; | ||
7635 | u16 idx; | ||
7636 | unsigned long flags; | ||
7637 | u64 class; | ||
7638 | int ret = 0; | ||
7639 | |||
7640 | if (loc >= tcam_get_size(np)) | ||
7641 | return -EINVAL; | ||
7642 | |||
7643 | niu_lock_parent(np, flags); | ||
7644 | |||
7645 | idx = tcam_get_index(np, loc); | ||
7646 | tp = &parent->tcam[idx]; | ||
7647 | |||
7648 | /* if the entry is of a user defined class, then update*/ | ||
7649 | class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >> | ||
7650 | TCAM_V4KEY0_CLASS_CODE_SHIFT; | ||
7651 | |||
7652 | if (class >= CLASS_CODE_USER_PROG1 && class <= CLASS_CODE_USER_PROG4) { | ||
7653 | int i; | ||
7654 | for (i = 0; i < NIU_L3_PROG_CLS; i++) { | ||
7655 | if (parent->l3_cls[i] == class) { | ||
7656 | parent->l3_cls_refcnt[i]--; | ||
7657 | if (!parent->l3_cls_refcnt[i]) { | ||
7658 | /* disable class */ | ||
7659 | ret = tcam_user_ip_class_enable(np, | ||
7660 | class, | ||
7661 | 0); | ||
7662 | if (ret) | ||
7663 | goto out; | ||
7664 | parent->l3_cls[i] = 0; | ||
7665 | parent->l3_cls_pid[i] = 0; | ||
7666 | } | ||
7667 | break; | ||
7668 | } | ||
7669 | } | ||
7670 | if (i == NIU_L3_PROG_CLS) { | ||
7671 | pr_info(PFX "niu%d: %s In niu_del_ethtool_tcam_entry," | ||
7672 | "Usr class 0x%llx not found \n", | ||
7673 | parent->index, np->dev->name, | ||
7674 | (unsigned long long) class); | ||
7675 | ret = -EINVAL; | ||
7676 | goto out; | ||
7677 | } | ||
7678 | } | ||
7679 | |||
7680 | ret = tcam_flush(np, idx); | ||
7681 | if (ret) | ||
7682 | goto out; | ||
7683 | |||
7684 | /* invalidate the entry */ | ||
7685 | tp->valid = 0; | ||
7686 | np->clas.tcam_valid_entries--; | ||
7687 | out: | ||
7688 | niu_unlock_parent(np, flags); | ||
7689 | |||
7690 | return ret; | ||
7691 | } | ||
7692 | |||
7693 | static int niu_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
7694 | { | ||
7695 | struct niu *np = netdev_priv(dev); | ||
7696 | int ret = 0; | ||
7697 | |||
7698 | switch (cmd->cmd) { | ||
7699 | case ETHTOOL_SRXFH: | ||
7700 | ret = niu_set_hash_opts(np, cmd); | ||
7701 | break; | ||
7702 | case ETHTOOL_SRXCLSRLINS: | ||
7703 | ret = niu_add_ethtool_tcam_entry(np, cmd); | ||
7704 | break; | ||
7705 | case ETHTOOL_SRXCLSRLDEL: | ||
7706 | ret = niu_del_ethtool_tcam_entry(np, cmd->fs.location); | ||
7707 | break; | ||
7708 | default: | ||
7709 | ret = -EINVAL; | ||
7710 | break; | ||
7711 | } | ||
7712 | |||
7713 | return ret; | ||
7714 | } | ||
7715 | |||
7066 | static const struct { | 7716 | static const struct { |
7067 | const char string[ETH_GSTRING_LEN]; | 7717 | const char string[ETH_GSTRING_LEN]; |
7068 | } niu_xmac_stat_keys[] = { | 7718 | } niu_xmac_stat_keys[] = { |
@@ -7296,8 +7946,8 @@ static const struct ethtool_ops niu_ethtool_ops = { | |||
7296 | .get_stats_count = niu_get_stats_count, | 7946 | .get_stats_count = niu_get_stats_count, |
7297 | .get_ethtool_stats = niu_get_ethtool_stats, | 7947 | .get_ethtool_stats = niu_get_ethtool_stats, |
7298 | .phys_id = niu_phys_id, | 7948 | .phys_id = niu_phys_id, |
7299 | .get_rxhash = niu_get_hash_opts, | 7949 | .get_rxnfc = niu_get_nfc, |
7300 | .set_rxhash = niu_set_hash_opts, | 7950 | .set_rxnfc = niu_set_nfc, |
7301 | }; | 7951 | }; |
7302 | 7952 | ||
7303 | static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, | 7953 | static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, |
@@ -8367,7 +9017,8 @@ static int __devinit niu_classifier_swstate_init(struct niu *np) | |||
8367 | niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", | 9017 | niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", |
8368 | np->parent->tcam_num_entries); | 9018 | np->parent->tcam_num_entries); |
8369 | 9019 | ||
8370 | cp->tcam_index = (u16) np->port; | 9020 | cp->tcam_top = (u16) np->port; |
9021 | cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports; | ||
8371 | cp->h1_init = 0xffffffff; | 9022 | cp->h1_init = 0xffffffff; |
8372 | cp->h2_init = 0xffff; | 9023 | cp->h2_init = 0xffff; |
8373 | 9024 | ||