aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSandeep Gopalpet <Sandeep.Kumar@freescale.com>2009-11-02 02:03:40 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-03 02:40:59 -0500
commit7a8b3372e29ff58ebdf94def26703afabd287f11 (patch)
tree7d4ae47bb2ddc7de481fb4da4a4f9f31e808e1bf /drivers/net
parent46ceb60ca80fa07703bc6eb8f4651f900dff5a82 (diff)
gianfar: Basic Support for programming hash rules
This patch provides basic hash rules programming via the ethtool interface. Signed-off-by: Sandeep Gopalpet <Sandeep.Kumar@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/gianfar.c73
-rw-r--r--drivers/net/gianfar.h93
-rw-r--r--drivers/net/gianfar_ethtool.c236
3 files changed, 402 insertions, 0 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index dc9fba09b17c..086d40dd526d 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -431,6 +431,9 @@ static const struct net_device_ops gfar_netdev_ops = {
431#endif 431#endif
432}; 432};
433 433
434unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
435unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
436
434void lock_rx_qs(struct gfar_private *priv) 437void lock_rx_qs(struct gfar_private *priv)
435{ 438{
436 int i = 0x0; 439 int i = 0x0;
@@ -766,6 +769,73 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
766 } 769 }
767 return new_bit_map; 770 return new_bit_map;
768} 771}
772
773u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class)
774{
775 u32 rqfpr = FPR_FILER_MASK;
776 u32 rqfcr = 0x0;
777
778 rqfar--;
779 rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT;
780 ftp_rqfpr[rqfar] = rqfpr;
781 ftp_rqfcr[rqfar] = rqfcr;
782 gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
783
784 rqfar--;
785 rqfcr = RQFCR_CMP_NOMATCH;
786 ftp_rqfpr[rqfar] = rqfpr;
787 ftp_rqfcr[rqfar] = rqfcr;
788 gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
789
790 rqfar--;
791 rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND;
792 rqfpr = class;
793 ftp_rqfcr[rqfar] = rqfcr;
794 ftp_rqfpr[rqfar] = rqfpr;
795 gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
796
797 rqfar--;
798 rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND;
799 rqfpr = class;
800 ftp_rqfcr[rqfar] = rqfcr;
801 ftp_rqfpr[rqfar] = rqfpr;
802 gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
803
804 return rqfar;
805}
806
807static void gfar_init_filer_table(struct gfar_private *priv)
808{
809 int i = 0x0;
810 u32 rqfar = MAX_FILER_IDX;
811 u32 rqfcr = 0x0;
812 u32 rqfpr = FPR_FILER_MASK;
813
814 /* Default rule */
815 rqfcr = RQFCR_CMP_MATCH;
816 ftp_rqfcr[rqfar] = rqfcr;
817 ftp_rqfpr[rqfar] = rqfpr;
818 gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
819
820 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6);
821 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP);
822 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP);
823 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4);
824 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP);
825 rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP);
826
827 /* cur_filer_idx indicated the fisrt non-masked rule */
828 priv->cur_filer_idx = rqfar;
829
830 /* Rest are masked rules */
831 rqfcr = RQFCR_CMP_NOMATCH;
832 for (i = 0; i < rqfar; i++) {
833 ftp_rqfcr[i] = rqfcr;
834 ftp_rqfpr[i] = rqfpr;
835 gfar_write_filer(priv, i, rqfcr, rqfpr);
836 }
837}
838
769/* Set up the ethernet device structure, private data, 839/* Set up the ethernet device structure, private data,
770 * and anything else we need before we start */ 840 * and anything else we need before we start */
771static int gfar_probe(struct of_device *ofdev, 841static int gfar_probe(struct of_device *ofdev,
@@ -1005,6 +1075,9 @@ static int gfar_probe(struct of_device *ofdev,
1005 priv->gfargrp[i].int_name_tx[len_devname] = '\0'; 1075 priv->gfargrp[i].int_name_tx[len_devname] = '\0';
1006 } 1076 }
1007 1077
1078 /* Initialize the filer table */
1079 gfar_init_filer_table(priv);
1080
1008 /* Create all the sysfs files */ 1081 /* Create all the sysfs files */
1009 gfar_init_sysfs(dev); 1082 gfar_init_sysfs(dev);
1010 1083
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a2c1f963cdd6..44b63daa7ff3 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -381,6 +381,84 @@ extern const char gfar_driver_version[];
381#define BD_LFLAG(flags) ((flags) << 16) 381#define BD_LFLAG(flags) ((flags) << 16)
382#define BD_LENGTH_MASK 0x0000ffff 382#define BD_LENGTH_MASK 0x0000ffff
383 383
384#define CLASS_CODE_UNRECOG 0x00
385#define CLASS_CODE_DUMMY1 0x01
386#define CLASS_CODE_ETHERTYPE1 0x02
387#define CLASS_CODE_ETHERTYPE2 0x03
388#define CLASS_CODE_USER_PROG1 0x04
389#define CLASS_CODE_USER_PROG2 0x05
390#define CLASS_CODE_USER_PROG3 0x06
391#define CLASS_CODE_USER_PROG4 0x07
392#define CLASS_CODE_TCP_IPV4 0x08
393#define CLASS_CODE_UDP_IPV4 0x09
394#define CLASS_CODE_AH_ESP_IPV4 0x0a
395#define CLASS_CODE_SCTP_IPV4 0x0b
396#define CLASS_CODE_TCP_IPV6 0x0c
397#define CLASS_CODE_UDP_IPV6 0x0d
398#define CLASS_CODE_AH_ESP_IPV6 0x0e
399#define CLASS_CODE_SCTP_IPV6 0x0f
400
401#define FPR_FILER_MASK 0xFFFFFFFF
402#define MAX_FILER_IDX 0xFF
403
404/* RQFCR register bits */
405#define RQFCR_GPI 0x80000000
406#define RQFCR_HASHTBL_Q 0x00000000
407#define RQFCR_HASHTBL_0 0x00020000
408#define RQFCR_HASHTBL_1 0x00040000
409#define RQFCR_HASHTBL_2 0x00060000
410#define RQFCR_HASHTBL_3 0x00080000
411#define RQFCR_HASH 0x00010000
412#define RQFCR_CLE 0x00000200
413#define RQFCR_RJE 0x00000100
414#define RQFCR_AND 0x00000080
415#define RQFCR_CMP_EXACT 0x00000000
416#define RQFCR_CMP_MATCH 0x00000020
417#define RQFCR_CMP_NOEXACT 0x00000040
418#define RQFCR_CMP_NOMATCH 0x00000060
419
420/* RQFCR PID values */
421#define RQFCR_PID_MASK 0x00000000
422#define RQFCR_PID_PARSE 0x00000001
423#define RQFCR_PID_ARB 0x00000002
424#define RQFCR_PID_DAH 0x00000003
425#define RQFCR_PID_DAL 0x00000004
426#define RQFCR_PID_SAH 0x00000005
427#define RQFCR_PID_SAL 0x00000006
428#define RQFCR_PID_ETY 0x00000007
429#define RQFCR_PID_VID 0x00000008
430#define RQFCR_PID_PRI 0x00000009
431#define RQFCR_PID_TOS 0x0000000A
432#define RQFCR_PID_L4P 0x0000000B
433#define RQFCR_PID_DIA 0x0000000C
434#define RQFCR_PID_SIA 0x0000000D
435#define RQFCR_PID_DPT 0x0000000E
436#define RQFCR_PID_SPT 0x0000000F
437
438/* RQFPR when PID is 0x0001 */
439#define RQFPR_HDR_GE_512 0x00200000
440#define RQFPR_LERR 0x00100000
441#define RQFPR_RAR 0x00080000
442#define RQFPR_RARQ 0x00040000
443#define RQFPR_AR 0x00020000
444#define RQFPR_ARQ 0x00010000
445#define RQFPR_EBC 0x00008000
446#define RQFPR_VLN 0x00004000
447#define RQFPR_CFI 0x00002000
448#define RQFPR_JUM 0x00001000
449#define RQFPR_IPF 0x00000800
450#define RQFPR_FIF 0x00000400
451#define RQFPR_IPV4 0x00000200
452#define RQFPR_IPV6 0x00000100
453#define RQFPR_ICC 0x00000080
454#define RQFPR_ICV 0x00000040
455#define RQFPR_TCP 0x00000020
456#define RQFPR_UDP 0x00000010
457#define RQFPR_TUC 0x00000008
458#define RQFPR_TUV 0x00000004
459#define RQFPR_PER 0x00000002
460#define RQFPR_EER 0x00000001
461
384/* TxBD status field bits */ 462/* TxBD status field bits */
385#define TXBD_READY 0x8000 463#define TXBD_READY 0x8000
386#define TXBD_PADCRC 0x4000 464#define TXBD_PADCRC 0x4000
@@ -959,6 +1037,8 @@ struct gfar_private {
959 unsigned int rx_stash_size; 1037 unsigned int rx_stash_size;
960 unsigned int rx_stash_index; 1038 unsigned int rx_stash_index;
961 1039
1040 u32 cur_filer_idx;
1041
962 struct sk_buff_head rx_recycle; 1042 struct sk_buff_head rx_recycle;
963 1043
964 struct vlan_group *vlgrp; 1044 struct vlan_group *vlgrp;
@@ -1002,6 +1082,9 @@ struct gfar_private {
1002 struct gfar_extra_stats extra_stats; 1082 struct gfar_extra_stats extra_stats;
1003}; 1083};
1004 1084
1085extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
1086extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
1087
1005static inline u32 gfar_read(volatile unsigned __iomem *addr) 1088static inline u32 gfar_read(volatile unsigned __iomem *addr)
1006{ 1089{
1007 u32 val; 1090 u32 val;
@@ -1014,6 +1097,16 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
1014 out_be32(addr, val); 1097 out_be32(addr, val);
1015} 1098}
1016 1099
1100static inline void gfar_write_filer(struct gfar_private *priv,
1101 unsigned int far, unsigned int fcr, unsigned int fpr)
1102{
1103 struct gfar __iomem *regs = priv->gfargrp[0].regs;
1104
1105 gfar_write(&regs->rqfar, far);
1106 gfar_write(&regs->rqfcr, fcr);
1107 gfar_write(&regs->rqfpr, fpr);
1108}
1109
1017extern void lock_rx_qs(struct gfar_private *priv); 1110extern void lock_rx_qs(struct gfar_private *priv);
1018extern void lock_tx_qs(struct gfar_private *priv); 1111extern void lock_tx_qs(struct gfar_private *priv);
1019extern void unlock_rx_qs(struct gfar_private *priv); 1112extern void unlock_rx_qs(struct gfar_private *priv);
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 562f6c20f591..1010367695e4 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -645,6 +645,241 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
645} 645}
646#endif 646#endif
647 647
648static int gfar_ethflow_to_class(int flow_type, u64 *class)
649{
650 switch (flow_type) {
651 case TCP_V4_FLOW:
652 *class = CLASS_CODE_TCP_IPV4;
653 break;
654 case UDP_V4_FLOW:
655 *class = CLASS_CODE_UDP_IPV4;
656 break;
657 case AH_V4_FLOW:
658 case ESP_V4_FLOW:
659 *class = CLASS_CODE_AH_ESP_IPV4;
660 break;
661 case SCTP_V4_FLOW:
662 *class = CLASS_CODE_SCTP_IPV4;
663 break;
664 case TCP_V6_FLOW:
665 *class = CLASS_CODE_TCP_IPV6;
666 break;
667 case UDP_V6_FLOW:
668 *class = CLASS_CODE_UDP_IPV6;
669 break;
670 case AH_V6_FLOW:
671 case ESP_V6_FLOW:
672 *class = CLASS_CODE_AH_ESP_IPV6;
673 break;
674 case SCTP_V6_FLOW:
675 *class = CLASS_CODE_SCTP_IPV6;
676 break;
677 default:
678 return 0;
679 }
680
681 return 1;
682}
683
684static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
685{
686 u32 fcr = 0x0, fpr = FPR_FILER_MASK;
687
688 if (ethflow & RXH_L2DA) {
689 fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH |
690 RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
691 ftp_rqfpr[priv->cur_filer_idx] = fpr;
692 ftp_rqfcr[priv->cur_filer_idx] = fcr;
693 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
694 priv->cur_filer_idx = priv->cur_filer_idx - 1;
695
696 fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH |
697 RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
698 ftp_rqfpr[priv->cur_filer_idx] = fpr;
699 ftp_rqfcr[priv->cur_filer_idx] = fcr;
700 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
701 priv->cur_filer_idx = priv->cur_filer_idx - 1;
702 }
703
704 if (ethflow & RXH_VLAN) {
705 fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH |
706 RQFCR_AND | RQFCR_HASHTBL_0;
707 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
708 ftp_rqfpr[priv->cur_filer_idx] = fpr;
709 ftp_rqfcr[priv->cur_filer_idx] = fcr;
710 priv->cur_filer_idx = priv->cur_filer_idx - 1;
711 }
712
713 if (ethflow & RXH_IP_SRC) {
714 fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
715 RQFCR_AND | RQFCR_HASHTBL_0;
716 ftp_rqfpr[priv->cur_filer_idx] = fpr;
717 ftp_rqfcr[priv->cur_filer_idx] = fcr;
718 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
719 priv->cur_filer_idx = priv->cur_filer_idx - 1;
720 }
721
722 if (ethflow & (RXH_IP_DST)) {
723 fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
724 RQFCR_AND | RQFCR_HASHTBL_0;
725 ftp_rqfpr[priv->cur_filer_idx] = fpr;
726 ftp_rqfcr[priv->cur_filer_idx] = fcr;
727 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
728 priv->cur_filer_idx = priv->cur_filer_idx - 1;
729 }
730
731 if (ethflow & RXH_L3_PROTO) {
732 fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH |
733 RQFCR_AND | RQFCR_HASHTBL_0;
734 ftp_rqfpr[priv->cur_filer_idx] = fpr;
735 ftp_rqfcr[priv->cur_filer_idx] = fcr;
736 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
737 priv->cur_filer_idx = priv->cur_filer_idx - 1;
738 }
739
740 if (ethflow & RXH_L4_B_0_1) {
741 fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
742 RQFCR_AND | RQFCR_HASHTBL_0;
743 ftp_rqfpr[priv->cur_filer_idx] = fpr;
744 ftp_rqfcr[priv->cur_filer_idx] = fcr;
745 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
746 priv->cur_filer_idx = priv->cur_filer_idx - 1;
747 }
748
749 if (ethflow & RXH_L4_B_2_3) {
750 fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
751 RQFCR_AND | RQFCR_HASHTBL_0;
752 ftp_rqfpr[priv->cur_filer_idx] = fpr;
753 ftp_rqfcr[priv->cur_filer_idx] = fcr;
754 gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
755 priv->cur_filer_idx = priv->cur_filer_idx - 1;
756 }
757}
758
759static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class)
760{
761 unsigned int last_rule_idx = priv->cur_filer_idx;
762 unsigned int cmp_rqfpr;
763 unsigned int local_rqfpr[MAX_FILER_IDX + 1];
764 unsigned int local_rqfcr[MAX_FILER_IDX + 1];
765 int i = 0x0, k = 0x0;
766 int j = MAX_FILER_IDX, l = 0x0;
767
768 switch (class) {
769 case TCP_V4_FLOW:
770 cmp_rqfpr = RQFPR_IPV4 |RQFPR_TCP;
771 break;
772 case UDP_V4_FLOW:
773 cmp_rqfpr = RQFPR_IPV4 |RQFPR_UDP;
774 break;
775 case TCP_V6_FLOW:
776 cmp_rqfpr = RQFPR_IPV6 |RQFPR_TCP;
777 break;
778 case UDP_V6_FLOW:
779 cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP;
780 break;
781 case IPV4_FLOW:
782 cmp_rqfpr = RQFPR_IPV4;
783 case IPV6_FLOW:
784 cmp_rqfpr = RQFPR_IPV6;
785 break;
786 default:
787 printk(KERN_ERR "Right now this class is not supported\n");
788 return 0;
789 }
790
791 for (i = 0; i < MAX_FILER_IDX + 1; i++) {
792 local_rqfpr[j] = ftp_rqfpr[i];
793 local_rqfcr[j] = ftp_rqfcr[i];
794 j--;
795 if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE |
796 RQFCR_CLE |RQFCR_AND)) &&
797 (ftp_rqfpr[i] == cmp_rqfpr))
798 break;
799 }
800
801 if (i == MAX_FILER_IDX + 1) {
802 printk(KERN_ERR "No parse rule found, ");
803 printk(KERN_ERR "can't create hash rules\n");
804 return 0;
805 }
806
807 /* If a match was found, then it begins the starting of a cluster rule
808 * if it was already programmed, we need to overwrite these rules
809 */
810 for (l = i+1; l < MAX_FILER_IDX; l++) {
811 if ((ftp_rqfcr[l] & RQFCR_CLE) &&
812 !(ftp_rqfcr[l] & RQFCR_AND)) {
813 ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
814 RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
815 ftp_rqfpr[l] = FPR_FILER_MASK;
816 gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]);
817 break;
818 }
819
820 if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND))
821 continue;
822 else {
823 local_rqfpr[j] = ftp_rqfpr[l];
824 local_rqfcr[j] = ftp_rqfcr[l];
825 j--;
826 }
827 }
828
829 priv->cur_filer_idx = l - 1;
830 last_rule_idx = l;
831
832 /* hash rules */
833 ethflow_to_filer_rules(priv, ethflow);
834
835 /* Write back the popped out rules again */
836 for (k = j+1; k < MAX_FILER_IDX; k++) {
837 ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
838 ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
839 gfar_write_filer(priv, priv->cur_filer_idx,
840 local_rqfcr[k], local_rqfpr[k]);
841 if (!priv->cur_filer_idx)
842 break;
843 priv->cur_filer_idx = priv->cur_filer_idx - 1;
844 }
845
846 return 1;
847}
848
849static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
850{
851 u64 class;
852
853 if (!gfar_ethflow_to_class(cmd->flow_type, &class))
854 return -EINVAL;
855
856 if (class < CLASS_CODE_USER_PROG1 ||
857 class > CLASS_CODE_SCTP_IPV6)
858 return -EINVAL;
859
860 /* write the filer rules here */
861 if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type))
862 return -1;
863
864 return 0;
865}
866
867static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
868{
869 struct gfar_private *priv = netdev_priv(dev);
870 int ret = 0;
871
872 switch(cmd->cmd) {
873 case ETHTOOL_SRXFH:
874 ret = gfar_set_hash_opts(priv, cmd);
875 break;
876 default:
877 ret = -EINVAL;
878 }
879
880 return ret;
881}
882
648const struct ethtool_ops gfar_ethtool_ops = { 883const struct ethtool_ops gfar_ethtool_ops = {
649 .get_settings = gfar_gsettings, 884 .get_settings = gfar_gsettings,
650 .set_settings = gfar_ssettings, 885 .set_settings = gfar_ssettings,
@@ -670,4 +905,5 @@ const struct ethtool_ops gfar_ethtool_ops = {
670 .get_wol = gfar_get_wol, 905 .get_wol = gfar_get_wol,
671 .set_wol = gfar_set_wol, 906 .set_wol = gfar_set_wol,
672#endif 907#endif
908 .set_rxnfc = gfar_set_nfc,
673}; 909};