aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/enic/enic_main.c
diff options
context:
space:
mode:
authorScott Feldman <scofeldm@cisco.com>2009-09-03 13:01:58 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-03 23:19:10 -0400
commit4badc385d1a9e140ad0992537237fc22211adad0 (patch)
tree5edf87f3240b4ad5c999e025c47d379f09f91296 /drivers/net/enic/enic_main.c
parent27e6c7d33835e7f347cdfb5025766b7d9a6596d1 (diff)
enic: workaround A0 erratum
A0 revision ASIC has an erratum on the RQ desc cache on chip where the cache can become corrupted causing pkt buf writes to wrong locations. The s/w workaround is to post a dummy RQ desc in the ring every 32 descs, causing a flush of the cache. A0 parts are not production, but there are enough of these parts in the wild in test setups to warrant including workaround. A1 revision ASIC parts fix erratum. Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic/enic_main.c')
-rw-r--r--drivers/net/enic/enic_main.c50
1 files changed, 47 insertions, 3 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 2821a1db547d..58cae6e6a59c 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -851,6 +851,50 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
851 return 0; 851 return 0;
852} 852}
853 853
854static int enic_rq_alloc_buf_a1(struct vnic_rq *rq)
855{
856 struct rq_enet_desc *desc = vnic_rq_next_desc(rq);
857
858 if (vnic_rq_posting_soon(rq)) {
859
860 /* SW workaround for A0 HW erratum: if we're just about
861 * to write posted_index, insert a dummy desc
862 * of type resvd
863 */
864
865 rq_enet_desc_enc(desc, 0, RQ_ENET_TYPE_RESV2, 0);
866 vnic_rq_post(rq, 0, 0, 0, 0);
867 } else {
868 return enic_rq_alloc_buf(rq);
869 }
870
871 return 0;
872}
873
874static int enic_set_rq_alloc_buf(struct enic *enic)
875{
876 enum vnic_dev_hw_version hw_ver;
877 int err;
878
879 err = vnic_dev_hw_version(enic->vdev, &hw_ver);
880 if (err)
881 return err;
882
883 switch (hw_ver) {
884 case VNIC_DEV_HW_VER_A1:
885 enic->rq_alloc_buf = enic_rq_alloc_buf_a1;
886 break;
887 case VNIC_DEV_HW_VER_A2:
888 case VNIC_DEV_HW_VER_UNKNOWN:
889 enic->rq_alloc_buf = enic_rq_alloc_buf;
890 break;
891 default:
892 return -ENODEV;
893 }
894
895 return 0;
896}
897
854static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, 898static int enic_get_skb_header(struct sk_buff *skb, void **iphdr,
855 void **tcph, u64 *hdr_flags, void *priv) 899 void **tcph, u64 *hdr_flags, void *priv)
856{ 900{
@@ -1058,7 +1102,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
1058 /* Replenish RQ 1102 /* Replenish RQ
1059 */ 1103 */
1060 1104
1061 vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); 1105 vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
1062 1106
1063 } else { 1107 } else {
1064 1108
@@ -1093,7 +1137,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
1093 /* Replenish RQ 1137 /* Replenish RQ
1094 */ 1138 */
1095 1139
1096 vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); 1140 vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
1097 1141
1098 /* Return intr event credits for this polling 1142 /* Return intr event credits for this polling
1099 * cycle. An intr event is the completion of a 1143 * cycle. An intr event is the completion of a
@@ -1269,7 +1313,7 @@ static int enic_open(struct net_device *netdev)
1269 } 1313 }
1270 1314
1271 for (i = 0; i < enic->rq_count; i++) { 1315 for (i = 0; i < enic->rq_count; i++) {
1272 err = vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); 1316 err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
1273 if (err) { 1317 if (err) {
1274 printk(KERN_ERR PFX 1318 printk(KERN_ERR PFX
1275 "%s: Unable to alloc receive buffers.\n", 1319 "%s: Unable to alloc receive buffers.\n",