Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / vnet / micveth.c
CommitLineData
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 <linux/ip.h>
37#include <linux/tcp.h>
38#include <linux/list.h>
39
40#include "mic/micveth.h"
41
42#define PWR_MGMT_NO_POLL_AFTER_LINKS_UP 1
43
44/* #define HOST */
45#define SBOX_MMIO_LENGTH (64 * 1024)
46
47/* Host - Card link initialization rotocol
48 * Card comes up and writes MICVETH_LINK_UP_MAGIC to scratch 14 & 15
49 * Host detects that the card side interface is up and writes the
50 * 1) address of the tx/rx descriptor ring buffer to scratch 14 & 15
51 * 2) last 2 octets of the MAC address (allows the host to identify
52 * the board number based on its mac address)
53 */
54
55/* Host - Card descriptor queue/ring buffer (from the perspective of the host)
56 *
57 * There is a transmit and a receive queue. Each queue entry has
58 * a physical address and a length.
59 *
60 * Packet transmission
61 * The host adds a queue entry with the physical address of the skb and its
62 * length and updates the write pointer. The receive side on the card sees the
63 * new entry, allocates a new skb, maps the host's skb, copies it to a locally
64 * allocated skb and updates the read pointer. The host side later frees up skbs
65 * starting from a cached read pointer upto the read pointer
66 *
67 * Packet reception
68 * The host "posts" skbs to the rx queue. The transmit routine on the card
69 * copies its local skb to the host skb, updates the write pointer and frees
70 * its local skb
71 */
72
73/* Vnet interrupts are now functional (with vnet=dma module parameter). In the
74 main flow of the driver all polling in the interrupt mode has been
75 eliminated. However, polling is still happening in clientpoll() routine which
76 tracks if the link is up or down. This can also be replaced by an interrupt
77 driven mechanism which will be done in the future. Apart from this, only
78 limited testing has been done in the interrupt mode, especially with respect
79 to sharing the interrupt with scif. Therefore, for now the default mode of
80 operation is still left as poll in micstart.
81*/
82
83#define SBOX_SDBIC0_DBREQ_BIT 0x80000000
84
85
86#ifdef HOST
87#else
88struct skb_node {
89 struct list_head list;
90 struct sk_buff *skb;
91};
92
93/* List of skbs to be transmitted - global for now assumes KN* has a single interface */
94struct list_head skb_list;
95LIST_HEAD(skb_list);
96#endif
97
98static void _micveth_process_descriptors(micveth_info_t *veth_info);
99
100#ifdef HOST
101#else
102static int micveth_xmit_enqueue(struct sk_buff *skb, struct net_device *dev, micveth_info_t *veth_info);
103static int micveth_xmit_dequeue(struct net_device *dev, micveth_info_t *veth_info);
104static struct sk_buff *dequeue_skb(micveth_info_t *veth_info);
105static void micvnet_tx_dequeue_handler(struct work_struct *work);
106
107int micveth_start(mic_ctx_t *mic_ctx);
108void micveth_stop(mic_ctx_t *mic_ctx);
109static int micveth_start_dev(struct net_device *dev);
110static int micveth_stop_dev(struct net_device *dev);
111#endif
112
113static void micveth_clientpoll(struct work_struct *work);
114static void micveth_poll(struct work_struct *work);
115static irqreturn_t micvnet_host_intr_handler(int irq, void *cookie);
116static void micvnet_intr_bh_handler(struct work_struct *work);
117static void micveth_send_intr(micveth_info_t *veth_info);
118int get_sbox_irq(int index);
119
120#ifdef HOST
121#else
122static mic_ctx_t mic_ctx_g;
123#endif
124
125micveth_t micveth;
126
127static int
128micveth_set_address(struct net_device *dev, void *p)
129{
130 struct sockaddr *sa = p;
131
132 if (!is_valid_ether_addr(sa->sa_data))
133 return -EADDRNOTAVAIL;
134
135 memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
136 return 0;
137}
138
139static void
140micveth_multicast_list(struct net_device *dev)
141{
142}
143
144#ifdef HOST
145#else
146/* Enqueues an skb for transmission. This is necessary because micveth_xmit is called in
147 interrupt context and we cannot call ioremap_nocache from interrupt context. */
148static int
149micveth_xmit_enqueue(struct sk_buff *skb, struct net_device *dev, micveth_info_t *veth_info)
150{
151 struct skb_node *new_node = kmalloc(sizeof(*new_node), GFP_ATOMIC);
152
153 if (!new_node)
154 return ENOMEM;
155 new_node->skb = skb;
156 spin_lock(&veth_info->vi_txlock);
157 list_add_tail(&new_node->list, &skb_list);
158 spin_unlock(&veth_info->vi_txlock);
159 return 0;
160}
161
162/* Dequeues a skb enqueued by micveth_xmit_enqueue */
163static struct sk_buff *
164dequeue_skb(micveth_info_t *veth_info)
165{
166 struct sk_buff *skb = NULL;
167 struct skb_node *skb_node = NULL;
168
169 spin_lock_bh(&veth_info->vi_txlock);
170 if (!list_empty(&skb_list))
171 {
172 skb_node = list_entry(skb_list.next, struct skb_node , list);
173 list_del(&skb_node->list);
174 skb = skb_node->skb;
175 }
176 spin_unlock_bh(&veth_info->vi_txlock);
177
178 if (skb_node)
179 kfree(skb_node);
180 return skb;
181}
182
183/* Transmits skbs that have been enqueued by the by micveth_xmit_enqueue */
184static int
185micveth_xmit_dequeue(struct net_device *dev, micveth_info_t *veth_info)
186{
187 veth_ring_t *ring;
188 ring_queue_t *tx_queue;
189 ring_desc_t *desc;
190 int next_tail;
191 void *dst;
192 struct sk_buff *skb;
193
194 while ((skb = dequeue_skb(veth_info))) {
195 ring = veth_info->ring_ptr;
196 tx_queue = &ring->r_rx;
197
198 next_tail = (tx_queue->rq_tail + 1) % tx_queue->rq_length;
199 if (next_tail == tx_queue->rq_head) {
200 printk(KERN_WARNING "dropping packet\n");
201 /* queue_full situation - just drop the packet and let the stack retry */
202 return 1;
203 }
204
205 desc = &tx_queue->rq_descs[tx_queue->rq_tail];
206 dst = ioremap_nocache(desc->rd_phys, skb->len);
207 if (!dst) {
208 tx_queue->rq_tail = (tx_queue->rq_tail + 1) % tx_queue->rq_length;
209 dev_kfree_skb(skb);
210 dev->stats.tx_dropped++;
211 continue;
212 }
213 desc->rd_length = skb->len;
214 desc->rd_valid = 1;
215 memcpy(dst, skb->data, skb->len);
216 /*
217 * Need a write memory barrier between copying the skb data to
218 * the buffer and updating the tail pointer. NOT an smp_wmb(),
219 * because this memory barrier needs to be done even if there is
220 * a single CPU in the system.
221 *
222 * No need for the serializing request (Si bug workaround in
223 * KNF), since the buffer exists in host memory. If the buffer
224 * lives in card memory, and this code is running on the host, we
225 * would need extra barriers and a "serializing request" on any write.
226 */
227 wmb();
228 tx_queue->rq_tail = (tx_queue->rq_tail + 1) % tx_queue->rq_length;
229 iounmap(dst);
230 dev_kfree_skb(skb);
231
232 if (mic_vnet_mode == VNET_MODE_INTR) {
233 micveth_send_intr(veth_info);
234 }
235 }
236
237 return 0;
238}
239
240static void
241micvnet_tx_dequeue_handler(struct work_struct *work)
242{
243 micveth_info_t *veth_info = container_of(work, micveth_info_t, vi_txws);
244 struct net_device *dev_veth = veth_info->vi_netdev;
245
246 micveth_xmit_dequeue(dev_veth, veth_info);
247}
248#endif
249
250#ifdef HOST
251#else // card
252/* Transmit callback */
253static int
254micveth_xmit(struct sk_buff *skb, struct net_device *dev)
255{
256 micveth_info_t *veth_info;
257
258 if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) {
259 kfree_skb(skb);
260 dev->stats.tx_dropped++;
261 return NETDEV_TX_OK;
262 }
263
264 dev->stats.tx_packets++;
265 dev->stats.tx_bytes += skb->len;
266
267 veth_info = &micveth.lv_info[0];
268 if (veth_info->vi_state == VETH_STATE_LINKUP) {
269 if (micveth_xmit_enqueue(skb, dev, veth_info)) {
270 dev_kfree_skb(skb);
271 dev->stats.tx_dropped++;
272 }
273 } else {
274 dev_kfree_skb(skb);
275 }
276
277 /* Reuse the interrupt workqueue to also queue tx dequeue tasks */
278 queue_work(veth_info->vi_wq, &veth_info->vi_txws);
279
280 return NETDEV_TX_OK;
281}
282#endif
283
284static int
285micveth_change_mtu(struct net_device *dev, int new_mtu)
286{
287 dev->mtu = new_mtu;
288 return 0;
289}
290
291
292/* Start callback */
293static int
294micveth_start_dev(struct net_device *dev)
295{
296 micveth_info_t *veth_info = dev->ml_priv;
297
298 micveth_start(veth_info->mic_ctx);
299 return 0;
300}
301
302/* Stop callback */
303static int
304micveth_stop_dev(struct net_device *dev)
305{
306 micveth_info_t *veth_info = dev->ml_priv;
307
308 micveth_stop(veth_info->mic_ctx);
309 return 0;
310}
311
312#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
313static const struct net_device_ops veth_netdev_ops = {
314 .ndo_open = micveth_start_dev,
315 .ndo_stop = micveth_stop_dev,
316 .ndo_start_xmit = micveth_xmit,
317 .ndo_validate_addr = eth_validate_addr,
318 .ndo_set_multicast_list = micveth_multicast_list,
319 .ndo_set_mac_address = micveth_set_address,
320 .ndo_change_mtu = micveth_change_mtu,
321};
322#endif
323
324static void
325micveth_setup(struct net_device *dev)
326{
327#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
328 dev->hard_start_xmit = micveth_xmit;
329 dev->set_multicast_list = micveth_multicast_list;
330 dev->set_mac_address = micveth_set_address;
331#endif
332 ether_setup(dev);
333
334 /* Initialize the device structure. */
335#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
336 dev->netdev_ops = &veth_netdev_ops;
337#endif
338 dev->destructor = free_netdev;
339
340 /* Fill in device structure with ethernet-generic values. */
341 dev->mtu = (MICVETH_MAX_PACKET_SIZE);
342 dev->tx_queue_len = 0;
343 dev->flags &= ~IFF_MULTICAST;
344 random_ether_addr(dev->dev_addr);
345}
346
347static int
348micveth_validate(struct nlattr *tb[], struct nlattr *data[])
349{
350 if (tb[IFLA_ADDRESS]) {
351 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
352 return -EINVAL;
353 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
354 return -EADDRNOTAVAIL;
355 }
356 return 0;
357}
358
359static struct rtnl_link_ops micveth_link_ops __read_mostly = {
360 .kind = "micveth",
361 .setup = micveth_setup,
362 .validate = micveth_validate,
363};
364
365static int
366micveth_probe_int(micveth_info_t *veth_info, mic_ctx_t *mic_ctx)
367{
368 struct net_device *dev_veth;
369 int err = 0;
370
371 veth_info->vi_sbox = ioremap_nocache(SBOX_BASE, SBOX_MMIO_LENGTH);
372 veth_info->vi_scratch14 = (uint32_t *)(veth_info->vi_sbox + SBOX_SCRATCH14);
373 veth_info->vi_scratch15 = (uint32_t *)(veth_info->vi_sbox + SBOX_SCRATCH14);
374 writel(0x55, veth_info->vi_sbox + SBOX_DCR);
375
376 veth_info->mic_ctx = mic_ctx;
377 mic_ctx->bi_vethinfo = (void *)veth_info;
378
379 spin_lock_init(&veth_info->vi_txlock);
380 spin_lock_init(&veth_info->vi_rxlock);
381
382 if (mic_vnet_mode == VNET_MODE_POLL)
383 INIT_DELAYED_WORK(&veth_info->vi_poll, micveth_poll);
384
385 snprintf(veth_info->vi_wqname, sizeof(veth_info->vi_wqname),
386 "VNET INTR %d", 0);
387 veth_info->vi_wq = create_singlethread_workqueue(veth_info->vi_wqname);
388 INIT_WORK(&veth_info->vi_txws, micvnet_tx_dequeue_handler);
389
390 if (mic_vnet_mode == VNET_MODE_INTR) {
391 if ((err = request_irq(get_sbox_irq(VNET_SBOX_INT_IDX),
392 micvnet_host_intr_handler, IRQF_DISABLED,
393 "micveth intr", veth_info))) {
394 printk(KERN_ERR "%s: interrupt registration failed\n", __func__);
395 return err;
396 }
397 INIT_WORK(&veth_info->vi_bh, micvnet_intr_bh_handler);
398 }
399
400 // Set the current sk_buff allocation size
401 veth_info->vi_skb_mtu = MICVETH_MAX_PACKET_SIZE + 32;
402
403#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
404 if ((dev_veth = alloc_netdev(sizeof(micveth_info_t), "mic%d", micveth_setup)) == NULL) {
405#else
406 if ((dev_veth = alloc_netdev(sizeof(micveth_info_t), "mic%d", NET_NAME_UNKNOWN, micveth_setup)) == NULL) {
407#endif
408 return -ENOMEM;
409 }
410
411 veth_info->vi_netdev = dev_veth;
412 dev_veth->ml_priv = veth_info;
413 dev_veth->rtnl_link_ops = &micveth_link_ops;
414
415 if ((err = register_netdev(dev_veth)) < 0) {
416 printk("register netdev failed %d\n", err);
417 free_netdev(dev_veth);
418 return err;
419 }
420
421 veth_info->vi_state = VETH_STATE_INITIALIZED;
422
423 /* Inform host after completing initialization */
424 printk("%s: writing magic to SC14 and SC15\n", __FUNCTION__);
425 writel(MICVETH_LINK_UP_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH14);
426 writel(MICVETH_LINK_UP_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH15);
427
428 return 0;
429}
430
431void
432micveth_remove_int(mic_ctx_t *mic_ctx)
433{
434 micveth_stop(mic_ctx);
435}
436
437static int __init
438micveth_create_int(int num_bds, struct device *dev)
439{
440 int bd;
441 int err = 0;
442
443 printk("micveth_init(%d)\n", num_bds);
444
445 micveth.lv_num_interfaces = num_bds;
446 micveth.lv_num_clients = num_bds;
447 micveth.lv_active_clients = 0;
448 micveth.lv_num_links_remaining = num_bds;
449
450 if ((err = rtnl_link_register(&micveth_link_ops))) {
451 printk(KERN_ERR "%s: rtnl_link_register failed!\n", __func__);
452 return err;
453 }
454
455 // Allocate space for the control of each device in the system.
456 micveth.lv_info = kmalloc(sizeof(micveth_info_t) * num_bds, GFP_KERNEL);
457 if (!micveth.lv_info) {
458 printk(KERN_ERR "%s: micveth_info alloc failed!\n", __func__);
459 return -ENOMEM;
460 }
461
462 // Initialize state mutex. Overloaded use for several fields.
463 mutex_init(&micveth.lv_state_mutex);
464
465 // Setup of timer for probeing active mic clients. When the total active board
466 // count is zero the poll is not running.
467 micveth.lv_pollstate = CLIENT_POLL_STOPPED;
468 INIT_DELAYED_WORK(&micveth.lv_poll, micveth_clientpoll);
469 init_waitqueue_head(&micveth.lv_wq);
470
471 // Init each of the existing boards.
472 for (bd = 0; bd < num_bds; bd++) {
473#ifdef HOST
474 micveth_probe_int(&micveth.lv_info[bd], &mic_data.dd_bi[bd]->bi_ctx);
475#else
476 micveth_probe_int(&micveth.lv_info[bd], &mic_ctx_g);
477#endif
478 }
479
480 return err;
481}
482
483static void
484micveth_exit_int(void)
485{
486 micveth_info_t *veth_info = &micveth.lv_info[0];
487#ifdef HOST
488#endif
489 micveth_stop(veth_info->mic_ctx);
490
491 destroy_workqueue(veth_info->vi_wq);
492 rtnl_link_unregister(&micveth_link_ops);
493
494#ifdef HOST
495#else // card
496 iounmap((void *)veth_info->ring_ptr);
497 iounmap(veth_info->vi_sbox);
498#endif
499
500 kfree(micveth.lv_info);
501}
502
503/* Card side - tell the host that the interface is up */
504static int
505micveth_start_int(mic_ctx_t *mic_ctx)
506{
507 micveth_info_t *veth_info = &micveth.lv_info[mic_ctx->bi_id];
508
509 // Eventuall (very soon) most of the descriptor allocation for a board will be done here
510 if (veth_info->vi_state != VETH_STATE_INITIALIZED)
511 return 0;
512
513 mutex_lock(&micveth.lv_state_mutex);
514
515 if (micveth.lv_pollstate == CLIENT_POLL_STOPPED) {
516 schedule_delayed_work(&micveth.lv_poll, msecs_to_jiffies(MICVETH_CLIENT_TIMER_DELAY));
517 micveth.lv_pollstate = CLIENT_POLL_RUNNING;
518 }
519
520 micveth.lv_active_clients++;
521 mutex_unlock(&micveth.lv_state_mutex);
522
523 veth_info->vi_state = VETH_STATE_LINKDOWN;
524
525 return 0;
526}
527
528/* Card side - tell the host that the interface is down */
529static void
530micveth_stop_int(mic_ctx_t *mic_ctx)
531{
532 micveth_info_t *veth_info = (micveth_info_t *)(mic_ctx->bi_vethinfo);
533
534 if (veth_info->vi_state == VETH_STATE_INITIALIZED)
535 return;
536
537 mutex_lock(&micveth.lv_state_mutex);
538 micveth.lv_active_clients--;
539 veth_info->vi_state = VETH_STATE_INITIALIZED;
540
541 if (micveth.lv_active_clients) {
542 mutex_unlock(&micveth.lv_state_mutex);
543 return;
544 }
545
546 micveth.lv_num_links_remaining = micveth.lv_num_clients;
547
548#if PWR_MGMT_NO_POLL_AFTER_LINKS_UP
549 micveth.lv_pollstate = CLIENT_POLL_STOPPED;
550 mutex_unlock(&micveth.lv_state_mutex);
551#else
552 micveth.lv_pollstate = CLIENT_POLL_STOPPING;
553 mutex_unlock(&micveth.lv_state_mutex);
554 wait_event(micveth.lv_wq, micveth.lv_pollstate == CLIENT_POLL_STOPPED);
555#endif
556
557#ifdef HOST
558#else // card
559 writel(MICVETH_LINK_DOWN_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH14);
560 writel(MICVETH_LINK_DOWN_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH15);
561#endif
562}
563
564#ifdef HOST
565#else // card
566/* Link detection */
567static void
568micveth_clientpoll(struct work_struct *work)
569{
570 micveth_info_t *veth_info;
571 mic_ctx_t *mic_ctx;
572 uint32_t scratch14;
573 uint32_t scratch15;
574 struct net_device *dev_veth;
575 veth_info = &micveth.lv_info[0];
576 dev_veth = veth_info->vi_netdev;
577 mic_ctx = veth_info->mic_ctx;
578 mutex_lock(&micveth.lv_state_mutex);
579
580 if (micveth.lv_pollstate == CLIENT_POLL_STOPPING) {
581 micveth.lv_pollstate = CLIENT_POLL_STOPPED;
582 mutex_unlock(&micveth.lv_state_mutex);
583 wake_up(&micveth.lv_wq);
584 return;
585 }
586
587 if (veth_info->vi_state == VETH_STATE_LINKUP) {
588 scratch14 = readl(veth_info->vi_sbox + SBOX_SCRATCH14);
589 scratch15 = readl(veth_info->vi_sbox + SBOX_SCRATCH15);
590
591 if ((MICVETH_LINK_DOWN_MAGIC == scratch14) &&
592 (MICVETH_LINK_DOWN_MAGIC == scratch15)) {
593 veth_info->vi_state = VETH_STATE_LINKDOWN;
594 }
595 } else {
596 scratch14 = readl(veth_info->vi_sbox + SBOX_SCRATCH14);
597 scratch15 = readl(veth_info->vi_sbox + SBOX_SCRATCH15);
598
599 if ((MICVETH_LINK_UP_MAGIC != scratch14) &&
600 (MICVETH_LINK_UP_MAGIC != scratch15)) {
601 printk("micveth_clientpoll(): SC14 and SC15 changed from MAGIC, I got the RB addresses!\n");
602 writel(MICVETH_LINK_UP_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH14);
603 writel(MICVETH_LINK_UP_MAGIC, veth_info->vi_sbox + SBOX_SCRATCH15);
604 dev_veth->dev_addr[4] = (scratch15 >> 24) & 0xff;
605 dev_veth->dev_addr[5] = (scratch15 >> 16) & 0xff;
606 veth_info->vi_ring.phys = ((uint64_t)(scratch15 & 0xffff) << 32) | scratch14;
607 veth_info->vi_ring.phys |= (1ULL << 39);
608 veth_info->vi_ring.length = sizeof(veth_ring_t);
609 veth_info->ring_ptr = ioremap_nocache(veth_info->vi_ring.phys, veth_info->vi_ring.length);
610 BUG_ON(veth_info->ring_ptr == NULL);
611
612 printk("micveth_clientpoll(): VETH_STATE_LINKUP\n");
613 veth_info->vi_state = VETH_STATE_LINKUP;
614 if (mic_vnet_mode == VNET_MODE_POLL) {
615 printk("micveth_clientpoll(): poll for work now !!\n");
616 schedule_delayed_work(&veth_info->vi_poll, msecs_to_jiffies(MICVETH_POLL_TIMER_DELAY));
617 }
618
619 micveth.lv_num_links_remaining--;
620 }
621 }
622 mutex_unlock(&micveth.lv_state_mutex);
623
624#if PWR_MGMT_NO_POLL_AFTER_LINKS_UP
625 if (micveth.lv_num_links_remaining)
626#endif
627 schedule_delayed_work(&micveth.lv_poll, msecs_to_jiffies(MICVETH_CLIENT_TIMER_DELAY));
628}
629#endif
630extern struct sk_buff *jsp_dbg1;
631
632#ifdef HOST
633#else // card
634static irqreturn_t
635micvnet_host_intr_handler(int irq, void *cookie)
636{
637 micveth_info_t *veth_info = cookie;
638 queue_work(veth_info->vi_wq, &veth_info->vi_bh);
639 return IRQ_HANDLED;
640}
641
642/* Ring host doorbell 3 interrupt */
643static void
644micveth_send_intr(micveth_info_t *veth_info)
645{
646 uint32_t db_reg;
647
648 // Ring host doorbell 3 interrupt
649 db_reg = readl(veth_info->vi_sbox + SBOX_SDBIC3) | SBOX_SDBIC0_DBREQ_BIT;
650 writel(db_reg, veth_info->vi_sbox + SBOX_SDBIC3);
651}
652
653static void
654_micveth_process_descriptors(micveth_info_t *veth_info)
655{
656 veth_ring_t *ring = veth_info->ring_ptr;
657 ring_queue_t *rx_queue = &ring->r_tx;
658 ring_desc_t desc;
659 struct sk_buff *skb;
660 void *pkt;
661 int receive_skb = 0;
662 int err;
663
664 if (veth_info->vi_state != VETH_STATE_LINKUP) {
665 return;
666 }
667
668 spin_lock(&veth_info->vi_rxlock);
669
670 while (rx_queue->rq_head != rx_queue->rq_tail) {
671 desc = rx_queue->rq_descs[rx_queue->rq_head];
672
673 veth_info->vi_netdev->stats.rx_packets++;
674 veth_info->vi_netdev->stats.rx_bytes += desc.rd_length;
675
676 pkt = ioremap_nocache(desc.rd_phys, desc.rd_length);
677 if (pkt == NULL) {
678 veth_info->vi_netdev->stats.rx_dropped++;
679 goto update_ring;
680 }
681
682 /* handle jumbo frame */
683 if (desc.rd_length > ETH_DATA_LEN)
684 skb = dev_alloc_skb(veth_info->vi_skb_mtu);
685 else
686 skb = dev_alloc_skb(ETH_DATA_LEN + 32);
687 if (skb == NULL) {
688 veth_info->vi_netdev->stats.rx_dropped++;
689 iounmap(pkt);
690 goto update_ring;
691 }
692
693 memcpy(skb_put(skb,desc.rd_length), pkt, desc.rd_length);
694 iounmap(pkt);
695 skb->dev = veth_info->vi_netdev;
696 skb->protocol = eth_type_trans(skb, skb->dev);
697 skb->ip_summed = CHECKSUM_NONE;
698 local_bh_disable();
699 err = netif_receive_skb(skb);
700 err = err;
701 local_bh_enable();
702 /*
703 * Need a general memory barrier between copying the data from
704 * the buffer and updating the head pointer. It's the general
705 * mb() because we're ordering the read of the data with the write.
706 *
707 * No need for the serializing request (Si bug workaround in
708 * KNF), since the buffer exists in host memory. If the buffer
709 * lives in card memory, and this code is running on the host, we
710 * would need extra barriers and a "serializing request" on any write.
711 */
712 mb();
713update_ring:
714 rx_queue->rq_head = (rx_queue->rq_head + 1) % rx_queue->rq_length;
715 receive_skb++;
716 }
717
718 /* Send intr to TX so that pending SKB's can be freed */
719 if (receive_skb && mic_vnet_mode == VNET_MODE_INTR) {
720 micveth_send_intr(veth_info);
721 }
722
723 spin_unlock(&veth_info->vi_rxlock);
724
725 if (mic_vnet_mode == VNET_MODE_POLL) {
726 schedule_delayed_work(&veth_info->vi_poll, msecs_to_jiffies(MICVETH_POLL_TIMER_DELAY));
727 }
728}
729
730static void
731micvnet_intr_bh_handler(struct work_struct *work)
732{
733 micveth_info_t *veth_info = container_of(work, micveth_info_t, vi_bh);
734 _micveth_process_descriptors(veth_info);
735}
736
737static void
738micveth_poll(struct work_struct *work)
739{
740 micveth_info_t *veth_info = container_of(work, micveth_info_t, vi_poll.work);
741
742 _micveth_process_descriptors(veth_info);
743}
744
745#endif
746
747#ifdef HOST
748#else // card
749static int __init
750micveth_module_init_int(void)
751{
752 mic_ctx_t *mic_ctx = &mic_ctx_g;
753 int ret = 0;
754
755 printk("micveth_probe()\n");
756 memset(mic_ctx, 0, sizeof(*mic_ctx));
757 mic_ctx->bi_id = 0;
758
759 if ((ret = micveth_init(NULL)))
760 return ret;
761 if ((ret = micveth_init_legacy(1, NULL)))
762 return ret;
763
764 return 0;
765}
766
767static void __exit
768micveth_module_exit_int(void)
769{
770 micveth_exit();
771}
772#endif
773
774/*
775 VNET driver public API. These are simply wrappers which either invoke the old
776 interrupt/poll mode functions or the new DMA mode functions. These are temporary and
777 will be phased out with the old interrupt/poll mode so only the DMA mode will be around
778 eventually.
779 */
780int __init
781micveth_init(struct device *dev)
782{
783 if (mic_vnet_mode == VNET_MODE_DMA)
784 return micvnet_init(dev);
785 /* Intr/poll modes use micveth_init_legacy */
786 return 0;
787}
788
789int __init
790micveth_init_legacy(int num_bds, struct device *dev)
791{
792 if (mic_vnet_mode != VNET_MODE_DMA)
793 return micveth_create_int(num_bds, dev);
794 /* DMA mode uses micveth_create */
795 return 0;
796}
797
798void
799micveth_exit(void)
800{
801 if (mic_vnet_mode == VNET_MODE_DMA)
802 micvnet_exit();
803 else
804 micveth_exit_int();
805}
806
807int
808micveth_probe(mic_ctx_t *mic_ctx)
809{
810 if (mic_vnet_mode == VNET_MODE_DMA)
811 return micvnet_probe(mic_ctx);
812 /* No support for micveth_probe in legacy intr/poll modes */
813 return 0;
814}
815
816void
817micveth_remove(mic_ctx_t *mic_ctx)
818{
819 if (mic_vnet_mode == VNET_MODE_DMA)
820 micvnet_remove(mic_ctx);
821 /* No support for micveth_remove in legacy intr/poll modes */
822}
823
824int
825micveth_start(mic_ctx_t *mic_ctx)
826{
827 if (mic_vnet_mode == VNET_MODE_DMA)
828 return micvnet_start(mic_ctx);
829 else
830 return micveth_start_int(mic_ctx);
831}
832
833void
834micveth_stop(mic_ctx_t *mic_ctx)
835{
836 if (mic_vnet_mode == VNET_MODE_DMA)
837 micvnet_stop(mic_ctx);
838 else
839 micveth_stop_int(mic_ctx);
840}
841
842static int __init
843micveth_module_init(void)
844{
845 printk("vnet: mode: %s, buffers: %d\n",
846 mic_vnet_modes[mic_vnet_mode], vnet_num_buffers);
847
848 if (mic_vnet_mode == VNET_MODE_DMA)
849 return micvnet_module_init();
850 else
851 return micveth_module_init_int();
852}
853
854static void __exit
855micveth_module_exit(void)
856{
857 if (mic_vnet_mode == VNET_MODE_DMA)
858 micvnet_module_exit();
859 else
860 micveth_module_exit_int();
861}
862
863#ifdef HOST
864#else // card
865module_init(micveth_module_init);
866module_exit(micveth_module_exit);
867
868MODULE_LICENSE("GPL");
869#endif