aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>2014-06-04 01:35:54 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2014-06-26 07:44:57 -0400
commit3ba3faeb62220411284551a6443395ce7960b17d (patch)
tree63892bf8f4377bb19930813a83ae57e9326c8176
parent7a208e83fcedc0b845facc17d05ead0b9b73a967 (diff)
i40e/i40evf: Big endian fixes for handling HMC
Fix HMC handling for big endian architectures. Change-ID: Id8c46fc341815d47bfe0af8b819f0ab9a1e9e515 Signed-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c247
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h28
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h28
3 files changed, 236 insertions, 67 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
index 870ab1ee072c..5a603a5e9aa8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
@@ -747,6 +747,194 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = {
747}; 747};
748 748
749/** 749/**
750 * i40e_write_byte - replace HMC context byte
751 * @hmc_bits: pointer to the HMC memory
752 * @ce_info: a description of the struct to be read from
753 * @src: the struct to be read from
754 **/
755static void i40e_write_byte(u8 *hmc_bits,
756 struct i40e_context_ele *ce_info,
757 u8 *src)
758{
759 u8 src_byte, dest_byte, mask;
760 u8 *from, *dest;
761 u16 shift_width;
762
763 /* copy from the next struct field */
764 from = src + ce_info->offset;
765
766 /* prepare the bits and mask */
767 shift_width = ce_info->lsb % 8;
768 mask = ((u8)1 << ce_info->width) - 1;
769
770 src_byte = *from;
771 src_byte &= mask;
772
773 /* shift to correct alignment */
774 mask <<= shift_width;
775 src_byte <<= shift_width;
776
777 /* get the current bits from the target bit string */
778 dest = hmc_bits + (ce_info->lsb / 8);
779
780 memcpy(&dest_byte, dest, sizeof(dest_byte));
781
782 dest_byte &= ~mask; /* get the bits not changing */
783 dest_byte |= src_byte; /* add in the new bits */
784
785 /* put it all back */
786 memcpy(dest, &dest_byte, sizeof(dest_byte));
787}
788
789/**
790 * i40e_write_word - replace HMC context word
791 * @hmc_bits: pointer to the HMC memory
792 * @ce_info: a description of the struct to be read from
793 * @src: the struct to be read from
794 **/
795static void i40e_write_word(u8 *hmc_bits,
796 struct i40e_context_ele *ce_info,
797 u8 *src)
798{
799 u16 src_word, mask;
800 u8 *from, *dest;
801 u16 shift_width;
802 __le16 dest_word;
803
804 /* copy from the next struct field */
805 from = src + ce_info->offset;
806
807 /* prepare the bits and mask */
808 shift_width = ce_info->lsb % 8;
809 mask = ((u16)1 << ce_info->width) - 1;
810
811 /* don't swizzle the bits until after the mask because the mask bits
812 * will be in a different bit position on big endian machines
813 */
814 src_word = *(u16 *)from;
815 src_word &= mask;
816
817 /* shift to correct alignment */
818 mask <<= shift_width;
819 src_word <<= shift_width;
820
821 /* get the current bits from the target bit string */
822 dest = hmc_bits + (ce_info->lsb / 8);
823
824 memcpy(&dest_word, dest, sizeof(dest_word));
825
826 dest_word &= ~(cpu_to_le16(mask)); /* get the bits not changing */
827 dest_word |= cpu_to_le16(src_word); /* add in the new bits */
828
829 /* put it all back */
830 memcpy(dest, &dest_word, sizeof(dest_word));
831}
832
833/**
834 * i40e_write_dword - replace HMC context dword
835 * @hmc_bits: pointer to the HMC memory
836 * @ce_info: a description of the struct to be read from
837 * @src: the struct to be read from
838 **/
839static void i40e_write_dword(u8 *hmc_bits,
840 struct i40e_context_ele *ce_info,
841 u8 *src)
842{
843 u32 src_dword, mask;
844 u8 *from, *dest;
845 u16 shift_width;
846 __le32 dest_dword;
847
848 /* copy from the next struct field */
849 from = src + ce_info->offset;
850
851 /* prepare the bits and mask */
852 shift_width = ce_info->lsb % 8;
853
854 /* if the field width is exactly 32 on an x86 machine, then the shift
855 * operation will not work because the SHL instructions count is masked
856 * to 5 bits so the shift will do nothing
857 */
858 if (ce_info->width < 32)
859 mask = ((u32)1 << ce_info->width) - 1;
860 else
861 mask = -1;
862
863 /* don't swizzle the bits until after the mask because the mask bits
864 * will be in a different bit position on big endian machines
865 */
866 src_dword = *(u32 *)from;
867 src_dword &= mask;
868
869 /* shift to correct alignment */
870 mask <<= shift_width;
871 src_dword <<= shift_width;
872
873 /* get the current bits from the target bit string */
874 dest = hmc_bits + (ce_info->lsb / 8);
875
876 memcpy(&dest_dword, dest, sizeof(dest_dword));
877
878 dest_dword &= ~(cpu_to_le32(mask)); /* get the bits not changing */
879 dest_dword |= cpu_to_le32(src_dword); /* add in the new bits */
880
881 /* put it all back */
882 memcpy(dest, &dest_dword, sizeof(dest_dword));
883}
884
885/**
886 * i40e_write_qword - replace HMC context qword
887 * @hmc_bits: pointer to the HMC memory
888 * @ce_info: a description of the struct to be read from
889 * @src: the struct to be read from
890 **/
891static void i40e_write_qword(u8 *hmc_bits,
892 struct i40e_context_ele *ce_info,
893 u8 *src)
894{
895 u64 src_qword, mask;
896 u8 *from, *dest;
897 u16 shift_width;
898 __le64 dest_qword;
899
900 /* copy from the next struct field */
901 from = src + ce_info->offset;
902
903 /* prepare the bits and mask */
904 shift_width = ce_info->lsb % 8;
905
906 /* if the field width is exactly 64 on an x86 machine, then the shift
907 * operation will not work because the SHL instructions count is masked
908 * to 6 bits so the shift will do nothing
909 */
910 if (ce_info->width < 64)
911 mask = ((u64)1 << ce_info->width) - 1;
912 else
913 mask = -1;
914
915 /* don't swizzle the bits until after the mask because the mask bits
916 * will be in a different bit position on big endian machines
917 */
918 src_qword = *(u64 *)from;
919 src_qword &= mask;
920
921 /* shift to correct alignment */
922 mask <<= shift_width;
923 src_qword <<= shift_width;
924
925 /* get the current bits from the target bit string */
926 dest = hmc_bits + (ce_info->lsb / 8);
927
928 memcpy(&dest_qword, dest, sizeof(dest_qword));
929
930 dest_qword &= ~(cpu_to_le64(mask)); /* get the bits not changing */
931 dest_qword |= cpu_to_le64(src_qword); /* add in the new bits */
932
933 /* put it all back */
934 memcpy(dest, &dest_qword, sizeof(dest_qword));
935}
936
937/**
750 * i40e_clear_hmc_context - zero out the HMC context bits 938 * i40e_clear_hmc_context - zero out the HMC context bits
751 * @hw: the hardware struct 939 * @hw: the hardware struct
752 * @context_bytes: pointer to the context bit array (DMA memory) 940 * @context_bytes: pointer to the context bit array (DMA memory)
@@ -772,71 +960,28 @@ static i40e_status i40e_set_hmc_context(u8 *context_bytes,
772 struct i40e_context_ele *ce_info, 960 struct i40e_context_ele *ce_info,
773 u8 *dest) 961 u8 *dest)
774{ 962{
775 u16 shift_width;
776 u64 bitfield;
777 u8 hi_byte;
778 u8 hi_mask;
779 u64 t_bits;
780 u64 mask;
781 u8 *p;
782 int f; 963 int f;
783 964
784 for (f = 0; ce_info[f].width != 0; f++) { 965 for (f = 0; ce_info[f].width != 0; f++) {
785 /* clear out the field */
786 bitfield = 0;
787 966
788 /* copy from the next struct field */ 967 /* we have to deal with each element of the HMC using the
789 p = dest + ce_info[f].offset; 968 * correct size so that we are correct regardless of the
969 * endianness of the machine
970 */
790 switch (ce_info[f].size_of) { 971 switch (ce_info[f].size_of) {
791 case 1: 972 case 1:
792 bitfield = *p; 973 i40e_write_byte(context_bytes, &ce_info[f], dest);
793 break; 974 break;
794 case 2: 975 case 2:
795 bitfield = cpu_to_le16(*(u16 *)p); 976 i40e_write_word(context_bytes, &ce_info[f], dest);
796 break; 977 break;
797 case 4: 978 case 4:
798 bitfield = cpu_to_le32(*(u32 *)p); 979 i40e_write_dword(context_bytes, &ce_info[f], dest);
799 break; 980 break;
800 case 8: 981 case 8:
801 bitfield = cpu_to_le64(*(u64 *)p); 982 i40e_write_qword(context_bytes, &ce_info[f], dest);
802 break; 983 break;
803 } 984 }
804
805 /* prepare the bits and mask */
806 shift_width = ce_info[f].lsb % 8;
807 mask = ((u64)1 << ce_info[f].width) - 1;
808
809 /* save upper bytes for special case */
810 hi_mask = (u8)((mask >> 56) & 0xff);
811 hi_byte = (u8)((bitfield >> 56) & 0xff);
812
813 /* shift to correct alignment */
814 mask <<= shift_width;
815 bitfield <<= shift_width;
816
817 /* get the current bits from the target bit string */
818 p = context_bytes + (ce_info[f].lsb / 8);
819 memcpy(&t_bits, p, sizeof(u64));
820
821 t_bits &= ~mask; /* get the bits not changing */
822 t_bits |= bitfield; /* add in the new bits */
823
824 /* put it all back */
825 memcpy(p, &t_bits, sizeof(u64));
826
827 /* deal with the special case if needed
828 * example: 62 bit field that starts in bit 5 of first byte
829 * will overlap 3 bits into byte 9
830 */
831 if ((shift_width + ce_info[f].width) > 64) {
832 u8 byte;
833
834 hi_mask >>= (8 - shift_width);
835 hi_byte >>= (8 - shift_width);
836 byte = p[8] & ~hi_mask; /* get the bits not changing */
837 byte |= hi_byte; /* add in the new bits */
838 p[8] = byte; /* put it back */
839 }
840 } 985 }
841 986
842 return 0; 987 return 0;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
index eb65fe23c4a7..e74128db5be5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
@@ -32,16 +32,22 @@ struct i40e_hw;
32 32
33/* HMC element context information */ 33/* HMC element context information */
34 34
35/* Rx queue context data */ 35/* Rx queue context data
36 *
37 * The sizes of the variables may be larger than needed due to crossing byte
38 * boundaries. If we do not have the width of the variable set to the correct
39 * size then we could end up shifting bits off the top of the variable when the
40 * variable is at the top of a byte and crosses over into the next byte.
41 */
36struct i40e_hmc_obj_rxq { 42struct i40e_hmc_obj_rxq {
37 u16 head; 43 u16 head;
38 u8 cpuid; 44 u16 cpuid; /* bigger than needed, see above for reason */
39 u64 base; 45 u64 base;
40 u16 qlen; 46 u16 qlen;
41#define I40E_RXQ_CTX_DBUFF_SHIFT 7 47#define I40E_RXQ_CTX_DBUFF_SHIFT 7
42 u8 dbuff; 48 u16 dbuff; /* bigger than needed, see above for reason */
43#define I40E_RXQ_CTX_HBUFF_SHIFT 6 49#define I40E_RXQ_CTX_HBUFF_SHIFT 6
44 u8 hbuff; 50 u16 hbuff; /* bigger than needed, see above for reason */
45 u8 dtype; 51 u8 dtype;
46 u8 dsize; 52 u8 dsize;
47 u8 crcstrip; 53 u8 crcstrip;
@@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq {
50 u8 hsplit_0; 56 u8 hsplit_0;
51 u8 hsplit_1; 57 u8 hsplit_1;
52 u8 showiv; 58 u8 showiv;
53 u16 rxmax; 59 u32 rxmax; /* bigger than needed, see above for reason */
54 u8 tphrdesc_ena; 60 u8 tphrdesc_ena;
55 u8 tphwdesc_ena; 61 u8 tphwdesc_ena;
56 u8 tphdata_ena; 62 u8 tphdata_ena;
57 u8 tphhead_ena; 63 u8 tphhead_ena;
58 u8 lrxqthresh; 64 u16 lrxqthresh; /* bigger than needed, see above for reason */
59 u8 prefena; /* NOTE: normally must be set to 1 at init */ 65 u8 prefena; /* NOTE: normally must be set to 1 at init */
60}; 66};
61 67
62/* Tx queue context data */ 68/* Tx queue context data
69*
70* The sizes of the variables may be larger than needed due to crossing byte
71* boundaries. If we do not have the width of the variable set to the correct
72* size then we could end up shifting bits off the top of the variable when the
73* variable is at the top of a byte and crosses over into the next byte.
74*/
63struct i40e_hmc_obj_txq { 75struct i40e_hmc_obj_txq {
64 u16 head; 76 u16 head;
65 u8 new_context; 77 u8 new_context;
@@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq {
69 u8 fd_ena; 81 u8 fd_ena;
70 u8 alt_vlan_ena; 82 u8 alt_vlan_ena;
71 u16 thead_wb; 83 u16 thead_wb;
72 u16 cpuid; 84 u8 cpuid;
73 u8 head_wb_ena; 85 u8 head_wb_ena;
74 u16 qlen; 86 u16 qlen;
75 u8 tphrdesc_ena; 87 u8 tphrdesc_ena;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
index d6f762241537..a5d79877354c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
@@ -32,16 +32,22 @@ struct i40e_hw;
32 32
33/* HMC element context information */ 33/* HMC element context information */
34 34
35/* Rx queue context data */ 35/* Rx queue context data
36 *
37 * The sizes of the variables may be larger than needed due to crossing byte
38 * boundaries. If we do not have the width of the variable set to the correct
39 * size then we could end up shifting bits off the top of the variable when the
40 * variable is at the top of a byte and crosses over into the next byte.
41 */
36struct i40e_hmc_obj_rxq { 42struct i40e_hmc_obj_rxq {
37 u16 head; 43 u16 head;
38 u8 cpuid; 44 u16 cpuid; /* bigger than needed, see above for reason */
39 u64 base; 45 u64 base;
40 u16 qlen; 46 u16 qlen;
41#define I40E_RXQ_CTX_DBUFF_SHIFT 7 47#define I40E_RXQ_CTX_DBUFF_SHIFT 7
42 u8 dbuff; 48 u16 dbuff; /* bigger than needed, see above for reason */
43#define I40E_RXQ_CTX_HBUFF_SHIFT 6 49#define I40E_RXQ_CTX_HBUFF_SHIFT 6
44 u8 hbuff; 50 u16 hbuff; /* bigger than needed, see above for reason */
45 u8 dtype; 51 u8 dtype;
46 u8 dsize; 52 u8 dsize;
47 u8 crcstrip; 53 u8 crcstrip;
@@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq {
50 u8 hsplit_0; 56 u8 hsplit_0;
51 u8 hsplit_1; 57 u8 hsplit_1;
52 u8 showiv; 58 u8 showiv;
53 u16 rxmax; 59 u32 rxmax; /* bigger than needed, see above for reason */
54 u8 tphrdesc_ena; 60 u8 tphrdesc_ena;
55 u8 tphwdesc_ena; 61 u8 tphwdesc_ena;
56 u8 tphdata_ena; 62 u8 tphdata_ena;
57 u8 tphhead_ena; 63 u8 tphhead_ena;
58 u8 lrxqthresh; 64 u16 lrxqthresh; /* bigger than needed, see above for reason */
59 u8 prefena; /* NOTE: normally must be set to 1 at init */ 65 u8 prefena; /* NOTE: normally must be set to 1 at init */
60}; 66};
61 67
62/* Tx queue context data */ 68/* Tx queue context data
69*
70* The sizes of the variables may be larger than needed due to crossing byte
71* boundaries. If we do not have the width of the variable set to the correct
72* size then we could end up shifting bits off the top of the variable when the
73* variable is at the top of a byte and crosses over into the next byte.
74*/
63struct i40e_hmc_obj_txq { 75struct i40e_hmc_obj_txq {
64 u16 head; 76 u16 head;
65 u8 new_context; 77 u8 new_context;
@@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq {
69 u8 fd_ena; 81 u8 fd_ena;
70 u8 alt_vlan_ena; 82 u8 alt_vlan_ena;
71 u16 thead_wb; 83 u16 thead_wb;
72 u16 cpuid; 84 u8 cpuid;
73 u8 head_wb_ena; 85 u8 head_wb_ena;
74 u16 qlen; 86 u16 qlen;
75 u8 tphrdesc_ena; 87 u8 tphrdesc_ena;