diff options
Diffstat (limited to 'drivers/net/enic')
-rw-r--r-- | drivers/net/enic/enic_main.c | 50 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.c | 19 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.h | 8 | ||||
-rw-r--r-- | drivers/net/enic/vnic_rq.h | 7 |
4 files changed, 80 insertions, 4 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2821a1db547..58cae6e6a59 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 | ||
854 | static 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 | |||
874 | static 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 | |||
854 | static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, | 898 | static 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", |
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index d5c28efedd9..c8d3fc7517b 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c | |||
@@ -349,6 +349,25 @@ int vnic_dev_fw_info(struct vnic_dev *vdev, | |||
349 | return err; | 349 | return err; |
350 | } | 350 | } |
351 | 351 | ||
352 | int vnic_dev_hw_version(struct vnic_dev *vdev, enum vnic_dev_hw_version *hw_ver) | ||
353 | { | ||
354 | struct vnic_devcmd_fw_info *fw_info; | ||
355 | int err; | ||
356 | |||
357 | err = vnic_dev_fw_info(vdev, &fw_info); | ||
358 | if (err) | ||
359 | return err; | ||
360 | |||
361 | if (strncmp(fw_info->hw_version, "A1", sizeof("A1")) == 0) | ||
362 | *hw_ver = VNIC_DEV_HW_VER_A1; | ||
363 | else if (strncmp(fw_info->hw_version, "A2", sizeof("A2")) == 0) | ||
364 | *hw_ver = VNIC_DEV_HW_VER_A2; | ||
365 | else | ||
366 | *hw_ver = VNIC_DEV_HW_VER_UNKNOWN; | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
352 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, | 371 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, |
353 | void *value) | 372 | void *value) |
354 | { | 373 | { |
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index d960edb8cdf..db1d63e0b97 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h | |||
@@ -41,6 +41,12 @@ static inline void writeq(u64 val, void __iomem *reg) | |||
41 | } | 41 | } |
42 | #endif | 42 | #endif |
43 | 43 | ||
44 | enum vnic_dev_hw_version { | ||
45 | VNIC_DEV_HW_VER_UNKNOWN, | ||
46 | VNIC_DEV_HW_VER_A1, | ||
47 | VNIC_DEV_HW_VER_A2, | ||
48 | }; | ||
49 | |||
44 | enum vnic_dev_intr_mode { | 50 | enum vnic_dev_intr_mode { |
45 | VNIC_DEV_INTR_MODE_UNKNOWN, | 51 | VNIC_DEV_INTR_MODE_UNKNOWN, |
46 | VNIC_DEV_INTR_MODE_INTX, | 52 | VNIC_DEV_INTR_MODE_INTX, |
@@ -88,6 +94,8 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
88 | u64 *a0, u64 *a1, int wait); | 94 | u64 *a0, u64 *a1, int wait); |
89 | int vnic_dev_fw_info(struct vnic_dev *vdev, | 95 | int vnic_dev_fw_info(struct vnic_dev *vdev, |
90 | struct vnic_devcmd_fw_info **fw_info); | 96 | struct vnic_devcmd_fw_info **fw_info); |
97 | int vnic_dev_hw_version(struct vnic_dev *vdev, | ||
98 | enum vnic_dev_hw_version *hw_ver); | ||
91 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, | 99 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, |
92 | void *value); | 100 | void *value); |
93 | int vnic_dev_stats_clear(struct vnic_dev *vdev); | 101 | int vnic_dev_stats_clear(struct vnic_dev *vdev); |
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index fd0ef66d2e9..f7b5730cb74 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h | |||
@@ -143,6 +143,11 @@ static inline void vnic_rq_post(struct vnic_rq *rq, | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | static inline int vnic_rq_posting_soon(struct vnic_rq *rq) | ||
147 | { | ||
148 | return ((rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0); | ||
149 | } | ||
150 | |||
146 | static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) | 151 | static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) |
147 | { | 152 | { |
148 | rq->ring.desc_avail += count; | 153 | rq->ring.desc_avail += count; |
@@ -186,7 +191,7 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, | |||
186 | { | 191 | { |
187 | int err; | 192 | int err; |
188 | 193 | ||
189 | while (vnic_rq_desc_avail(rq) > 1) { | 194 | while (vnic_rq_desc_avail(rq) > 0) { |
190 | 195 | ||
191 | err = (*buf_fill)(rq); | 196 | err = (*buf_fill)(rq); |
192 | if (err) | 197 | if (err) |