Commit | Line | Data |
---|---|---|
800f879a AT |
1 | /* |
2 | * Copyright 2010-2017 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License, version 2, | |
6 | * as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * Disclaimer: The codes contained in these modules may be specific to | |
14 | * the Intel Software Development Platform codenamed Knights Ferry, | |
15 | * and the Intel product codenamed Knights Corner, and are not backward | |
16 | * compatible with other Intel products. Additionally, Intel will NOT | |
17 | * support the codes or instruction set in future products. | |
18 | * | |
19 | * Intel offers no warranty of any kind regarding the code. This code is | |
20 | * licensed on an "AS IS" basis and Intel is not obligated to provide | |
21 | * any support, assistance, installation, training, or other services | |
22 | * of any kind. Intel is also not obligated to provide any updates, | |
23 | * enhancements or extensions. Intel specifically disclaims any warranty | |
24 | * of merchantability, non-infringement, fitness for any particular | |
25 | * purpose, and any other warranty. | |
26 | * | |
27 | * Further, Intel disclaims all liability of any kind, including but | |
28 | * not limited to liability for infringement of any proprietary rights, | |
29 | * relating to the use of the code, even if Intel is notified of the | |
30 | * possibility of such liability. Except as expressly stated in an Intel | |
31 | * license agreement provided with this code and agreed upon with Intel, | |
32 | * no license, express or implied, by estoppel or otherwise, to any | |
33 | * intellectual property rights is granted herein. | |
34 | */ | |
35 | ||
36 | #include "micint.h" | |
37 | #include "mic_common.h" | |
38 | #include <mic/micsboxdefine.h> | |
39 | #include <linux/ip.h> | |
40 | #include <linux/tcp.h> | |
41 | #include <linux/kernel.h> | |
42 | #include "mic/micveth.h" | |
43 | ||
44 | #define PWR_MGMT_NO_POLL_AFTER_LINKS_UP 1 | |
45 | ||
46 | /* | |
47 | In intr/poll modes, mic_smpt_uninit has already been called before | |
48 | micveth_destroy is called during rmmod. This results in host driver crash. The | |
49 | current workaround is, given the 'legacy' nature of VNET intr/poll modes, to | |
50 | not call mic_ctx_unmap_single() at rmmod. This workaround will result in some | |
51 | unmapped memory and a warn_on from micscif_smpt.c. | |
52 | */ | |
53 | #define WA_UNMAP_AT_RMMOD 0 | |
54 | ||
55 | static void micveth_clientpoll(struct work_struct *work); | |
56 | static void micveth_poll(struct work_struct *work); | |
57 | static int micvnet_host_doorbell_intr_handler(mic_ctx_t *mic_ctx, int doorbell); | |
58 | static void micvnet_intr_bh_handler(struct work_struct *work); | |
59 | void micveth_send_intr(micveth_info_t *veth_info); | |
60 | ||
61 | micveth_t micveth; | |
62 | ||
63 | void dump_skb(struct sk_buff *skb, int xmit); | |
64 | ||
65 | static inline | |
66 | mic_ctx_t *veth_to_ctx(micveth_info_t *veth_info) | |
67 | { | |
68 | return veth_info->mic_ctx; | |
69 | } | |
70 | ||
71 | static int | |
72 | micveth_set_address(struct net_device *dev, void *p) | |
73 | { | |
74 | struct sockaddr *sa = p; | |
75 | ||
76 | if (!is_valid_ether_addr(sa->sa_data)) | |
77 | return -EADDRNOTAVAIL; | |
78 | ||
79 | memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); | |
80 | return 0; | |
81 | } | |
82 | ||
83 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) | |
84 | static void | |
85 | micveth_multicast_list(struct net_device *dev) | |
86 | { | |
87 | } | |
88 | #endif | |
89 | ||
90 | static int | |
91 | micveth_deliver(struct sk_buff *skb, struct net_device *dev, micveth_info_t *veth_info) | |
92 | { | |
93 | veth_ring_t *ring; | |
94 | ring_queue_t *tx_queue; | |
95 | ring_desc_t *desc; | |
96 | ring_packet_t *packet; | |
97 | int next_tail; | |
98 | ||
99 | //dump_skb(skb, 1); | |
100 | ||
101 | spin_lock(&veth_info->vi_txlock); | |
102 | ring = &veth_info->vi_ring.ring; | |
103 | tx_queue = &ring->r_tx; | |
104 | ||
105 | next_tail = (tx_queue->rq_tail + 1) % tx_queue->rq_length; | |
106 | if (next_tail == tx_queue->rq_head) { | |
107 | // queue_full situation - just drop the packet and let the stack retry | |
108 | spin_unlock(&veth_info->vi_txlock); | |
109 | return 1; | |
110 | } | |
111 | ||
112 | desc = &tx_queue->rq_descs[tx_queue->rq_tail]; | |
113 | packet = &veth_info->vi_tx_desc[tx_queue->rq_tail]; | |
114 | packet->pd_skb = skb; | |
115 | packet->pd_phys = mic_ctx_map_single(veth_to_ctx(veth_info), | |
116 | skb->data, skb->len); | |
117 | packet->pd_length = skb->len; | |
118 | desc->rd_phys = packet->pd_phys; | |
119 | desc->rd_length = skb->len; | |
120 | desc->rd_valid = 1; | |
121 | ||
122 | /* | |
123 | * Need a write memory barrier between copying the skb data to | |
124 | * the buffer and updating the tail pointer. NOT an smp_wmb(), | |
125 | * because this memory barrier needs to be done even if there is | |
126 | * a single CPU in the system. | |
127 | */ | |
128 | wmb(); | |
129 | tx_queue->rq_tail = (tx_queue->rq_tail + 1) % tx_queue->rq_length; | |
130 | spin_unlock(&veth_info->vi_txlock); | |
131 | ||
132 | if (mic_vnet_mode == VNET_MODE_INTR) { | |
133 | micveth_send_intr(veth_info); | |
134 | } | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static int | |
140 | micveth_xmit(struct sk_buff *skb, struct net_device *dev) | |
141 | { | |
142 | micveth_info_t *veth_info; | |
143 | ||
144 | if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) { | |
145 | kfree_skb(skb); | |
146 | dev->stats.tx_dropped++; | |
147 | return NETDEV_TX_OK; | |
148 | } | |
149 | ||
150 | dev->stats.tx_packets++; | |
151 | dev->stats.tx_bytes += skb->len; | |
152 | ||
153 | veth_info = dev->ml_priv; | |
154 | ||
155 | if (veth_info->vi_state != VETH_STATE_LINKUP) { | |
156 | kfree_skb(skb); | |
157 | dev->stats.tx_dropped++; | |
158 | return NETDEV_TX_OK; | |
159 | } | |
160 | ||
161 | if (micveth_deliver(skb, dev, veth_info)) { | |
162 | kfree_skb(skb); | |
163 | dev->stats.tx_dropped++; | |
164 | } | |
165 | ||
166 | return NETDEV_TX_OK; | |
167 | } | |
168 | ||
169 | static int | |
170 | micveth_change_mtu(struct net_device *dev, int new_mtu) | |
171 | { | |
172 | dev->mtu = new_mtu; | |
173 | return 0; | |
174 | } | |
175 | ||
176 | /* Start callback */ | |
177 | static int | |
178 | micveth_start_dev(struct net_device *dev) | |
179 | { | |
180 | micveth_info_t *veth_info = dev->ml_priv; | |
181 | ||
182 | micveth_start(veth_info->mic_ctx); | |
183 | return 0; | |
184 | } | |
185 | ||
186 | /* Stop callback */ | |
187 | static int | |
188 | micveth_stop_dev(struct net_device *dev) | |
189 | { | |
190 | micveth_info_t *veth_info = dev->ml_priv; | |
191 | ||
192 | micveth_stop(veth_info->mic_ctx); | |
193 | return 0; | |
194 | } | |
195 | ||
196 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) | |
197 | static const struct net_device_ops veth_netdev_ops = { | |
198 | .ndo_open = micveth_start_dev, | |
199 | .ndo_stop = micveth_stop_dev, | |
200 | .ndo_start_xmit = micveth_xmit, | |
201 | .ndo_validate_addr = eth_validate_addr, | |
202 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) | |
203 | .ndo_set_multicast_list = micveth_multicast_list, | |
204 | #endif | |
205 | .ndo_set_mac_address = micveth_set_address, | |
206 | .ndo_change_mtu = micveth_change_mtu, | |
207 | }; | |
208 | #endif | |
209 | ||
210 | static void | |
211 | micveth_setup(struct net_device *dev) | |
212 | { | |
213 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) | |
214 | dev->hard_start_xmit = micveth_xmit; | |
215 | dev->set_multicast_list = micveth_multicast_list; | |
216 | dev->set_mac_address = micveth_set_address; | |
217 | #endif | |
218 | ether_setup(dev); | |
219 | ||
220 | /* Initialize the device structure. */ | |
221 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) | |
222 | dev->netdev_ops = &veth_netdev_ops; | |
223 | #endif | |
224 | dev->destructor = free_netdev; | |
225 | ||
226 | /* Fill in device structure with ethernet-generic values. */ | |
227 | dev->mtu = (MICVETH_MAX_PACKET_SIZE); | |
228 | dev->tx_queue_len = 0; | |
229 | dev->flags &= ~IFF_MULTICAST; | |
230 | random_ether_addr(dev->dev_addr); | |
231 | } | |
232 | ||
233 | static int | |
234 | micveth_validate(struct nlattr *tb[], struct nlattr *data[]) | |
235 | { | |
236 | if (tb[IFLA_ADDRESS]) { | |
237 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | |
238 | return -EINVAL; | |
239 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | |
240 | return -EADDRNOTAVAIL; | |
241 | } | |
242 | return 0; | |
243 | } | |
244 | ||
245 | static struct rtnl_link_ops micveth_link_ops __read_mostly = { | |
246 | .kind = "micveth", | |
247 | .setup = micveth_setup, | |
248 | .validate = micveth_validate, | |
249 | }; | |
250 | ||
251 | static int | |
252 | micveth_probe_int(micveth_info_t *veth_info, mic_ctx_t *mic_ctx) | |
253 | { | |
254 | struct net_device *dev_veth; | |
255 | ring_queue_t *queue; | |
256 | ring_desc_t *desc; | |
257 | ring_packet_t *packet; | |
258 | int idx; | |
259 | int err = 0; | |
260 | ||
261 | veth_info->vi_pdev = mic_ctx->bi_pdev; | |
262 | veth_info->vi_sbox = (uint8_t *)((unsigned long)mic_ctx->mmio.va + | |
263 | HOST_SBOX_BASE_ADDRESS); | |
264 | veth_info->vi_scratch14 = (uint32_t *)((unsigned long)mic_ctx->mmio.va + | |
265 | HOST_SBOX_BASE_ADDRESS + SBOX_SCRATCH14); | |
266 | veth_info->vi_scratch15 = (uint32_t *)((unsigned long)mic_ctx->mmio.va + | |
267 | HOST_SBOX_BASE_ADDRESS + SBOX_SCRATCH15); | |
268 | veth_info->mic_ctx = mic_ctx; | |
269 | mic_ctx->bi_vethinfo = (void *)veth_info; | |
270 | ||
271 | spin_lock_init(&veth_info->vi_txlock); | |
272 | spin_lock_init(&veth_info->vi_rxlock); | |
273 | ||
274 | if (mic_vnet_mode == VNET_MODE_POLL) | |
275 | INIT_DELAYED_WORK(&veth_info->vi_poll, micveth_poll); | |
276 | ||
277 | // Set the current sk_buff allocation size | |
278 | veth_info->vi_skb_mtu = MICVETH_MAX_PACKET_SIZE + 32; | |
279 | ||
280 | // Get the physical memory address for the ring descriptors | |
281 | veth_info->vi_ring.phys = mic_ctx_map_single(veth_to_ctx(veth_info), &veth_info->vi_ring.ring, | |
282 | sizeof(veth_ring_t)); | |
283 | veth_info->vi_ring.length = sizeof(veth_ring_t); | |
284 | ||
285 | queue = &veth_info->vi_ring.ring.r_tx; | |
286 | queue->rq_head = 0; | |
287 | queue->rq_tail = 0; | |
288 | queue->rq_length = MICVETH_TRANSFER_FIFO_SIZE; | |
289 | ||
290 | veth_info->vi_pend = 0; | |
291 | ||
292 | packet = &veth_info->vi_tx_desc[0]; | |
293 | for (idx = 0; idx < queue->rq_length; idx++) { | |
294 | desc = &queue->rq_descs[idx]; | |
295 | packet[idx].pd_skb = NULL; | |
296 | packet[idx].pd_phys = 0; | |
297 | packet[idx].pd_length = 0; | |
298 | ||
299 | desc->rd_phys = 0; | |
300 | desc->rd_length = 0; | |
301 | desc->rd_valid = 0; | |
302 | } | |
303 | ||
304 | // This is the recieve end. | |
305 | queue = &veth_info->vi_ring.ring.r_rx; | |
306 | queue->rq_head = 0; | |
307 | queue->rq_tail = 0; | |
308 | queue->rq_length = MICVETH_TRANSFER_FIFO_SIZE; | |
309 | ||
310 | packet = &veth_info->vi_rx_desc[0]; | |
311 | for (idx = 0; idx < queue->rq_length; idx++) { | |
312 | desc = &queue->rq_descs[idx]; | |
313 | if (!(packet[idx].pd_skb = dev_alloc_skb(veth_info->vi_skb_mtu))) | |
314 | return -ENOMEM; | |
315 | packet[idx].pd_phys = mic_ctx_map_single(veth_to_ctx(veth_info), packet[idx].pd_skb->data, | |
316 | veth_info->vi_skb_mtu); | |
317 | packet[idx].pd_length = veth_info->vi_skb_mtu; | |
318 | ||
319 | desc->rd_phys = packet[idx].pd_phys; | |
320 | desc->rd_length = packet[idx].pd_length; | |
321 | desc->rd_valid = 1; | |
322 | } | |
323 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) | |
324 | if ((dev_veth = alloc_netdev(sizeof(micveth_info_t), "mic%d", micveth_setup)) == NULL) { | |
325 | #else | |
326 | if ((dev_veth = alloc_netdev(sizeof(micveth_info_t), "mic%d", NET_NAME_UNKNOWN, micveth_setup)) == NULL) { | |
327 | #endif | |
328 | return -ENOMEM; | |
329 | } | |
330 | ||
331 | veth_info->vi_netdev = dev_veth; | |
332 | dev_veth->ml_priv = veth_info; | |
333 | dev_veth->rtnl_link_ops = &micveth_link_ops; | |
334 | ||
335 | if ((err = register_netdev(dev_veth)) < 0) { | |
336 | printk("register netdev failed %d\n", err); | |
337 | free_netdev(dev_veth); | |
338 | return err; | |
339 | } | |
340 | ||
341 | veth_info->vi_state = VETH_STATE_INITIALIZED; | |
342 | return 0; | |
343 | } | |
344 | ||
345 | static ssize_t show_veth(struct device *dev, | |
346 | struct device_attribute *attr, char *buf); | |
347 | DEVICE_ATTR(veth, S_IRUGO, show_veth, NULL); | |
348 | ||
349 | static int | |
350 | micveth_init_int(int num_bds, struct device *dev) | |
351 | { | |
352 | int bd; | |
353 | int err = 0; | |
354 | ||
355 | micveth.lv_num_interfaces = num_bds; | |
356 | micveth.lv_num_clients = num_bds; | |
357 | micveth.lv_active_clients = 0; | |
358 | micveth.lv_num_links_remaining = num_bds; | |
359 | ||
360 | BUG_ON(rtnl_link_register(&micveth_link_ops)); | |
361 | ||
362 | // Allocate space for the control of each device in the system. | |
363 | micveth.lv_info = kmalloc(sizeof(micveth_info_t) * num_bds, GFP_KERNEL); | |
364 | ||
365 | // Initialize state mutex. Overloaded use for several fields. | |
366 | mutex_init(&micveth.lv_state_mutex); | |
367 | ||
368 | // Setup of timer for probeing active mic clients. When the total active board | |
369 | // count is zero the poll is not running. | |
370 | micveth.lv_pollstate = CLIENT_POLL_STOPPED; | |
371 | INIT_DELAYED_WORK(&micveth.lv_poll, micveth_clientpoll); | |
372 | init_waitqueue_head(&micveth.lv_wq); | |
373 | ||
374 | // Init each of the existing boards. | |
375 | for (bd = 0; bd < num_bds; bd++) { | |
376 | micveth_probe_int(&micveth.lv_info[bd], &mic_data.dd_bi[bd]->bi_ctx); | |
377 | } | |
378 | ||
379 | err = device_create_file(dev, &dev_attr_veth); | |
380 | return err; | |
381 | } | |
382 | ||
383 | static void | |
384 | micveth_exit_int(void) | |
385 | { | |
386 | mic_ctx_t *mic_ctx = kmalloc(sizeof(mic_ctx_t), GFP_KERNEL); | |
387 | micveth_info_t *veth_info; | |
388 | ring_packet_t *packet; | |
389 | int bd; | |
390 | int idx; | |
391 | ||
392 | rtnl_link_unregister(&micveth_link_ops); | |
393 | ||
394 | for (bd = 0; bd < micveth.lv_num_clients; bd++) { | |
395 | veth_info = &micveth.lv_info[bd]; | |
396 | ||
397 | /* veth_info->mic_ctx == mic_data.dd_bi[bd] is freed in | |
398 | remove so cannot be used in exit */ | |
399 | mic_ctx->bi_vethinfo = veth_info; | |
400 | micveth_stop(mic_ctx); | |
401 | ||
402 | #if WA_UNMAP_AT_RMMOD | |
403 | mic_ctx_unmap_single(veth_to_ctx(veth_info), veth_info->vi_ring.phys, | |
404 | sizeof(veth_ring_t)); | |
405 | #endif | |
406 | ||
407 | for (idx = 0; idx < veth_info->vi_ring.ring.r_tx.rq_length; idx++) { | |
408 | packet = &veth_info->vi_tx_desc[idx]; | |
409 | if (packet->pd_skb != NULL) { | |
410 | #if WA_UNMAP_AT_RMMOD | |
411 | mic_ctx_unmap_single(veth_to_ctx(veth_info), packet->pd_phys, | |
412 | packet->pd_skb->len); | |
413 | #endif | |
414 | kfree_skb(packet->pd_skb); | |
415 | } | |
416 | } | |
417 | ||
418 | for (idx = 0; idx < veth_info->vi_ring.ring.r_rx.rq_length; idx++) { | |
419 | packet = &veth_info->vi_rx_desc[idx]; | |
420 | #if WA_UNMAP_AT_RMMOD | |
421 | mic_ctx_unmap_single(veth_to_ctx(veth_info), packet->pd_phys, packet->pd_skb->len); | |
422 | #endif | |
423 | kfree_skb(packet->pd_skb); | |
424 | } | |
425 | } | |
426 | ||
427 | kfree(mic_ctx); | |
428 | kfree(micveth.lv_info); | |
429 | } | |
430 | ||
431 | static int | |
432 | micveth_start_int(mic_ctx_t *mic_ctx) | |
433 | { | |
434 | micveth_info_t *veth_info = &micveth.lv_info[mic_ctx->bi_id]; | |
435 | ||
436 | // Eventuall (very soon) most of the descriptor allocation for a board will be done here | |
437 | if (veth_info->vi_state != VETH_STATE_INITIALIZED) | |
438 | return 0; | |
439 | ||
440 | mutex_lock(&micveth.lv_state_mutex); | |
441 | ||
442 | if (micveth.lv_pollstate == CLIENT_POLL_STOPPED) { | |
443 | schedule_delayed_work(&micveth.lv_poll, msecs_to_jiffies(MICVETH_CLIENT_TIMER_DELAY)); | |
444 | micveth.lv_pollstate = CLIENT_POLL_RUNNING; | |
445 | } | |
446 | ||
447 | micveth.lv_active_clients++; | |
448 | mutex_unlock(&micveth.lv_state_mutex); | |
449 | ||
450 | veth_info->vi_pend = 0; | |
451 | ||
452 | veth_info->vi_ring.ring.r_tx.rq_head = 0; | |
453 | veth_info->vi_ring.ring.r_tx.rq_tail = 0; | |
454 | ||
455 | veth_info->vi_ring.ring.r_rx.rq_head = 0; | |
456 | veth_info->vi_ring.ring.r_rx.rq_tail = 0; | |
457 | veth_info->vi_state = VETH_STATE_LINKDOWN; | |
458 | ||
459 | if (mic_vnet_mode == VNET_MODE_INTR) { | |
460 | snprintf(veth_info->vi_wqname, sizeof(veth_info->vi_wqname), | |
461 | "VNET INTR %d\n", mic_ctx->bi_id); | |
462 | veth_info->vi_wq = create_singlethread_workqueue(veth_info->vi_wqname); | |
463 | INIT_WORK(&veth_info->vi_bh, micvnet_intr_bh_handler); | |
464 | ||
465 | // Install interrupt handler on doorbell 3 | |
466 | mic_reg_irqhandler(mic_ctx, 3, "Host DoorBell 3", | |
467 | micvnet_host_doorbell_intr_handler); | |
468 | } | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
473 | static void | |
474 | micveth_stop_int(mic_ctx_t *mic_ctx) | |
475 | { | |
476 | micveth_info_t *veth_info = (micveth_info_t *)(mic_ctx->bi_vethinfo); | |
477 | ||
478 | if (veth_info->vi_state == VETH_STATE_INITIALIZED) | |
479 | return; | |
480 | ||
481 | mutex_lock(&micveth.lv_state_mutex); | |
482 | ||
483 | if (mic_vnet_mode == VNET_MODE_INTR) { | |
484 | // Remove interrupt handler on doorbell 3 | |
485 | mic_unreg_irqhandler(mic_ctx, 3, "Host DoorBell 3"); | |
486 | ||
487 | destroy_workqueue(veth_info->vi_wq); | |
488 | } | |
489 | ||
490 | micveth.lv_active_clients--; | |
491 | veth_info->vi_state = VETH_STATE_INITIALIZED; | |
492 | ||
493 | if (micveth.lv_active_clients) { | |
494 | mutex_unlock(&micveth.lv_state_mutex); | |
495 | return; | |
496 | } | |
497 | ||
498 | micveth.lv_num_links_remaining = micveth.lv_num_clients; | |
499 | ||
500 | #if PWR_MGMT_NO_POLL_AFTER_LINKS_UP | |
501 | micveth.lv_pollstate = CLIENT_POLL_STOPPED; | |
502 | mutex_unlock(&micveth.lv_state_mutex); | |
503 | #else | |
504 | micveth.lv_pollstate = CLIENT_POLL_STOPPING; | |
505 | mutex_unlock(&micveth.lv_state_mutex); | |
506 | wait_event(micveth.lv_wq, micveth.lv_pollstate == CLIENT_POLL_STOPPED); | |
507 | #endif | |
508 | } | |
509 | ||
510 | #define NO_SRATCHREGREAD_AFTER_CONNECT 1 | |
511 | static void | |
512 | micveth_clientpoll(struct work_struct *work) | |
513 | { | |
514 | micveth_info_t *veth_info; | |
515 | uint32_t transRingHi; | |
516 | uint32_t transRingLo; | |
517 | uint32_t scratch14 = 0; | |
518 | uint32_t scratch15 = 0; | |
519 | int bd; | |
520 | static int enter = 0; | |
521 | ||
522 | if (enter == 0) | |
523 | { | |
524 | printk("micveth is polling\n"); | |
525 | enter = 1; | |
526 | } | |
527 | ||
528 | mutex_lock(&micveth.lv_state_mutex); | |
529 | if (micveth.lv_pollstate == CLIENT_POLL_STOPPING) { | |
530 | micveth.lv_pollstate = CLIENT_POLL_STOPPED; | |
531 | mutex_unlock(&micveth.lv_state_mutex); | |
532 | wake_up(&micveth.lv_wq); | |
533 | return; | |
534 | } | |
535 | ||
536 | // Check for state changes for each board in the system | |
537 | for (bd = 0; bd < micveth.lv_num_clients; bd++) { | |
538 | veth_info = &micveth.lv_info[bd]; | |
539 | ||
540 | // Do not poll boards that have not had the interface started. | |
541 | if (veth_info->vi_state == VETH_STATE_INITIALIZED) { | |
542 | break; | |
543 | } | |
544 | ||
545 | #ifdef NO_SRATCHREGREAD_AFTER_CONNECT | |
546 | if(veth_info->vi_state != VETH_STATE_LINKUP) { | |
547 | #endif | |
548 | scratch14 = readl(veth_info->vi_scratch14); | |
549 | scratch15 = readl(veth_info->vi_scratch15); | |
550 | #ifdef NO_SRATCHREGREAD_AFTER_CONNECT | |
551 | } | |
552 | #endif | |
553 | ||
554 | if (veth_info->vi_state == VETH_STATE_LINKUP) { | |
555 | if (scratch14 == MICVETH_LINK_DOWN_MAGIC) { | |
556 | veth_info->vi_state = VETH_STATE_LINKDOWN; | |
557 | } | |
558 | } else if (veth_info->vi_state == VETH_STATE_LINKDOWN) { | |
559 | if (scratch14 == MICVETH_LINK_UP_MAGIC) { | |
560 | // Write the transfer ring address. | |
561 | transRingHi = (uint32_t)(veth_info->vi_ring.phys >> 32); | |
562 | transRingLo = (uint32_t)(veth_info->vi_ring.phys & 0xffffffff); | |
563 | ||
564 | writel(transRingLo, veth_info->vi_scratch14); | |
565 | writel(transRingHi, veth_info->vi_scratch15); | |
566 | ||
567 | veth_info->vi_state = VETH_STATE_LINKUP; | |
568 | printk("MIC virtual ethernet up for board %d\n", bd); | |
569 | #ifdef MIC_IS_EMULATION | |
570 | printk("Card wrote Magic: It must be UP!\n"); | |
571 | #endif | |
572 | ||
573 | if (mic_vnet_mode == VNET_MODE_POLL) { | |
574 | schedule_delayed_work(&veth_info->vi_poll, | |
575 | msecs_to_jiffies(MICVETH_POLL_TIMER_DELAY)); | |
576 | } | |
577 | ||
578 | micveth.lv_num_links_remaining--; | |
579 | } | |
580 | #ifdef MIC_IS_EMULATION | |
581 | else if (scratch14) { | |
582 | printk("---> 0x%x \n", scratch14); | |
583 | writel(0x0, veth_info->vi_scratch14); | |
584 | } | |
585 | #endif | |
586 | } | |
587 | } | |
588 | ||
589 | mutex_unlock(&micveth.lv_state_mutex); | |
590 | ||
591 | #if PWR_MGMT_NO_POLL_AFTER_LINKS_UP | |
592 | if (micveth.lv_num_links_remaining) | |
593 | #endif | |
594 | schedule_delayed_work(&micveth.lv_poll, msecs_to_jiffies(MICVETH_CLIENT_TIMER_DELAY)); | |
595 | } | |
596 | ||
597 | static int | |
598 | micvnet_host_doorbell_intr_handler(mic_ctx_t *mic_ctx, int doorbell) | |
599 | { | |
600 | micveth_info_t *veth_info; | |
601 | veth_info = &micveth.lv_info[mic_ctx->bi_id]; | |
602 | queue_work(veth_info->vi_wq, &veth_info->vi_bh); | |
603 | return 0; | |
604 | } | |
605 | ||
606 | void | |
607 | micveth_send_intr(micveth_info_t *veth_info) | |
608 | { | |
609 | mic_ctx_t *mic_ctx = veth_info->mic_ctx; | |
610 | mic_send_vnet_intr(mic_ctx); | |
611 | } | |
612 | ||
613 | void | |
614 | _micveth_process_descriptors(micveth_info_t *veth_info) | |
615 | { | |
616 | veth_ring_t *ring = &veth_info->vi_ring.ring; | |
617 | ring_queue_t *rx_queue = &ring->r_rx; | |
618 | ring_queue_t *tx_queue = &ring->r_tx; | |
619 | ring_desc_t *desc; | |
620 | ring_packet_t *packet; | |
621 | struct sk_buff *skb; | |
622 | int receive_skb = 0; | |
623 | int err; | |
624 | ||
625 | if (veth_info->vi_state != VETH_STATE_LINKUP) { | |
626 | return; | |
627 | } | |
628 | ||
629 | spin_lock_bh(&veth_info->vi_rxlock); | |
630 | ||
631 | while (rx_queue->rq_head != rx_queue->rq_tail) { | |
632 | desc = &rx_queue->rq_descs[rx_queue->rq_head]; | |
633 | ||
634 | veth_info->vi_netdev->stats.rx_packets++; | |
635 | veth_info->vi_netdev->stats.rx_bytes += desc->rd_length; | |
636 | ||
637 | packet = &veth_info->vi_rx_desc[rx_queue->rq_head]; | |
638 | ||
639 | skb = packet->pd_skb; | |
640 | skb_put(skb, desc->rd_length); | |
641 | ||
642 | //dump_skb(skb, 0); | |
643 | mic_ctx_unmap_single(veth_to_ctx(veth_info), packet->pd_phys, veth_info->vi_skb_mtu); | |
644 | packet->pd_skb = dev_alloc_skb(veth_info->vi_skb_mtu); | |
645 | packet->pd_phys = mic_ctx_map_single(veth_to_ctx(veth_info), packet->pd_skb->data, | |
646 | veth_info->vi_skb_mtu); | |
647 | desc->rd_phys = packet->pd_phys; | |
648 | desc->rd_length = packet->pd_length; | |
649 | ||
650 | skb->dev = veth_info->vi_netdev; | |
651 | skb->protocol = eth_type_trans(skb, skb->dev); | |
652 | skb->ip_summed = CHECKSUM_NONE; | |
653 | ||
654 | err = netif_receive_skb(skb); | |
655 | /* | |
656 | * Need a general memory barrier between copying the data from | |
657 | * the buffer and updating the head pointer. It's the general | |
658 | * mb() because we're ordering the read of the data with the write. | |
659 | */ | |
660 | mb(); | |
661 | rx_queue->rq_head = (rx_queue->rq_head + 1) % rx_queue->rq_length; | |
662 | receive_skb++; | |
663 | } | |
664 | ||
665 | /* Send intr to TX so that pending SKB's can be freed */ | |
666 | if (receive_skb && mic_vnet_mode == VNET_MODE_INTR) { | |
667 | micveth_send_intr(veth_info); | |
668 | } | |
669 | ||
670 | spin_unlock_bh(&veth_info->vi_rxlock); | |
671 | ||
672 | spin_lock_bh(&veth_info->vi_txlock); | |
673 | ||
674 | // Also handle completed tx requests | |
675 | while (veth_info->vi_pend != tx_queue->rq_head) { | |
676 | desc = &tx_queue->rq_descs[veth_info->vi_pend]; | |
677 | packet = &veth_info->vi_tx_desc[veth_info->vi_pend]; | |
678 | ||
679 | skb = packet->pd_skb; | |
680 | packet->pd_skb = NULL; | |
681 | ||
682 | mic_ctx_unmap_single(veth_to_ctx(veth_info), packet->pd_phys, skb->len); | |
683 | packet->pd_phys = 0; | |
684 | ||
685 | kfree_skb(skb); | |
686 | ||
687 | veth_info->vi_pend = (veth_info->vi_pend + 1) % tx_queue->rq_length; | |
688 | } | |
689 | ||
690 | spin_unlock_bh(&veth_info->vi_txlock); | |
691 | ||
692 | if (mic_vnet_mode == VNET_MODE_POLL) { | |
693 | schedule_delayed_work(&veth_info->vi_poll, msecs_to_jiffies(MICVETH_POLL_TIMER_DELAY)); | |
694 | } | |
695 | } | |
696 | ||
697 | static void | |
698 | micvnet_intr_bh_handler(struct work_struct *work) | |
699 | { | |
700 | micveth_info_t *veth_info = container_of(work, micveth_info_t, vi_bh); | |
701 | _micveth_process_descriptors(veth_info); | |
702 | } | |
703 | ||
704 | static void | |
705 | micveth_poll(struct work_struct *work) | |
706 | { | |
707 | micveth_info_t *veth_info = container_of(work, micveth_info_t, vi_poll.work); | |
708 | ||
709 | _micveth_process_descriptors(veth_info); | |
710 | } | |
711 | ||
712 | static ssize_t | |
713 | show_veth(struct device *dev, struct device_attribute *attr, char *buf) | |
714 | { | |
715 | return snprintf(buf, PAGE_SIZE, "%s\n", | |
716 | micveth.lv_pollstate == CLIENT_POLL_RUNNING ? | |
717 | "running" : "stopped"); | |
718 | } | |
719 | ||
720 | /* | |
721 | VNET driver public API. These are simply wrappers which either invoke the old | |
722 | interrupt/poll mode functions or the new DMA mode functions. These are temporary and | |
723 | will be phased out with the old interrupt/poll mode so only the DMA mode will be around | |
724 | eventually. | |
725 | */ | |
726 | int __init | |
727 | micveth_init(struct device *dev) | |
728 | { | |
729 | printk("vnet: mode: %s, buffers: %d\n", | |
730 | mic_vnet_modes[mic_vnet_mode], vnet_num_buffers); | |
731 | ||
732 | if (mic_vnet_mode == VNET_MODE_DMA) | |
733 | return micvnet_init(dev); | |
734 | /* Intr/poll modes use micveth_init_legacy */ | |
735 | return 0; | |
736 | } | |
737 | ||
738 | int __init | |
739 | micveth_init_legacy(int num_bds, struct device *dev) | |
740 | { | |
741 | if (mic_vnet_mode != VNET_MODE_DMA) | |
742 | return micveth_init_int(num_bds, dev); | |
743 | /* DMA mode uses micveth_init */ | |
744 | return 0; | |
745 | } | |
746 | ||
747 | void | |
748 | micveth_exit(void) | |
749 | { | |
750 | if (mic_vnet_mode == VNET_MODE_DMA) | |
751 | micvnet_exit(); | |
752 | else | |
753 | micveth_exit_int(); | |
754 | } | |
755 | ||
756 | int | |
757 | micveth_probe(mic_ctx_t *mic_ctx) | |
758 | { | |
759 | if (mic_vnet_mode == VNET_MODE_DMA) | |
760 | return micvnet_probe(mic_ctx); | |
761 | /* No support for micveth_probe in legacy intr/poll modes */ | |
762 | return 0; | |
763 | } | |
764 | ||
765 | void | |
766 | micveth_remove(mic_ctx_t *mic_ctx) | |
767 | { | |
768 | if (mic_vnet_mode == VNET_MODE_DMA) | |
769 | micvnet_remove(mic_ctx); | |
770 | /* No support for micveth_remove in legacy intr/poll modes */ | |
771 | } | |
772 | ||
773 | int | |
774 | micveth_start(mic_ctx_t *mic_ctx) | |
775 | { | |
776 | micveth_info_t *veth_info = mic_ctx->bi_vethinfo; | |
777 | int err; | |
778 | ||
779 | if (mic_vnet_mode == VNET_MODE_DMA) | |
780 | err = micvnet_start(mic_ctx); | |
781 | else | |
782 | err = micveth_start_int(mic_ctx); | |
783 | ||
784 | if (!err) | |
785 | netif_carrier_on(veth_info->vi_netdev); | |
786 | ||
787 | return err; | |
788 | } | |
789 | ||
790 | void | |
791 | micveth_stop(mic_ctx_t *mic_ctx) | |
792 | { | |
793 | micveth_info_t *veth_info = mic_ctx->bi_vethinfo; | |
794 | ||
795 | if (mic_vnet_mode == VNET_MODE_DMA) | |
796 | micvnet_stop(mic_ctx); | |
797 | else | |
798 | micveth_stop_int(mic_ctx); | |
799 | ||
800 | if (veth_info) | |
801 | netif_carrier_off(veth_info->vi_netdev); | |
802 | } |