2 * Copyright (c) 2007-2011, ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
14 #include <barrelfish/barrelfish.h>
15 #include <barrelfish/nameservice_client.h>
16 #include <barrelfish/deferred.h>
17 #include <barrelfish/debug.h>
20 // TODO only required for htonl
24 #include <if/sfn5122f_defs.h>
25 #include <if/sfn5122f_devif_defs.h>
26 #include <if/net_filter_defs.h>
29 #include "sfn5122f_debug.h"
30 #include "buffer_tbl.h"
38 struct sfn5122f_devif_binding *devif;
39 struct capref tx_frame;
40 struct capref rx_frame;
41 struct capref ev_frame;
49 // first entries of the buffer table to make up queue
60 static bool use_msix = false;
61 static const char *service_name = "sfn5122f";
62 static sfn5122f_t *d = NULL;
64 //static sfn5122f_msix_t *d_msix = NULL;
65 static uint64_t d_mac[2];
66 static int initialized = 0;
67 static struct capref *regframe;
69 static struct capref int_ker;
70 static void* int_ker_virt;
72 static struct capref mac_stats;
73 static void* mac_virt;
74 static uint64_t mac_phys;
78 static uint32_t cap[2];
79 static uint32_t speed[2];
80 static uint32_t flags[2];
81 static uint32_t fcntl [2];
84 static uint32_t phy_caps[2];
85 static uint32_t phy_flags[2];
86 static uint32_t phy_media[2];
87 /* Loopback mode none and speed */
88 static uint32_t phy_loopback_mode = 0;
89 //static uint32_t phy_loopback_speed = 0;
91 static uint32_t wol_filter_id = 0;
93 static bool csum_offload = 1;
95 static uint32_t rx_indir_tbl[128];
98 static struct queue_state queues[1024];
99 /* PCI device address passed on command line */
100 static uint32_t pci_bus = PCI_DONT_CARE;
101 static uint32_t pci_device = PCI_DONT_CARE;
102 static uint32_t pci_vendor = PCI_DONT_CARE;
103 static uint32_t pci_devid = PCI_DONT_CARE;
104 static uint32_t pci_function = 0;
106 static struct bmallocator msix_alloc;
107 static size_t cdriver_msix = -1;
108 static uint8_t cdriver_vector;
110 static bool use_interrupt = true;
112 // first to start everything
113 static bool first = 1;
116 uint8_t rx_hash_key[40];
121 enum filter_type_ip {
130 enum filter_type_mac {
137 struct sfn5122f_filter_ip {
154 struct sfn5122f_filter_mac {
171 /* scatter and rss enable */
172 static bool rss_en = 0;
173 static bool scatter_en = 0;
174 static struct sfn5122f_filter_ip filters_rx_ip[NUM_FILTERS_IP];
175 //static struct sfn5122f_filter_ip filters_tx_ip[NUM_FILTERS_IP];
178 static struct sfn5122f_filter_mac filters_rx_ip[NUM_FILTERS_MAC];
179 static struct sfn5122f_filter_mac filters_tx_ip[NUM_FILTERS_MAC];
183 /******************************************************************************/
186 static void device_init(void);
187 static void start_all(void);
188 static void probe_all(void);
189 static uint32_t init_txq(uint16_t n, lpaddr_t phys, bool csum, bool userspace);
190 static uint32_t init_rxq(uint16_t n, lpaddr_t phys, bool userspace);
191 static uint32_t init_evq(uint16_t n, lpaddr_t phys, bool interrupt);
192 static void queue_hw_stop(uint16_t n);
194 static void setup_interrupt(size_t *msix_index, uint8_t core, uint8_t vector);
195 static void global_interrupt_handler(void* arg);
197 /***************************************************************************/
200 static void sfn5122f_filter_port_setup(int idx, struct sfn5122f_filter_ip* filter)
202 sfn5122f_rx_filter_tbl_lo_t filter_lo = 0;
203 sfn5122f_rx_filter_tbl_hi_t filter_hi = 0;
205 if (filter->type_ip == net_filter_PORT_UDP) {
207 // Add destination IP
208 filter_hi = sfn5122f_rx_filter_tbl_hi_dest_ip_insert(filter_hi,
210 filter_lo = sfn5122f_rx_filter_tbl_lo_src_ip_insert(filter_lo,
212 filter_hi = sfn5122f_rx_filter_tbl_hi_tcp_udp_insert(filter_hi, 1);
213 filter_lo = sfn5122f_rx_filter_tbl_lo_src_tcp_dest_udp_insert(
214 filter_lo, filter->dst_port);
216 filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, 0);
217 filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, 0);
218 DEBUG("UPD filter index %d: ip_dst %x port_dst %d ip_src %x port_src %d"
220 idx, filter->dst_ip, filter->dst_port,
221 filter->src_ip, filter->src_port, filter->queue);
224 if (filter->type_ip == net_filter_PORT_TCP) {
225 // Add dst IP and port
226 filter_hi = sfn5122f_rx_filter_tbl_hi_dest_ip_insert(filter_hi,
228 filter_lo = sfn5122f_rx_filter_tbl_lo_src_ip_insert(filter_lo,
230 filter_lo = sfn5122f_rx_filter_tbl_lo_dest_port_tcp_insert(filter_lo,
232 filter_hi = sfn5122f_rx_filter_tbl_hi_tcp_udp_insert(filter_hi, 0);
233 filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, 0);
234 filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, 0);
235 DEBUG("TCP filter index %d: ip_dst %x port_dst %d ip_src %x port_src %d"
237 idx, filter->dst_ip, filter->dst_port,
238 filter->src_ip, filter->src_port, filter->queue);
241 filter_hi = sfn5122f_rx_filter_tbl_hi_rxq_id_insert(filter_hi, filter->queue);
242 filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, rss_en);
243 filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, scatter_en);
245 sfn5122f_rx_filter_tbl_lo_wr(d, idx, filter_lo);
246 sfn5122f_rx_filter_tbl_hi_wr(d, idx, filter_hi);
249 static uint32_t build_key(struct sfn5122f_filter_ip* f)
251 uint32_t data[4] = {0,0,0,0};
259 if (f->type_ip == net_filter_PORT_UDP) {
269 data[0] = host1 << 16 | port1;
270 data[1] = port2 << 16 | host1 >> 16;
273 return data[0] ^ data[1] ^ data[2] ^ data[3];
276 static uint16_t filter_hash(uint32_t key)
280 /* First 16 rounds */
281 tmp = 0x1fff ^ key >> 16;
282 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
283 tmp = tmp ^ tmp >> 9;
285 tmp = tmp ^ tmp << 13 ^ key;
286 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
287 return tmp ^ tmp >> 9;
291 static bool filter_equals(struct sfn5122f_filter_ip* f1,
292 struct sfn5122f_filter_ip* f2)
294 if (f1->type_ip != f2->type_ip) {
296 } else if ((f1->src_ip != f2->src_ip) ||
297 (f1->dst_ip != f2->dst_ip) ||
298 (f1->queue != f2->queue)) {
300 } else if ((f1->src_port != f2->src_port) &&
301 (f2->dst_port != f1->dst_port)) {
308 static uint16_t filter_increment(uint32_t key)
313 static int ftqf_alloc(struct sfn5122f_filter_ip* f)
315 // Documentation suggest hashing using a certain algorithm
318 unsigned int incr = 0;
321 hash = filter_hash(key);
322 incr = filter_increment(key);
324 key = hash & (NUM_FILTERS_IP - 1);
327 if (filters_rx_ip[key].enabled == false) {
335 key = (key + incr) & (NUM_FILTERS_IP - 1);
342 static errval_t reg_port_filter(struct sfn5122f_filter_ip* f, uint64_t* fid)
346 DEBUG("reg_port_filter: called\n");
348 if ((filt_ind=ftqf_alloc(f)) < 0) {
349 return FILTER_ERR_NOT_ENOUGH_MEMORY;
352 filters_rx_ip[filt_ind] = *f;
353 filters_rx_ip[filt_ind].enabled = true;
355 sfn5122f_filter_port_setup(filt_ind, f);
364 /***************************************************************************/
365 /* Helper functions*/
366 static void decode_link(uint32_t fcntl1 , uint32_t flags1 , uint32_t speed1)
370 DEBUG("LINK MODE: AUTO \n");
373 DEBUG("LINK MODE: RX/TX \n");
376 DEBUG("LINK MODE: RESPOND \n");
379 DEBUG("LINK MODE: NONE \n");
382 DEBUG("LINK SPEED: %"PRIu32" \n", speed1);
383 DEBUG("LINK FLAGS: %8lX \n", (long unsigned int) flags1);
384 if (!!(flags1 & 1)) {
385 DEBUG("LINK IS UP \n");
388 if (!!(flags1 & 1 << 0x1)) {
389 DEBUG("LINK IS FULL DUPLEX \n");
394 static void handle_assertions(void)
401 memset(in, 0, sizeof(in));
402 in[CMD_GET_ASSERTS_IN_CLEAR_OFFSET] = 0;
404 err = mcdi_rpc(CMD_GET_ASSERTS, in , CMD_GET_ASSERTS_IN_LEN, out,
405 CMD_GET_ASSERTS_OUT_LEN, &outlen, pci_function, d);
406 assert(err_is_ok(err));
409 /* TODO handle assertions */
410 printf("THERE WERE ASSERTIONS: %"PRIu8" \n ", out[0]);
411 /* exit assertions -> special reboot*/
413 err = mcdi_rpc(CMD_REBOOT, in, CMD_REBOOT_IN_LEN ,
414 NULL, 0, NULL, pci_function, d);
415 assert(err_is_ok(err));
420 /* Get Link and write settings into global variables */
421 static void get_link(uint8_t port)
423 uint8_t out[CMD_GET_LINK_OUT_LEN];
426 err = mcdi_rpc(CMD_GET_LINK, NULL, 0 , out, CMD_GET_LINK_OUT_LEN, NULL, port,d);
427 assert(err_is_ok(err));
429 memcpy(&cap[port], out, 4);
430 memcpy(&speed[port], out+CMD_GET_LINK_OUT_SPEED_OFFSET, 4);
431 memcpy(&fcntl[port], out+CMD_GET_LINK_OUT_FCNTL_OFFSET, 4);
432 memcpy(&flags[port], out+CMD_GET_LINK_OUT_FLAGS_OFFSET, 4);
434 decode_link(fcntl[port], flags[port], speed[port]);
440 static void init_port(uint8_t port)
442 uint8_t in[CMD_SET_MAC_IN_LEN];
446 memcpy(in + CMD_SET_MAC_IN_ADR_OFFSET, &d_mac[port], 6 );
447 /* linux driver sets these bits */
452 memcpy(in + CMD_SET_MAC_IN_MTU_OFFSET , ®, 4);
454 in[CMD_SET_MAC_IN_DRAIN_OFFSET] = 0;
455 /* Reject unicast packets? */
456 in[CMD_SET_MAC_IN_REJECT_OFFSET] = 1;
457 /* Set wanted flow control of the card 2 -> bidirectional*/
458 in[CMD_SET_MAC_IN_FCTNL_OFFSET] = 2;
459 err = mcdi_rpc(CMD_SET_MAC, in, CMD_SET_MAC_IN_LEN, NULL, 0, NULL, port, d);
460 assert(err_is_ok(err));
462 memset(mc_hash, 0, sizeof(mc_hash));
463 err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
464 NULL, 0 , NULL, port, d);
465 assert(err_is_ok(err));
467 memset(in, 0 , sizeof(in));
468 memcpy(in + CMD_SET_LINK_IN_CAP_OFFSET, &cap[pci_function], 4);
470 err = mcdi_rpc(CMD_SET_LINK, in, CMD_SET_LINK_IN_LEN, NULL, 0, NULL, 0, d);
471 assert(err_is_ok(err));
474 static void start_port(uint8_t port)
476 uint8_t in[CMD_SET_MAC_IN_LEN];
480 memset(&in, 0, sizeof(in));
482 err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
483 NULL, 0 , NULL, port, d);
484 assert(err_is_ok(err));
487 memcpy(in + CMD_SET_MAC_IN_ADR_OFFSET, &d_mac[port], 6 );
488 /* seems like the linux driver sets all bits not set
489 from the MAC address to 1*/
494 memcpy(in + CMD_SET_MAC_IN_MTU_OFFSET , ®, 4);
495 in[CMD_SET_MAC_IN_DRAIN_OFFSET] = 0;
496 /* Reject unicast packets ? */
497 in[CMD_SET_MAC_IN_REJECT_OFFSET] = 1;
498 /* Set wanted functionality (flow control) of card -> set to 2 for RX/TX
500 in[CMD_SET_MAC_IN_FCTNL_OFFSET] = 2;
501 err = mcdi_rpc(CMD_SET_MAC, in, CMD_SET_MAC_IN_LEN, NULL, 0, NULL, port, d);
502 assert(err_is_ok(err));
504 err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
505 NULL, 0 , NULL, port, d);
507 assert(err_is_ok(err));
510 /******************************************************************************
512 *****************************************************************************/
514 static void probe_all(void)
524 struct frame_identity frameid = { .base = 0, .bytes = 0 };
529 // Test and clear MC-reboot flag for port/function
530 offset = MCDI_REBOOT_OFFSET(pci_function);
531 reg = sfn5122f_mc_treg_smem_rd(d,offset);
533 sfn5122f_mc_treg_smem_wr(d,offset,0);
536 /*print out any assertions */
538 // Let BMC know that driver is in charg of filter/link setttings
539 // before we can restet NIC
540 memset(&in, 0, sizeof(in));
541 memset(&out, 0 , sizeof(out));
543 r = mcdi_rpc(CMD_GET_VERSION, NULL, 0, out, CMD_GET_VERSION_OUT_LEN,
544 &outlen, pci_function, d);
545 assert(err_is_ok(r));
548 memset(&out, 0 , sizeof(out));
550 // driver is operating / + update
553 r = mcdi_rpc(CMD_DRV_ATTACH, in, CMD_DRV_ATTACH_IN_LEN, out,
554 CMD_DRV_ATTACH_OUT_LEN, &outlen, pci_function, d);
555 assert(err_is_ok(r));
558 r = mcdi_rpc(CMD_PORT_RESET, NULL, 0, NULL, 0, NULL, pci_function, d);
559 assert(err_is_ok(r));
562 if(mcdi_rpc(CMD_WOL_FILTER_GET, NULL, 0, out, CMD_WOL_FILTER_GET_OUT_LEN,
563 &outlen, pci_function, d) == SYS_ERR_OK) {
564 memcpy(&wol_filter_id, out , 4);
566 // Reset filter of card
567 mcdi_rpc(CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL, pci_function, d);
570 // memory for INT_KER
571 int_ker_virt = alloc_map_frame(VREGION_FLAGS_READ_WRITE,
572 2*sizeof(uint64_t), &int_ker);
573 memset(int_ker_virt, 0, 2*sizeof(uint64_t));
574 // Read in non volatile configuration
575 memset(&out, 0, sizeof(out));
576 r = mcdi_rpc(CMD_GET_BOARD_CONFIG, NULL, 0, out,
577 CMD_GET_BOARD_CONFIG_OUT_LEN, &outlen, pci_function, d);
578 assert(err_is_ok(r));
580 memcpy(&d_mac[0], out+MCDI_MAC_PORT_OFFSET(0) ,6);
581 memcpy(&d_mac[1], out+MCDI_MAC_PORT_OFFSET(1) ,6);
583 // read phy configuration
584 r = mcdi_rpc(CMD_GET_PHY_CFG, NULL, 0, out, CMD_GET_PHY_CFG_OUT_LEN, &outlen,
586 assert(err_is_ok(r));
588 memcpy(&phy_caps[pci_function], out+CMD_GET_PHY_CFG_OUT_CAP_OFFSET, 4);
589 memcpy(&phy_flags[pci_function], out+CMD_GET_PHY_CFG_OUT_FLAGS_OFFSET, 4);
590 memcpy(&phy_media[pci_function], out+CMD_GET_PHY_CFG_OUT_MEDIA_OFFSET, 4);
592 // get loopback modes
593 r = mcdi_rpc(CMD_GET_LOOPBACK_MODES, NULL, 0, out,
594 CMD_GET_LOOPBACK_MODES_OUT_LEN, &outlen, pci_function, d);
595 assert(err_is_ok(r));
596 memcpy(&phy_loopback_mode, out+CMD_GET_LOOPBACK_MODES_SUGGESTED_OFFSET,4);
597 // loopback mode NONE is no valid condition
598 phy_loopback_mode &= ~(1);
602 mac_virt = alloc_map_frame(VREGION_FLAGS_READ_WRITE,
603 NUM_MAC_STATS*sizeof(uint64_t),
606 assert(mac_virt != NULL);
607 r = invoke_frame_identify(mac_stats, &frameid);
608 assert(err_is_ok(r));
609 mac_phys = frameid.base;
610 memset(mac_virt, 0, NUM_MAC_STATS*sizeof(uint64_t));
613 memset(&in, 0, sizeof(in));
614 memcpy(in, &mac_phys, 8);
616 // Settings for DMA of MAC stats
617 in[CMD_MAC_STATS_IN_CMD_OFFSET] = 0x6;
618 in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET] = 8;
619 in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET+1] = 3;
620 r = mcdi_rpc(CMD_MAC_STATS, in, CMD_MAC_STATS_IN_LEN, NULL, 0, NULL,
622 assert(err_is_ok(r));
628 // Init card IP filters
629 static void init_rx_filter_config(void)
631 uint64_t reg_hi, reg_lo;
633 for (int i = 0; i < NUM_FILTERS_IP; i++) {
634 sfn5122f_rx_filter_tbl_lo_wr(d, i, 0);
635 sfn5122f_rx_filter_tbl_hi_wr(d, i, 0);
638 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_rd(d);
639 reg_hi = sfn5122f_rx_filter_ctl_reg_hi_rd(d);
641 reg_hi = sfn5122f_rx_filter_ctl_reg_hi_ethernet_full_search_limit_insert(reg_hi, 1);
642 reg_hi = sfn5122f_rx_filter_ctl_reg_hi_ethernet_wildcard_search_limit_insert(reg_hi, 3);
644 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_multicast_nomatch_q_id_lo_insert(reg_lo, 0);
645 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_unicast_nomatch_q_id_insert(reg_lo, 0);
646 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_unicast_nomatch_rss_enabled_insert(reg_lo, 0);
647 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_multicast_nomatch_rss_enabled_insert(reg_lo, 0);
649 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_udp_full_srch_limit_insert(reg_lo, 1);
650 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_udp_wild_srch_limit_insert(reg_lo, 3);
651 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_tcp_full_srch_limit_insert(reg_lo, 1);
652 reg_lo = sfn5122f_rx_filter_ctl_reg_lo_tcp_wild_srch_limit_insert(reg_lo, 3);
655 sfn5122f_rx_filter_ctl_reg_lo_wr(d,reg_lo);
656 sfn5122f_rx_filter_ctl_reg_hi_wr(d,reg_hi);
660 static void device_init(void)
663 struct frame_identity frameid = { .base = 0, .bytes = 0 };
664 uint64_t reg, reg2; // tmp_key = 0;
665 uint8_t in[24]; // set length to biggest in length needed
667 memset(&in, 0, sizeof(in));
669 // recover from failed assertion post-reset
672 /* ignore TX of packets 16 bytes and less */
673 reg = sfn5122f_tx_reserved_reg_lo_rd(d);
674 reg = sfn5122f_tx_reserved_reg_lo_tx_flush_min_len_en_insert(reg, 1);
675 sfn5122f_tx_reserved_reg_lo_wr(d, reg);
676 sfn5122f_tx_reserved_reg_hi_wr(d, sfn5122f_tx_reserved_reg_hi_rd(d));
677 //Disable TX_NO_EOP_DISC_EN because else would limit packets to 16
678 reg = sfn5122f_tx_cfg_reg_lo_rd(d);
679 reg = sfn5122f_tx_cfg_reg_lo_tx_no_eop_disc_en_insert(reg, 0);
680 reg = sfn5122f_tx_cfg_reg_lo_tx_ownerr_ctl_insert(reg, 1);
681 reg = sfn5122f_tx_cfg_reg_lo_tx_filter_en_bit_insert(reg, 1);
682 sfn5122f_tx_cfg_reg_lo_wr(d, reg);
683 sfn5122f_tx_cfg_reg_hi_wr(d, sfn5122f_tx_cfg_reg_hi_rd(d));
685 reg = sfn5122f_rx_cfg_reg_lo_rd(d);
686 // unset bit and set other bit which are not in documentation (43 and 47)
687 reg = sfn5122f_rx_cfg_reg_lo_rx_desc_push_en_insert(reg, 0) ;
688 reg = sfn5122f_rx_cfg_reg_lo_rx_ingr_en_insert(reg, 1);
689 //reg = sfn5122f_rx_cfg_reg_lo_rx_usr_buf_size_insert(reg, (MTU_MAX-256) >> 5);
690 reg = sfn5122f_rx_cfg_reg_lo_rx_usr_buf_size_insert(reg, 4096 >> 5);
691 //reg = sfn5122f_rx_cfg_reg_lo_rx_ownerr_ctl_insert(reg, 1);
692 reg = sfn5122f_rx_cfg_reg_lo_rx_ip_hash_insert(reg, 1);
693 //reg = sfn5122f_rx_cfg_reg_lo_rx_hash_insrt_hdr_insert(reg, 1);
694 reg = sfn5122f_rx_cfg_reg_lo_rx_hash_alg_insert(reg, 1);
695 sfn5122f_rx_cfg_reg_lo_wr(d, reg);
696 sfn5122f_rx_cfg_reg_hi_wr(d, sfn5122f_rx_cfg_reg_hi_rd(d));
697 /* enable event logging, no UART
698 Event destination is queue 0 */
700 r = mcdi_rpc(CMD_LOG_CTRL, in, CMD_LOG_CTRL_IN_LEN,
701 NULL, 0, NULL, pci_function, d);
702 assert(err_is_ok(r));
704 /* Set destination of TX/RX flush event */
706 sfn5122f_dp_ctrl_reg_lo_fls_evq_id_wrf(d, 0);
707 sfn5122f_dp_ctrl_reg_hi_wr(d, sfn5122f_dp_ctrl_reg_hi_rd(d));
709 /* Disalbe user events for now */
710 sfn5122f_usr_ev_cfg_lo_usrev_dis_wrf(d , 1);
711 sfn5122f_usr_ev_cfg_hi_wr(d, sfn5122f_usr_ev_cfg_hi_rd(d));
714 // This seems to be not device specific i.e. works for other
716 /* Set position of descriptor caches in SRAM */
717 sfn5122f_srm_tx_dc_cfg_reg_lo_wr(d, TX_DC_BASE);
718 sfn5122f_srm_tx_dc_cfg_reg_hi_wr(d, sfn5122f_srm_tx_dc_cfg_reg_hi_rd(d));
719 sfn5122f_srm_rx_dc_cfg_reg_lo_srm_rx_dc_base_adr_wrf(d, RX_DC_BASE);
720 sfn5122f_srm_rx_dc_cfg_reg_hi_wr(d, sfn5122f_srm_rx_dc_cfg_reg_hi_rd(d));
722 /* Set TX descriptor cache size to 16 */
723 sfn5122f_tx_dc_cfg_reg_lo_tx_dc_size_wrf(d, 1);
724 sfn5122f_tx_dc_cfg_reg_hi_wr(d, sfn5122f_tx_dc_cfg_reg_hi_rd(d));
726 /* Set RX descriptor cache size to 64 and low watermark */
727 sfn5122f_rx_dc_cfg_reg_lo_rx_dc_size_wrf(d, 3);
728 sfn5122f_rx_dc_cfg_reg_hi_wr(d, sfn5122f_rx_dc_cfg_reg_hi_rd(d));
731 reg = sfn5122f_rx_dc_pf_wm_reg_lo_rx_dc_pf_lwm_insert(reg, RX_DESC_CACHE_SIZE -8);
732 sfn5122f_rx_dc_pf_wm_reg_lo_wr(d, reg);
733 sfn5122f_rx_dc_pf_wm_reg_hi_wr(d, sfn5122f_rx_dc_pf_wm_reg_hi_rd(d));
735 /*programm init ker address for interrupts */
736 r = invoke_frame_identify(int_ker, &frameid);
737 assert(err_is_ok(r));
739 sfn5122f_int_adr_reg_ker_lo_wr(d, frameid.base);
740 reg = sfn5122f_int_adr_reg_ker_hi_rd(d);
742 // disable vector write if we use MSI-X
744 reg = sfn5122f_int_adr_reg_ker_hi_norm_int_vec_dis_ker_insert(reg, 1);
745 if (cdriver_msix == -1) {
746 r = pci_setup_inthandler(global_interrupt_handler, NULL, &cdriver_vector);
747 assert(err_is_ok(r));
748 setup_interrupt(&cdriver_msix, disp_get_core_id(), cdriver_vector);
751 reg = sfn5122f_int_adr_reg_ker_hi_norm_int_vec_dis_ker_insert(reg, 0);
753 sfn5122f_int_adr_reg_ker_hi_wr(d, reg);
755 /* Enable all the genuinley fatal interrupts */
756 reg = sfn5122f_fatal_intr_reg_ker_lo_ill_adr_int_ker_en_insert(reg, 1);
757 /* Enable rxbuf/txbuf interrupt fields not documented.
759 reg = sfn5122f_fatal_intr_reg_ker_lo_rxbuf_own_int_ker_en_insert(reg, 1);
760 reg = sfn5122f_fatal_intr_reg_ker_lo_txbuf_own_int_ker_en_insert(reg, 1);
762 //reg = sfn5122f_fatal_intr_reg_ker_lo_sram_perr_int_p_ker_en_insert(reg, 1);
763 sfn5122f_fatal_intr_reg_ker_lo_wr(d, ~reg);
764 sfn5122f_fatal_intr_reg_ker_hi_wr(d, 0XFFFFFFFFFFFFFFFF);
766 /* Setup RSS indirection table (maps from hash value to packet to RXQ) */
767 for (int i = 0; i < 128; i++) {
769 sfn5122f_rx_indirection_tbl_wr( d, i, rx_indir_tbl[i]);
772 /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
773 * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
774 (from linux driver) */
775 reg = sfn5122f_tx_reserved_reg_lo_rd(d);
776 reg = sfn5122f_tx_reserved_reg_lo_tx_rx_spacer_en_insert(reg, 1);
777 reg = sfn5122f_tx_reserved_reg_lo_tx_one_pkt_per_q_insert(reg, 0);
778 reg = sfn5122f_tx_reserved_reg_lo_tx_dis_non_ip_ev_insert(reg, 1);
780 /* Enable software events */
781 reg = sfn5122f_tx_reserved_reg_lo_tx_soft_evt_en_insert(reg, 1);
782 /* Prefetch threshold 2 => fetch when descriptor cache half empty */
783 reg = sfn5122f_tx_reserved_reg_lo_tx_pref_threshold_insert(reg, 2);
784 /* Disable hardware watchdog which can misfire */
785 reg = sfn5122f_tx_reserved_reg_lo_tx_pref_wd_tmr_insert(reg, 0x3fffff);
786 /* Squash TX of packets of 16 bytes or less */
787 reg = sfn5122f_tx_reserved_reg_lo_tx_flush_min_len_en_insert(reg, 1);
789 reg2 = sfn5122f_tx_reserved_reg_hi_rd(d);
790 reg2 = sfn5122f_tx_reserved_reg_hi_tx_push_en_insert(reg2, 0);
791 reg2 = sfn5122f_tx_reserved_reg_hi_tx_push_chk_dis_insert(reg2, 0);
792 //reg2 = sfn5122f_tx_reserved_reg_hi_tx_rx_spacer_insert(reg2, 0xfe);
793 reg2 = sfn5122f_tx_reserved_reg_hi_tx_rx_spacer_insert(reg2, 0x1);
794 sfn5122f_tx_reserved_reg_lo_wr(d, reg);
795 sfn5122f_tx_reserved_reg_hi_wr(d, reg2);
797 init_port(pci_function);
798 get_link(pci_function);
799 DEBUG("BASIC CARD INIT DONE \n");
802 static void start_all(void)
806 start_port(pci_function);
808 memset(int_ker_virt, 0, 2*sizeof(uint64_t));
809 /* Enable interrupts */
810 /* Use an interrupt level unused by event queues */
811 reg = sfn5122f_int_en_reg_ker_lo_rd(d);
813 reg = sfn5122f_int_en_reg_ker_lo_ker_int_leve_sel_insert(reg, 0);
816 reg = sfn5122f_int_en_reg_ker_lo_ker_int_leve_sel_insert(reg, 0x1f);
818 reg = sfn5122f_int_en_reg_ker_lo_drv_int_en_ker_insert(reg, 1);
820 /* undocumented field */
821 reg = sfn5122f_int_en_reg_ker_lo_ker_int_ker_insert(reg, 0);
822 sfn5122f_int_en_reg_ker_lo_wr(d, reg);
823 sfn5122f_int_en_reg_ker_hi_wr(d, sfn5122f_int_en_reg_ker_hi_rd(d));
825 /* Start MAC stats */
827 uint8_t in[CMD_MAC_STATS_IN_LEN];
828 unsigned long long* stats = (unsigned long long *) mac_virt;
831 memset(in, 0, sizeof(in));
832 stats[0x60] = (unsigned long long) (-1);
833 memcpy(in, &mac_phys, 8);
834 pointer = (uint8_t *) &mac_phys;
835 in[CMD_MAC_STATS_IN_CMD_OFFSET] = 0xD;
838 in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET] = 8;
839 in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET+1] = 3;
840 errval_t err = mcdi_rpc(CMD_MAC_STATS, in, CMD_MAC_STATS_IN_LEN,
841 NULL, 0, NULL, pci_function, d);
842 assert(err_is_ok(err));
846 /**************************************************************************
848 ***************************************************************************/
851 static void queue_hw_stop(uint16_t n)
856 reg = sfn5122f_tx_flush_descq_reg_lo_rd(d);
857 reg = sfn5122f_tx_flush_descq_reg_lo_tx_flush_descq_insert(reg, n);
858 reg = sfn5122f_tx_flush_descq_reg_lo_tx_flush_descq_cmd_insert(reg, 1);
859 sfn5122f_tx_flush_descq_reg_lo_wr(d, reg);
860 sfn5122f_tx_flush_descq_reg_hi_wr(d, sfn5122f_tx_flush_descq_reg_hi_rd(d));
862 reg = sfn5122f_rx_flush_descq_reg_lo_rd(d);
863 reg = sfn5122f_rx_flush_descq_reg_lo_rx_flush_descq_insert(reg, n);
864 reg = sfn5122f_rx_flush_descq_reg_lo_rx_flush_descq_cmd_insert(reg, 1);
865 sfn5122f_rx_flush_descq_reg_lo_wr(d, reg);
866 sfn5122f_rx_flush_descq_reg_hi_wr(d, sfn5122f_rx_flush_descq_reg_hi_rd(d));
868 /* TODO Wait for DRIVER_EVENT */
869 /* clear pointer table entries */
870 sfn5122f_tx_desc_ptr_tbl_lo_wr(d, n, 0);
871 sfn5122f_tx_desc_ptr_tbl_hi_wr(d, n, 0);
872 sfn5122f_rx_desc_ptr_tbl_lo_wr(d, n, 0);
873 sfn5122f_rx_desc_ptr_tbl_hi_wr(d, n, 0);
875 /*Free RX queue tbl entries*/
877 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
878 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg,
879 queues[n].rx_buf_tbl);
881 if (queues[n].userspace) {
882 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
883 queues[n].rx_buf_tbl + NUM_ENT_RX_USR);
885 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
886 queues[n].rx_buf_tbl + NUM_ENT_RX);
889 /*Free TX queue tbl entries*/
891 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
892 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
893 queues[n].tx_buf_tbl + NUM_ENT_TX );
894 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg,
895 queues[n].tx_buf_tbl);
897 /*Free EV queue tbl entries*/
899 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
900 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
901 queues[n].ev_buf_tbl + NUM_ENT_EVQ );
902 reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg,
903 queues[n].ev_buf_tbl);
908 static uint32_t init_evq(uint16_t n, lpaddr_t phys, bool interrupt)
912 //struct frame_identity frameid = { .base = 0, .bytes = 0 };
913 uint64_t reg, buffer_offset;
916 reg = sfn5122f_timer_tbl_lo_timer_q_en_insert(reg, 1);
917 // set to 0 if interrupts for receives/sends should be generated
919 reg = sfn5122f_timer_tbl_lo_host_notify_mode_insert(reg, 0);
921 reg = sfn5122f_timer_tbl_lo_int_pend_insert(reg, 0);
922 reg = sfn5122f_timer_tbl_lo_int_armd_insert(reg, 0);
923 if (use_interrupt && interrupt) {
924 reg = sfn5122f_timer_tbl_lo_host_notify_mode_insert(reg, 0);
926 reg = sfn5122f_timer_tbl_lo_host_notify_mode_insert(reg, 1);
929 // timer mode disabled
930 reg = sfn5122f_timer_tbl_lo_timer_mode_insert(reg, 0);
931 sfn5122f_timer_tbl_lo_wr(d, n, reg);
932 sfn5122f_timer_tbl_hi_wr(d, n, sfn5122f_timer_tbl_hi_rd(d, n));
935 r = invoke_frame_identify(queues[n].ev_frame, &frameid);
936 assert(err_is_ok(r));
937 ev_phys = frameid.base;
940 buffer_offset = alloc_buf_tbl_entries(phys, NUM_ENT_EVQ, 0, 0, d);
941 if (buffer_offset == -1) {
945 DEBUG("EV_QUEUE_%d: buf_off %ld, phys 0x%lx\n",n , buffer_offset, phys);
947 reg = sfn5122f_evq_ptr_tbl_lo_rd(d, n);
948 reg = sfn5122f_evq_ptr_tbl_lo_evq_en_insert(reg, 1);
949 reg = sfn5122f_evq_ptr_tbl_lo_evq_size_insert(reg, 6);
950 reg = sfn5122f_evq_ptr_tbl_lo_evq_buf_base_id_insert(reg,
953 sfn5122f_evq_ptr_tbl_lo_wr(d, n, reg);
954 sfn5122f_evq_ptr_tbl_hi_wr(d, n, sfn5122f_evq_ptr_tbl_hi_rd(d, n));
956 /* No write collection for this register */
957 reg = sfn5122f_timer_command_reg_lo_rd(d,n);
958 reg = sfn5122f_timer_command_reg_lo_tc_timer_val_insert(reg, 0);
960 reg = sfn5122f_timer_command_reg_lo_tc_timer_mode_insert(reg, 0);
962 reg = sfn5122f_timer_command_reg_lo_tc_timer_mode_insert(reg, 0);
965 sfn5122f_timer_command_reg_lo_wr(d, n, reg);
967 sfn5122f_evq_rptr_reg_wr(d, n, queues[n].ev_head);
969 return buffer_offset;
972 static uint32_t init_rxq(uint16_t n, lpaddr_t phys, bool userspace)
974 uint64_t reg_lo, reg_hi, buffer_offset;
976 * This will define a buffer in the buffer table, allowing
977 * it to be used for event queues, descriptor rings etc.
979 /* Get physical addresses for rx/tx rings and event queue */
983 buffer_offset = alloc_buf_tbl_entries(phys, NUM_ENT_RX_USR, 0, false, d);
985 buffer_offset = alloc_buf_tbl_entries(phys, NUM_ENT_RX, 0, false, d);
988 if (buffer_offset == -1) {
992 DEBUG("RX_QUEUE_%d: buf_off %ld, phys %lx\n", n,
993 buffer_offset, phys);
995 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rd(d, n);
996 reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rd(d, n);
997 /* Which buffer table entries are used (which is the first entry) */
998 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_buf_base_id_insert(reg_lo, buffer_offset);
999 /* Which event queue is associated with this queue*/
1000 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_evq_id_insert(reg_lo, n);
1003 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_owner_id_insert(reg_lo, 0);
1005 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_owner_id_insert(reg_lo, n+1);
1008 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_label_insert(reg_lo, n);
1010 /* 1024 entries = 1 (512 = 0; 2048 = 2 ; 4096 = 3) */
1011 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_size_insert(reg_lo, 3);
1014 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_type_insert(reg_lo, 0);
1016 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_type_insert(reg_lo, 1);
1019 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_jumbo_insert(reg_lo, 0);
1021 reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_en_insert(reg_lo, 1);
1023 /* Hardware verifies data digest */
1024 reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rx_iscsi_ddig_en_insert(reg_hi, 0);
1025 reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rx_iscsi_hdig_en_insert(reg_hi, 0);
1027 sfn5122f_rx_desc_ptr_tbl_lo_wr(d, n, reg_lo);
1028 sfn5122f_rx_desc_ptr_tbl_hi_wr(d, n, reg_hi);
1030 return buffer_offset;
1034 static uint32_t init_txq(uint16_t n, uint64_t phys,
1035 bool csum, bool userspace)
1038 uint64_t reg, reg1, buffer_offset;
1040 buffer_offset = alloc_buf_tbl_entries(phys, NUM_ENT_TX, 0, 0, d);
1042 if (buffer_offset == -1) {
1046 DEBUG("TX_QUEUE_%d: buf_off %ld, phys %lx\n",n , buffer_offset, phys);
1047 /* setup TX queue */
1048 reg = sfn5122f_tx_desc_ptr_tbl_lo_rd(d, n);
1049 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_rd(d, n);
1050 /* Which buffer table entries are used (which is the first entry) */
1051 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_buf_base_id_insert(reg,
1053 /* Which event queue is associated with this queue */
1054 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_evq_id_insert(reg , n);
1056 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_owner_id_insert(reg, 0);
1058 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_owner_id_insert(reg, n+1);
1060 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_label_insert(reg , n);
1061 /* 1024 entries = 1 (512 = 0; 2048 = 2 ; 4096 = 3) */
1062 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_size_insert(reg , 3);
1064 /* No user lvl networking */
1066 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_type_insert(reg, 0);
1068 reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_type_insert(reg, 1);
1071 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_iscsi_ddig_en_insert(reg1, 0);
1072 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_iscsi_hdig_en_insert(reg1, 0);
1074 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_non_ip_drop_dis_insert(reg1, 1);
1077 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_descq_en_insert(reg1 , 1);
1079 /* Enable offload of checksum */
1080 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_ip_chksm_dis_insert(reg1, !csum);
1081 reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_tcp_chksm_dis_insert(reg1, !csum);
1082 sfn5122f_tx_desc_ptr_tbl_lo_wr(d, n, reg);
1083 sfn5122f_tx_desc_ptr_tbl_hi_wr(d, n, reg1);
1085 return buffer_offset;
1089 static void setup_interrupt(size_t *msix_index, uint8_t core, uint8_t vector)
1095 res = bmallocator_alloc(&msix_alloc, msix_index);
1098 err = get_apicid_from_core(core, &dest);
1099 assert(err_is_ok(err));
1101 err = pci_msix_vector_init(*msix_index, dest, vector);
1102 assert(err_is_ok(err));
1104 DEBUG("MSI-X vector setup index=%"PRIx64", core=%d apic=%d swvec=%x\n",
1105 *msix_index, core, dest, vector);
1108 static void resend_interrupt(void* arg)
1111 uint64_t i = (uint64_t) arg;
1112 err = queues[i].devif->tx_vtbl.interrupt(queues[i].devif, NOP_CONT, i);
1113 // If the queue is busy, there is already an oustanding message
1114 if (err_is_fail(err) && err != FLOUNDER_ERR_TX_BUSY) {
1115 USER_PANIC("Error when sending interrupt %s \n", err_getstring(err));
1119 /** Here are the global interrupts handled. */
1120 static void global_interrupt_handler(void* arg)
1124 uint32_t q_to_check;
1126 uint8_t* net_ivec_fatal = (uint8_t *) int_ker_virt;
1128 // bit 64 is indicator for a fatal event
1129 syserr = (net_ivec_fatal[8] & 0x1);
1131 // TODO handle fatal interrupt
1132 USER_PANIC("FATAL INTERRUPT");
1137 q_to_check = sfn5122f_int_isr0_reg_lo_rd(d);
1139 for (uint64_t i = 0; i < 32; i++) {
1140 if ((q_to_check >> i) & 0x1) {
1141 if (queues[i].use_irq && queues[i].devif != NULL) {
1142 DEBUG("Interrupt to queue %lu \n", i);
1143 err = queues[i].devif->tx_vtbl.interrupt(queues[i].devif, NOP_CONT, i);
1144 if (err_is_fail(err)) {
1145 err = queues[i].devif->register_send(queues[i].devif,
1146 get_default_waitset(),
1147 MKCONT(resend_interrupt, (void*)i));
1153 // Don't need to start event queues because we're already polling
1156 /******************************************************************************/
1157 /* Management interface implemetation */
1159 static errval_t cd_create_queue_rpc(struct sfn5122f_devif_binding *b, struct capref frame,
1160 bool user, bool interrupt, bool qzero,
1161 uint8_t core, uint8_t msix_vector,
1162 uint64_t *mac, uint16_t *qid, struct capref *regs,
1166 DEBUG("cd_create_queue \n");
1169 struct frame_identity id;
1172 for (int i = 1; i < NUM_QUEUES; i++) {
1173 if (queues[i].enabled == false) {
1180 *ret_err = NIC_ERR_ALLOC_QUEUE;
1182 return NIC_ERR_ALLOC_QUEUE;
1186 if (queues[0].enabled == false) {
1189 printf("Default queue already initalized \n");
1190 return NIC_ERR_ALLOC_QUEUE;
1196 queues[n].use_irq = interrupt;
1197 queues[n].enabled = false;
1198 queues[n].tx_frame = frame;
1199 queues[n].tx_head = 0;
1200 queues[n].rx_head = 0;
1201 queues[n].ev_head = 0;
1202 queues[n].rxbufsz = MTU_MAX;
1203 queues[n].devif = b;
1204 queues[n].userspace = user;
1205 queues[n].msix_index = -1;
1206 queues[n].msix_intdest = core;
1207 queues[n].msix_intvec = msix_vector;
1210 if (queues[n].use_irq && use_msix) {
1211 if (queues[n].msix_intvec != 0) {
1212 if (queues[n].msix_index == -1) {
1213 setup_interrupt(&queues[n].msix_index, queues[n].msix_intdest,
1214 queues[n].msix_intvec);
1219 err = invoke_frame_identify(frame, &id);
1220 assert(err_is_ok(err));
1222 queues[n].tx_buf_tbl = init_txq(n, id.base, csum_offload, user);
1223 queues[n].rx_buf_tbl = init_rxq(n, id.base+ sizeof(uint64_t)*TX_ENTRIES, user);
1225 queues[n].ev_buf_tbl = init_evq(n, id.base+sizeof(uint64_t)*(TX_ENTRIES+RX_ENTRIES),
1227 if(queues[n].ev_buf_tbl == -1 ||
1228 queues[n].tx_buf_tbl == -1 ||
1229 queues[n].rx_buf_tbl == -1){
1230 *ret_err = NIC_ERR_ALLOC_QUEUE;
1232 return NIC_ERR_ALLOC_QUEUE;
1235 queues[n].enabled = true;
1236 DEBUG("created queue %d \n", n);
1238 *mac = d_mac[pci_function];
1241 err = slot_alloc(regs);
1242 assert(err_is_ok(err));
1243 err = cap_copy(*regs, *regframe);
1244 assert(err_is_ok(err));
1246 *ret_err = SYS_ERR_OK;
1253 static void cd_create_queue(struct sfn5122f_devif_binding *b, struct capref frame,
1254 bool user, bool interrupt, bool qzero, uint8_t core,
1255 uint8_t msix_vector)
1265 cd_create_queue_rpc(b, frame, user, interrupt, false, core,
1266 msix_vector, &mac, &queueid, ®s, &err);
1268 err = b->tx_vtbl.create_queue_response(b, NOP_CONT, mac, queueid, regs, err);
1269 assert(err_is_ok(err));
1270 DEBUG("cd_create_queue end\n");
1274 static errval_t cd_register_region_rpc(struct sfn5122f_devif_binding *b, uint16_t qid,
1275 struct capref region, uint64_t *buftbl_id, errval_t *ret_err)
1279 struct frame_identity id;
1280 uint64_t buffer_offset = 0;
1282 err = invoke_frame_identify(region, &id);
1283 if (err_is_fail(err)) {
1284 err = b->tx_vtbl.register_region_response(b, NOP_CONT, 0, NIC_ERR_REGISTER_REGION);
1285 assert(err_is_ok(err));
1288 size_t size = id.bytes;
1289 lpaddr_t addr = id.base;
1291 // TODO unsigned/signed
1292 buffer_offset = alloc_buf_tbl_entries(addr, size/BUF_SIZE, qid, true, d);
1293 if (buffer_offset == -1) {
1298 *buftbl_id = buffer_offset;
1299 *ret_err = SYS_ERR_OK;
1304 static void cd_register_region(struct sfn5122f_devif_binding *b, uint16_t qid,
1305 struct capref region)
1307 errval_t err, msgerr;
1309 err = cd_register_region_rpc(b, qid, region, &id, &msgerr);
1311 err = b->tx_vtbl.register_region_response(b, NOP_CONT, id, msgerr);
1315 static void cd_deregister_region(struct sfn5122f_devif_binding *b, uint64_t buftbl_id,
1319 free_buf_tbl_entries(buftbl_id, size/BUF_SIZE, d);
1321 err = b->tx_vtbl.deregister_region_response(b, NOP_CONT, SYS_ERR_OK);
1322 assert(err_is_ok(err));
1325 static void cd_destroy_queue(struct sfn5122f_devif_binding *b, uint16_t qid)
1330 queues[qid].enabled = false;
1331 queues[qid].devif = NULL;
1333 err = b->tx_vtbl.destroy_queue_response(b, NOP_CONT, SYS_ERR_OK);
1334 assert(err_is_ok(err));
1337 static void cd_control(struct sfn5122f_devif_binding *b, uint64_t request,
1342 struct queue_state *q = b->st;
1345 DEBUG("control arg=0x%lx\n", arg);
1347 struct sfn5122f_filter_ip f = {
1348 .dst_port = ((uint32_t)arg >> 16),
1349 .dst_ip = htonl((uint32_t)(arg >> 32)),
1352 .type_ip = arg & 0x1,
1357 err = reg_port_filter(&f, &fid);
1359 DEBUG("register filter: 0x%x:%u UDP=%u -> q=%u @ index=%lu %s\n",f.dst_ip,
1360 f.dst_port, f.type_ip, f.queue, fid, err_getstring(err));
1363 err = b->tx_vtbl.control_response(b, NOP_CONT, fid, err);
1364 assert(err_is_ok(err));
1367 static void export_devif_cb(void *st, errval_t err, iref_t iref)
1369 const char *suffix = "_sfn5122fmng_devif";
1370 char name[strlen(service_name) + strlen(suffix) + 1];
1372 assert(err_is_ok(err));
1374 // Build label for interal management service
1375 sprintf(name, "%s%s", service_name, suffix);
1377 err = nameservice_register(name, iref);
1378 assert(err_is_ok(err));
1379 DEBUG("Devif Management interface exported\n");
1385 /****************************************************************************/
1386 /* Net filter interface implementation */
1387 /****************************************************************************/
1390 static errval_t cb_install_filter(struct net_filter_binding *b,
1391 net_filter_filter_type_t type,
1399 struct sfn5122f_filter_ip f = {
1400 .dst_port = dst_port,
1401 .src_port = src_port,
1402 .dst_ip = htonl(dst_ip),
1403 .src_ip = htonl(src_ip),
1409 errval_t err = reg_port_filter(&f, fid);
1410 assert(err_is_ok(err));
1411 DEBUG("filter registered: err=%"PRIu64", fid=%"PRIu64"\n", err, *fid);
1416 static errval_t cb_remove_filter(struct net_filter_binding *b,
1417 net_filter_filter_type_t type,
1421 if ((type == net_filter_PORT_UDP || type == net_filter_PORT_TCP)
1422 && filters_rx_ip[filter_id].enabled == true) {
1423 filters_rx_ip[filter_id].enabled = false;
1425 sfn5122f_rx_filter_tbl_lo_wr(d, filter_id, 0);
1426 sfn5122f_rx_filter_tbl_hi_wr(d, filter_id, 0);
1429 *err = NET_FILTER_ERR_NOT_FOUND;
1432 DEBUG("unregister_filter: called (%"PRIx64")\n", filter_id);
1436 static struct net_filter_rpc_rx_vtbl net_filter_rpc_rx_vtbl = {
1437 .install_filter_ip_call = cb_install_filter,
1438 .remove_filter_call = cb_remove_filter,
1439 .install_filter_mac_call = NULL,
1442 static void net_filter_export_cb(void *st, errval_t err, iref_t iref)
1445 printf("exported net filter interface\n");
1446 err = nameservice_register("net_filter_sfn5122f", iref);
1447 assert(err_is_ok(err));
1448 DEBUG("Net filter interface exported\n");
1452 static errval_t net_filter_connect_cb(void *st, struct net_filter_binding *b)
1454 printf("New connection on net filter interface\n");
1455 b->rpc_rx_vtbl = net_filter_rpc_rx_vtbl;
1460 static errval_t connect_devif_cb(void *st, struct sfn5122f_devif_binding *b)
1462 DEBUG("New connection on devif management interface\n");
1464 //b->rx_vtbl = rx_vtbl_devif;
1466 b->rx_vtbl.create_queue_call = cd_create_queue;
1467 b->rx_vtbl.destroy_queue_call = cd_destroy_queue;
1468 b->rx_vtbl.register_region_call = cd_register_region;
1469 b->rx_vtbl.deregister_region_call = cd_deregister_region;
1470 b->rx_vtbl.control_call = cd_control;
1473 b->rpc_rx_vtbl.create_queue_call = cd_create_queue_rpc;
1474 b->rpc_rx_vtbl.register_region_call = cd_register_region_rpc;
1480 * Initialize management interface for queue drivers.
1481 * This has to be done _after_ the hardware is initialized.
1483 static void initialize_mngif(void)
1487 r = sfn5122f_devif_export(NULL, export_devif_cb, connect_devif_cb,
1488 get_default_waitset(), 1);
1489 assert(err_is_ok(r));
1491 r = net_filter_export(NULL, net_filter_export_cb, net_filter_connect_cb,
1492 get_default_waitset(), 1);
1493 assert(err_is_ok(r));
1496 /******************************************************************************/
1497 /* Initialization code for driver */
1499 /** Callback from pci to initialize a specific PCI device. */
1500 static void pci_init_card(struct device_mem* bar_info, int bar_count)
1505 d = malloc(sizeof(*d));
1506 /* Map first BAR for register access */
1507 assert(bar_count >= 1);
1508 DEBUG("BAR count %d \n", bar_count);
1509 map_device(&bar_info[0]);
1510 regframe = bar_info[0].frame_cap;
1511 DEBUG("BAR[0] mapped (v=%llx p=%llx l=%llx)\n",
1512 (unsigned long long) bar_info[0].vaddr,
1513 (unsigned long long) bar_info[0].paddr,
1514 (unsigned long long) bar_info[0].bytes);
1516 /* Initialize Mackerel binding */
1517 sfn5122f_initialize(d, (void*) bar_info[0].vaddr);
1518 d_virt = bar_info[0].vaddr;
1520 // Initialize manager for MSI-X vectors
1522 //d_msix = malloc(sizeof(*d_msix));
1523 //map_device(&bar_info[1]);
1524 //sfn5122f_msix_initialize(d_msix, (void*) bar_info[1].vaddr);
1525 DEBUG("Enabling MSI-X interrupts\n");
1526 uint16_t msix_count = 0;
1527 err = pci_msix_enable(&msix_count);
1528 assert(err_is_ok(err));
1529 assert(msix_count > 0);
1530 DEBUG("MSI-X #vecs=%d\n", msix_count);
1532 res = bmallocator_init(&msix_alloc, msix_count);
1535 DEBUG("Using legacy interrupts\n");
1538 /* Get all information needed */
1540 /* Initialize hardware registers etc. */
1541 /* Start interrups / mac_stats etc. */
1543 /* Init rx filters */
1544 init_rx_filter_config();
1545 /* initalize managemnt interface */
1554 static void parse_cmdline(int argc, char **argv)
1557 * XXX: the following contains a hack only to start the driver when
1558 * the supplied bus/dev/funct matches the Kaluga start arguments.
1562 for (i = 1; i < argc; i++) {
1563 if (strncmp(argv[i], "cardname=", strlen("cardname=") - 1) == 0) {
1564 service_name = argv[i] + strlen("cardname=");
1565 } else if (strncmp(argv[i], "bus=", strlen("bus=") - 1) == 0) {
1566 tmp = atol(argv[i] + strlen("bus="));
1567 if (pci_bus == PCI_DONT_CARE) {
1571 if (pci_bus != tmp) {
1572 printf("DRIVER STARTED FOR BUS: 0x%x/0x%x\n", pci_bus, tmp);
1575 pci_bus = atol(argv[i] + strlen("bus="));
1576 } else if (strncmp(argv[i], "device=", strlen("device=") - 1) == 0) {
1577 tmp = atol(argv[i] + strlen("device="));
1578 if (pci_device == PCI_DONT_CARE) {
1582 if (pci_device != tmp) {
1583 printf("DRIVER STARTED FOR DEVICE: 0x%x/0x%x\n", pci_device, tmp);
1587 } else if (strncmp(argv[i], "function=", strlen("function=") - 1) == 0){
1588 tmp = atol(argv[i] + strlen("function="));
1589 if (pci_function == PCI_DONT_CARE) {
1593 if (pci_function != tmp) {
1594 printf("DRIVER STARTED FOR FUNCTION: 0x%x/0x%x\n", pci_bus, tmp);
1598 if (pci_function != 0) {
1599 USER_PANIC("Second port not implemented, please use function=0")
1601 } else if (strncmp(argv[i], "msix=", strlen("msix=") - 1) == 0){
1602 USER_PANIC("MSI-X not fully supported yet");
1603 use_msix = !!atol(argv[i] + strlen("msix="));
1604 //qd_rgument(argv[i]);
1606 printf("Unrecognized argument %s ignored \n", argv[i]);
1612 static void eventloop(void)
1616 ws = get_default_waitset();
1617 DEBUG("SFN5122F enter event loop \n");
1623 static void cd_main(void)
1629 int main(int argc, char** argv)
1631 DEBUG("SFN5122F driver started \n");
1635 uint32_t parsed = sscanf(argv[argc - 1], "%x:%x:%x:%x:%x", &pci_vendor,
1636 &pci_devid, &pci_bus, &pci_device, &pci_function);
1638 pci_vendor = PCI_DONT_CARE;
1639 pci_devid = PCI_DONT_CARE;
1640 pci_bus = PCI_DONT_CARE;
1641 pci_device = PCI_DONT_CARE;
1644 if ((pci_vendor != PCI_VENDOR_SOLARFLARE) || (pci_devid != DEVICE_ID)) {
1645 printf("VENDOR/DEVICE ID MISMATCH: %x/%x %x/%x \n",
1646 pci_vendor, PCI_VENDOR_SOLARFLARE, pci_devid, DEVICE_ID);
1652 parse_cmdline(argc, argv);
1655 /* Register our device driver */
1656 err = pci_client_connect();
1657 assert(err_is_ok(err));
1658 err = pci_register_driver_irq(pci_init_card, PCI_CLASS_ETHERNET,
1659 PCI_DONT_CARE, PCI_DONT_CARE,
1660 pci_vendor, pci_devid,
1661 pci_bus, pci_device, pci_function,
1662 global_interrupt_handler, NULL);
1664 while (!initialized) {
1665 event_dispatch(get_default_waitset());
1668 DEBUG("SFN5122F driver networking init \n");
1669 err = networking_init("sfn5122f", NET_FLAGS_BLOCKING_INIT | NET_FLAGS_DO_DHCP |
1670 NET_FLAGS_DEFAULT_QUEUE);
1671 assert(err_is_ok(err));
1673 DEBUG("SFN5122F driver networking init done\n");