diff options
author | Sathya Perla <sathyap@serverengines.com> | 2009-03-12 02:32:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-12 02:32:22 -0400 |
commit | 6b7c5b947c671a96e39f9526a5fd70c178b8dfd1 (patch) | |
tree | 6fba014e23f72f569dc3e89f3fc51c9e67c41850 /drivers | |
parent | 2c5849ea38fdad477d72dcf1c8c4842db4b33aae (diff) |
net: Add be2net driver.
Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/benet/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/benet/Makefile | 7 | ||||
-rw-r--r-- | drivers/net/benet/be.h | 327 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.c | 861 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.h | 688 | ||||
-rw-r--r-- | drivers/net/benet/be_ethtool.c | 362 | ||||
-rw-r--r-- | drivers/net/benet/be_hw.h | 211 | ||||
-rw-r--r-- | drivers/net/benet/be_main.c | 1903 |
10 files changed, 4369 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5c28b06dac6e..435e2e3a82c8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2630,6 +2630,8 @@ config QLGE | |||
2630 | 2630 | ||
2631 | source "drivers/net/sfc/Kconfig" | 2631 | source "drivers/net/sfc/Kconfig" |
2632 | 2632 | ||
2633 | source "drivers/net/benet/Kconfig" | ||
2634 | |||
2633 | endif # NETDEV_10000 | 2635 | endif # NETDEV_10000 |
2634 | 2636 | ||
2635 | source "drivers/net/tokenring/Kconfig" | 2637 | source "drivers/net/tokenring/Kconfig" |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6d9bba58b9a4..471baaff229f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_GIANFAR) += gianfar_driver.o | |||
22 | obj-$(CONFIG_TEHUTI) += tehuti.o | 22 | obj-$(CONFIG_TEHUTI) += tehuti.o |
23 | obj-$(CONFIG_ENIC) += enic/ | 23 | obj-$(CONFIG_ENIC) += enic/ |
24 | obj-$(CONFIG_JME) += jme.o | 24 | obj-$(CONFIG_JME) += jme.o |
25 | obj-$(CONFIG_BE2NET) += benet/ | ||
25 | 26 | ||
26 | gianfar_driver-objs := gianfar.o \ | 27 | gianfar_driver-objs := gianfar.o \ |
27 | gianfar_ethtool.o \ | 28 | gianfar_ethtool.o \ |
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig new file mode 100644 index 000000000000..c6934f179c09 --- /dev/null +++ b/drivers/net/benet/Kconfig | |||
@@ -0,0 +1,7 @@ | |||
1 | config BE2NET | ||
2 | tristate "ServerEngines' 10Gbps NIC - BladeEngine 2" | ||
3 | depends on PCI && INET | ||
4 | select INET_LRO | ||
5 | help | ||
6 | This driver implements the NIC functionality for ServerEngines' | ||
7 | 10Gbps network adapter - BladeEngine 2. | ||
diff --git a/drivers/net/benet/Makefile b/drivers/net/benet/Makefile new file mode 100644 index 000000000000..a60cd8051135 --- /dev/null +++ b/drivers/net/benet/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile to build the network driver for ServerEngine's BladeEngine. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_BE2NET) += be2net.o | ||
6 | |||
7 | be2net-y := be_main.o be_cmds.o be_ethtool.o | ||
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h new file mode 100644 index 000000000000..63d593d53153 --- /dev/null +++ b/drivers/net/benet/be.h | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | #ifndef BE_H | ||
19 | #define BE_H | ||
20 | |||
21 | #include <linux/pci.h> | ||
22 | #include <linux/etherdevice.h> | ||
23 | #include <linux/version.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <net/tcp.h> | ||
26 | #include <net/ip.h> | ||
27 | #include <net/ipv6.h> | ||
28 | #include <linux/if_vlan.h> | ||
29 | #include <linux/workqueue.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/inet_lro.h> | ||
32 | |||
33 | #include "be_hw.h" | ||
34 | |||
35 | #define DRV_VER "2.0.348" | ||
36 | #define DRV_NAME "be2net" | ||
37 | #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" | ||
38 | #define DRV_DESC BE_NAME "Driver" | ||
39 | |||
40 | /* Number of bytes of an RX frame that are copied to skb->data */ | ||
41 | #define BE_HDR_LEN 64 | ||
42 | #define BE_MAX_JUMBO_FRAME_SIZE 9018 | ||
43 | #define BE_MIN_MTU 256 | ||
44 | |||
45 | #define BE_NUM_VLANS_SUPPORTED 64 | ||
46 | #define BE_MAX_EQD 96 | ||
47 | #define BE_MAX_TX_FRAG_COUNT 30 | ||
48 | |||
49 | #define EVNT_Q_LEN 1024 | ||
50 | #define TX_Q_LEN 2048 | ||
51 | #define TX_CQ_LEN 1024 | ||
52 | #define RX_Q_LEN 1024 /* Does not support any other value */ | ||
53 | #define RX_CQ_LEN 1024 | ||
54 | #define MCC_Q_LEN 64 /* total size not to exceed 8 pages */ | ||
55 | #define MCC_CQ_LEN 256 | ||
56 | |||
57 | #define BE_NAPI_WEIGHT 64 | ||
58 | #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ | ||
59 | #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) | ||
60 | |||
61 | #define BE_MAX_LRO_DESCRIPTORS 16 | ||
62 | #define BE_MAX_FRAGS_PER_FRAME 16 | ||
63 | |||
64 | struct be_dma_mem { | ||
65 | void *va; | ||
66 | dma_addr_t dma; | ||
67 | u32 size; | ||
68 | }; | ||
69 | |||
70 | struct be_queue_info { | ||
71 | struct be_dma_mem dma_mem; | ||
72 | u16 len; | ||
73 | u16 entry_size; /* Size of an element in the queue */ | ||
74 | u16 id; | ||
75 | u16 tail, head; | ||
76 | bool created; | ||
77 | atomic_t used; /* Number of valid elements in the queue */ | ||
78 | }; | ||
79 | |||
80 | struct be_ctrl_info { | ||
81 | u8 __iomem *csr; | ||
82 | u8 __iomem *db; /* Door Bell */ | ||
83 | u8 __iomem *pcicfg; /* PCI config space */ | ||
84 | int pci_func; | ||
85 | |||
86 | /* Mbox used for cmd request/response */ | ||
87 | spinlock_t cmd_lock; /* For serializing cmds to BE card */ | ||
88 | struct be_dma_mem mbox_mem; | ||
89 | /* Mbox mem is adjusted to align to 16 bytes. The allocated addr | ||
90 | * is stored for freeing purpose */ | ||
91 | struct be_dma_mem mbox_mem_alloced; | ||
92 | }; | ||
93 | |||
94 | #include "be_cmds.h" | ||
95 | |||
96 | struct be_drvr_stats { | ||
97 | u32 be_tx_reqs; /* number of TX requests initiated */ | ||
98 | u32 be_tx_stops; /* number of times TX Q was stopped */ | ||
99 | u32 be_fwd_reqs; /* number of send reqs through forwarding i/f */ | ||
100 | u32 be_tx_wrbs; /* number of tx WRBs used */ | ||
101 | u32 be_tx_events; /* number of tx completion events */ | ||
102 | u32 be_tx_compl; /* number of tx completion entries processed */ | ||
103 | u64 be_tx_jiffies; | ||
104 | ulong be_tx_bytes; | ||
105 | ulong be_tx_bytes_prev; | ||
106 | u32 be_tx_rate; | ||
107 | |||
108 | u32 cache_barrier[16]; | ||
109 | |||
110 | u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */ | ||
111 | u32 be_polls; /* number of times NAPI called poll function */ | ||
112 | u32 be_rx_events; /* number of ucast rx completion events */ | ||
113 | u32 be_rx_compl; /* number of rx completion entries processed */ | ||
114 | u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */ | ||
115 | u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */ | ||
116 | u64 be_rx_jiffies; | ||
117 | ulong be_rx_bytes; | ||
118 | ulong be_rx_bytes_prev; | ||
119 | u32 be_rx_rate; | ||
120 | /* number of non ether type II frames dropped where | ||
121 | * frame len > length field of Mac Hdr */ | ||
122 | u32 be_802_3_dropped_frames; | ||
123 | /* number of non ether type II frames malformed where | ||
124 | * in frame len < length field of Mac Hdr */ | ||
125 | u32 be_802_3_malformed_frames; | ||
126 | u32 be_rxcp_err; /* Num rx completion entries w/ err set. */ | ||
127 | ulong rx_fps_jiffies; /* jiffies at last FPS calc */ | ||
128 | u32 be_rx_frags; | ||
129 | u32 be_prev_rx_frags; | ||
130 | u32 be_rx_fps; /* Rx frags per second */ | ||
131 | }; | ||
132 | |||
133 | struct be_stats_obj { | ||
134 | struct be_drvr_stats drvr_stats; | ||
135 | struct net_device_stats net_stats; | ||
136 | struct be_dma_mem cmd; | ||
137 | }; | ||
138 | |||
139 | struct be_eq_obj { | ||
140 | struct be_queue_info q; | ||
141 | char desc[32]; | ||
142 | |||
143 | /* Adaptive interrupt coalescing (AIC) info */ | ||
144 | bool enable_aic; | ||
145 | u16 min_eqd; /* in usecs */ | ||
146 | u16 max_eqd; /* in usecs */ | ||
147 | u16 cur_eqd; /* in usecs */ | ||
148 | |||
149 | struct napi_struct napi; | ||
150 | }; | ||
151 | |||
152 | struct be_tx_obj { | ||
153 | struct be_queue_info q; | ||
154 | struct be_queue_info cq; | ||
155 | /* Remember the skbs that were transmitted */ | ||
156 | struct sk_buff *sent_skb_list[TX_Q_LEN]; | ||
157 | }; | ||
158 | |||
159 | /* Struct to remember the pages posted for rx frags */ | ||
160 | struct be_rx_page_info { | ||
161 | struct page *page; | ||
162 | dma_addr_t bus; | ||
163 | u16 page_offset; | ||
164 | bool last_page_user; | ||
165 | }; | ||
166 | |||
167 | struct be_rx_obj { | ||
168 | struct be_queue_info q; | ||
169 | struct be_queue_info cq; | ||
170 | struct be_rx_page_info page_info_tbl[RX_Q_LEN]; | ||
171 | struct net_lro_mgr lro_mgr; | ||
172 | struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS]; | ||
173 | }; | ||
174 | |||
175 | #define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */ | ||
176 | struct be_adapter { | ||
177 | struct pci_dev *pdev; | ||
178 | struct net_device *netdev; | ||
179 | |||
180 | /* Mbox, pci config, csr address information */ | ||
181 | struct be_ctrl_info ctrl; | ||
182 | |||
183 | struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS]; | ||
184 | bool msix_enabled; | ||
185 | bool isr_registered; | ||
186 | |||
187 | /* TX Rings */ | ||
188 | struct be_eq_obj tx_eq; | ||
189 | struct be_tx_obj tx_obj; | ||
190 | |||
191 | u32 cache_line_break[8]; | ||
192 | |||
193 | /* Rx rings */ | ||
194 | struct be_eq_obj rx_eq; | ||
195 | struct be_rx_obj rx_obj; | ||
196 | u32 big_page_size; /* Compounded page size shared by rx wrbs */ | ||
197 | |||
198 | struct vlan_group *vlan_grp; | ||
199 | u16 num_vlans; | ||
200 | u8 vlan_tag[VLAN_GROUP_ARRAY_LEN]; | ||
201 | |||
202 | struct be_stats_obj stats; | ||
203 | /* Work queue used to perform periodic tasks like getting statistics */ | ||
204 | struct delayed_work work; | ||
205 | |||
206 | /* Ethtool knobs and info */ | ||
207 | bool rx_csum; /* BE card must perform rx-checksumming */ | ||
208 | u32 max_rx_coal; | ||
209 | char fw_ver[FW_VER_LEN]; | ||
210 | u32 if_handle; /* Used to configure filtering */ | ||
211 | u32 pmac_id; /* MAC addr handle used by BE card */ | ||
212 | |||
213 | struct be_link_info link; | ||
214 | u32 port_num; | ||
215 | }; | ||
216 | |||
217 | extern struct ethtool_ops be_ethtool_ops; | ||
218 | |||
219 | #define drvr_stats(adapter) (&adapter->stats.drvr_stats) | ||
220 | |||
221 | #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) | ||
222 | |||
223 | static inline u32 MODULO(u16 val, u16 limit) | ||
224 | { | ||
225 | BUG_ON(limit & (limit - 1)); | ||
226 | return val & (limit - 1); | ||
227 | } | ||
228 | |||
229 | static inline void index_adv(u16 *index, u16 val, u16 limit) | ||
230 | { | ||
231 | *index = MODULO((*index + val), limit); | ||
232 | } | ||
233 | |||
234 | static inline void index_inc(u16 *index, u16 limit) | ||
235 | { | ||
236 | *index = MODULO((*index + 1), limit); | ||
237 | } | ||
238 | |||
239 | #define PAGE_SHIFT_4K 12 | ||
240 | #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) | ||
241 | |||
242 | /* Returns number of pages spanned by the data starting at the given addr */ | ||
243 | #define PAGES_4K_SPANNED(_address, size) \ | ||
244 | ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ | ||
245 | (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) | ||
246 | |||
247 | /* Byte offset into the page corresponding to given address */ | ||
248 | #define OFFSET_IN_PAGE(addr) \ | ||
249 | ((size_t)(addr) & (PAGE_SIZE_4K-1)) | ||
250 | |||
251 | /* Returns bit offset within a DWORD of a bitfield */ | ||
252 | #define AMAP_BIT_OFFSET(_struct, field) \ | ||
253 | (((size_t)&(((_struct *)0)->field))%32) | ||
254 | |||
255 | /* Returns the bit mask of the field that is NOT shifted into location. */ | ||
256 | static inline u32 amap_mask(u32 bitsize) | ||
257 | { | ||
258 | return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1); | ||
259 | } | ||
260 | |||
261 | static inline void | ||
262 | amap_set(void *ptr, u32 dw_offset, u32 mask, u32 offset, u32 value) | ||
263 | { | ||
264 | u32 *dw = (u32 *) ptr + dw_offset; | ||
265 | *dw &= ~(mask << offset); | ||
266 | *dw |= (mask & value) << offset; | ||
267 | } | ||
268 | |||
269 | #define AMAP_SET_BITS(_struct, field, ptr, val) \ | ||
270 | amap_set(ptr, \ | ||
271 | offsetof(_struct, field)/32, \ | ||
272 | amap_mask(sizeof(((_struct *)0)->field)), \ | ||
273 | AMAP_BIT_OFFSET(_struct, field), \ | ||
274 | val) | ||
275 | |||
276 | static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset) | ||
277 | { | ||
278 | u32 *dw = (u32 *) ptr; | ||
279 | return mask & (*(dw + dw_offset) >> offset); | ||
280 | } | ||
281 | |||
282 | #define AMAP_GET_BITS(_struct, field, ptr) \ | ||
283 | amap_get(ptr, \ | ||
284 | offsetof(_struct, field)/32, \ | ||
285 | amap_mask(sizeof(((_struct *)0)->field)), \ | ||
286 | AMAP_BIT_OFFSET(_struct, field)) | ||
287 | |||
288 | #define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len) | ||
289 | #define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len) | ||
290 | static inline void swap_dws(void *wrb, int len) | ||
291 | { | ||
292 | #ifdef __BIG_ENDIAN | ||
293 | u32 *dw = wrb; | ||
294 | BUG_ON(len % 4); | ||
295 | do { | ||
296 | *dw = cpu_to_le32(*dw); | ||
297 | dw++; | ||
298 | len -= 4; | ||
299 | } while (len); | ||
300 | #endif /* __BIG_ENDIAN */ | ||
301 | } | ||
302 | |||
303 | static inline u8 is_tcp_pkt(struct sk_buff *skb) | ||
304 | { | ||
305 | u8 val = 0; | ||
306 | |||
307 | if (ip_hdr(skb)->version == 4) | ||
308 | val = (ip_hdr(skb)->protocol == IPPROTO_TCP); | ||
309 | else if (ip_hdr(skb)->version == 6) | ||
310 | val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP); | ||
311 | |||
312 | return val; | ||
313 | } | ||
314 | |||
315 | static inline u8 is_udp_pkt(struct sk_buff *skb) | ||
316 | { | ||
317 | u8 val = 0; | ||
318 | |||
319 | if (ip_hdr(skb)->version == 4) | ||
320 | val = (ip_hdr(skb)->protocol == IPPROTO_UDP); | ||
321 | else if (ip_hdr(skb)->version == 6) | ||
322 | val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_UDP); | ||
323 | |||
324 | return val; | ||
325 | } | ||
326 | |||
327 | #endif /* BE_H */ | ||
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c new file mode 100644 index 000000000000..d444aed962bc --- /dev/null +++ b/drivers/net/benet/be_cmds.c | |||
@@ -0,0 +1,861 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | #include "be.h" | ||
19 | |||
20 | static int be_mbox_db_ready_wait(void __iomem *db) | ||
21 | { | ||
22 | int cnt = 0, wait = 5; | ||
23 | u32 ready; | ||
24 | |||
25 | do { | ||
26 | ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK; | ||
27 | if (ready) | ||
28 | break; | ||
29 | |||
30 | if (cnt > 200000) { | ||
31 | printk(KERN_WARNING DRV_NAME | ||
32 | ": mbox_db poll timed out\n"); | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | if (cnt > 50) | ||
37 | wait = 200; | ||
38 | cnt += wait; | ||
39 | udelay(wait); | ||
40 | } while (true); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Insert the mailbox address into the doorbell in two steps | ||
47 | */ | ||
48 | static int be_mbox_db_ring(struct be_ctrl_info *ctrl) | ||
49 | { | ||
50 | int status; | ||
51 | u16 compl_status, extd_status; | ||
52 | u32 val = 0; | ||
53 | void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; | ||
54 | struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; | ||
55 | struct be_mcc_mailbox *mbox = mbox_mem->va; | ||
56 | struct be_mcc_cq_entry *cqe = &mbox->cqe; | ||
57 | |||
58 | memset(cqe, 0, sizeof(*cqe)); | ||
59 | |||
60 | val &= ~MPU_MAILBOX_DB_RDY_MASK; | ||
61 | val |= MPU_MAILBOX_DB_HI_MASK; | ||
62 | /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ | ||
63 | val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; | ||
64 | iowrite32(val, db); | ||
65 | |||
66 | /* wait for ready to be set */ | ||
67 | status = be_mbox_db_ready_wait(db); | ||
68 | if (status != 0) | ||
69 | return status; | ||
70 | |||
71 | val = 0; | ||
72 | val &= ~MPU_MAILBOX_DB_RDY_MASK; | ||
73 | val &= ~MPU_MAILBOX_DB_HI_MASK; | ||
74 | /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ | ||
75 | val |= (u32)(mbox_mem->dma >> 4) << 2; | ||
76 | iowrite32(val, db); | ||
77 | |||
78 | status = be_mbox_db_ready_wait(db); | ||
79 | if (status != 0) | ||
80 | return status; | ||
81 | |||
82 | /* compl entry has been made now */ | ||
83 | be_dws_le_to_cpu(cqe, sizeof(*cqe)); | ||
84 | if (!(cqe->flags & CQE_FLAGS_VALID_MASK)) { | ||
85 | printk(KERN_WARNING DRV_NAME ": ERROR invalid mbox compl\n"); | ||
86 | return -1; | ||
87 | } | ||
88 | |||
89 | compl_status = (cqe->status >> CQE_STATUS_COMPL_SHIFT) & | ||
90 | CQE_STATUS_COMPL_MASK; | ||
91 | if (compl_status != MCC_STATUS_SUCCESS) { | ||
92 | extd_status = (cqe->status >> CQE_STATUS_EXTD_SHIFT) & | ||
93 | CQE_STATUS_EXTD_MASK; | ||
94 | printk(KERN_WARNING DRV_NAME | ||
95 | ": ERROR in cmd compl. status(compl/extd)=%d/%d\n", | ||
96 | compl_status, extd_status); | ||
97 | } | ||
98 | |||
99 | return compl_status; | ||
100 | } | ||
101 | |||
102 | static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) | ||
103 | { | ||
104 | u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); | ||
105 | |||
106 | *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK; | ||
107 | if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK) | ||
108 | return -1; | ||
109 | else | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage) | ||
114 | { | ||
115 | u16 stage, cnt, error; | ||
116 | for (cnt = 0; cnt < 5000; cnt++) { | ||
117 | error = be_POST_stage_get(ctrl, &stage); | ||
118 | if (error) | ||
119 | return -1; | ||
120 | |||
121 | if (stage == poll_stage) | ||
122 | break; | ||
123 | udelay(1000); | ||
124 | } | ||
125 | if (stage != poll_stage) | ||
126 | return -1; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | |||
131 | int be_cmd_POST(struct be_ctrl_info *ctrl) | ||
132 | { | ||
133 | u16 stage, error; | ||
134 | |||
135 | error = be_POST_stage_get(ctrl, &stage); | ||
136 | if (error) | ||
137 | goto err; | ||
138 | |||
139 | if (stage == POST_STAGE_ARMFW_RDY) | ||
140 | return 0; | ||
141 | |||
142 | if (stage != POST_STAGE_AWAITING_HOST_RDY) | ||
143 | goto err; | ||
144 | |||
145 | /* On awaiting host rdy, reset and again poll on awaiting host rdy */ | ||
146 | iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); | ||
147 | error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY); | ||
148 | if (error) | ||
149 | goto err; | ||
150 | |||
151 | /* Now kickoff POST and poll on armfw ready */ | ||
152 | iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); | ||
153 | error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY); | ||
154 | if (error) | ||
155 | goto err; | ||
156 | |||
157 | return 0; | ||
158 | err: | ||
159 | printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage); | ||
160 | return -1; | ||
161 | } | ||
162 | |||
163 | static inline void *embedded_payload(struct be_mcc_wrb *wrb) | ||
164 | { | ||
165 | return wrb->payload.embedded_payload; | ||
166 | } | ||
167 | |||
168 | static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) | ||
169 | { | ||
170 | return &wrb->payload.sgl[0]; | ||
171 | } | ||
172 | |||
173 | /* Don't touch the hdr after it's prepared */ | ||
174 | static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, | ||
175 | bool embedded, u8 sge_cnt) | ||
176 | { | ||
177 | if (embedded) | ||
178 | wrb->embedded |= MCC_WRB_EMBEDDED_MASK; | ||
179 | else | ||
180 | wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << | ||
181 | MCC_WRB_SGE_CNT_SHIFT; | ||
182 | wrb->payload_length = payload_len; | ||
183 | be_dws_cpu_to_le(wrb, 20); | ||
184 | } | ||
185 | |||
186 | /* Don't touch the hdr after it's prepared */ | ||
187 | static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, | ||
188 | u8 subsystem, u8 opcode, int cmd_len) | ||
189 | { | ||
190 | req_hdr->opcode = opcode; | ||
191 | req_hdr->subsystem = subsystem; | ||
192 | req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); | ||
193 | } | ||
194 | |||
195 | static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, | ||
196 | struct be_dma_mem *mem) | ||
197 | { | ||
198 | int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); | ||
199 | u64 dma = (u64)mem->dma; | ||
200 | |||
201 | for (i = 0; i < buf_pages; i++) { | ||
202 | pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); | ||
203 | pages[i].hi = cpu_to_le32(upper_32_bits(dma)); | ||
204 | dma += PAGE_SIZE_4K; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /* Converts interrupt delay in microseconds to multiplier value */ | ||
209 | static u32 eq_delay_to_mult(u32 usec_delay) | ||
210 | { | ||
211 | #define MAX_INTR_RATE 651042 | ||
212 | const u32 round = 10; | ||
213 | u32 multiplier; | ||
214 | |||
215 | if (usec_delay == 0) | ||
216 | multiplier = 0; | ||
217 | else { | ||
218 | u32 interrupt_rate = 1000000 / usec_delay; | ||
219 | /* Max delay, corresponding to the lowest interrupt rate */ | ||
220 | if (interrupt_rate == 0) | ||
221 | multiplier = 1023; | ||
222 | else { | ||
223 | multiplier = (MAX_INTR_RATE - interrupt_rate) * round; | ||
224 | multiplier /= interrupt_rate; | ||
225 | /* Round the multiplier to the closest value.*/ | ||
226 | multiplier = (multiplier + round/2) / round; | ||
227 | multiplier = min(multiplier, (u32)1023); | ||
228 | } | ||
229 | } | ||
230 | return multiplier; | ||
231 | } | ||
232 | |||
233 | static inline struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem) | ||
234 | { | ||
235 | return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; | ||
236 | } | ||
237 | |||
238 | int be_cmd_eq_create(struct be_ctrl_info *ctrl, | ||
239 | struct be_queue_info *eq, int eq_delay) | ||
240 | { | ||
241 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
242 | struct be_cmd_req_eq_create *req = embedded_payload(wrb); | ||
243 | struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); | ||
244 | struct be_dma_mem *q_mem = &eq->dma_mem; | ||
245 | int status; | ||
246 | |||
247 | spin_lock(&ctrl->cmd_lock); | ||
248 | memset(wrb, 0, sizeof(*wrb)); | ||
249 | |||
250 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
251 | |||
252 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
253 | OPCODE_COMMON_EQ_CREATE, sizeof(*req)); | ||
254 | |||
255 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); | ||
256 | |||
257 | AMAP_SET_BITS(struct amap_eq_context, func, req->context, | ||
258 | ctrl->pci_func); | ||
259 | AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); | ||
260 | /* 4byte eqe*/ | ||
261 | AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); | ||
262 | AMAP_SET_BITS(struct amap_eq_context, count, req->context, | ||
263 | __ilog2_u32(eq->len/256)); | ||
264 | AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context, | ||
265 | eq_delay_to_mult(eq_delay)); | ||
266 | be_dws_cpu_to_le(req->context, sizeof(req->context)); | ||
267 | |||
268 | be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); | ||
269 | |||
270 | status = be_mbox_db_ring(ctrl); | ||
271 | if (!status) { | ||
272 | eq->id = le16_to_cpu(resp->eq_id); | ||
273 | eq->created = true; | ||
274 | } | ||
275 | spin_unlock(&ctrl->cmd_lock); | ||
276 | return status; | ||
277 | } | ||
278 | |||
279 | int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, | ||
280 | u8 type, bool permanent, u32 if_handle) | ||
281 | { | ||
282 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
283 | struct be_cmd_req_mac_query *req = embedded_payload(wrb); | ||
284 | struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); | ||
285 | int status; | ||
286 | |||
287 | spin_lock(&ctrl->cmd_lock); | ||
288 | memset(wrb, 0, sizeof(*wrb)); | ||
289 | |||
290 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
291 | |||
292 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
293 | OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req)); | ||
294 | |||
295 | req->type = type; | ||
296 | if (permanent) { | ||
297 | req->permanent = 1; | ||
298 | } else { | ||
299 | req->if_id = cpu_to_le16((u16)if_handle); | ||
300 | req->permanent = 0; | ||
301 | } | ||
302 | |||
303 | status = be_mbox_db_ring(ctrl); | ||
304 | if (!status) | ||
305 | memcpy(mac_addr, resp->mac.addr, ETH_ALEN); | ||
306 | |||
307 | spin_unlock(&ctrl->cmd_lock); | ||
308 | return status; | ||
309 | } | ||
310 | |||
311 | int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, | ||
312 | u32 if_id, u32 *pmac_id) | ||
313 | { | ||
314 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
315 | struct be_cmd_req_pmac_add *req = embedded_payload(wrb); | ||
316 | int status; | ||
317 | |||
318 | spin_lock(&ctrl->cmd_lock); | ||
319 | memset(wrb, 0, sizeof(*wrb)); | ||
320 | |||
321 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
322 | |||
323 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
324 | OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req)); | ||
325 | |||
326 | req->if_id = cpu_to_le32(if_id); | ||
327 | memcpy(req->mac_address, mac_addr, ETH_ALEN); | ||
328 | |||
329 | status = be_mbox_db_ring(ctrl); | ||
330 | if (!status) { | ||
331 | struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); | ||
332 | *pmac_id = le32_to_cpu(resp->pmac_id); | ||
333 | } | ||
334 | |||
335 | spin_unlock(&ctrl->cmd_lock); | ||
336 | return status; | ||
337 | } | ||
338 | |||
339 | int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) | ||
340 | { | ||
341 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
342 | struct be_cmd_req_pmac_del *req = embedded_payload(wrb); | ||
343 | int status; | ||
344 | |||
345 | spin_lock(&ctrl->cmd_lock); | ||
346 | memset(wrb, 0, sizeof(*wrb)); | ||
347 | |||
348 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
349 | |||
350 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
351 | OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req)); | ||
352 | |||
353 | req->if_id = cpu_to_le32(if_id); | ||
354 | req->pmac_id = cpu_to_le32(pmac_id); | ||
355 | |||
356 | status = be_mbox_db_ring(ctrl); | ||
357 | spin_unlock(&ctrl->cmd_lock); | ||
358 | |||
359 | return status; | ||
360 | } | ||
361 | |||
362 | int be_cmd_cq_create(struct be_ctrl_info *ctrl, | ||
363 | struct be_queue_info *cq, struct be_queue_info *eq, | ||
364 | bool sol_evts, bool no_delay, int coalesce_wm) | ||
365 | { | ||
366 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
367 | struct be_cmd_req_cq_create *req = embedded_payload(wrb); | ||
368 | struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); | ||
369 | struct be_dma_mem *q_mem = &cq->dma_mem; | ||
370 | void *ctxt = &req->context; | ||
371 | int status; | ||
372 | |||
373 | spin_lock(&ctrl->cmd_lock); | ||
374 | memset(wrb, 0, sizeof(*wrb)); | ||
375 | |||
376 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
377 | |||
378 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
379 | OPCODE_COMMON_CQ_CREATE, sizeof(*req)); | ||
380 | |||
381 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); | ||
382 | |||
383 | AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm); | ||
384 | AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay); | ||
385 | AMAP_SET_BITS(struct amap_cq_context, count, ctxt, | ||
386 | __ilog2_u32(cq->len/256)); | ||
387 | AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1); | ||
388 | AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts); | ||
389 | AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); | ||
390 | AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); | ||
391 | AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 0); | ||
392 | AMAP_SET_BITS(struct amap_cq_context, func, ctxt, ctrl->pci_func); | ||
393 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); | ||
394 | |||
395 | be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); | ||
396 | |||
397 | status = be_mbox_db_ring(ctrl); | ||
398 | if (!status) { | ||
399 | cq->id = le16_to_cpu(resp->cq_id); | ||
400 | cq->created = true; | ||
401 | } | ||
402 | spin_unlock(&ctrl->cmd_lock); | ||
403 | |||
404 | return status; | ||
405 | } | ||
406 | |||
407 | int be_cmd_txq_create(struct be_ctrl_info *ctrl, | ||
408 | struct be_queue_info *txq, | ||
409 | struct be_queue_info *cq) | ||
410 | { | ||
411 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
412 | struct be_cmd_req_eth_tx_create *req = embedded_payload(wrb); | ||
413 | struct be_dma_mem *q_mem = &txq->dma_mem; | ||
414 | void *ctxt = &req->context; | ||
415 | int status; | ||
416 | u32 len_encoded; | ||
417 | |||
418 | spin_lock(&ctrl->cmd_lock); | ||
419 | memset(wrb, 0, sizeof(*wrb)); | ||
420 | |||
421 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
422 | |||
423 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE, | ||
424 | sizeof(*req)); | ||
425 | |||
426 | req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); | ||
427 | req->ulp_num = BE_ULP1_NUM; | ||
428 | req->type = BE_ETH_TX_RING_TYPE_STANDARD; | ||
429 | |||
430 | len_encoded = fls(txq->len); /* log2(len) + 1 */ | ||
431 | if (len_encoded == 16) | ||
432 | len_encoded = 0; | ||
433 | AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded); | ||
434 | AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, | ||
435 | ctrl->pci_func); | ||
436 | AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); | ||
437 | AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); | ||
438 | |||
439 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); | ||
440 | |||
441 | be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); | ||
442 | |||
443 | status = be_mbox_db_ring(ctrl); | ||
444 | if (!status) { | ||
445 | struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); | ||
446 | txq->id = le16_to_cpu(resp->cid); | ||
447 | txq->created = true; | ||
448 | } | ||
449 | spin_unlock(&ctrl->cmd_lock); | ||
450 | |||
451 | return status; | ||
452 | } | ||
453 | |||
454 | int be_cmd_rxq_create(struct be_ctrl_info *ctrl, | ||
455 | struct be_queue_info *rxq, u16 cq_id, u16 frag_size, | ||
456 | u16 max_frame_size, u32 if_id, u32 rss) | ||
457 | { | ||
458 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
459 | struct be_cmd_req_eth_rx_create *req = embedded_payload(wrb); | ||
460 | struct be_dma_mem *q_mem = &rxq->dma_mem; | ||
461 | int status; | ||
462 | |||
463 | spin_lock(&ctrl->cmd_lock); | ||
464 | memset(wrb, 0, sizeof(*wrb)); | ||
465 | |||
466 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
467 | |||
468 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE, | ||
469 | sizeof(*req)); | ||
470 | |||
471 | req->cq_id = cpu_to_le16(cq_id); | ||
472 | req->frag_size = fls(frag_size) - 1; | ||
473 | req->num_pages = 2; | ||
474 | be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); | ||
475 | req->interface_id = cpu_to_le32(if_id); | ||
476 | req->max_frame_size = cpu_to_le16(max_frame_size); | ||
477 | req->rss_queue = cpu_to_le32(rss); | ||
478 | |||
479 | status = be_mbox_db_ring(ctrl); | ||
480 | if (!status) { | ||
481 | struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); | ||
482 | rxq->id = le16_to_cpu(resp->id); | ||
483 | rxq->created = true; | ||
484 | } | ||
485 | spin_unlock(&ctrl->cmd_lock); | ||
486 | |||
487 | return status; | ||
488 | } | ||
489 | |||
490 | /* Generic destroyer function for all types of queues */ | ||
491 | int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, | ||
492 | int queue_type) | ||
493 | { | ||
494 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
495 | struct be_cmd_req_q_destroy *req = embedded_payload(wrb); | ||
496 | u8 subsys = 0, opcode = 0; | ||
497 | int status; | ||
498 | |||
499 | spin_lock(&ctrl->cmd_lock); | ||
500 | |||
501 | memset(wrb, 0, sizeof(*wrb)); | ||
502 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
503 | |||
504 | switch (queue_type) { | ||
505 | case QTYPE_EQ: | ||
506 | subsys = CMD_SUBSYSTEM_COMMON; | ||
507 | opcode = OPCODE_COMMON_EQ_DESTROY; | ||
508 | break; | ||
509 | case QTYPE_CQ: | ||
510 | subsys = CMD_SUBSYSTEM_COMMON; | ||
511 | opcode = OPCODE_COMMON_CQ_DESTROY; | ||
512 | break; | ||
513 | case QTYPE_TXQ: | ||
514 | subsys = CMD_SUBSYSTEM_ETH; | ||
515 | opcode = OPCODE_ETH_TX_DESTROY; | ||
516 | break; | ||
517 | case QTYPE_RXQ: | ||
518 | subsys = CMD_SUBSYSTEM_ETH; | ||
519 | opcode = OPCODE_ETH_RX_DESTROY; | ||
520 | break; | ||
521 | default: | ||
522 | printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n"); | ||
523 | status = -1; | ||
524 | goto err; | ||
525 | } | ||
526 | be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); | ||
527 | req->id = cpu_to_le16(q->id); | ||
528 | |||
529 | status = be_mbox_db_ring(ctrl); | ||
530 | err: | ||
531 | spin_unlock(&ctrl->cmd_lock); | ||
532 | |||
533 | return status; | ||
534 | } | ||
535 | |||
536 | /* Create an rx filtering policy configuration on an i/f */ | ||
537 | int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, | ||
538 | bool pmac_invalid, u32 *if_handle, u32 *pmac_id) | ||
539 | { | ||
540 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
541 | struct be_cmd_req_if_create *req = embedded_payload(wrb); | ||
542 | int status; | ||
543 | |||
544 | spin_lock(&ctrl->cmd_lock); | ||
545 | memset(wrb, 0, sizeof(*wrb)); | ||
546 | |||
547 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
548 | |||
549 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
550 | OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req)); | ||
551 | |||
552 | req->capability_flags = cpu_to_le32(flags); | ||
553 | req->enable_flags = cpu_to_le32(flags); | ||
554 | if (!pmac_invalid) | ||
555 | memcpy(req->mac_addr, mac, ETH_ALEN); | ||
556 | |||
557 | status = be_mbox_db_ring(ctrl); | ||
558 | if (!status) { | ||
559 | struct be_cmd_resp_if_create *resp = embedded_payload(wrb); | ||
560 | *if_handle = le32_to_cpu(resp->interface_id); | ||
561 | if (!pmac_invalid) | ||
562 | *pmac_id = le32_to_cpu(resp->pmac_id); | ||
563 | } | ||
564 | |||
565 | spin_unlock(&ctrl->cmd_lock); | ||
566 | return status; | ||
567 | } | ||
568 | |||
569 | int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) | ||
570 | { | ||
571 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
572 | struct be_cmd_req_if_destroy *req = embedded_payload(wrb); | ||
573 | int status; | ||
574 | |||
575 | spin_lock(&ctrl->cmd_lock); | ||
576 | memset(wrb, 0, sizeof(*wrb)); | ||
577 | |||
578 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
579 | |||
580 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
581 | OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); | ||
582 | |||
583 | req->interface_id = cpu_to_le32(interface_id); | ||
584 | status = be_mbox_db_ring(ctrl); | ||
585 | |||
586 | spin_unlock(&ctrl->cmd_lock); | ||
587 | |||
588 | return status; | ||
589 | } | ||
590 | |||
591 | /* Get stats is a non embedded command: the request is not embedded inside | ||
592 | * WRB but is a separate dma memory block | ||
593 | */ | ||
594 | int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) | ||
595 | { | ||
596 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
597 | struct be_cmd_req_get_stats *req = nonemb_cmd->va; | ||
598 | struct be_sge *sge = nonembedded_sgl(wrb); | ||
599 | int status; | ||
600 | |||
601 | spin_lock(&ctrl->cmd_lock); | ||
602 | memset(wrb, 0, sizeof(*wrb)); | ||
603 | |||
604 | memset(req, 0, sizeof(*req)); | ||
605 | |||
606 | be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); | ||
607 | |||
608 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, | ||
609 | OPCODE_ETH_GET_STATISTICS, sizeof(*req)); | ||
610 | sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); | ||
611 | sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); | ||
612 | sge->len = cpu_to_le32(nonemb_cmd->size); | ||
613 | |||
614 | status = be_mbox_db_ring(ctrl); | ||
615 | if (!status) { | ||
616 | struct be_cmd_resp_get_stats *resp = nonemb_cmd->va; | ||
617 | be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); | ||
618 | } | ||
619 | |||
620 | spin_unlock(&ctrl->cmd_lock); | ||
621 | return status; | ||
622 | } | ||
623 | |||
624 | int be_cmd_link_status_query(struct be_ctrl_info *ctrl, | ||
625 | struct be_link_info *link) | ||
626 | { | ||
627 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
628 | struct be_cmd_req_link_status *req = embedded_payload(wrb); | ||
629 | int status; | ||
630 | |||
631 | spin_lock(&ctrl->cmd_lock); | ||
632 | memset(wrb, 0, sizeof(*wrb)); | ||
633 | |||
634 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
635 | |||
636 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
637 | OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); | ||
638 | |||
639 | status = be_mbox_db_ring(ctrl); | ||
640 | if (!status) { | ||
641 | struct be_cmd_resp_link_status *resp = embedded_payload(wrb); | ||
642 | link->speed = resp->mac_speed; | ||
643 | link->duplex = resp->mac_duplex; | ||
644 | link->fault = resp->mac_fault; | ||
645 | } else { | ||
646 | link->speed = PHY_LINK_SPEED_ZERO; | ||
647 | } | ||
648 | |||
649 | spin_unlock(&ctrl->cmd_lock); | ||
650 | return status; | ||
651 | } | ||
652 | |||
653 | int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) | ||
654 | { | ||
655 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
656 | struct be_cmd_req_get_fw_version *req = embedded_payload(wrb); | ||
657 | int status; | ||
658 | |||
659 | spin_lock(&ctrl->cmd_lock); | ||
660 | memset(wrb, 0, sizeof(*wrb)); | ||
661 | |||
662 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
663 | |||
664 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
665 | OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); | ||
666 | |||
667 | status = be_mbox_db_ring(ctrl); | ||
668 | if (!status) { | ||
669 | struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); | ||
670 | strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); | ||
671 | } | ||
672 | |||
673 | spin_unlock(&ctrl->cmd_lock); | ||
674 | return status; | ||
675 | } | ||
676 | |||
677 | /* set the EQ delay interval of an EQ to specified value */ | ||
678 | int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) | ||
679 | { | ||
680 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
681 | struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb); | ||
682 | int status; | ||
683 | |||
684 | spin_lock(&ctrl->cmd_lock); | ||
685 | memset(wrb, 0, sizeof(*wrb)); | ||
686 | |||
687 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
688 | |||
689 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
690 | OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); | ||
691 | |||
692 | req->num_eq = cpu_to_le32(1); | ||
693 | req->delay[0].eq_id = cpu_to_le32(eq_id); | ||
694 | req->delay[0].phase = 0; | ||
695 | req->delay[0].delay_multiplier = cpu_to_le32(eqd); | ||
696 | |||
697 | status = be_mbox_db_ring(ctrl); | ||
698 | |||
699 | spin_unlock(&ctrl->cmd_lock); | ||
700 | return status; | ||
701 | } | ||
702 | |||
703 | int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, | ||
704 | u32 num, bool untagged, bool promiscuous) | ||
705 | { | ||
706 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
707 | struct be_cmd_req_vlan_config *req = embedded_payload(wrb); | ||
708 | int status; | ||
709 | |||
710 | spin_lock(&ctrl->cmd_lock); | ||
711 | memset(wrb, 0, sizeof(*wrb)); | ||
712 | |||
713 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
714 | |||
715 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
716 | OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req)); | ||
717 | |||
718 | req->interface_id = if_id; | ||
719 | req->promiscuous = promiscuous; | ||
720 | req->untagged = untagged; | ||
721 | req->num_vlan = num; | ||
722 | if (!promiscuous) { | ||
723 | memcpy(req->normal_vlan, vtag_array, | ||
724 | req->num_vlan * sizeof(vtag_array[0])); | ||
725 | } | ||
726 | |||
727 | status = be_mbox_db_ring(ctrl); | ||
728 | |||
729 | spin_unlock(&ctrl->cmd_lock); | ||
730 | return status; | ||
731 | } | ||
732 | |||
733 | int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) | ||
734 | { | ||
735 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
736 | struct be_cmd_req_promiscuous_config *req = embedded_payload(wrb); | ||
737 | int status; | ||
738 | |||
739 | spin_lock(&ctrl->cmd_lock); | ||
740 | memset(wrb, 0, sizeof(*wrb)); | ||
741 | |||
742 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
743 | |||
744 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, | ||
745 | OPCODE_ETH_PROMISCUOUS, sizeof(*req)); | ||
746 | |||
747 | if (port_num) | ||
748 | req->port1_promiscuous = en; | ||
749 | else | ||
750 | req->port0_promiscuous = en; | ||
751 | |||
752 | status = be_mbox_db_ring(ctrl); | ||
753 | |||
754 | spin_unlock(&ctrl->cmd_lock); | ||
755 | return status; | ||
756 | } | ||
757 | |||
758 | int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, | ||
759 | u32 num, bool promiscuous) | ||
760 | { | ||
761 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
762 | struct be_cmd_req_mcast_mac_config *req = embedded_payload(wrb); | ||
763 | int status; | ||
764 | |||
765 | spin_lock(&ctrl->cmd_lock); | ||
766 | memset(wrb, 0, sizeof(*wrb)); | ||
767 | |||
768 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
769 | |||
770 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
771 | OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req)); | ||
772 | |||
773 | req->interface_id = if_id; | ||
774 | req->promiscuous = promiscuous; | ||
775 | if (!promiscuous) { | ||
776 | req->num_mac = cpu_to_le16(num); | ||
777 | if (num) | ||
778 | memcpy(req->mac, mac_table, ETH_ALEN * num); | ||
779 | } | ||
780 | |||
781 | status = be_mbox_db_ring(ctrl); | ||
782 | |||
783 | spin_unlock(&ctrl->cmd_lock); | ||
784 | return status; | ||
785 | } | ||
786 | |||
787 | int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) | ||
788 | { | ||
789 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
790 | struct be_cmd_req_set_flow_control *req = embedded_payload(wrb); | ||
791 | int status; | ||
792 | |||
793 | spin_lock(&ctrl->cmd_lock); | ||
794 | |||
795 | memset(wrb, 0, sizeof(*wrb)); | ||
796 | |||
797 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
798 | |||
799 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
800 | OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req)); | ||
801 | |||
802 | req->tx_flow_control = cpu_to_le16((u16)tx_fc); | ||
803 | req->rx_flow_control = cpu_to_le16((u16)rx_fc); | ||
804 | |||
805 | status = be_mbox_db_ring(ctrl); | ||
806 | |||
807 | spin_unlock(&ctrl->cmd_lock); | ||
808 | return status; | ||
809 | } | ||
810 | |||
811 | int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) | ||
812 | { | ||
813 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
814 | struct be_cmd_req_get_flow_control *req = embedded_payload(wrb); | ||
815 | int status; | ||
816 | |||
817 | spin_lock(&ctrl->cmd_lock); | ||
818 | |||
819 | memset(wrb, 0, sizeof(*wrb)); | ||
820 | |||
821 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
822 | |||
823 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
824 | OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); | ||
825 | |||
826 | status = be_mbox_db_ring(ctrl); | ||
827 | if (!status) { | ||
828 | struct be_cmd_resp_get_flow_control *resp = | ||
829 | embedded_payload(wrb); | ||
830 | *tx_fc = le16_to_cpu(resp->tx_flow_control); | ||
831 | *rx_fc = le16_to_cpu(resp->rx_flow_control); | ||
832 | } | ||
833 | |||
834 | spin_unlock(&ctrl->cmd_lock); | ||
835 | return status; | ||
836 | } | ||
837 | |||
838 | int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) | ||
839 | { | ||
840 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | ||
841 | struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb); | ||
842 | int status; | ||
843 | |||
844 | spin_lock(&ctrl->cmd_lock); | ||
845 | |||
846 | memset(wrb, 0, sizeof(*wrb)); | ||
847 | |||
848 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | ||
849 | |||
850 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, | ||
851 | OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); | ||
852 | |||
853 | status = be_mbox_db_ring(ctrl); | ||
854 | if (!status) { | ||
855 | struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); | ||
856 | *port_num = le32_to_cpu(resp->phys_port); | ||
857 | } | ||
858 | |||
859 | spin_unlock(&ctrl->cmd_lock); | ||
860 | return status; | ||
861 | } | ||
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h new file mode 100644 index 000000000000..e499e2d5b8c3 --- /dev/null +++ b/drivers/net/benet/be_cmds.h | |||
@@ -0,0 +1,688 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * The driver sends configuration and managements command requests to the | ||
20 | * firmware in the BE. These requests are communicated to the processor | ||
21 | * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one | ||
22 | * WRB inside a MAILBOX. | ||
23 | * The commands are serviced by the ARM processor in the BladeEngine's MPU. | ||
24 | */ | ||
25 | |||
26 | struct be_sge { | ||
27 | u32 pa_lo; | ||
28 | u32 pa_hi; | ||
29 | u32 len; | ||
30 | }; | ||
31 | |||
32 | #define MCC_WRB_EMBEDDED_MASK 1 /* bit 0 of dword 0*/ | ||
33 | #define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */ | ||
34 | #define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */ | ||
35 | struct be_mcc_wrb { | ||
36 | u32 embedded; /* dword 0 */ | ||
37 | u32 payload_length; /* dword 1 */ | ||
38 | u32 tag0; /* dword 2 */ | ||
39 | u32 tag1; /* dword 3 */ | ||
40 | u32 rsvd; /* dword 4 */ | ||
41 | union { | ||
42 | u8 embedded_payload[236]; /* used by embedded cmds */ | ||
43 | struct be_sge sgl[19]; /* used by non-embedded cmds */ | ||
44 | } payload; | ||
45 | }; | ||
46 | |||
47 | #define CQE_FLAGS_VALID_MASK (1 << 31) | ||
48 | #define CQE_FLAGS_ASYNC_MASK (1 << 30) | ||
49 | #define CQE_FLAGS_COMPLETED_MASK (1 << 28) | ||
50 | #define CQE_FLAGS_CONSUMED_MASK (1 << 27) | ||
51 | |||
52 | /* Completion Status */ | ||
53 | enum { | ||
54 | MCC_STATUS_SUCCESS = 0x0, | ||
55 | /* The client does not have sufficient privileges to execute the command */ | ||
56 | MCC_STATUS_INSUFFICIENT_PRIVILEGES = 0x1, | ||
57 | /* A parameter in the command was invalid. */ | ||
58 | MCC_STATUS_INVALID_PARAMETER = 0x2, | ||
59 | /* There are insufficient chip resources to execute the command */ | ||
60 | MCC_STATUS_INSUFFICIENT_RESOURCES = 0x3, | ||
61 | /* The command is completing because the queue was getting flushed */ | ||
62 | MCC_STATUS_QUEUE_FLUSHING = 0x4, | ||
63 | /* The command is completing with a DMA error */ | ||
64 | MCC_STATUS_DMA_FAILED = 0x5 | ||
65 | }; | ||
66 | |||
67 | #define CQE_STATUS_COMPL_MASK 0xFFFF | ||
68 | #define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ | ||
69 | #define CQE_STATUS_EXTD_MASK 0xFFFF | ||
70 | #define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */ | ||
71 | |||
72 | struct be_mcc_cq_entry { | ||
73 | u32 status; /* dword 0 */ | ||
74 | u32 tag0; /* dword 1 */ | ||
75 | u32 tag1; /* dword 2 */ | ||
76 | u32 flags; /* dword 3 */ | ||
77 | }; | ||
78 | |||
79 | struct be_mcc_mailbox { | ||
80 | struct be_mcc_wrb wrb; | ||
81 | struct be_mcc_cq_entry cqe; | ||
82 | }; | ||
83 | |||
84 | #define CMD_SUBSYSTEM_COMMON 0x1 | ||
85 | #define CMD_SUBSYSTEM_ETH 0x3 | ||
86 | |||
87 | #define OPCODE_COMMON_NTWK_MAC_QUERY 1 | ||
88 | #define OPCODE_COMMON_NTWK_MAC_SET 2 | ||
89 | #define OPCODE_COMMON_NTWK_MULTICAST_SET 3 | ||
90 | #define OPCODE_COMMON_NTWK_VLAN_CONFIG 4 | ||
91 | #define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5 | ||
92 | #define OPCODE_COMMON_CQ_CREATE 12 | ||
93 | #define OPCODE_COMMON_EQ_CREATE 13 | ||
94 | #define OPCODE_COMMON_MCC_CREATE 21 | ||
95 | #define OPCODE_COMMON_NTWK_RX_FILTER 34 | ||
96 | #define OPCODE_COMMON_GET_FW_VERSION 35 | ||
97 | #define OPCODE_COMMON_SET_FLOW_CONTROL 36 | ||
98 | #define OPCODE_COMMON_GET_FLOW_CONTROL 37 | ||
99 | #define OPCODE_COMMON_SET_FRAME_SIZE 39 | ||
100 | #define OPCODE_COMMON_MODIFY_EQ_DELAY 41 | ||
101 | #define OPCODE_COMMON_FIRMWARE_CONFIG 42 | ||
102 | #define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50 | ||
103 | #define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51 | ||
104 | #define OPCODE_COMMON_CQ_DESTROY 54 | ||
105 | #define OPCODE_COMMON_EQ_DESTROY 55 | ||
106 | #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 | ||
107 | #define OPCODE_COMMON_NTWK_PMAC_ADD 59 | ||
108 | #define OPCODE_COMMON_NTWK_PMAC_DEL 60 | ||
109 | |||
110 | #define OPCODE_ETH_ACPI_CONFIG 2 | ||
111 | #define OPCODE_ETH_PROMISCUOUS 3 | ||
112 | #define OPCODE_ETH_GET_STATISTICS 4 | ||
113 | #define OPCODE_ETH_TX_CREATE 7 | ||
114 | #define OPCODE_ETH_RX_CREATE 8 | ||
115 | #define OPCODE_ETH_TX_DESTROY 9 | ||
116 | #define OPCODE_ETH_RX_DESTROY 10 | ||
117 | |||
118 | struct be_cmd_req_hdr { | ||
119 | u8 opcode; /* dword 0 */ | ||
120 | u8 subsystem; /* dword 0 */ | ||
121 | u8 port_number; /* dword 0 */ | ||
122 | u8 domain; /* dword 0 */ | ||
123 | u32 timeout; /* dword 1 */ | ||
124 | u32 request_length; /* dword 2 */ | ||
125 | u32 rsvd; /* dword 3 */ | ||
126 | }; | ||
127 | |||
128 | #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ | ||
129 | #define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */ | ||
130 | struct be_cmd_resp_hdr { | ||
131 | u32 info; /* dword 0 */ | ||
132 | u32 status; /* dword 1 */ | ||
133 | u32 response_length; /* dword 2 */ | ||
134 | u32 actual_resp_len; /* dword 3 */ | ||
135 | }; | ||
136 | |||
137 | struct phys_addr { | ||
138 | u32 lo; | ||
139 | u32 hi; | ||
140 | }; | ||
141 | |||
142 | /************************** | ||
143 | * BE Command definitions * | ||
144 | **************************/ | ||
145 | |||
146 | /* Pseudo amap definition in which each bit of the actual structure is defined | ||
147 | * as a byte: used to calculate offset/shift/mask of each field */ | ||
148 | struct amap_eq_context { | ||
149 | u8 cidx[13]; /* dword 0*/ | ||
150 | u8 rsvd0[3]; /* dword 0*/ | ||
151 | u8 epidx[13]; /* dword 0*/ | ||
152 | u8 valid; /* dword 0*/ | ||
153 | u8 rsvd1; /* dword 0*/ | ||
154 | u8 size; /* dword 0*/ | ||
155 | u8 pidx[13]; /* dword 1*/ | ||
156 | u8 rsvd2[3]; /* dword 1*/ | ||
157 | u8 pd[10]; /* dword 1*/ | ||
158 | u8 count[3]; /* dword 1*/ | ||
159 | u8 solevent; /* dword 1*/ | ||
160 | u8 stalled; /* dword 1*/ | ||
161 | u8 armed; /* dword 1*/ | ||
162 | u8 rsvd3[4]; /* dword 2*/ | ||
163 | u8 func[8]; /* dword 2*/ | ||
164 | u8 rsvd4; /* dword 2*/ | ||
165 | u8 delaymult[10]; /* dword 2*/ | ||
166 | u8 rsvd5[2]; /* dword 2*/ | ||
167 | u8 phase[2]; /* dword 2*/ | ||
168 | u8 nodelay; /* dword 2*/ | ||
169 | u8 rsvd6[4]; /* dword 2*/ | ||
170 | u8 rsvd7[32]; /* dword 3*/ | ||
171 | } __packed; | ||
172 | |||
173 | struct be_cmd_req_eq_create { | ||
174 | struct be_cmd_req_hdr hdr; | ||
175 | u16 num_pages; /* sword */ | ||
176 | u16 rsvd0; /* sword */ | ||
177 | u8 context[sizeof(struct amap_eq_context) / 8]; | ||
178 | struct phys_addr pages[8]; | ||
179 | } __packed; | ||
180 | |||
181 | struct be_cmd_resp_eq_create { | ||
182 | struct be_cmd_resp_hdr resp_hdr; | ||
183 | u16 eq_id; /* sword */ | ||
184 | u16 rsvd0; /* sword */ | ||
185 | } __packed; | ||
186 | |||
187 | /******************** Mac query ***************************/ | ||
188 | enum { | ||
189 | MAC_ADDRESS_TYPE_STORAGE = 0x0, | ||
190 | MAC_ADDRESS_TYPE_NETWORK = 0x1, | ||
191 | MAC_ADDRESS_TYPE_PD = 0x2, | ||
192 | MAC_ADDRESS_TYPE_MANAGEMENT = 0x3 | ||
193 | }; | ||
194 | |||
195 | struct mac_addr { | ||
196 | u16 size_of_struct; | ||
197 | u8 addr[ETH_ALEN]; | ||
198 | } __packed; | ||
199 | |||
200 | struct be_cmd_req_mac_query { | ||
201 | struct be_cmd_req_hdr hdr; | ||
202 | u8 type; | ||
203 | u8 permanent; | ||
204 | u16 if_id; | ||
205 | } __packed; | ||
206 | |||
207 | struct be_cmd_resp_mac_query { | ||
208 | struct be_cmd_resp_hdr hdr; | ||
209 | struct mac_addr mac; | ||
210 | }; | ||
211 | |||
212 | /******************** PMac Add ***************************/ | ||
213 | struct be_cmd_req_pmac_add { | ||
214 | struct be_cmd_req_hdr hdr; | ||
215 | u32 if_id; | ||
216 | u8 mac_address[ETH_ALEN]; | ||
217 | u8 rsvd0[2]; | ||
218 | } __packed; | ||
219 | |||
220 | struct be_cmd_resp_pmac_add { | ||
221 | struct be_cmd_resp_hdr hdr; | ||
222 | u32 pmac_id; | ||
223 | }; | ||
224 | |||
225 | /******************** PMac Del ***************************/ | ||
226 | struct be_cmd_req_pmac_del { | ||
227 | struct be_cmd_req_hdr hdr; | ||
228 | u32 if_id; | ||
229 | u32 pmac_id; | ||
230 | }; | ||
231 | |||
232 | /******************** Create CQ ***************************/ | ||
233 | /* Pseudo amap definition in which each bit of the actual structure is defined | ||
234 | * as a byte: used to calculate offset/shift/mask of each field */ | ||
235 | struct amap_cq_context { | ||
236 | u8 cidx[11]; /* dword 0*/ | ||
237 | u8 rsvd0; /* dword 0*/ | ||
238 | u8 coalescwm[2]; /* dword 0*/ | ||
239 | u8 nodelay; /* dword 0*/ | ||
240 | u8 epidx[11]; /* dword 0*/ | ||
241 | u8 rsvd1; /* dword 0*/ | ||
242 | u8 count[2]; /* dword 0*/ | ||
243 | u8 valid; /* dword 0*/ | ||
244 | u8 solevent; /* dword 0*/ | ||
245 | u8 eventable; /* dword 0*/ | ||
246 | u8 pidx[11]; /* dword 1*/ | ||
247 | u8 rsvd2; /* dword 1*/ | ||
248 | u8 pd[10]; /* dword 1*/ | ||
249 | u8 eqid[8]; /* dword 1*/ | ||
250 | u8 stalled; /* dword 1*/ | ||
251 | u8 armed; /* dword 1*/ | ||
252 | u8 rsvd3[4]; /* dword 2*/ | ||
253 | u8 func[8]; /* dword 2*/ | ||
254 | u8 rsvd4[20]; /* dword 2*/ | ||
255 | u8 rsvd5[32]; /* dword 3*/ | ||
256 | } __packed; | ||
257 | |||
258 | struct be_cmd_req_cq_create { | ||
259 | struct be_cmd_req_hdr hdr; | ||
260 | u16 num_pages; | ||
261 | u16 rsvd0; | ||
262 | u8 context[sizeof(struct amap_cq_context) / 8]; | ||
263 | struct phys_addr pages[8]; | ||
264 | } __packed; | ||
265 | |||
266 | struct be_cmd_resp_cq_create { | ||
267 | struct be_cmd_resp_hdr hdr; | ||
268 | u16 cq_id; | ||
269 | u16 rsvd0; | ||
270 | } __packed; | ||
271 | |||
272 | /******************** Create TxQ ***************************/ | ||
273 | #define BE_ETH_TX_RING_TYPE_STANDARD 2 | ||
274 | #define BE_ULP1_NUM 1 | ||
275 | |||
276 | /* Pseudo amap definition in which each bit of the actual structure is defined | ||
277 | * as a byte: used to calculate offset/shift/mask of each field */ | ||
278 | struct amap_tx_context { | ||
279 | u8 rsvd0[16]; /* dword 0 */ | ||
280 | u8 tx_ring_size[4]; /* dword 0 */ | ||
281 | u8 rsvd1[26]; /* dword 0 */ | ||
282 | u8 pci_func_id[8]; /* dword 1 */ | ||
283 | u8 rsvd2[9]; /* dword 1 */ | ||
284 | u8 ctx_valid; /* dword 1 */ | ||
285 | u8 cq_id_send[16]; /* dword 2 */ | ||
286 | u8 rsvd3[16]; /* dword 2 */ | ||
287 | u8 rsvd4[32]; /* dword 3 */ | ||
288 | u8 rsvd5[32]; /* dword 4 */ | ||
289 | u8 rsvd6[32]; /* dword 5 */ | ||
290 | u8 rsvd7[32]; /* dword 6 */ | ||
291 | u8 rsvd8[32]; /* dword 7 */ | ||
292 | u8 rsvd9[32]; /* dword 8 */ | ||
293 | u8 rsvd10[32]; /* dword 9 */ | ||
294 | u8 rsvd11[32]; /* dword 10 */ | ||
295 | u8 rsvd12[32]; /* dword 11 */ | ||
296 | u8 rsvd13[32]; /* dword 12 */ | ||
297 | u8 rsvd14[32]; /* dword 13 */ | ||
298 | u8 rsvd15[32]; /* dword 14 */ | ||
299 | u8 rsvd16[32]; /* dword 15 */ | ||
300 | } __packed; | ||
301 | |||
302 | struct be_cmd_req_eth_tx_create { | ||
303 | struct be_cmd_req_hdr hdr; | ||
304 | u8 num_pages; | ||
305 | u8 ulp_num; | ||
306 | u8 type; | ||
307 | u8 bound_port; | ||
308 | u8 context[sizeof(struct amap_tx_context) / 8]; | ||
309 | struct phys_addr pages[8]; | ||
310 | } __packed; | ||
311 | |||
312 | struct be_cmd_resp_eth_tx_create { | ||
313 | struct be_cmd_resp_hdr hdr; | ||
314 | u16 cid; | ||
315 | u16 rsvd0; | ||
316 | } __packed; | ||
317 | |||
318 | /******************** Create RxQ ***************************/ | ||
319 | struct be_cmd_req_eth_rx_create { | ||
320 | struct be_cmd_req_hdr hdr; | ||
321 | u16 cq_id; | ||
322 | u8 frag_size; | ||
323 | u8 num_pages; | ||
324 | struct phys_addr pages[2]; | ||
325 | u32 interface_id; | ||
326 | u16 max_frame_size; | ||
327 | u16 rsvd0; | ||
328 | u32 rss_queue; | ||
329 | } __packed; | ||
330 | |||
331 | struct be_cmd_resp_eth_rx_create { | ||
332 | struct be_cmd_resp_hdr hdr; | ||
333 | u16 id; | ||
334 | u8 cpu_id; | ||
335 | u8 rsvd0; | ||
336 | } __packed; | ||
337 | |||
338 | /******************** Q Destroy ***************************/ | ||
339 | /* Type of Queue to be destroyed */ | ||
340 | enum { | ||
341 | QTYPE_EQ = 1, | ||
342 | QTYPE_CQ, | ||
343 | QTYPE_TXQ, | ||
344 | QTYPE_RXQ | ||
345 | }; | ||
346 | |||
347 | struct be_cmd_req_q_destroy { | ||
348 | struct be_cmd_req_hdr hdr; | ||
349 | u16 id; | ||
350 | u16 bypass_flush; /* valid only for rx q destroy */ | ||
351 | } __packed; | ||
352 | |||
353 | /************ I/f Create (it's actually I/f Config Create)**********/ | ||
354 | |||
355 | /* Capability flags for the i/f */ | ||
356 | enum be_if_flags { | ||
357 | BE_IF_FLAGS_RSS = 0x4, | ||
358 | BE_IF_FLAGS_PROMISCUOUS = 0x8, | ||
359 | BE_IF_FLAGS_BROADCAST = 0x10, | ||
360 | BE_IF_FLAGS_UNTAGGED = 0x20, | ||
361 | BE_IF_FLAGS_ULP = 0x40, | ||
362 | BE_IF_FLAGS_VLAN_PROMISCUOUS = 0x80, | ||
363 | BE_IF_FLAGS_VLAN = 0x100, | ||
364 | BE_IF_FLAGS_MCAST_PROMISCUOUS = 0x200, | ||
365 | BE_IF_FLAGS_PASS_L2_ERRORS = 0x400, | ||
366 | BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800 | ||
367 | }; | ||
368 | |||
369 | /* An RX interface is an object with one or more MAC addresses and | ||
370 | * filtering capabilities. */ | ||
371 | struct be_cmd_req_if_create { | ||
372 | struct be_cmd_req_hdr hdr; | ||
373 | u32 version; /* ignore currntly */ | ||
374 | u32 capability_flags; | ||
375 | u32 enable_flags; | ||
376 | u8 mac_addr[ETH_ALEN]; | ||
377 | u8 rsvd0; | ||
378 | u8 pmac_invalid; /* if set, don't attach the mac addr to the i/f */ | ||
379 | u32 vlan_tag; /* not used currently */ | ||
380 | } __packed; | ||
381 | |||
382 | struct be_cmd_resp_if_create { | ||
383 | struct be_cmd_resp_hdr hdr; | ||
384 | u32 interface_id; | ||
385 | u32 pmac_id; | ||
386 | }; | ||
387 | |||
388 | /****** I/f Destroy(it's actually I/f Config Destroy )**********/ | ||
389 | struct be_cmd_req_if_destroy { | ||
390 | struct be_cmd_req_hdr hdr; | ||
391 | u32 interface_id; | ||
392 | }; | ||
393 | |||
394 | /*************** HW Stats Get **********************************/ | ||
395 | struct be_port_rxf_stats { | ||
396 | u32 rx_bytes_lsd; /* dword 0*/ | ||
397 | u32 rx_bytes_msd; /* dword 1*/ | ||
398 | u32 rx_total_frames; /* dword 2*/ | ||
399 | u32 rx_unicast_frames; /* dword 3*/ | ||
400 | u32 rx_multicast_frames; /* dword 4*/ | ||
401 | u32 rx_broadcast_frames; /* dword 5*/ | ||
402 | u32 rx_crc_errors; /* dword 6*/ | ||
403 | u32 rx_alignment_symbol_errors; /* dword 7*/ | ||
404 | u32 rx_pause_frames; /* dword 8*/ | ||
405 | u32 rx_control_frames; /* dword 9*/ | ||
406 | u32 rx_in_range_errors; /* dword 10*/ | ||
407 | u32 rx_out_range_errors; /* dword 11*/ | ||
408 | u32 rx_frame_too_long; /* dword 12*/ | ||
409 | u32 rx_address_match_errors; /* dword 13*/ | ||
410 | u32 rx_vlan_mismatch; /* dword 14*/ | ||
411 | u32 rx_dropped_too_small; /* dword 15*/ | ||
412 | u32 rx_dropped_too_short; /* dword 16*/ | ||
413 | u32 rx_dropped_header_too_small; /* dword 17*/ | ||
414 | u32 rx_dropped_tcp_length; /* dword 18*/ | ||
415 | u32 rx_dropped_runt; /* dword 19*/ | ||
416 | u32 rx_64_byte_packets; /* dword 20*/ | ||
417 | u32 rx_65_127_byte_packets; /* dword 21*/ | ||
418 | u32 rx_128_256_byte_packets; /* dword 22*/ | ||
419 | u32 rx_256_511_byte_packets; /* dword 23*/ | ||
420 | u32 rx_512_1023_byte_packets; /* dword 24*/ | ||
421 | u32 rx_1024_1518_byte_packets; /* dword 25*/ | ||
422 | u32 rx_1519_2047_byte_packets; /* dword 26*/ | ||
423 | u32 rx_2048_4095_byte_packets; /* dword 27*/ | ||
424 | u32 rx_4096_8191_byte_packets; /* dword 28*/ | ||
425 | u32 rx_8192_9216_byte_packets; /* dword 29*/ | ||
426 | u32 rx_ip_checksum_errs; /* dword 30*/ | ||
427 | u32 rx_tcp_checksum_errs; /* dword 31*/ | ||
428 | u32 rx_udp_checksum_errs; /* dword 32*/ | ||
429 | u32 rx_non_rss_packets; /* dword 33*/ | ||
430 | u32 rx_ipv4_packets; /* dword 34*/ | ||
431 | u32 rx_ipv6_packets; /* dword 35*/ | ||
432 | u32 rx_ipv4_bytes_lsd; /* dword 36*/ | ||
433 | u32 rx_ipv4_bytes_msd; /* dword 37*/ | ||
434 | u32 rx_ipv6_bytes_lsd; /* dword 38*/ | ||
435 | u32 rx_ipv6_bytes_msd; /* dword 39*/ | ||
436 | u32 rx_chute1_packets; /* dword 40*/ | ||
437 | u32 rx_chute2_packets; /* dword 41*/ | ||
438 | u32 rx_chute3_packets; /* dword 42*/ | ||
439 | u32 rx_management_packets; /* dword 43*/ | ||
440 | u32 rx_switched_unicast_packets; /* dword 44*/ | ||
441 | u32 rx_switched_multicast_packets; /* dword 45*/ | ||
442 | u32 rx_switched_broadcast_packets; /* dword 46*/ | ||
443 | u32 tx_bytes_lsd; /* dword 47*/ | ||
444 | u32 tx_bytes_msd; /* dword 48*/ | ||
445 | u32 tx_unicastframes; /* dword 49*/ | ||
446 | u32 tx_multicastframes; /* dword 50*/ | ||
447 | u32 tx_broadcastframes; /* dword 51*/ | ||
448 | u32 tx_pauseframes; /* dword 52*/ | ||
449 | u32 tx_controlframes; /* dword 53*/ | ||
450 | u32 tx_64_byte_packets; /* dword 54*/ | ||
451 | u32 tx_65_127_byte_packets; /* dword 55*/ | ||
452 | u32 tx_128_256_byte_packets; /* dword 56*/ | ||
453 | u32 tx_256_511_byte_packets; /* dword 57*/ | ||
454 | u32 tx_512_1023_byte_packets; /* dword 58*/ | ||
455 | u32 tx_1024_1518_byte_packets; /* dword 59*/ | ||
456 | u32 tx_1519_2047_byte_packets; /* dword 60*/ | ||
457 | u32 tx_2048_4095_byte_packets; /* dword 61*/ | ||
458 | u32 tx_4096_8191_byte_packets; /* dword 62*/ | ||
459 | u32 tx_8192_9216_byte_packets; /* dword 63*/ | ||
460 | u32 rx_fifo_overflow; /* dword 64*/ | ||
461 | u32 rx_input_fifo_overflow; /* dword 65*/ | ||
462 | }; | ||
463 | |||
464 | struct be_rxf_stats { | ||
465 | struct be_port_rxf_stats port[2]; | ||
466 | u32 rx_drops_no_pbuf; /* dword 132*/ | ||
467 | u32 rx_drops_no_txpb; /* dword 133*/ | ||
468 | u32 rx_drops_no_erx_descr; /* dword 134*/ | ||
469 | u32 rx_drops_no_tpre_descr; /* dword 135*/ | ||
470 | u32 management_rx_port_packets; /* dword 136*/ | ||
471 | u32 management_rx_port_bytes; /* dword 137*/ | ||
472 | u32 management_rx_port_pause_frames; /* dword 138*/ | ||
473 | u32 management_rx_port_errors; /* dword 139*/ | ||
474 | u32 management_tx_port_packets; /* dword 140*/ | ||
475 | u32 management_tx_port_bytes; /* dword 141*/ | ||
476 | u32 management_tx_port_pause; /* dword 142*/ | ||
477 | u32 management_rx_port_rxfifo_overflow; /* dword 143*/ | ||
478 | u32 rx_drops_too_many_frags; /* dword 144*/ | ||
479 | u32 rx_drops_invalid_ring; /* dword 145*/ | ||
480 | u32 forwarded_packets; /* dword 146*/ | ||
481 | u32 rx_drops_mtu; /* dword 147*/ | ||
482 | u32 rsvd0[15]; | ||
483 | }; | ||
484 | |||
485 | struct be_erx_stats { | ||
486 | u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/ | ||
487 | u32 debug_wdma_sent_hold; /* dword 44*/ | ||
488 | u32 debug_wdma_pbfree_sent_hold; /* dword 45*/ | ||
489 | u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/ | ||
490 | u32 debug_pmem_pbuf_dealloc; /* dword 47*/ | ||
491 | }; | ||
492 | |||
493 | struct be_hw_stats { | ||
494 | struct be_rxf_stats rxf; | ||
495 | u32 rsvd[48]; | ||
496 | struct be_erx_stats erx; | ||
497 | }; | ||
498 | |||
499 | struct be_cmd_req_get_stats { | ||
500 | struct be_cmd_req_hdr hdr; | ||
501 | u8 rsvd[sizeof(struct be_hw_stats)]; | ||
502 | }; | ||
503 | |||
504 | struct be_cmd_resp_get_stats { | ||
505 | struct be_cmd_resp_hdr hdr; | ||
506 | struct be_hw_stats hw_stats; | ||
507 | }; | ||
508 | |||
509 | struct be_cmd_req_vlan_config { | ||
510 | struct be_cmd_req_hdr hdr; | ||
511 | u8 interface_id; | ||
512 | u8 promiscuous; | ||
513 | u8 untagged; | ||
514 | u8 num_vlan; | ||
515 | u16 normal_vlan[64]; | ||
516 | } __packed; | ||
517 | |||
518 | struct be_cmd_req_promiscuous_config { | ||
519 | struct be_cmd_req_hdr hdr; | ||
520 | u8 port0_promiscuous; | ||
521 | u8 port1_promiscuous; | ||
522 | u16 rsvd0; | ||
523 | } __packed; | ||
524 | |||
525 | struct macaddr { | ||
526 | u8 byte[ETH_ALEN]; | ||
527 | }; | ||
528 | |||
529 | struct be_cmd_req_mcast_mac_config { | ||
530 | struct be_cmd_req_hdr hdr; | ||
531 | u16 num_mac; | ||
532 | u8 promiscuous; | ||
533 | u8 interface_id; | ||
534 | struct macaddr mac[32]; | ||
535 | } __packed; | ||
536 | |||
537 | static inline struct be_hw_stats * | ||
538 | hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd) | ||
539 | { | ||
540 | return &cmd->hw_stats; | ||
541 | } | ||
542 | |||
543 | /******************** Link Status Query *******************/ | ||
544 | struct be_cmd_req_link_status { | ||
545 | struct be_cmd_req_hdr hdr; | ||
546 | u32 rsvd; | ||
547 | }; | ||
548 | |||
549 | struct be_link_info { | ||
550 | u8 duplex; | ||
551 | u8 speed; | ||
552 | u8 fault; | ||
553 | }; | ||
554 | |||
555 | enum { | ||
556 | PHY_LINK_DUPLEX_NONE = 0x0, | ||
557 | PHY_LINK_DUPLEX_HALF = 0x1, | ||
558 | PHY_LINK_DUPLEX_FULL = 0x2 | ||
559 | }; | ||
560 | |||
561 | enum { | ||
562 | PHY_LINK_SPEED_ZERO = 0x0, /* => No link */ | ||
563 | PHY_LINK_SPEED_10MBPS = 0x1, | ||
564 | PHY_LINK_SPEED_100MBPS = 0x2, | ||
565 | PHY_LINK_SPEED_1GBPS = 0x3, | ||
566 | PHY_LINK_SPEED_10GBPS = 0x4 | ||
567 | }; | ||
568 | |||
569 | struct be_cmd_resp_link_status { | ||
570 | struct be_cmd_resp_hdr hdr; | ||
571 | u8 physical_port; | ||
572 | u8 mac_duplex; | ||
573 | u8 mac_speed; | ||
574 | u8 mac_fault; | ||
575 | u8 mgmt_mac_duplex; | ||
576 | u8 mgmt_mac_speed; | ||
577 | u16 rsvd0; | ||
578 | } __packed; | ||
579 | |||
580 | /******************** Get FW Version *******************/ | ||
581 | #define FW_VER_LEN 32 | ||
582 | struct be_cmd_req_get_fw_version { | ||
583 | struct be_cmd_req_hdr hdr; | ||
584 | u8 rsvd0[FW_VER_LEN]; | ||
585 | u8 rsvd1[FW_VER_LEN]; | ||
586 | } __packed; | ||
587 | |||
588 | struct be_cmd_resp_get_fw_version { | ||
589 | struct be_cmd_resp_hdr hdr; | ||
590 | u8 firmware_version_string[FW_VER_LEN]; | ||
591 | u8 fw_on_flash_version_string[FW_VER_LEN]; | ||
592 | } __packed; | ||
593 | |||
594 | /******************** Set Flow Contrl *******************/ | ||
595 | struct be_cmd_req_set_flow_control { | ||
596 | struct be_cmd_req_hdr hdr; | ||
597 | u16 tx_flow_control; | ||
598 | u16 rx_flow_control; | ||
599 | } __packed; | ||
600 | |||
601 | /******************** Get Flow Contrl *******************/ | ||
602 | struct be_cmd_req_get_flow_control { | ||
603 | struct be_cmd_req_hdr hdr; | ||
604 | u32 rsvd; | ||
605 | }; | ||
606 | |||
607 | struct be_cmd_resp_get_flow_control { | ||
608 | struct be_cmd_resp_hdr hdr; | ||
609 | u16 tx_flow_control; | ||
610 | u16 rx_flow_control; | ||
611 | } __packed; | ||
612 | |||
613 | /******************** Modify EQ Delay *******************/ | ||
614 | struct be_cmd_req_modify_eq_delay { | ||
615 | struct be_cmd_req_hdr hdr; | ||
616 | u32 num_eq; | ||
617 | struct { | ||
618 | u32 eq_id; | ||
619 | u32 phase; | ||
620 | u32 delay_multiplier; | ||
621 | } delay[8]; | ||
622 | } __packed; | ||
623 | |||
624 | struct be_cmd_resp_modify_eq_delay { | ||
625 | struct be_cmd_resp_hdr hdr; | ||
626 | u32 rsvd0; | ||
627 | } __packed; | ||
628 | |||
629 | /******************** Get FW Config *******************/ | ||
630 | struct be_cmd_req_query_fw_cfg { | ||
631 | struct be_cmd_req_hdr hdr; | ||
632 | u32 rsvd[30]; | ||
633 | }; | ||
634 | |||
635 | struct be_cmd_resp_query_fw_cfg { | ||
636 | struct be_cmd_resp_hdr hdr; | ||
637 | u32 be_config_number; | ||
638 | u32 asic_revision; | ||
639 | u32 phys_port; | ||
640 | u32 function_mode; | ||
641 | u32 rsvd[26]; | ||
642 | }; | ||
643 | |||
644 | extern int be_pci_fnum_get(struct be_ctrl_info *ctrl); | ||
645 | extern int be_cmd_POST(struct be_ctrl_info *ctrl); | ||
646 | extern int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, | ||
647 | u8 type, bool permanent, u32 if_handle); | ||
648 | extern int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, | ||
649 | u32 if_id, u32 *pmac_id); | ||
650 | extern int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id); | ||
651 | extern int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 if_flags, u8 *mac, | ||
652 | bool pmac_invalid, u32 *if_handle, u32 *pmac_id); | ||
653 | extern int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 if_handle); | ||
654 | extern int be_cmd_eq_create(struct be_ctrl_info *ctrl, | ||
655 | struct be_queue_info *eq, int eq_delay); | ||
656 | extern int be_cmd_cq_create(struct be_ctrl_info *ctrl, | ||
657 | struct be_queue_info *cq, struct be_queue_info *eq, | ||
658 | bool sol_evts, bool no_delay, | ||
659 | int num_cqe_dma_coalesce); | ||
660 | extern int be_cmd_txq_create(struct be_ctrl_info *ctrl, | ||
661 | struct be_queue_info *txq, | ||
662 | struct be_queue_info *cq); | ||
663 | extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl, | ||
664 | struct be_queue_info *rxq, u16 cq_id, | ||
665 | u16 frag_size, u16 max_frame_size, u32 if_id, | ||
666 | u32 rss); | ||
667 | extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, | ||
668 | int type); | ||
669 | extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, | ||
670 | struct be_link_info *link); | ||
671 | extern int be_cmd_reset(struct be_ctrl_info *ctrl); | ||
672 | extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, | ||
673 | struct be_dma_mem *nonemb_cmd); | ||
674 | extern int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver); | ||
675 | |||
676 | extern int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd); | ||
677 | extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, | ||
678 | u16 *vtag_array, u32 num, bool untagged, | ||
679 | bool promiscuous); | ||
680 | extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, | ||
681 | u8 port_num, bool en); | ||
682 | extern int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, | ||
683 | u8 *mac_table, u32 num, bool promiscuous); | ||
684 | extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, | ||
685 | u32 tx_fc, u32 rx_fc); | ||
686 | extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, | ||
687 | u32 *tx_fc, u32 *rx_fc); | ||
688 | extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num); | ||
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c new file mode 100644 index 000000000000..04f4b73fa8d8 --- /dev/null +++ b/drivers/net/benet/be_ethtool.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | #include "be.h" | ||
19 | #include <linux/ethtool.h> | ||
20 | |||
21 | struct be_ethtool_stat { | ||
22 | char desc[ETH_GSTRING_LEN]; | ||
23 | int type; | ||
24 | int size; | ||
25 | int offset; | ||
26 | }; | ||
27 | |||
28 | enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT}; | ||
29 | #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ | ||
30 | offsetof(_struct, field) | ||
31 | #define NETSTAT_INFO(field) #field, NETSTAT,\ | ||
32 | FIELDINFO(struct net_device_stats,\ | ||
33 | field) | ||
34 | #define DRVSTAT_INFO(field) #field, DRVSTAT,\ | ||
35 | FIELDINFO(struct be_drvr_stats, field) | ||
36 | #define MISCSTAT_INFO(field) #field, MISCSTAT,\ | ||
37 | FIELDINFO(struct be_rxf_stats, field) | ||
38 | #define PORTSTAT_INFO(field) #field, PORTSTAT,\ | ||
39 | FIELDINFO(struct be_port_rxf_stats, \ | ||
40 | field) | ||
41 | #define ERXSTAT_INFO(field) #field, ERXSTAT,\ | ||
42 | FIELDINFO(struct be_erx_stats, field) | ||
43 | |||
44 | static const struct be_ethtool_stat et_stats[] = { | ||
45 | {NETSTAT_INFO(rx_packets)}, | ||
46 | {NETSTAT_INFO(tx_packets)}, | ||
47 | {NETSTAT_INFO(rx_bytes)}, | ||
48 | {NETSTAT_INFO(tx_bytes)}, | ||
49 | {NETSTAT_INFO(rx_errors)}, | ||
50 | {NETSTAT_INFO(tx_errors)}, | ||
51 | {NETSTAT_INFO(rx_dropped)}, | ||
52 | {NETSTAT_INFO(tx_dropped)}, | ||
53 | {DRVSTAT_INFO(be_tx_reqs)}, | ||
54 | {DRVSTAT_INFO(be_tx_stops)}, | ||
55 | {DRVSTAT_INFO(be_fwd_reqs)}, | ||
56 | {DRVSTAT_INFO(be_tx_wrbs)}, | ||
57 | {DRVSTAT_INFO(be_polls)}, | ||
58 | {DRVSTAT_INFO(be_tx_events)}, | ||
59 | {DRVSTAT_INFO(be_rx_events)}, | ||
60 | {DRVSTAT_INFO(be_tx_compl)}, | ||
61 | {DRVSTAT_INFO(be_rx_compl)}, | ||
62 | {DRVSTAT_INFO(be_ethrx_post_fail)}, | ||
63 | {DRVSTAT_INFO(be_802_3_dropped_frames)}, | ||
64 | {DRVSTAT_INFO(be_802_3_malformed_frames)}, | ||
65 | {DRVSTAT_INFO(be_tx_rate)}, | ||
66 | {DRVSTAT_INFO(be_rx_rate)}, | ||
67 | {PORTSTAT_INFO(rx_unicast_frames)}, | ||
68 | {PORTSTAT_INFO(rx_multicast_frames)}, | ||
69 | {PORTSTAT_INFO(rx_broadcast_frames)}, | ||
70 | {PORTSTAT_INFO(rx_crc_errors)}, | ||
71 | {PORTSTAT_INFO(rx_alignment_symbol_errors)}, | ||
72 | {PORTSTAT_INFO(rx_pause_frames)}, | ||
73 | {PORTSTAT_INFO(rx_control_frames)}, | ||
74 | {PORTSTAT_INFO(rx_in_range_errors)}, | ||
75 | {PORTSTAT_INFO(rx_out_range_errors)}, | ||
76 | {PORTSTAT_INFO(rx_frame_too_long)}, | ||
77 | {PORTSTAT_INFO(rx_address_match_errors)}, | ||
78 | {PORTSTAT_INFO(rx_vlan_mismatch)}, | ||
79 | {PORTSTAT_INFO(rx_dropped_too_small)}, | ||
80 | {PORTSTAT_INFO(rx_dropped_too_short)}, | ||
81 | {PORTSTAT_INFO(rx_dropped_header_too_small)}, | ||
82 | {PORTSTAT_INFO(rx_dropped_tcp_length)}, | ||
83 | {PORTSTAT_INFO(rx_dropped_runt)}, | ||
84 | {PORTSTAT_INFO(rx_fifo_overflow)}, | ||
85 | {PORTSTAT_INFO(rx_input_fifo_overflow)}, | ||
86 | {PORTSTAT_INFO(rx_ip_checksum_errs)}, | ||
87 | {PORTSTAT_INFO(rx_tcp_checksum_errs)}, | ||
88 | {PORTSTAT_INFO(rx_udp_checksum_errs)}, | ||
89 | {PORTSTAT_INFO(rx_non_rss_packets)}, | ||
90 | {PORTSTAT_INFO(rx_ipv4_packets)}, | ||
91 | {PORTSTAT_INFO(rx_ipv6_packets)}, | ||
92 | {PORTSTAT_INFO(tx_unicastframes)}, | ||
93 | {PORTSTAT_INFO(tx_multicastframes)}, | ||
94 | {PORTSTAT_INFO(tx_broadcastframes)}, | ||
95 | {PORTSTAT_INFO(tx_pauseframes)}, | ||
96 | {PORTSTAT_INFO(tx_controlframes)}, | ||
97 | {MISCSTAT_INFO(rx_drops_no_pbuf)}, | ||
98 | {MISCSTAT_INFO(rx_drops_no_txpb)}, | ||
99 | {MISCSTAT_INFO(rx_drops_no_erx_descr)}, | ||
100 | {MISCSTAT_INFO(rx_drops_no_tpre_descr)}, | ||
101 | {MISCSTAT_INFO(rx_drops_too_many_frags)}, | ||
102 | {MISCSTAT_INFO(rx_drops_invalid_ring)}, | ||
103 | {MISCSTAT_INFO(forwarded_packets)}, | ||
104 | {MISCSTAT_INFO(rx_drops_mtu)}, | ||
105 | {ERXSTAT_INFO(rx_drops_no_fragments)}, | ||
106 | }; | ||
107 | #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) | ||
108 | |||
109 | static void | ||
110 | be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) | ||
111 | { | ||
112 | struct be_adapter *adapter = netdev_priv(netdev); | ||
113 | |||
114 | strcpy(drvinfo->driver, DRV_NAME); | ||
115 | strcpy(drvinfo->version, DRV_VER); | ||
116 | strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN); | ||
117 | strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); | ||
118 | drvinfo->testinfo_len = 0; | ||
119 | drvinfo->regdump_len = 0; | ||
120 | drvinfo->eedump_len = 0; | ||
121 | } | ||
122 | |||
123 | static int | ||
124 | be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) | ||
125 | { | ||
126 | struct be_adapter *adapter = netdev_priv(netdev); | ||
127 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
128 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
129 | |||
130 | coalesce->rx_max_coalesced_frames = adapter->max_rx_coal; | ||
131 | |||
132 | coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; | ||
133 | coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd; | ||
134 | coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd; | ||
135 | |||
136 | coalesce->tx_coalesce_usecs = tx_eq->cur_eqd; | ||
137 | coalesce->tx_coalesce_usecs_high = tx_eq->max_eqd; | ||
138 | coalesce->tx_coalesce_usecs_low = tx_eq->min_eqd; | ||
139 | |||
140 | coalesce->use_adaptive_rx_coalesce = rx_eq->enable_aic; | ||
141 | coalesce->use_adaptive_tx_coalesce = tx_eq->enable_aic; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * This routine is used to set interrup coalescing delay *as well as* | ||
148 | * the number of pkts to coalesce for LRO. | ||
149 | */ | ||
150 | static int | ||
151 | be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) | ||
152 | { | ||
153 | struct be_adapter *adapter = netdev_priv(netdev); | ||
154 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
155 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
156 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
157 | u32 tx_max, tx_min, tx_cur; | ||
158 | u32 rx_max, rx_min, rx_cur; | ||
159 | int status = 0; | ||
160 | |||
161 | if (coalesce->use_adaptive_tx_coalesce == 1) | ||
162 | return -EINVAL; | ||
163 | |||
164 | adapter->max_rx_coal = coalesce->rx_max_coalesced_frames; | ||
165 | if (adapter->max_rx_coal > MAX_SKB_FRAGS) | ||
166 | adapter->max_rx_coal = MAX_SKB_FRAGS - 1; | ||
167 | |||
168 | /* if AIC is being turned on now, start with an EQD of 0 */ | ||
169 | if (rx_eq->enable_aic == 0 && | ||
170 | coalesce->use_adaptive_rx_coalesce == 1) { | ||
171 | rx_eq->cur_eqd = 0; | ||
172 | } | ||
173 | rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; | ||
174 | |||
175 | rx_max = coalesce->rx_coalesce_usecs_high; | ||
176 | rx_min = coalesce->rx_coalesce_usecs_low; | ||
177 | rx_cur = coalesce->rx_coalesce_usecs; | ||
178 | |||
179 | tx_max = coalesce->tx_coalesce_usecs_high; | ||
180 | tx_min = coalesce->tx_coalesce_usecs_low; | ||
181 | tx_cur = coalesce->tx_coalesce_usecs; | ||
182 | |||
183 | if (tx_cur > BE_MAX_EQD) | ||
184 | tx_cur = BE_MAX_EQD; | ||
185 | if (tx_eq->cur_eqd != tx_cur) { | ||
186 | status = be_cmd_modify_eqd(ctrl, tx_eq->q.id, tx_cur); | ||
187 | if (!status) | ||
188 | tx_eq->cur_eqd = tx_cur; | ||
189 | } | ||
190 | |||
191 | if (rx_eq->enable_aic) { | ||
192 | if (rx_max > BE_MAX_EQD) | ||
193 | rx_max = BE_MAX_EQD; | ||
194 | if (rx_min > rx_max) | ||
195 | rx_min = rx_max; | ||
196 | rx_eq->max_eqd = rx_max; | ||
197 | rx_eq->min_eqd = rx_min; | ||
198 | if (rx_eq->cur_eqd > rx_max) | ||
199 | rx_eq->cur_eqd = rx_max; | ||
200 | if (rx_eq->cur_eqd < rx_min) | ||
201 | rx_eq->cur_eqd = rx_min; | ||
202 | } else { | ||
203 | if (rx_cur > BE_MAX_EQD) | ||
204 | rx_cur = BE_MAX_EQD; | ||
205 | if (rx_eq->cur_eqd != rx_cur) { | ||
206 | status = be_cmd_modify_eqd(ctrl, rx_eq->q.id, rx_cur); | ||
207 | if (!status) | ||
208 | rx_eq->cur_eqd = rx_cur; | ||
209 | } | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static u32 be_get_rx_csum(struct net_device *netdev) | ||
215 | { | ||
216 | struct be_adapter *adapter = netdev_priv(netdev); | ||
217 | |||
218 | return adapter->rx_csum; | ||
219 | } | ||
220 | |||
221 | static int be_set_rx_csum(struct net_device *netdev, uint32_t data) | ||
222 | { | ||
223 | struct be_adapter *adapter = netdev_priv(netdev); | ||
224 | |||
225 | if (data) | ||
226 | adapter->rx_csum = true; | ||
227 | else | ||
228 | adapter->rx_csum = false; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void | ||
234 | be_get_ethtool_stats(struct net_device *netdev, | ||
235 | struct ethtool_stats *stats, uint64_t *data) | ||
236 | { | ||
237 | struct be_adapter *adapter = netdev_priv(netdev); | ||
238 | struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats; | ||
239 | struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); | ||
240 | struct be_rxf_stats *rxf_stats = &hw_stats->rxf; | ||
241 | struct be_port_rxf_stats *port_stats = | ||
242 | &rxf_stats->port[adapter->port_num]; | ||
243 | struct net_device_stats *net_stats = &adapter->stats.net_stats; | ||
244 | struct be_erx_stats *erx_stats = &hw_stats->erx; | ||
245 | void *p = NULL; | ||
246 | int i; | ||
247 | |||
248 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { | ||
249 | switch (et_stats[i].type) { | ||
250 | case NETSTAT: | ||
251 | p = net_stats; | ||
252 | break; | ||
253 | case DRVSTAT: | ||
254 | p = drvr_stats; | ||
255 | break; | ||
256 | case PORTSTAT: | ||
257 | p = port_stats; | ||
258 | break; | ||
259 | case MISCSTAT: | ||
260 | p = rxf_stats; | ||
261 | break; | ||
262 | case ERXSTAT: /* Currently only one ERX stat is provided */ | ||
263 | p = (u32 *)erx_stats + adapter->rx_obj.q.id; | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | p = (u8 *)p + et_stats[i].offset; | ||
268 | data[i] = (et_stats[i].size == sizeof(u64)) ? | ||
269 | *(u64 *)p: *(u32 *)p; | ||
270 | } | ||
271 | |||
272 | return; | ||
273 | } | ||
274 | |||
275 | static void | ||
276 | be_get_stat_strings(struct net_device *netdev, uint32_t stringset, | ||
277 | uint8_t *data) | ||
278 | { | ||
279 | int i; | ||
280 | switch (stringset) { | ||
281 | case ETH_SS_STATS: | ||
282 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { | ||
283 | memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN); | ||
284 | data += ETH_GSTRING_LEN; | ||
285 | } | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static int be_get_stats_count(struct net_device *netdev) | ||
291 | { | ||
292 | return ETHTOOL_STATS_NUM; | ||
293 | } | ||
294 | |||
295 | static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | ||
296 | { | ||
297 | ecmd->speed = SPEED_10000; | ||
298 | ecmd->duplex = DUPLEX_FULL; | ||
299 | ecmd->autoneg = AUTONEG_DISABLE; | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) | ||
305 | { | ||
306 | struct be_adapter *adapter = netdev_priv(netdev); | ||
307 | |||
308 | ring->rx_max_pending = adapter->rx_obj.q.len; | ||
309 | ring->tx_max_pending = adapter->tx_obj.q.len; | ||
310 | |||
311 | ring->rx_pending = atomic_read(&adapter->rx_obj.q.used); | ||
312 | ring->tx_pending = atomic_read(&adapter->tx_obj.q.used); | ||
313 | } | ||
314 | |||
315 | static void | ||
316 | be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) | ||
317 | { | ||
318 | struct be_adapter *adapter = netdev_priv(netdev); | ||
319 | |||
320 | be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause, | ||
321 | &ecmd->rx_pause); | ||
322 | ecmd->autoneg = AUTONEG_ENABLE; | ||
323 | } | ||
324 | |||
325 | static int | ||
326 | be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) | ||
327 | { | ||
328 | struct be_adapter *adapter = netdev_priv(netdev); | ||
329 | int status; | ||
330 | |||
331 | if (ecmd->autoneg != AUTONEG_ENABLE) | ||
332 | return -EINVAL; | ||
333 | |||
334 | status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause, | ||
335 | ecmd->rx_pause); | ||
336 | if (!status) | ||
337 | dev_warn(&adapter->pdev->dev, "Pause param set failed.\n"); | ||
338 | |||
339 | return status; | ||
340 | } | ||
341 | |||
342 | struct ethtool_ops be_ethtool_ops = { | ||
343 | .get_settings = be_get_settings, | ||
344 | .get_drvinfo = be_get_drvinfo, | ||
345 | .get_link = ethtool_op_get_link, | ||
346 | .get_coalesce = be_get_coalesce, | ||
347 | .set_coalesce = be_set_coalesce, | ||
348 | .get_ringparam = be_get_ringparam, | ||
349 | .get_pauseparam = be_get_pauseparam, | ||
350 | .set_pauseparam = be_set_pauseparam, | ||
351 | .get_rx_csum = be_get_rx_csum, | ||
352 | .set_rx_csum = be_set_rx_csum, | ||
353 | .get_tx_csum = ethtool_op_get_tx_csum, | ||
354 | .set_tx_csum = ethtool_op_set_tx_csum, | ||
355 | .get_sg = ethtool_op_get_sg, | ||
356 | .set_sg = ethtool_op_set_sg, | ||
357 | .get_tso = ethtool_op_get_tso, | ||
358 | .set_tso = ethtool_op_set_tso, | ||
359 | .get_strings = be_get_stat_strings, | ||
360 | .get_stats_count = be_get_stats_count, | ||
361 | .get_ethtool_stats = be_get_ethtool_stats, | ||
362 | }; | ||
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h new file mode 100644 index 000000000000..b132aa4893ca --- /dev/null +++ b/drivers/net/benet/be_hw.h | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | /********* Mailbox door bell *************/ | ||
19 | /* Used for driver communication with the FW. | ||
20 | * The software must write this register twice to post any command. First, | ||
21 | * it writes the register with hi=1 and the upper bits of the physical address | ||
22 | * for the MAILBOX structure. Software must poll the ready bit until this | ||
23 | * is acknowledged. Then, sotware writes the register with hi=0 with the lower | ||
24 | * bits in the address. It must poll the ready bit until the command is | ||
25 | * complete. Upon completion, the MAILBOX will contain a valid completion | ||
26 | * queue entry. | ||
27 | */ | ||
28 | #define MPU_MAILBOX_DB_OFFSET 0x160 | ||
29 | #define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */ | ||
30 | #define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */ | ||
31 | |||
32 | #define MPU_EP_CONTROL 0 | ||
33 | |||
34 | /********** MPU semphore ******************/ | ||
35 | #define MPU_EP_SEMAPHORE_OFFSET 0xac | ||
36 | #define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF | ||
37 | #define EP_SEMAPHORE_POST_ERR_MASK 0x1 | ||
38 | #define EP_SEMAPHORE_POST_ERR_SHIFT 31 | ||
39 | /* MPU semphore POST stage values */ | ||
40 | #define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */ | ||
41 | #define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */ | ||
42 | #define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */ | ||
43 | #define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ | ||
44 | |||
45 | /********* Memory BAR register ************/ | ||
46 | #define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc | ||
47 | /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt | ||
48 | * Disable" may still globally block interrupts in addition to individual | ||
49 | * interrupt masks; a mechanism for the device driver to block all interrupts | ||
50 | * atomically without having to arbitrate for the PCI Interrupt Disable bit | ||
51 | * with the OS. | ||
52 | */ | ||
53 | #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ | ||
54 | /* PCI physical function number */ | ||
55 | #define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK 0x7 /* bits 26 - 28 */ | ||
56 | #define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT 26 | ||
57 | |||
58 | /********* Event Q door bell *************/ | ||
59 | #define DB_EQ_OFFSET DB_CQ_OFFSET | ||
60 | #define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */ | ||
61 | /* Clear the interrupt for this eq */ | ||
62 | #define DB_EQ_CLR_SHIFT (9) /* bit 9 */ | ||
63 | /* Must be 1 */ | ||
64 | #define DB_EQ_EVNT_SHIFT (10) /* bit 10 */ | ||
65 | /* Number of event entries processed */ | ||
66 | #define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ | ||
67 | /* Rearm bit */ | ||
68 | #define DB_EQ_REARM_SHIFT (29) /* bit 29 */ | ||
69 | |||
70 | /********* Compl Q door bell *************/ | ||
71 | #define DB_CQ_OFFSET 0x120 | ||
72 | #define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ | ||
73 | /* Number of event entries processed */ | ||
74 | #define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ | ||
75 | /* Rearm bit */ | ||
76 | #define DB_CQ_REARM_SHIFT (29) /* bit 29 */ | ||
77 | |||
78 | /********** TX ULP door bell *************/ | ||
79 | #define DB_TXULP1_OFFSET 0x60 | ||
80 | #define DB_TXULP_RING_ID_MASK 0x7FF /* bits 0 - 10 */ | ||
81 | /* Number of tx entries posted */ | ||
82 | #define DB_TXULP_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */ | ||
83 | #define DB_TXULP_NUM_POSTED_MASK 0x3FFF /* bits 16 - 29 */ | ||
84 | |||
85 | /********** RQ(erx) door bell ************/ | ||
86 | #define DB_RQ_OFFSET 0x100 | ||
87 | #define DB_RQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ | ||
88 | /* Number of rx frags posted */ | ||
89 | #define DB_RQ_NUM_POSTED_SHIFT (24) /* bits 24 - 31 */ | ||
90 | |||
91 | /* | ||
92 | * BE descriptors: host memory data structures whose formats | ||
93 | * are hardwired in BE silicon. | ||
94 | */ | ||
95 | /* Event Queue Descriptor */ | ||
96 | #define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */ | ||
97 | #define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */ | ||
98 | #define EQ_ENTRY_RES_ID_SHIFT 16 | ||
99 | struct be_eq_entry { | ||
100 | u32 evt; | ||
101 | }; | ||
102 | |||
103 | /* TX Queue Descriptor */ | ||
104 | #define ETH_WRB_FRAG_LEN_MASK 0xFFFF | ||
105 | struct be_eth_wrb { | ||
106 | u32 frag_pa_hi; /* dword 0 */ | ||
107 | u32 frag_pa_lo; /* dword 1 */ | ||
108 | u32 rsvd0; /* dword 2 */ | ||
109 | u32 frag_len; /* dword 3: bits 0 - 15 */ | ||
110 | } __packed; | ||
111 | |||
112 | /* Pseudo amap definition for eth_hdr_wrb in which each bit of the | ||
113 | * actual structure is defined as a byte : used to calculate | ||
114 | * offset/shift/mask of each field */ | ||
115 | struct amap_eth_hdr_wrb { | ||
116 | u8 rsvd0[32]; /* dword 0 */ | ||
117 | u8 rsvd1[32]; /* dword 1 */ | ||
118 | u8 complete; /* dword 2 */ | ||
119 | u8 event; | ||
120 | u8 crc; | ||
121 | u8 forward; | ||
122 | u8 ipsec; | ||
123 | u8 mgmt; | ||
124 | u8 ipcs; | ||
125 | u8 udpcs; | ||
126 | u8 tcpcs; | ||
127 | u8 lso; | ||
128 | u8 vlan; | ||
129 | u8 gso[2]; | ||
130 | u8 num_wrb[5]; | ||
131 | u8 lso_mss[14]; | ||
132 | u8 len[16]; /* dword 3 */ | ||
133 | u8 vlan_tag[16]; | ||
134 | } __packed; | ||
135 | |||
136 | struct be_eth_hdr_wrb { | ||
137 | u32 dw[4]; | ||
138 | }; | ||
139 | |||
140 | /* TX Compl Queue Descriptor */ | ||
141 | |||
142 | /* Pseudo amap definition for eth_tx_compl in which each bit of the | ||
143 | * actual structure is defined as a byte: used to calculate | ||
144 | * offset/shift/mask of each field */ | ||
145 | struct amap_eth_tx_compl { | ||
146 | u8 wrb_index[16]; /* dword 0 */ | ||
147 | u8 ct[2]; /* dword 0 */ | ||
148 | u8 port[2]; /* dword 0 */ | ||
149 | u8 rsvd0[8]; /* dword 0 */ | ||
150 | u8 status[4]; /* dword 0 */ | ||
151 | u8 user_bytes[16]; /* dword 1 */ | ||
152 | u8 nwh_bytes[8]; /* dword 1 */ | ||
153 | u8 lso; /* dword 1 */ | ||
154 | u8 cast_enc[2]; /* dword 1 */ | ||
155 | u8 rsvd1[5]; /* dword 1 */ | ||
156 | u8 rsvd2[32]; /* dword 2 */ | ||
157 | u8 pkts[16]; /* dword 3 */ | ||
158 | u8 ringid[11]; /* dword 3 */ | ||
159 | u8 hash_val[4]; /* dword 3 */ | ||
160 | u8 valid; /* dword 3 */ | ||
161 | } __packed; | ||
162 | |||
163 | struct be_eth_tx_compl { | ||
164 | u32 dw[4]; | ||
165 | }; | ||
166 | |||
167 | /* RX Queue Descriptor */ | ||
168 | struct be_eth_rx_d { | ||
169 | u32 fragpa_hi; | ||
170 | u32 fragpa_lo; | ||
171 | }; | ||
172 | |||
173 | /* RX Compl Queue Descriptor */ | ||
174 | |||
175 | /* Pseudo amap definition for eth_rx_compl in which each bit of the | ||
176 | * actual structure is defined as a byte: used to calculate | ||
177 | * offset/shift/mask of each field */ | ||
178 | struct amap_eth_rx_compl { | ||
179 | u8 vlan_tag[16]; /* dword 0 */ | ||
180 | u8 pktsize[14]; /* dword 0 */ | ||
181 | u8 port; /* dword 0 */ | ||
182 | u8 ip_opt; /* dword 0 */ | ||
183 | u8 err; /* dword 1 */ | ||
184 | u8 rsshp; /* dword 1 */ | ||
185 | u8 ipf; /* dword 1 */ | ||
186 | u8 tcpf; /* dword 1 */ | ||
187 | u8 udpf; /* dword 1 */ | ||
188 | u8 ipcksm; /* dword 1 */ | ||
189 | u8 l4_cksm; /* dword 1 */ | ||
190 | u8 ip_version; /* dword 1 */ | ||
191 | u8 macdst[6]; /* dword 1 */ | ||
192 | u8 vtp; /* dword 1 */ | ||
193 | u8 rsvd0; /* dword 1 */ | ||
194 | u8 fragndx[10]; /* dword 1 */ | ||
195 | u8 ct[2]; /* dword 1 */ | ||
196 | u8 sw; /* dword 1 */ | ||
197 | u8 numfrags[3]; /* dword 1 */ | ||
198 | u8 rss_flush; /* dword 2 */ | ||
199 | u8 cast_enc[2]; /* dword 2 */ | ||
200 | u8 qnq; /* dword 2 */ | ||
201 | u8 rss_bank; /* dword 2 */ | ||
202 | u8 rsvd1[23]; /* dword 2 */ | ||
203 | u8 lro_pkt; /* dword 2 */ | ||
204 | u8 rsvd2[2]; /* dword 2 */ | ||
205 | u8 valid; /* dword 2 */ | ||
206 | u8 rsshash[32]; /* dword 3 */ | ||
207 | } __packed; | ||
208 | |||
209 | struct be_eth_rx_compl { | ||
210 | u32 dw[4]; | ||
211 | }; | ||
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c new file mode 100644 index 000000000000..897a63de5bdb --- /dev/null +++ b/drivers/net/benet/be_main.c | |||
@@ -0,0 +1,1903 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 - 2009 ServerEngines | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 | ||
7 | * as published by the Free Software Foundation. The full GNU General | ||
8 | * Public License is included in this distribution in the file called COPYING. | ||
9 | * | ||
10 | * Contact Information: | ||
11 | * linux-drivers@serverengines.com | ||
12 | * | ||
13 | * ServerEngines | ||
14 | * 209 N. Fair Oaks Ave | ||
15 | * Sunnyvale, CA 94085 | ||
16 | */ | ||
17 | |||
18 | #include "be.h" | ||
19 | |||
20 | MODULE_VERSION(DRV_VER); | ||
21 | MODULE_DEVICE_TABLE(pci, be_dev_ids); | ||
22 | MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); | ||
23 | MODULE_AUTHOR("ServerEngines Corporation"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | |||
26 | static unsigned int rx_frag_size = 2048; | ||
27 | module_param(rx_frag_size, uint, S_IRUGO); | ||
28 | MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); | ||
29 | |||
30 | #define BE_VENDOR_ID 0x19a2 | ||
31 | #define BE2_DEVICE_ID_1 0x0211 | ||
32 | static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { | ||
33 | { PCI_DEVICE(BE_VENDOR_ID, BE2_DEVICE_ID_1) }, | ||
34 | { 0 } | ||
35 | }; | ||
36 | MODULE_DEVICE_TABLE(pci, be_dev_ids); | ||
37 | |||
38 | static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) | ||
39 | { | ||
40 | struct be_dma_mem *mem = &q->dma_mem; | ||
41 | if (mem->va) | ||
42 | pci_free_consistent(adapter->pdev, mem->size, | ||
43 | mem->va, mem->dma); | ||
44 | } | ||
45 | |||
46 | static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, | ||
47 | u16 len, u16 entry_size) | ||
48 | { | ||
49 | struct be_dma_mem *mem = &q->dma_mem; | ||
50 | |||
51 | memset(q, 0, sizeof(*q)); | ||
52 | q->len = len; | ||
53 | q->entry_size = entry_size; | ||
54 | mem->size = len * entry_size; | ||
55 | mem->va = pci_alloc_consistent(adapter->pdev, mem->size, &mem->dma); | ||
56 | if (!mem->va) | ||
57 | return -1; | ||
58 | memset(mem->va, 0, mem->size); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static inline void *queue_head_node(struct be_queue_info *q) | ||
63 | { | ||
64 | return q->dma_mem.va + q->head * q->entry_size; | ||
65 | } | ||
66 | |||
67 | static inline void *queue_tail_node(struct be_queue_info *q) | ||
68 | { | ||
69 | return q->dma_mem.va + q->tail * q->entry_size; | ||
70 | } | ||
71 | |||
72 | static inline void queue_head_inc(struct be_queue_info *q) | ||
73 | { | ||
74 | index_inc(&q->head, q->len); | ||
75 | } | ||
76 | |||
77 | static inline void queue_tail_inc(struct be_queue_info *q) | ||
78 | { | ||
79 | index_inc(&q->tail, q->len); | ||
80 | } | ||
81 | |||
82 | static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) | ||
83 | { | ||
84 | u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; | ||
85 | u32 reg = ioread32(addr); | ||
86 | u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; | ||
87 | if (!enabled && enable) { | ||
88 | reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; | ||
89 | } else if (enabled && !enable) { | ||
90 | reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; | ||
91 | } else { | ||
92 | printk(KERN_WARNING DRV_NAME | ||
93 | ": bad value in membar_int_ctrl reg=0x%x\n", reg); | ||
94 | return; | ||
95 | } | ||
96 | iowrite32(reg, addr); | ||
97 | } | ||
98 | |||
99 | static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) | ||
100 | { | ||
101 | u32 val = 0; | ||
102 | val |= qid & DB_RQ_RING_ID_MASK; | ||
103 | val |= posted << DB_RQ_NUM_POSTED_SHIFT; | ||
104 | iowrite32(val, ctrl->db + DB_RQ_OFFSET); | ||
105 | } | ||
106 | |||
107 | static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) | ||
108 | { | ||
109 | u32 val = 0; | ||
110 | val |= qid & DB_TXULP_RING_ID_MASK; | ||
111 | val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; | ||
112 | iowrite32(val, ctrl->db + DB_TXULP1_OFFSET); | ||
113 | } | ||
114 | |||
115 | static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, | ||
116 | bool arm, bool clear_int, u16 num_popped) | ||
117 | { | ||
118 | u32 val = 0; | ||
119 | val |= qid & DB_EQ_RING_ID_MASK; | ||
120 | if (arm) | ||
121 | val |= 1 << DB_EQ_REARM_SHIFT; | ||
122 | if (clear_int) | ||
123 | val |= 1 << DB_EQ_CLR_SHIFT; | ||
124 | val |= 1 << DB_EQ_EVNT_SHIFT; | ||
125 | val |= num_popped << DB_EQ_NUM_POPPED_SHIFT; | ||
126 | iowrite32(val, ctrl->db + DB_EQ_OFFSET); | ||
127 | } | ||
128 | |||
129 | static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, | ||
130 | bool arm, u16 num_popped) | ||
131 | { | ||
132 | u32 val = 0; | ||
133 | val |= qid & DB_CQ_RING_ID_MASK; | ||
134 | if (arm) | ||
135 | val |= 1 << DB_CQ_REARM_SHIFT; | ||
136 | val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; | ||
137 | iowrite32(val, ctrl->db + DB_CQ_OFFSET); | ||
138 | } | ||
139 | |||
140 | |||
141 | static int be_mac_addr_set(struct net_device *netdev, void *p) | ||
142 | { | ||
143 | struct be_adapter *adapter = netdev_priv(netdev); | ||
144 | struct sockaddr *addr = p; | ||
145 | int status = 0; | ||
146 | |||
147 | if (netif_running(netdev)) { | ||
148 | status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle, | ||
149 | adapter->pmac_id); | ||
150 | if (status) | ||
151 | return status; | ||
152 | |||
153 | status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data, | ||
154 | adapter->if_handle, &adapter->pmac_id); | ||
155 | } | ||
156 | |||
157 | if (!status) | ||
158 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | ||
159 | |||
160 | return status; | ||
161 | } | ||
162 | |||
163 | static void netdev_stats_update(struct be_adapter *adapter) | ||
164 | { | ||
165 | struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); | ||
166 | struct be_rxf_stats *rxf_stats = &hw_stats->rxf; | ||
167 | struct be_port_rxf_stats *port_stats = | ||
168 | &rxf_stats->port[adapter->port_num]; | ||
169 | struct net_device_stats *dev_stats = &adapter->stats.net_stats; | ||
170 | |||
171 | dev_stats->rx_packets = port_stats->rx_total_frames; | ||
172 | dev_stats->tx_packets = port_stats->tx_unicastframes + | ||
173 | port_stats->tx_multicastframes + port_stats->tx_broadcastframes; | ||
174 | dev_stats->rx_bytes = (u64) port_stats->rx_bytes_msd << 32 | | ||
175 | (u64) port_stats->rx_bytes_lsd; | ||
176 | dev_stats->tx_bytes = (u64) port_stats->tx_bytes_msd << 32 | | ||
177 | (u64) port_stats->tx_bytes_lsd; | ||
178 | |||
179 | /* bad pkts received */ | ||
180 | dev_stats->rx_errors = port_stats->rx_crc_errors + | ||
181 | port_stats->rx_alignment_symbol_errors + | ||
182 | port_stats->rx_in_range_errors + | ||
183 | port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; | ||
184 | |||
185 | /* packet transmit problems */ | ||
186 | dev_stats->tx_errors = 0; | ||
187 | |||
188 | /* no space in linux buffers */ | ||
189 | dev_stats->rx_dropped = 0; | ||
190 | |||
191 | /* no space available in linux */ | ||
192 | dev_stats->tx_dropped = 0; | ||
193 | |||
194 | dev_stats->multicast = port_stats->tx_multicastframes; | ||
195 | dev_stats->collisions = 0; | ||
196 | |||
197 | /* detailed rx errors */ | ||
198 | dev_stats->rx_length_errors = port_stats->rx_in_range_errors + | ||
199 | port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; | ||
200 | /* receive ring buffer overflow */ | ||
201 | dev_stats->rx_over_errors = 0; | ||
202 | dev_stats->rx_crc_errors = port_stats->rx_crc_errors; | ||
203 | |||
204 | /* frame alignment errors */ | ||
205 | dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; | ||
206 | /* receiver fifo overrun */ | ||
207 | /* drops_no_pbuf is no per i/f, it's per BE card */ | ||
208 | dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + | ||
209 | port_stats->rx_input_fifo_overflow + | ||
210 | rxf_stats->rx_drops_no_pbuf; | ||
211 | /* receiver missed packetd */ | ||
212 | dev_stats->rx_missed_errors = 0; | ||
213 | /* detailed tx_errors */ | ||
214 | dev_stats->tx_aborted_errors = 0; | ||
215 | dev_stats->tx_carrier_errors = 0; | ||
216 | dev_stats->tx_fifo_errors = 0; | ||
217 | dev_stats->tx_heartbeat_errors = 0; | ||
218 | dev_stats->tx_window_errors = 0; | ||
219 | } | ||
220 | |||
221 | static void be_link_status_update(struct be_adapter *adapter) | ||
222 | { | ||
223 | struct be_link_info *prev = &adapter->link; | ||
224 | struct be_link_info now = { 0 }; | ||
225 | struct net_device *netdev = adapter->netdev; | ||
226 | |||
227 | be_cmd_link_status_query(&adapter->ctrl, &now); | ||
228 | |||
229 | /* If link came up or went down */ | ||
230 | if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO || | ||
231 | prev->speed == PHY_LINK_SPEED_ZERO)) { | ||
232 | if (now.speed == PHY_LINK_SPEED_ZERO) { | ||
233 | netif_stop_queue(netdev); | ||
234 | netif_carrier_off(netdev); | ||
235 | printk(KERN_INFO "%s: Link down\n", netdev->name); | ||
236 | } else { | ||
237 | netif_start_queue(netdev); | ||
238 | netif_carrier_on(netdev); | ||
239 | printk(KERN_INFO "%s: Link up\n", netdev->name); | ||
240 | } | ||
241 | } | ||
242 | *prev = now; | ||
243 | } | ||
244 | |||
245 | /* Update the EQ delay n BE based on the RX frags consumed / sec */ | ||
246 | static void be_rx_eqd_update(struct be_adapter *adapter) | ||
247 | { | ||
248 | u32 eqd; | ||
249 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
250 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
251 | struct be_drvr_stats *stats = &adapter->stats.drvr_stats; | ||
252 | |||
253 | /* Update once a second */ | ||
254 | if (((jiffies - stats->rx_fps_jiffies) < HZ) || rx_eq->enable_aic == 0) | ||
255 | return; | ||
256 | |||
257 | stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) / | ||
258 | ((jiffies - stats->rx_fps_jiffies) / HZ); | ||
259 | |||
260 | stats->rx_fps_jiffies = jiffies; | ||
261 | stats->be_prev_rx_frags = stats->be_rx_frags; | ||
262 | eqd = stats->be_rx_fps / 110000; | ||
263 | eqd = eqd << 3; | ||
264 | if (eqd > rx_eq->max_eqd) | ||
265 | eqd = rx_eq->max_eqd; | ||
266 | if (eqd < rx_eq->min_eqd) | ||
267 | eqd = rx_eq->min_eqd; | ||
268 | if (eqd < 10) | ||
269 | eqd = 0; | ||
270 | if (eqd != rx_eq->cur_eqd) | ||
271 | be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd); | ||
272 | |||
273 | rx_eq->cur_eqd = eqd; | ||
274 | } | ||
275 | |||
276 | static void be_worker(struct work_struct *work) | ||
277 | { | ||
278 | struct be_adapter *adapter = | ||
279 | container_of(work, struct be_adapter, work.work); | ||
280 | int status; | ||
281 | |||
282 | /* Check link */ | ||
283 | be_link_status_update(adapter); | ||
284 | |||
285 | /* Get Stats */ | ||
286 | status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); | ||
287 | if (!status) | ||
288 | netdev_stats_update(adapter); | ||
289 | |||
290 | /* Set EQ delay */ | ||
291 | be_rx_eqd_update(adapter); | ||
292 | |||
293 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); | ||
294 | } | ||
295 | |||
296 | static struct net_device_stats *be_get_stats(struct net_device *dev) | ||
297 | { | ||
298 | struct be_adapter *adapter = netdev_priv(dev); | ||
299 | |||
300 | return &adapter->stats.net_stats; | ||
301 | } | ||
302 | |||
303 | static void be_tx_stats_update(struct be_adapter *adapter, | ||
304 | u32 wrb_cnt, u32 copied, bool stopped) | ||
305 | { | ||
306 | struct be_drvr_stats *stats = &adapter->stats.drvr_stats; | ||
307 | stats->be_tx_reqs++; | ||
308 | stats->be_tx_wrbs += wrb_cnt; | ||
309 | stats->be_tx_bytes += copied; | ||
310 | if (stopped) | ||
311 | stats->be_tx_stops++; | ||
312 | |||
313 | /* Update tx rate once in two seconds */ | ||
314 | if ((jiffies - stats->be_tx_jiffies) > 2 * HZ) { | ||
315 | u32 r; | ||
316 | r = (stats->be_tx_bytes - stats->be_tx_bytes_prev) / | ||
317 | ((u32) (jiffies - stats->be_tx_jiffies) / HZ); | ||
318 | r = (r / 1000000); /* M bytes/s */ | ||
319 | stats->be_tx_rate = (r * 8); /* M bits/s */ | ||
320 | stats->be_tx_jiffies = jiffies; | ||
321 | stats->be_tx_bytes_prev = stats->be_tx_bytes; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | /* Determine number of WRB entries needed to xmit data in an skb */ | ||
326 | static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) | ||
327 | { | ||
328 | int cnt = 0; | ||
329 | while (skb) { | ||
330 | if (skb->len > skb->data_len) | ||
331 | cnt++; | ||
332 | cnt += skb_shinfo(skb)->nr_frags; | ||
333 | skb = skb_shinfo(skb)->frag_list; | ||
334 | } | ||
335 | /* to account for hdr wrb */ | ||
336 | cnt++; | ||
337 | if (cnt & 1) { | ||
338 | /* add a dummy to make it an even num */ | ||
339 | cnt++; | ||
340 | *dummy = true; | ||
341 | } else | ||
342 | *dummy = false; | ||
343 | BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); | ||
344 | return cnt; | ||
345 | } | ||
346 | |||
347 | static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) | ||
348 | { | ||
349 | wrb->frag_pa_hi = upper_32_bits(addr); | ||
350 | wrb->frag_pa_lo = addr & 0xFFFFFFFF; | ||
351 | wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; | ||
352 | } | ||
353 | |||
354 | static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, | ||
355 | bool vlan, u32 wrb_cnt, u32 len) | ||
356 | { | ||
357 | memset(hdr, 0, sizeof(*hdr)); | ||
358 | |||
359 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1); | ||
360 | |||
361 | if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) { | ||
362 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1); | ||
363 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss, | ||
364 | hdr, skb_shinfo(skb)->gso_size); | ||
365 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
366 | if (is_tcp_pkt(skb)) | ||
367 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1); | ||
368 | else if (is_udp_pkt(skb)) | ||
369 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1); | ||
370 | } | ||
371 | |||
372 | if (vlan && vlan_tx_tag_present(skb)) { | ||
373 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); | ||
374 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, | ||
375 | hdr, vlan_tx_tag_get(skb)); | ||
376 | } | ||
377 | |||
378 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); | ||
379 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1); | ||
380 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt); | ||
381 | AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len); | ||
382 | } | ||
383 | |||
384 | |||
385 | static int make_tx_wrbs(struct be_adapter *adapter, | ||
386 | struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) | ||
387 | { | ||
388 | u64 busaddr; | ||
389 | u32 i, copied = 0; | ||
390 | struct pci_dev *pdev = adapter->pdev; | ||
391 | struct sk_buff *first_skb = skb; | ||
392 | struct be_queue_info *txq = &adapter->tx_obj.q; | ||
393 | struct be_eth_wrb *wrb; | ||
394 | struct be_eth_hdr_wrb *hdr; | ||
395 | |||
396 | atomic_add(wrb_cnt, &txq->used); | ||
397 | hdr = queue_head_node(txq); | ||
398 | queue_head_inc(txq); | ||
399 | |||
400 | while (skb) { | ||
401 | if (skb->len > skb->data_len) { | ||
402 | int len = skb->len - skb->data_len; | ||
403 | busaddr = pci_map_single(pdev, skb->data, len, | ||
404 | PCI_DMA_TODEVICE); | ||
405 | wrb = queue_head_node(txq); | ||
406 | wrb_fill(wrb, busaddr, len); | ||
407 | be_dws_cpu_to_le(wrb, sizeof(*wrb)); | ||
408 | queue_head_inc(txq); | ||
409 | copied += len; | ||
410 | } | ||
411 | |||
412 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
413 | struct skb_frag_struct *frag = | ||
414 | &skb_shinfo(skb)->frags[i]; | ||
415 | busaddr = pci_map_page(pdev, frag->page, | ||
416 | frag->page_offset, | ||
417 | frag->size, PCI_DMA_TODEVICE); | ||
418 | wrb = queue_head_node(txq); | ||
419 | wrb_fill(wrb, busaddr, frag->size); | ||
420 | be_dws_cpu_to_le(wrb, sizeof(*wrb)); | ||
421 | queue_head_inc(txq); | ||
422 | copied += frag->size; | ||
423 | } | ||
424 | skb = skb_shinfo(skb)->frag_list; | ||
425 | } | ||
426 | |||
427 | if (dummy_wrb) { | ||
428 | wrb = queue_head_node(txq); | ||
429 | wrb_fill(wrb, 0, 0); | ||
430 | be_dws_cpu_to_le(wrb, sizeof(*wrb)); | ||
431 | queue_head_inc(txq); | ||
432 | } | ||
433 | |||
434 | wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false, | ||
435 | wrb_cnt, copied); | ||
436 | be_dws_cpu_to_le(hdr, sizeof(*hdr)); | ||
437 | |||
438 | return copied; | ||
439 | } | ||
440 | |||
441 | static int be_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
442 | { | ||
443 | struct be_adapter *adapter = netdev_priv(netdev); | ||
444 | struct be_tx_obj *tx_obj = &adapter->tx_obj; | ||
445 | struct be_queue_info *txq = &tx_obj->q; | ||
446 | u32 wrb_cnt = 0, copied = 0; | ||
447 | u32 start = txq->head; | ||
448 | bool dummy_wrb, stopped = false; | ||
449 | |||
450 | wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb); | ||
451 | |||
452 | copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb); | ||
453 | |||
454 | /* record the sent skb in the sent_skb table */ | ||
455 | BUG_ON(tx_obj->sent_skb_list[start]); | ||
456 | tx_obj->sent_skb_list[start] = skb; | ||
457 | |||
458 | /* Ensure that txq has space for the next skb; Else stop the queue | ||
459 | * *BEFORE* ringing the tx doorbell, so that we serialze the | ||
460 | * tx compls of the current transmit which'll wake up the queue | ||
461 | */ | ||
462 | if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= txq->len) { | ||
463 | netif_stop_queue(netdev); | ||
464 | stopped = true; | ||
465 | } | ||
466 | |||
467 | be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); | ||
468 | |||
469 | netdev->trans_start = jiffies; | ||
470 | |||
471 | be_tx_stats_update(adapter, wrb_cnt, copied, stopped); | ||
472 | return NETDEV_TX_OK; | ||
473 | } | ||
474 | |||
475 | static int be_change_mtu(struct net_device *netdev, int new_mtu) | ||
476 | { | ||
477 | struct be_adapter *adapter = netdev_priv(netdev); | ||
478 | if (new_mtu < BE_MIN_MTU || | ||
479 | new_mtu > BE_MAX_JUMBO_FRAME_SIZE) { | ||
480 | dev_info(&adapter->pdev->dev, | ||
481 | "MTU must be between %d and %d bytes\n", | ||
482 | BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE); | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n", | ||
486 | netdev->mtu, new_mtu); | ||
487 | netdev->mtu = new_mtu; | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured, | ||
493 | * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured, | ||
494 | * set the BE in promiscuous VLAN mode. | ||
495 | */ | ||
496 | static void be_vids_config(struct net_device *netdev) | ||
497 | { | ||
498 | struct be_adapter *adapter = netdev_priv(netdev); | ||
499 | u16 vtag[BE_NUM_VLANS_SUPPORTED]; | ||
500 | u16 ntags = 0, i; | ||
501 | |||
502 | if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED) { | ||
503 | /* Construct VLAN Table to give to HW */ | ||
504 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | ||
505 | if (adapter->vlan_tag[i]) { | ||
506 | vtag[ntags] = cpu_to_le16(i); | ||
507 | ntags++; | ||
508 | } | ||
509 | } | ||
510 | be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, | ||
511 | vtag, ntags, 1, 0); | ||
512 | } else { | ||
513 | be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, | ||
514 | NULL, 0, 1, 1); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) | ||
519 | { | ||
520 | struct be_adapter *adapter = netdev_priv(netdev); | ||
521 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
522 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
523 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
524 | |||
525 | be_eq_notify(ctrl, rx_eq->q.id, false, false, 0); | ||
526 | be_eq_notify(ctrl, tx_eq->q.id, false, false, 0); | ||
527 | adapter->vlan_grp = grp; | ||
528 | be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); | ||
529 | be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); | ||
530 | } | ||
531 | |||
532 | static void be_vlan_add_vid(struct net_device *netdev, u16 vid) | ||
533 | { | ||
534 | struct be_adapter *adapter = netdev_priv(netdev); | ||
535 | |||
536 | adapter->num_vlans++; | ||
537 | adapter->vlan_tag[vid] = 1; | ||
538 | |||
539 | be_vids_config(netdev); | ||
540 | } | ||
541 | |||
542 | static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) | ||
543 | { | ||
544 | struct be_adapter *adapter = netdev_priv(netdev); | ||
545 | |||
546 | adapter->num_vlans--; | ||
547 | adapter->vlan_tag[vid] = 0; | ||
548 | |||
549 | vlan_group_set_device(adapter->vlan_grp, vid, NULL); | ||
550 | be_vids_config(netdev); | ||
551 | } | ||
552 | |||
553 | static void be_set_multicast_filter(struct net_device *netdev) | ||
554 | { | ||
555 | struct be_adapter *adapter = netdev_priv(netdev); | ||
556 | struct dev_mc_list *mc_ptr; | ||
557 | u8 mac_addr[32][ETH_ALEN]; | ||
558 | int i = 0; | ||
559 | |||
560 | if (netdev->flags & IFF_ALLMULTI) { | ||
561 | /* set BE in Multicast promiscuous */ | ||
562 | be_cmd_mcast_mac_set(&adapter->ctrl, | ||
563 | adapter->if_handle, NULL, 0, true); | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { | ||
568 | memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN); | ||
569 | if (++i >= 32) { | ||
570 | be_cmd_mcast_mac_set(&adapter->ctrl, | ||
571 | adapter->if_handle, &mac_addr[0][0], i, false); | ||
572 | i = 0; | ||
573 | } | ||
574 | |||
575 | } | ||
576 | |||
577 | if (i) { | ||
578 | /* reset the promiscuous mode also. */ | ||
579 | be_cmd_mcast_mac_set(&adapter->ctrl, | ||
580 | adapter->if_handle, &mac_addr[0][0], i, false); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void be_set_multicast_list(struct net_device *netdev) | ||
585 | { | ||
586 | struct be_adapter *adapter = netdev_priv(netdev); | ||
587 | |||
588 | if (netdev->flags & IFF_PROMISC) { | ||
589 | be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 1); | ||
590 | } else { | ||
591 | be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 0); | ||
592 | be_set_multicast_filter(netdev); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static void be_rx_rate_update(struct be_adapter *adapter, u32 pktsize, | ||
597 | u16 numfrags) | ||
598 | { | ||
599 | struct be_drvr_stats *stats = &adapter->stats.drvr_stats; | ||
600 | u32 rate; | ||
601 | |||
602 | stats->be_rx_compl++; | ||
603 | stats->be_rx_frags += numfrags; | ||
604 | stats->be_rx_bytes += pktsize; | ||
605 | |||
606 | /* Update the rate once in two seconds */ | ||
607 | if ((jiffies - stats->be_rx_jiffies) < 2 * HZ) | ||
608 | return; | ||
609 | |||
610 | rate = (stats->be_rx_bytes - stats->be_rx_bytes_prev) / | ||
611 | ((u32) (jiffies - stats->be_rx_jiffies) / HZ); | ||
612 | rate = (rate / 1000000); /* MB/Sec */ | ||
613 | stats->be_rx_rate = (rate * 8); /* Mega Bits/Sec */ | ||
614 | stats->be_rx_jiffies = jiffies; | ||
615 | stats->be_rx_bytes_prev = stats->be_rx_bytes; | ||
616 | } | ||
617 | |||
618 | static struct be_rx_page_info * | ||
619 | get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) | ||
620 | { | ||
621 | struct be_rx_page_info *rx_page_info; | ||
622 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
623 | |||
624 | rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx]; | ||
625 | BUG_ON(!rx_page_info->page); | ||
626 | |||
627 | if (rx_page_info->last_page_user) | ||
628 | pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus), | ||
629 | adapter->big_page_size, PCI_DMA_FROMDEVICE); | ||
630 | |||
631 | atomic_dec(&rxq->used); | ||
632 | return rx_page_info; | ||
633 | } | ||
634 | |||
635 | /* Throwaway the data in the Rx completion */ | ||
636 | static void be_rx_compl_discard(struct be_adapter *adapter, | ||
637 | struct be_eth_rx_compl *rxcp) | ||
638 | { | ||
639 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
640 | struct be_rx_page_info *page_info; | ||
641 | u16 rxq_idx, i, num_rcvd; | ||
642 | |||
643 | rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); | ||
644 | num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); | ||
645 | |||
646 | for (i = 0; i < num_rcvd; i++) { | ||
647 | page_info = get_rx_page_info(adapter, rxq_idx); | ||
648 | put_page(page_info->page); | ||
649 | memset(page_info, 0, sizeof(*page_info)); | ||
650 | index_inc(&rxq_idx, rxq->len); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * skb_fill_rx_data forms a complete skb for an ether frame | ||
656 | * indicated by rxcp. | ||
657 | */ | ||
658 | static void skb_fill_rx_data(struct be_adapter *adapter, | ||
659 | struct sk_buff *skb, struct be_eth_rx_compl *rxcp) | ||
660 | { | ||
661 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
662 | struct be_rx_page_info *page_info; | ||
663 | u16 rxq_idx, i, num_rcvd; | ||
664 | u32 pktsize, hdr_len, curr_frag_len; | ||
665 | u8 *start; | ||
666 | |||
667 | rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); | ||
668 | pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); | ||
669 | num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); | ||
670 | |||
671 | page_info = get_rx_page_info(adapter, rxq_idx); | ||
672 | |||
673 | start = page_address(page_info->page) + page_info->page_offset; | ||
674 | prefetch(start); | ||
675 | |||
676 | /* Copy data in the first descriptor of this completion */ | ||
677 | curr_frag_len = min(pktsize, rx_frag_size); | ||
678 | |||
679 | /* Copy the header portion into skb_data */ | ||
680 | hdr_len = min((u32)BE_HDR_LEN, curr_frag_len); | ||
681 | memcpy(skb->data, start, hdr_len); | ||
682 | skb->len = curr_frag_len; | ||
683 | if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */ | ||
684 | /* Complete packet has now been moved to data */ | ||
685 | put_page(page_info->page); | ||
686 | skb->data_len = 0; | ||
687 | skb->tail += curr_frag_len; | ||
688 | } else { | ||
689 | skb_shinfo(skb)->nr_frags = 1; | ||
690 | skb_shinfo(skb)->frags[0].page = page_info->page; | ||
691 | skb_shinfo(skb)->frags[0].page_offset = | ||
692 | page_info->page_offset + hdr_len; | ||
693 | skb_shinfo(skb)->frags[0].size = curr_frag_len - hdr_len; | ||
694 | skb->data_len = curr_frag_len - hdr_len; | ||
695 | skb->tail += hdr_len; | ||
696 | } | ||
697 | memset(page_info, 0, sizeof(*page_info)); | ||
698 | |||
699 | if (pktsize <= rx_frag_size) { | ||
700 | BUG_ON(num_rcvd != 1); | ||
701 | return; | ||
702 | } | ||
703 | |||
704 | /* More frags present for this completion */ | ||
705 | pktsize -= curr_frag_len; /* account for above copied frag */ | ||
706 | for (i = 1; i < num_rcvd; i++) { | ||
707 | index_inc(&rxq_idx, rxq->len); | ||
708 | page_info = get_rx_page_info(adapter, rxq_idx); | ||
709 | |||
710 | curr_frag_len = min(pktsize, rx_frag_size); | ||
711 | |||
712 | skb_shinfo(skb)->frags[i].page = page_info->page; | ||
713 | skb_shinfo(skb)->frags[i].page_offset = page_info->page_offset; | ||
714 | skb_shinfo(skb)->frags[i].size = curr_frag_len; | ||
715 | skb->len += curr_frag_len; | ||
716 | skb->data_len += curr_frag_len; | ||
717 | skb_shinfo(skb)->nr_frags++; | ||
718 | pktsize -= curr_frag_len; | ||
719 | |||
720 | memset(page_info, 0, sizeof(*page_info)); | ||
721 | } | ||
722 | |||
723 | be_rx_rate_update(adapter, pktsize, num_rcvd); | ||
724 | return; | ||
725 | } | ||
726 | |||
727 | /* Process the RX completion indicated by rxcp when LRO is disabled */ | ||
728 | static void be_rx_compl_process(struct be_adapter *adapter, | ||
729 | struct be_eth_rx_compl *rxcp) | ||
730 | { | ||
731 | struct sk_buff *skb; | ||
732 | u32 vtp, vid; | ||
733 | int l4_cksm; | ||
734 | |||
735 | l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); | ||
736 | vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); | ||
737 | |||
738 | skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); | ||
739 | if (!skb) { | ||
740 | if (net_ratelimit()) | ||
741 | dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); | ||
742 | be_rx_compl_discard(adapter, rxcp); | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | skb_reserve(skb, NET_IP_ALIGN); | ||
747 | |||
748 | skb_fill_rx_data(adapter, skb, rxcp); | ||
749 | |||
750 | if (l4_cksm && adapter->rx_csum) | ||
751 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
752 | else | ||
753 | skb->ip_summed = CHECKSUM_NONE; | ||
754 | |||
755 | skb->truesize = skb->len + sizeof(struct sk_buff); | ||
756 | skb->protocol = eth_type_trans(skb, adapter->netdev); | ||
757 | skb->dev = adapter->netdev; | ||
758 | |||
759 | if (vtp) { | ||
760 | if (!adapter->vlan_grp || adapter->num_vlans == 0) { | ||
761 | kfree_skb(skb); | ||
762 | return; | ||
763 | } | ||
764 | vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); | ||
765 | vid = be16_to_cpu(vid); | ||
766 | vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid); | ||
767 | } else { | ||
768 | netif_receive_skb(skb); | ||
769 | } | ||
770 | |||
771 | adapter->netdev->last_rx = jiffies; | ||
772 | |||
773 | return; | ||
774 | } | ||
775 | |||
776 | /* Process the RX completion indicated by rxcp when LRO is enabled */ | ||
777 | static void be_rx_compl_process_lro(struct be_adapter *adapter, | ||
778 | struct be_eth_rx_compl *rxcp) | ||
779 | { | ||
780 | struct be_rx_page_info *page_info; | ||
781 | struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; | ||
782 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
783 | u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; | ||
784 | u16 i, rxq_idx = 0, vid; | ||
785 | |||
786 | num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); | ||
787 | pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); | ||
788 | vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); | ||
789 | rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); | ||
790 | |||
791 | remaining = pkt_size; | ||
792 | for (i = 0; i < num_rcvd; i++) { | ||
793 | page_info = get_rx_page_info(adapter, rxq_idx); | ||
794 | |||
795 | curr_frag_len = min(remaining, rx_frag_size); | ||
796 | |||
797 | rx_frags[i].page = page_info->page; | ||
798 | rx_frags[i].page_offset = page_info->page_offset; | ||
799 | rx_frags[i].size = curr_frag_len; | ||
800 | remaining -= curr_frag_len; | ||
801 | |||
802 | index_inc(&rxq_idx, rxq->len); | ||
803 | |||
804 | memset(page_info, 0, sizeof(*page_info)); | ||
805 | } | ||
806 | |||
807 | if (likely(!vlanf)) { | ||
808 | lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size, | ||
809 | pkt_size, NULL, 0); | ||
810 | } else { | ||
811 | vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); | ||
812 | vid = be16_to_cpu(vid); | ||
813 | |||
814 | if (!adapter->vlan_grp || adapter->num_vlans == 0) | ||
815 | return; | ||
816 | |||
817 | lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr, | ||
818 | rx_frags, pkt_size, pkt_size, adapter->vlan_grp, | ||
819 | vid, NULL, 0); | ||
820 | } | ||
821 | |||
822 | be_rx_rate_update(adapter, pkt_size, num_rcvd); | ||
823 | return; | ||
824 | } | ||
825 | |||
826 | static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) | ||
827 | { | ||
828 | struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq); | ||
829 | |||
830 | if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0) | ||
831 | return NULL; | ||
832 | |||
833 | be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); | ||
834 | |||
835 | rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; | ||
836 | |||
837 | queue_tail_inc(&adapter->rx_obj.cq); | ||
838 | return rxcp; | ||
839 | } | ||
840 | |||
841 | static inline struct page *be_alloc_pages(u32 size) | ||
842 | { | ||
843 | gfp_t alloc_flags = GFP_ATOMIC; | ||
844 | u32 order = get_order(size); | ||
845 | if (order > 0) | ||
846 | alloc_flags |= __GFP_COMP; | ||
847 | return alloc_pages(alloc_flags, order); | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * Allocate a page, split it to fragments of size rx_frag_size and post as | ||
852 | * receive buffers to BE | ||
853 | */ | ||
854 | static void be_post_rx_frags(struct be_adapter *adapter) | ||
855 | { | ||
856 | struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl; | ||
857 | struct be_rx_page_info *page_info = NULL; | ||
858 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
859 | struct page *pagep = NULL; | ||
860 | struct be_eth_rx_d *rxd; | ||
861 | u64 page_dmaaddr = 0, frag_dmaaddr; | ||
862 | u32 posted, page_offset = 0; | ||
863 | |||
864 | |||
865 | page_info = &page_info_tbl[rxq->head]; | ||
866 | for (posted = 0; posted < MAX_RX_POST && !page_info->page; posted++) { | ||
867 | if (!pagep) { | ||
868 | pagep = be_alloc_pages(adapter->big_page_size); | ||
869 | if (unlikely(!pagep)) { | ||
870 | drvr_stats(adapter)->be_ethrx_post_fail++; | ||
871 | break; | ||
872 | } | ||
873 | page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0, | ||
874 | adapter->big_page_size, | ||
875 | PCI_DMA_FROMDEVICE); | ||
876 | page_info->page_offset = 0; | ||
877 | } else { | ||
878 | get_page(pagep); | ||
879 | page_info->page_offset = page_offset + rx_frag_size; | ||
880 | } | ||
881 | page_offset = page_info->page_offset; | ||
882 | page_info->page = pagep; | ||
883 | pci_unmap_addr_set(page_info, bus, page_dmaaddr); | ||
884 | frag_dmaaddr = page_dmaaddr + page_info->page_offset; | ||
885 | |||
886 | rxd = queue_head_node(rxq); | ||
887 | rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF); | ||
888 | rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr)); | ||
889 | queue_head_inc(rxq); | ||
890 | |||
891 | /* Any space left in the current big page for another frag? */ | ||
892 | if ((page_offset + rx_frag_size + rx_frag_size) > | ||
893 | adapter->big_page_size) { | ||
894 | pagep = NULL; | ||
895 | page_info->last_page_user = true; | ||
896 | } | ||
897 | page_info = &page_info_tbl[rxq->head]; | ||
898 | } | ||
899 | if (pagep) | ||
900 | page_info->last_page_user = true; | ||
901 | |||
902 | if (posted) { | ||
903 | be_rxq_notify(&adapter->ctrl, rxq->id, posted); | ||
904 | atomic_add(posted, &rxq->used); | ||
905 | } | ||
906 | |||
907 | return; | ||
908 | } | ||
909 | |||
910 | static struct be_eth_tx_compl * | ||
911 | be_tx_compl_get(struct be_adapter *adapter) | ||
912 | { | ||
913 | struct be_queue_info *tx_cq = &adapter->tx_obj.cq; | ||
914 | struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); | ||
915 | |||
916 | if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) | ||
917 | return NULL; | ||
918 | |||
919 | be_dws_le_to_cpu(txcp, sizeof(*txcp)); | ||
920 | |||
921 | txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0; | ||
922 | |||
923 | queue_tail_inc(tx_cq); | ||
924 | return txcp; | ||
925 | } | ||
926 | |||
927 | static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) | ||
928 | { | ||
929 | struct be_queue_info *txq = &adapter->tx_obj.q; | ||
930 | struct be_eth_wrb *wrb; | ||
931 | struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; | ||
932 | struct sk_buff *sent_skb; | ||
933 | u64 busaddr; | ||
934 | u16 cur_index, num_wrbs = 0; | ||
935 | |||
936 | cur_index = txq->tail; | ||
937 | sent_skb = sent_skbs[cur_index]; | ||
938 | BUG_ON(!sent_skb); | ||
939 | sent_skbs[cur_index] = NULL; | ||
940 | |||
941 | do { | ||
942 | cur_index = txq->tail; | ||
943 | wrb = queue_tail_node(txq); | ||
944 | be_dws_le_to_cpu(wrb, sizeof(*wrb)); | ||
945 | busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; | ||
946 | if (busaddr != 0) { | ||
947 | pci_unmap_single(adapter->pdev, busaddr, | ||
948 | wrb->frag_len, PCI_DMA_TODEVICE); | ||
949 | } | ||
950 | num_wrbs++; | ||
951 | queue_tail_inc(txq); | ||
952 | } while (cur_index != last_index); | ||
953 | |||
954 | atomic_sub(num_wrbs, &txq->used); | ||
955 | |||
956 | kfree_skb(sent_skb); | ||
957 | } | ||
958 | |||
959 | static void be_rx_q_clean(struct be_adapter *adapter) | ||
960 | { | ||
961 | struct be_rx_page_info *page_info; | ||
962 | struct be_queue_info *rxq = &adapter->rx_obj.q; | ||
963 | struct be_queue_info *rx_cq = &adapter->rx_obj.cq; | ||
964 | struct be_eth_rx_compl *rxcp; | ||
965 | u16 tail; | ||
966 | |||
967 | /* First cleanup pending rx completions */ | ||
968 | while ((rxcp = be_rx_compl_get(adapter)) != NULL) { | ||
969 | be_rx_compl_discard(adapter, rxcp); | ||
970 | be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); | ||
971 | } | ||
972 | |||
973 | /* Then free posted rx buffer that were not used */ | ||
974 | tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; | ||
975 | for (; tail != rxq->head; index_inc(&tail, rxq->len)) { | ||
976 | page_info = get_rx_page_info(adapter, tail); | ||
977 | put_page(page_info->page); | ||
978 | memset(page_info, 0, sizeof(*page_info)); | ||
979 | } | ||
980 | BUG_ON(atomic_read(&rxq->used)); | ||
981 | } | ||
982 | |||
983 | static void be_tx_q_clean(struct be_adapter *adapter) | ||
984 | { | ||
985 | struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; | ||
986 | struct sk_buff *sent_skb; | ||
987 | struct be_queue_info *txq = &adapter->tx_obj.q; | ||
988 | u16 last_index; | ||
989 | bool dummy_wrb; | ||
990 | |||
991 | while (atomic_read(&txq->used)) { | ||
992 | sent_skb = sent_skbs[txq->tail]; | ||
993 | last_index = txq->tail; | ||
994 | index_adv(&last_index, | ||
995 | wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len); | ||
996 | be_tx_compl_process(adapter, last_index); | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | static void be_tx_queues_destroy(struct be_adapter *adapter) | ||
1001 | { | ||
1002 | struct be_queue_info *q; | ||
1003 | |||
1004 | q = &adapter->tx_obj.q; | ||
1005 | if (q->created) | ||
1006 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); | ||
1007 | be_queue_free(adapter, q); | ||
1008 | |||
1009 | q = &adapter->tx_obj.cq; | ||
1010 | if (q->created) | ||
1011 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); | ||
1012 | be_queue_free(adapter, q); | ||
1013 | |||
1014 | /* No more tx completions can be rcvd now; clean up if there are | ||
1015 | * any pending completions or pending tx requests */ | ||
1016 | be_tx_q_clean(adapter); | ||
1017 | |||
1018 | q = &adapter->tx_eq.q; | ||
1019 | if (q->created) | ||
1020 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); | ||
1021 | be_queue_free(adapter, q); | ||
1022 | } | ||
1023 | |||
1024 | static int be_tx_queues_create(struct be_adapter *adapter) | ||
1025 | { | ||
1026 | struct be_queue_info *eq, *q, *cq; | ||
1027 | |||
1028 | adapter->tx_eq.max_eqd = 0; | ||
1029 | adapter->tx_eq.min_eqd = 0; | ||
1030 | adapter->tx_eq.cur_eqd = 96; | ||
1031 | adapter->tx_eq.enable_aic = false; | ||
1032 | /* Alloc Tx Event queue */ | ||
1033 | eq = &adapter->tx_eq.q; | ||
1034 | if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, sizeof(struct be_eq_entry))) | ||
1035 | return -1; | ||
1036 | |||
1037 | /* Ask BE to create Tx Event queue */ | ||
1038 | if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd)) | ||
1039 | goto tx_eq_free; | ||
1040 | /* Alloc TX eth compl queue */ | ||
1041 | cq = &adapter->tx_obj.cq; | ||
1042 | if (be_queue_alloc(adapter, cq, TX_CQ_LEN, | ||
1043 | sizeof(struct be_eth_tx_compl))) | ||
1044 | goto tx_eq_destroy; | ||
1045 | |||
1046 | /* Ask BE to create Tx eth compl queue */ | ||
1047 | if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3)) | ||
1048 | goto tx_cq_free; | ||
1049 | |||
1050 | /* Alloc TX eth queue */ | ||
1051 | q = &adapter->tx_obj.q; | ||
1052 | if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb))) | ||
1053 | goto tx_cq_destroy; | ||
1054 | |||
1055 | /* Ask BE to create Tx eth queue */ | ||
1056 | if (be_cmd_txq_create(&adapter->ctrl, q, cq)) | ||
1057 | goto tx_q_free; | ||
1058 | return 0; | ||
1059 | |||
1060 | tx_q_free: | ||
1061 | be_queue_free(adapter, q); | ||
1062 | tx_cq_destroy: | ||
1063 | be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); | ||
1064 | tx_cq_free: | ||
1065 | be_queue_free(adapter, cq); | ||
1066 | tx_eq_destroy: | ||
1067 | be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); | ||
1068 | tx_eq_free: | ||
1069 | be_queue_free(adapter, eq); | ||
1070 | return -1; | ||
1071 | } | ||
1072 | |||
1073 | static void be_rx_queues_destroy(struct be_adapter *adapter) | ||
1074 | { | ||
1075 | struct be_queue_info *q; | ||
1076 | |||
1077 | q = &adapter->rx_obj.q; | ||
1078 | if (q->created) { | ||
1079 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ); | ||
1080 | be_rx_q_clean(adapter); | ||
1081 | } | ||
1082 | be_queue_free(adapter, q); | ||
1083 | |||
1084 | q = &adapter->rx_obj.cq; | ||
1085 | if (q->created) | ||
1086 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); | ||
1087 | be_queue_free(adapter, q); | ||
1088 | |||
1089 | q = &adapter->rx_eq.q; | ||
1090 | if (q->created) | ||
1091 | be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); | ||
1092 | be_queue_free(adapter, q); | ||
1093 | } | ||
1094 | |||
1095 | static int be_rx_queues_create(struct be_adapter *adapter) | ||
1096 | { | ||
1097 | struct be_queue_info *eq, *q, *cq; | ||
1098 | int rc; | ||
1099 | |||
1100 | adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; | ||
1101 | adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; | ||
1102 | adapter->rx_eq.max_eqd = BE_MAX_EQD; | ||
1103 | adapter->rx_eq.min_eqd = 0; | ||
1104 | adapter->rx_eq.cur_eqd = 0; | ||
1105 | adapter->rx_eq.enable_aic = true; | ||
1106 | |||
1107 | /* Alloc Rx Event queue */ | ||
1108 | eq = &adapter->rx_eq.q; | ||
1109 | rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, | ||
1110 | sizeof(struct be_eq_entry)); | ||
1111 | if (rc) | ||
1112 | return rc; | ||
1113 | |||
1114 | /* Ask BE to create Rx Event queue */ | ||
1115 | rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd); | ||
1116 | if (rc) | ||
1117 | goto rx_eq_free; | ||
1118 | |||
1119 | /* Alloc RX eth compl queue */ | ||
1120 | cq = &adapter->rx_obj.cq; | ||
1121 | rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, | ||
1122 | sizeof(struct be_eth_rx_compl)); | ||
1123 | if (rc) | ||
1124 | goto rx_eq_destroy; | ||
1125 | |||
1126 | /* Ask BE to create Rx eth compl queue */ | ||
1127 | rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3); | ||
1128 | if (rc) | ||
1129 | goto rx_cq_free; | ||
1130 | |||
1131 | /* Alloc RX eth queue */ | ||
1132 | q = &adapter->rx_obj.q; | ||
1133 | rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d)); | ||
1134 | if (rc) | ||
1135 | goto rx_cq_destroy; | ||
1136 | |||
1137 | /* Ask BE to create Rx eth queue */ | ||
1138 | rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size, | ||
1139 | BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); | ||
1140 | if (rc) | ||
1141 | goto rx_q_free; | ||
1142 | |||
1143 | return 0; | ||
1144 | rx_q_free: | ||
1145 | be_queue_free(adapter, q); | ||
1146 | rx_cq_destroy: | ||
1147 | be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); | ||
1148 | rx_cq_free: | ||
1149 | be_queue_free(adapter, cq); | ||
1150 | rx_eq_destroy: | ||
1151 | be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); | ||
1152 | rx_eq_free: | ||
1153 | be_queue_free(adapter, eq); | ||
1154 | return rc; | ||
1155 | } | ||
1156 | static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) | ||
1157 | { | ||
1158 | struct be_eq_entry *entry = queue_tail_node(&eq_obj->q); | ||
1159 | u32 evt = entry->evt; | ||
1160 | |||
1161 | if (!evt) | ||
1162 | return false; | ||
1163 | |||
1164 | evt = le32_to_cpu(evt); | ||
1165 | *rid = (evt >> EQ_ENTRY_RES_ID_SHIFT) & EQ_ENTRY_RES_ID_MASK; | ||
1166 | entry->evt = 0; | ||
1167 | queue_tail_inc(&eq_obj->q); | ||
1168 | return true; | ||
1169 | } | ||
1170 | |||
1171 | static int event_handle(struct be_ctrl_info *ctrl, | ||
1172 | struct be_eq_obj *eq_obj) | ||
1173 | { | ||
1174 | u16 rid = 0, num = 0; | ||
1175 | |||
1176 | while (event_get(eq_obj, &rid)) | ||
1177 | num++; | ||
1178 | |||
1179 | /* We can see an interrupt and no event */ | ||
1180 | be_eq_notify(ctrl, eq_obj->q.id, true, true, num); | ||
1181 | if (num) | ||
1182 | napi_schedule(&eq_obj->napi); | ||
1183 | |||
1184 | return num; | ||
1185 | } | ||
1186 | |||
1187 | static irqreturn_t be_intx(int irq, void *dev) | ||
1188 | { | ||
1189 | struct be_adapter *adapter = dev; | ||
1190 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1191 | int rx, tx; | ||
1192 | |||
1193 | tx = event_handle(ctrl, &adapter->tx_eq); | ||
1194 | rx = event_handle(ctrl, &adapter->rx_eq); | ||
1195 | |||
1196 | if (rx || tx) | ||
1197 | return IRQ_HANDLED; | ||
1198 | else | ||
1199 | return IRQ_NONE; | ||
1200 | } | ||
1201 | |||
1202 | static irqreturn_t be_msix_rx(int irq, void *dev) | ||
1203 | { | ||
1204 | struct be_adapter *adapter = dev; | ||
1205 | |||
1206 | event_handle(&adapter->ctrl, &adapter->rx_eq); | ||
1207 | |||
1208 | return IRQ_HANDLED; | ||
1209 | } | ||
1210 | |||
1211 | static irqreturn_t be_msix_tx(int irq, void *dev) | ||
1212 | { | ||
1213 | struct be_adapter *adapter = dev; | ||
1214 | |||
1215 | event_handle(&adapter->ctrl, &adapter->tx_eq); | ||
1216 | |||
1217 | return IRQ_HANDLED; | ||
1218 | } | ||
1219 | |||
1220 | static inline bool do_lro(struct be_adapter *adapter, | ||
1221 | struct be_eth_rx_compl *rxcp) | ||
1222 | { | ||
1223 | int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); | ||
1224 | int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); | ||
1225 | |||
1226 | if (err) | ||
1227 | drvr_stats(adapter)->be_rxcp_err++; | ||
1228 | |||
1229 | return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ? | ||
1230 | false : true; | ||
1231 | } | ||
1232 | |||
1233 | int be_poll_rx(struct napi_struct *napi, int budget) | ||
1234 | { | ||
1235 | struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi); | ||
1236 | struct be_adapter *adapter = | ||
1237 | container_of(rx_eq, struct be_adapter, rx_eq); | ||
1238 | struct be_queue_info *rx_cq = &adapter->rx_obj.cq; | ||
1239 | struct be_eth_rx_compl *rxcp; | ||
1240 | u32 work_done; | ||
1241 | |||
1242 | for (work_done = 0; work_done < budget; work_done++) { | ||
1243 | rxcp = be_rx_compl_get(adapter); | ||
1244 | if (!rxcp) | ||
1245 | break; | ||
1246 | |||
1247 | if (do_lro(adapter, rxcp)) | ||
1248 | be_rx_compl_process_lro(adapter, rxcp); | ||
1249 | else | ||
1250 | be_rx_compl_process(adapter, rxcp); | ||
1251 | } | ||
1252 | |||
1253 | lro_flush_all(&adapter->rx_obj.lro_mgr); | ||
1254 | |||
1255 | /* Refill the queue */ | ||
1256 | if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) | ||
1257 | be_post_rx_frags(adapter); | ||
1258 | |||
1259 | /* All consumed */ | ||
1260 | if (work_done < budget) { | ||
1261 | napi_complete(napi); | ||
1262 | be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done); | ||
1263 | } else { | ||
1264 | /* More to be consumed; continue with interrupts disabled */ | ||
1265 | be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done); | ||
1266 | } | ||
1267 | return work_done; | ||
1268 | } | ||
1269 | |||
1270 | /* For TX we don't honour budget; consume everything */ | ||
1271 | int be_poll_tx(struct napi_struct *napi, int budget) | ||
1272 | { | ||
1273 | struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); | ||
1274 | struct be_adapter *adapter = | ||
1275 | container_of(tx_eq, struct be_adapter, tx_eq); | ||
1276 | struct be_tx_obj *tx_obj = &adapter->tx_obj; | ||
1277 | struct be_queue_info *tx_cq = &tx_obj->cq; | ||
1278 | struct be_queue_info *txq = &tx_obj->q; | ||
1279 | struct be_eth_tx_compl *txcp; | ||
1280 | u32 num_cmpl = 0; | ||
1281 | u16 end_idx; | ||
1282 | |||
1283 | while ((txcp = be_tx_compl_get(adapter))) { | ||
1284 | end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, | ||
1285 | wrb_index, txcp); | ||
1286 | be_tx_compl_process(adapter, end_idx); | ||
1287 | num_cmpl++; | ||
1288 | } | ||
1289 | |||
1290 | /* As Tx wrbs have been freed up, wake up netdev queue if | ||
1291 | * it was stopped due to lack of tx wrbs. | ||
1292 | */ | ||
1293 | if (netif_queue_stopped(adapter->netdev) && | ||
1294 | atomic_read(&txq->used) < txq->len / 2) { | ||
1295 | netif_wake_queue(adapter->netdev); | ||
1296 | } | ||
1297 | |||
1298 | napi_complete(napi); | ||
1299 | |||
1300 | be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); | ||
1301 | |||
1302 | drvr_stats(adapter)->be_tx_events++; | ||
1303 | drvr_stats(adapter)->be_tx_compl += num_cmpl; | ||
1304 | |||
1305 | return 1; | ||
1306 | } | ||
1307 | |||
1308 | static void be_msix_enable(struct be_adapter *adapter) | ||
1309 | { | ||
1310 | int i, status; | ||
1311 | |||
1312 | for (i = 0; i < BE_NUM_MSIX_VECTORS; i++) | ||
1313 | adapter->msix_entries[i].entry = i; | ||
1314 | |||
1315 | status = pci_enable_msix(adapter->pdev, adapter->msix_entries, | ||
1316 | BE_NUM_MSIX_VECTORS); | ||
1317 | if (status == 0) | ||
1318 | adapter->msix_enabled = true; | ||
1319 | return; | ||
1320 | } | ||
1321 | |||
1322 | static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) | ||
1323 | { | ||
1324 | return adapter->msix_entries[eq_id - | ||
1325 | 8 * adapter->ctrl.pci_func].vector; | ||
1326 | } | ||
1327 | |||
1328 | static int be_msix_register(struct be_adapter *adapter) | ||
1329 | { | ||
1330 | struct net_device *netdev = adapter->netdev; | ||
1331 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
1332 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
1333 | int status, vec; | ||
1334 | |||
1335 | sprintf(tx_eq->desc, "%s-tx", netdev->name); | ||
1336 | vec = be_msix_vec_get(adapter, tx_eq->q.id); | ||
1337 | status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter); | ||
1338 | if (status) | ||
1339 | goto err; | ||
1340 | |||
1341 | sprintf(rx_eq->desc, "%s-rx", netdev->name); | ||
1342 | vec = be_msix_vec_get(adapter, rx_eq->q.id); | ||
1343 | status = request_irq(vec, be_msix_rx, 0, rx_eq->desc, adapter); | ||
1344 | if (status) { /* Free TX IRQ */ | ||
1345 | vec = be_msix_vec_get(adapter, tx_eq->q.id); | ||
1346 | free_irq(vec, adapter); | ||
1347 | goto err; | ||
1348 | } | ||
1349 | return 0; | ||
1350 | err: | ||
1351 | dev_warn(&adapter->pdev->dev, | ||
1352 | "MSIX Request IRQ failed - err %d\n", status); | ||
1353 | pci_disable_msix(adapter->pdev); | ||
1354 | adapter->msix_enabled = false; | ||
1355 | return status; | ||
1356 | } | ||
1357 | |||
1358 | static int be_irq_register(struct be_adapter *adapter) | ||
1359 | { | ||
1360 | struct net_device *netdev = adapter->netdev; | ||
1361 | int status; | ||
1362 | |||
1363 | if (adapter->msix_enabled) { | ||
1364 | status = be_msix_register(adapter); | ||
1365 | if (status == 0) | ||
1366 | goto done; | ||
1367 | } | ||
1368 | |||
1369 | /* INTx */ | ||
1370 | netdev->irq = adapter->pdev->irq; | ||
1371 | status = request_irq(netdev->irq, be_intx, IRQF_SHARED, netdev->name, | ||
1372 | adapter); | ||
1373 | if (status) { | ||
1374 | dev_err(&adapter->pdev->dev, | ||
1375 | "INTx request IRQ failed - err %d\n", status); | ||
1376 | return status; | ||
1377 | } | ||
1378 | done: | ||
1379 | adapter->isr_registered = true; | ||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1383 | static void be_irq_unregister(struct be_adapter *adapter) | ||
1384 | { | ||
1385 | struct net_device *netdev = adapter->netdev; | ||
1386 | int vec; | ||
1387 | |||
1388 | if (!adapter->isr_registered) | ||
1389 | return; | ||
1390 | |||
1391 | /* INTx */ | ||
1392 | if (!adapter->msix_enabled) { | ||
1393 | free_irq(netdev->irq, adapter); | ||
1394 | goto done; | ||
1395 | } | ||
1396 | |||
1397 | /* MSIx */ | ||
1398 | vec = be_msix_vec_get(adapter, adapter->tx_eq.q.id); | ||
1399 | free_irq(vec, adapter); | ||
1400 | vec = be_msix_vec_get(adapter, adapter->rx_eq.q.id); | ||
1401 | free_irq(vec, adapter); | ||
1402 | done: | ||
1403 | adapter->isr_registered = false; | ||
1404 | return; | ||
1405 | } | ||
1406 | |||
1407 | static int be_open(struct net_device *netdev) | ||
1408 | { | ||
1409 | struct be_adapter *adapter = netdev_priv(netdev); | ||
1410 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1411 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
1412 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
1413 | u32 if_flags; | ||
1414 | int status; | ||
1415 | |||
1416 | if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS | | ||
1417 | BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED | | ||
1418 | BE_IF_FLAGS_PASS_L3L4_ERRORS; | ||
1419 | status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr, | ||
1420 | false/* pmac_invalid */, &adapter->if_handle, | ||
1421 | &adapter->pmac_id); | ||
1422 | if (status != 0) | ||
1423 | goto do_none; | ||
1424 | |||
1425 | status = be_cmd_set_flow_control(ctrl, true, true); | ||
1426 | if (status != 0) | ||
1427 | goto if_destroy; | ||
1428 | |||
1429 | status = be_tx_queues_create(adapter); | ||
1430 | if (status != 0) | ||
1431 | goto if_destroy; | ||
1432 | |||
1433 | status = be_rx_queues_create(adapter); | ||
1434 | if (status != 0) | ||
1435 | goto tx_qs_destroy; | ||
1436 | |||
1437 | /* First time posting */ | ||
1438 | be_post_rx_frags(adapter); | ||
1439 | |||
1440 | napi_enable(&rx_eq->napi); | ||
1441 | napi_enable(&tx_eq->napi); | ||
1442 | |||
1443 | be_irq_register(adapter); | ||
1444 | |||
1445 | be_intr_set(ctrl, true); | ||
1446 | |||
1447 | /* The evt queues are created in the unarmed state; arm them */ | ||
1448 | be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); | ||
1449 | be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); | ||
1450 | |||
1451 | /* The compl queues are created in the unarmed state; arm them */ | ||
1452 | be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); | ||
1453 | be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0); | ||
1454 | |||
1455 | be_link_status_update(adapter); | ||
1456 | |||
1457 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); | ||
1458 | return 0; | ||
1459 | |||
1460 | tx_qs_destroy: | ||
1461 | be_tx_queues_destroy(adapter); | ||
1462 | if_destroy: | ||
1463 | be_cmd_if_destroy(ctrl, adapter->if_handle); | ||
1464 | do_none: | ||
1465 | return status; | ||
1466 | } | ||
1467 | |||
1468 | static int be_close(struct net_device *netdev) | ||
1469 | { | ||
1470 | struct be_adapter *adapter = netdev_priv(netdev); | ||
1471 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1472 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | ||
1473 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | ||
1474 | int vec; | ||
1475 | |||
1476 | cancel_delayed_work(&adapter->work); | ||
1477 | |||
1478 | netif_stop_queue(netdev); | ||
1479 | netif_carrier_off(netdev); | ||
1480 | adapter->link.speed = PHY_LINK_SPEED_ZERO; | ||
1481 | |||
1482 | be_intr_set(ctrl, false); | ||
1483 | |||
1484 | if (adapter->msix_enabled) { | ||
1485 | vec = be_msix_vec_get(adapter, tx_eq->q.id); | ||
1486 | synchronize_irq(vec); | ||
1487 | vec = be_msix_vec_get(adapter, rx_eq->q.id); | ||
1488 | synchronize_irq(vec); | ||
1489 | } else { | ||
1490 | synchronize_irq(netdev->irq); | ||
1491 | } | ||
1492 | be_irq_unregister(adapter); | ||
1493 | |||
1494 | napi_disable(&rx_eq->napi); | ||
1495 | napi_disable(&tx_eq->napi); | ||
1496 | |||
1497 | be_rx_queues_destroy(adapter); | ||
1498 | be_tx_queues_destroy(adapter); | ||
1499 | |||
1500 | be_cmd_if_destroy(ctrl, adapter->if_handle); | ||
1501 | return 0; | ||
1502 | } | ||
1503 | |||
1504 | static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, | ||
1505 | void **ip_hdr, void **tcpudp_hdr, | ||
1506 | u64 *hdr_flags, void *priv) | ||
1507 | { | ||
1508 | struct ethhdr *eh; | ||
1509 | struct vlan_ethhdr *veh; | ||
1510 | struct iphdr *iph; | ||
1511 | u8 *va = page_address(frag->page) + frag->page_offset; | ||
1512 | unsigned long ll_hlen; | ||
1513 | |||
1514 | prefetch(va); | ||
1515 | eh = (struct ethhdr *)va; | ||
1516 | *mac_hdr = eh; | ||
1517 | ll_hlen = ETH_HLEN; | ||
1518 | if (eh->h_proto != htons(ETH_P_IP)) { | ||
1519 | if (eh->h_proto == htons(ETH_P_8021Q)) { | ||
1520 | veh = (struct vlan_ethhdr *)va; | ||
1521 | if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) | ||
1522 | return -1; | ||
1523 | |||
1524 | ll_hlen += VLAN_HLEN; | ||
1525 | } else { | ||
1526 | return -1; | ||
1527 | } | ||
1528 | } | ||
1529 | *hdr_flags = LRO_IPV4; | ||
1530 | iph = (struct iphdr *)(va + ll_hlen); | ||
1531 | *ip_hdr = iph; | ||
1532 | if (iph->protocol != IPPROTO_TCP) | ||
1533 | return -1; | ||
1534 | *hdr_flags |= LRO_TCP; | ||
1535 | *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); | ||
1536 | |||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev) | ||
1541 | { | ||
1542 | struct net_lro_mgr *lro_mgr; | ||
1543 | |||
1544 | lro_mgr = &adapter->rx_obj.lro_mgr; | ||
1545 | lro_mgr->dev = netdev; | ||
1546 | lro_mgr->features = LRO_F_NAPI; | ||
1547 | lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; | ||
1548 | lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
1549 | lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS; | ||
1550 | lro_mgr->lro_arr = adapter->rx_obj.lro_desc; | ||
1551 | lro_mgr->get_frag_header = be_get_frag_header; | ||
1552 | lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME; | ||
1553 | } | ||
1554 | |||
1555 | static struct net_device_ops be_netdev_ops = { | ||
1556 | .ndo_open = be_open, | ||
1557 | .ndo_stop = be_close, | ||
1558 | .ndo_start_xmit = be_xmit, | ||
1559 | .ndo_get_stats = be_get_stats, | ||
1560 | .ndo_set_rx_mode = be_set_multicast_list, | ||
1561 | .ndo_set_mac_address = be_mac_addr_set, | ||
1562 | .ndo_change_mtu = be_change_mtu, | ||
1563 | .ndo_validate_addr = eth_validate_addr, | ||
1564 | .ndo_vlan_rx_register = be_vlan_register, | ||
1565 | .ndo_vlan_rx_add_vid = be_vlan_add_vid, | ||
1566 | .ndo_vlan_rx_kill_vid = be_vlan_rem_vid, | ||
1567 | }; | ||
1568 | |||
1569 | static void be_netdev_init(struct net_device *netdev) | ||
1570 | { | ||
1571 | struct be_adapter *adapter = netdev_priv(netdev); | ||
1572 | |||
1573 | netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | | ||
1574 | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | | ||
1575 | NETIF_F_IPV6_CSUM | NETIF_F_TSO6; | ||
1576 | |||
1577 | netdev->flags |= IFF_MULTICAST; | ||
1578 | |||
1579 | BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); | ||
1580 | |||
1581 | SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); | ||
1582 | |||
1583 | be_lro_init(adapter, netdev); | ||
1584 | |||
1585 | netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, | ||
1586 | BE_NAPI_WEIGHT); | ||
1587 | netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx, | ||
1588 | BE_NAPI_WEIGHT); | ||
1589 | |||
1590 | netif_carrier_off(netdev); | ||
1591 | netif_stop_queue(netdev); | ||
1592 | } | ||
1593 | |||
1594 | static void be_unmap_pci_bars(struct be_adapter *adapter) | ||
1595 | { | ||
1596 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1597 | if (ctrl->csr) | ||
1598 | iounmap(ctrl->csr); | ||
1599 | if (ctrl->db) | ||
1600 | iounmap(ctrl->db); | ||
1601 | if (ctrl->pcicfg) | ||
1602 | iounmap(ctrl->pcicfg); | ||
1603 | } | ||
1604 | |||
1605 | static int be_map_pci_bars(struct be_adapter *adapter) | ||
1606 | { | ||
1607 | u8 __iomem *addr; | ||
1608 | |||
1609 | addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2), | ||
1610 | pci_resource_len(adapter->pdev, 2)); | ||
1611 | if (addr == NULL) | ||
1612 | return -ENOMEM; | ||
1613 | adapter->ctrl.csr = addr; | ||
1614 | |||
1615 | addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4), | ||
1616 | 128 * 1024); | ||
1617 | if (addr == NULL) | ||
1618 | goto pci_map_err; | ||
1619 | adapter->ctrl.db = addr; | ||
1620 | |||
1621 | addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), | ||
1622 | pci_resource_len(adapter->pdev, 1)); | ||
1623 | if (addr == NULL) | ||
1624 | goto pci_map_err; | ||
1625 | adapter->ctrl.pcicfg = addr; | ||
1626 | |||
1627 | return 0; | ||
1628 | pci_map_err: | ||
1629 | be_unmap_pci_bars(adapter); | ||
1630 | return -ENOMEM; | ||
1631 | } | ||
1632 | |||
1633 | |||
1634 | static void be_ctrl_cleanup(struct be_adapter *adapter) | ||
1635 | { | ||
1636 | struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced; | ||
1637 | |||
1638 | be_unmap_pci_bars(adapter); | ||
1639 | |||
1640 | if (mem->va) | ||
1641 | pci_free_consistent(adapter->pdev, mem->size, | ||
1642 | mem->va, mem->dma); | ||
1643 | } | ||
1644 | |||
1645 | /* Initialize the mbox required to send cmds to BE */ | ||
1646 | static int be_ctrl_init(struct be_adapter *adapter) | ||
1647 | { | ||
1648 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1649 | struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; | ||
1650 | struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; | ||
1651 | int status; | ||
1652 | u32 val; | ||
1653 | |||
1654 | status = be_map_pci_bars(adapter); | ||
1655 | if (status) | ||
1656 | return status; | ||
1657 | |||
1658 | mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; | ||
1659 | mbox_mem_alloc->va = pci_alloc_consistent(adapter->pdev, | ||
1660 | mbox_mem_alloc->size, &mbox_mem_alloc->dma); | ||
1661 | if (!mbox_mem_alloc->va) { | ||
1662 | be_unmap_pci_bars(adapter); | ||
1663 | return -1; | ||
1664 | } | ||
1665 | mbox_mem_align->size = sizeof(struct be_mcc_mailbox); | ||
1666 | mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); | ||
1667 | mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); | ||
1668 | memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); | ||
1669 | spin_lock_init(&ctrl->cmd_lock); | ||
1670 | |||
1671 | val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); | ||
1672 | ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & | ||
1673 | MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; | ||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | static void be_stats_cleanup(struct be_adapter *adapter) | ||
1678 | { | ||
1679 | struct be_stats_obj *stats = &adapter->stats; | ||
1680 | struct be_dma_mem *cmd = &stats->cmd; | ||
1681 | |||
1682 | if (cmd->va) | ||
1683 | pci_free_consistent(adapter->pdev, cmd->size, | ||
1684 | cmd->va, cmd->dma); | ||
1685 | } | ||
1686 | |||
1687 | static int be_stats_init(struct be_adapter *adapter) | ||
1688 | { | ||
1689 | struct be_stats_obj *stats = &adapter->stats; | ||
1690 | struct be_dma_mem *cmd = &stats->cmd; | ||
1691 | |||
1692 | cmd->size = sizeof(struct be_cmd_req_get_stats); | ||
1693 | cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); | ||
1694 | if (cmd->va == NULL) | ||
1695 | return -1; | ||
1696 | return 0; | ||
1697 | } | ||
1698 | |||
1699 | static void __devexit be_remove(struct pci_dev *pdev) | ||
1700 | { | ||
1701 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
1702 | if (!adapter) | ||
1703 | return; | ||
1704 | |||
1705 | unregister_netdev(adapter->netdev); | ||
1706 | |||
1707 | be_stats_cleanup(adapter); | ||
1708 | |||
1709 | be_ctrl_cleanup(adapter); | ||
1710 | |||
1711 | if (adapter->msix_enabled) { | ||
1712 | pci_disable_msix(adapter->pdev); | ||
1713 | adapter->msix_enabled = false; | ||
1714 | } | ||
1715 | |||
1716 | pci_set_drvdata(pdev, NULL); | ||
1717 | pci_release_regions(pdev); | ||
1718 | pci_disable_device(pdev); | ||
1719 | |||
1720 | free_netdev(adapter->netdev); | ||
1721 | } | ||
1722 | |||
1723 | static int be_hw_up(struct be_adapter *adapter) | ||
1724 | { | ||
1725 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1726 | int status; | ||
1727 | |||
1728 | status = be_cmd_POST(ctrl); | ||
1729 | if (status) | ||
1730 | return status; | ||
1731 | |||
1732 | status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver); | ||
1733 | if (status) | ||
1734 | return status; | ||
1735 | |||
1736 | status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num); | ||
1737 | return status; | ||
1738 | } | ||
1739 | |||
1740 | static int __devinit be_probe(struct pci_dev *pdev, | ||
1741 | const struct pci_device_id *pdev_id) | ||
1742 | { | ||
1743 | int status = 0; | ||
1744 | struct be_adapter *adapter; | ||
1745 | struct net_device *netdev; | ||
1746 | struct be_ctrl_info *ctrl; | ||
1747 | u8 mac[ETH_ALEN]; | ||
1748 | |||
1749 | status = pci_enable_device(pdev); | ||
1750 | if (status) | ||
1751 | goto do_none; | ||
1752 | |||
1753 | status = pci_request_regions(pdev, DRV_NAME); | ||
1754 | if (status) | ||
1755 | goto disable_dev; | ||
1756 | pci_set_master(pdev); | ||
1757 | |||
1758 | netdev = alloc_etherdev(sizeof(struct be_adapter)); | ||
1759 | if (netdev == NULL) { | ||
1760 | status = -ENOMEM; | ||
1761 | goto rel_reg; | ||
1762 | } | ||
1763 | adapter = netdev_priv(netdev); | ||
1764 | adapter->pdev = pdev; | ||
1765 | pci_set_drvdata(pdev, adapter); | ||
1766 | adapter->netdev = netdev; | ||
1767 | |||
1768 | be_msix_enable(adapter); | ||
1769 | |||
1770 | status = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | ||
1771 | if (!status) { | ||
1772 | netdev->features |= NETIF_F_HIGHDMA; | ||
1773 | } else { | ||
1774 | status = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
1775 | if (status) { | ||
1776 | dev_err(&pdev->dev, "Could not set PCI DMA Mask\n"); | ||
1777 | goto free_netdev; | ||
1778 | } | ||
1779 | } | ||
1780 | |||
1781 | ctrl = &adapter->ctrl; | ||
1782 | status = be_ctrl_init(adapter); | ||
1783 | if (status) | ||
1784 | goto free_netdev; | ||
1785 | |||
1786 | status = be_stats_init(adapter); | ||
1787 | if (status) | ||
1788 | goto ctrl_clean; | ||
1789 | |||
1790 | status = be_hw_up(adapter); | ||
1791 | if (status) | ||
1792 | goto stats_clean; | ||
1793 | |||
1794 | status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK, | ||
1795 | true /* permanent */, 0); | ||
1796 | if (status) | ||
1797 | goto stats_clean; | ||
1798 | memcpy(netdev->dev_addr, mac, ETH_ALEN); | ||
1799 | |||
1800 | INIT_DELAYED_WORK(&adapter->work, be_worker); | ||
1801 | be_netdev_init(netdev); | ||
1802 | SET_NETDEV_DEV(netdev, &adapter->pdev->dev); | ||
1803 | |||
1804 | status = register_netdev(netdev); | ||
1805 | if (status != 0) | ||
1806 | goto stats_clean; | ||
1807 | |||
1808 | dev_info(&pdev->dev, BE_NAME " port %d\n", adapter->port_num); | ||
1809 | return 0; | ||
1810 | |||
1811 | stats_clean: | ||
1812 | be_stats_cleanup(adapter); | ||
1813 | ctrl_clean: | ||
1814 | be_ctrl_cleanup(adapter); | ||
1815 | free_netdev: | ||
1816 | free_netdev(adapter->netdev); | ||
1817 | rel_reg: | ||
1818 | pci_release_regions(pdev); | ||
1819 | disable_dev: | ||
1820 | pci_disable_device(pdev); | ||
1821 | do_none: | ||
1822 | dev_warn(&pdev->dev, BE_NAME " initialization failed\n"); | ||
1823 | return status; | ||
1824 | } | ||
1825 | |||
1826 | static int be_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1827 | { | ||
1828 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
1829 | struct net_device *netdev = adapter->netdev; | ||
1830 | |||
1831 | netif_device_detach(netdev); | ||
1832 | if (netif_running(netdev)) { | ||
1833 | rtnl_lock(); | ||
1834 | be_close(netdev); | ||
1835 | rtnl_unlock(); | ||
1836 | } | ||
1837 | |||
1838 | pci_save_state(pdev); | ||
1839 | pci_disable_device(pdev); | ||
1840 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static int be_resume(struct pci_dev *pdev) | ||
1845 | { | ||
1846 | int status = 0; | ||
1847 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
1848 | struct net_device *netdev = adapter->netdev; | ||
1849 | |||
1850 | netif_device_detach(netdev); | ||
1851 | |||
1852 | status = pci_enable_device(pdev); | ||
1853 | if (status) | ||
1854 | return status; | ||
1855 | |||
1856 | pci_set_power_state(pdev, 0); | ||
1857 | pci_restore_state(pdev); | ||
1858 | |||
1859 | be_vids_config(netdev); | ||
1860 | |||
1861 | if (netif_running(netdev)) { | ||
1862 | rtnl_lock(); | ||
1863 | be_open(netdev); | ||
1864 | rtnl_unlock(); | ||
1865 | } | ||
1866 | netif_device_attach(netdev); | ||
1867 | return 0; | ||
1868 | } | ||
1869 | |||
1870 | static struct pci_driver be_driver = { | ||
1871 | .name = DRV_NAME, | ||
1872 | .id_table = be_dev_ids, | ||
1873 | .probe = be_probe, | ||
1874 | .remove = be_remove, | ||
1875 | .suspend = be_suspend, | ||
1876 | .resume = be_resume | ||
1877 | }; | ||
1878 | |||
1879 | static int __init be_init_module(void) | ||
1880 | { | ||
1881 | if (rx_frag_size != 8192 && rx_frag_size != 4096 | ||
1882 | && rx_frag_size != 2048) { | ||
1883 | printk(KERN_WARNING DRV_NAME | ||
1884 | " : Module param rx_frag_size must be 2048/4096/8192." | ||
1885 | " Using 2048\n"); | ||
1886 | rx_frag_size = 2048; | ||
1887 | } | ||
1888 | /* Ensure rx_frag_size is aligned to chache line */ | ||
1889 | if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) { | ||
1890 | printk(KERN_WARNING DRV_NAME | ||
1891 | " : Bad module param rx_frag_size. Using 2048\n"); | ||
1892 | rx_frag_size = 2048; | ||
1893 | } | ||
1894 | |||
1895 | return pci_register_driver(&be_driver); | ||
1896 | } | ||
1897 | module_init(be_init_module); | ||
1898 | |||
1899 | static void __exit be_exit_module(void) | ||
1900 | { | ||
1901 | pci_unregister_driver(&be_driver); | ||
1902 | } | ||
1903 | module_exit(be_exit_module); | ||