DeviceQueue: Solarflare driver added
authorRoni Häcki <roni.haecki@inf.ethz.ch>
Thu, 8 Sep 2016 10:48:49 +0000 (12:48 +0200)
committerRoni Häcki <roni.haecki@inf.ethz.ch>
Thu, 8 Sep 2016 10:48:49 +0000 (12:48 +0200)
Signed-off-by: Roni Häcki <roni.haecki@inf.ethz.ch>

25 files changed:
devices/Hakefile
devices/sfn5122f.dev [new file with mode: 0644]
devices/sfn5122f_q.dev [new file with mode: 0644]
errors/errno.fugu
hake/symbolic_targets.mk
if/Hakefile
if/sfn5122f.if [new file with mode: 0644]
include/pci/devids.h
lib/net_device_manager/Hakefile
lib/net_device_manager/device_manager.c
lib/net_device_manager/port_management_support.h
lib/net_device_manager/sfn5122f_filt_cl_impl.c [new file with mode: 0644]
usr/drivers/solarflare/Hakefile [new file with mode: 0644]
usr/drivers/solarflare/buffer_tbl.c [new file with mode: 0644]
usr/drivers/solarflare/buffer_tbl.h [new file with mode: 0644]
usr/drivers/solarflare/helper.c [new file with mode: 0644]
usr/drivers/solarflare/helper.h [new file with mode: 0644]
usr/drivers/solarflare/mcdi_rpc.c [new file with mode: 0644]
usr/drivers/solarflare/mcdi_rpc.h [new file with mode: 0644]
usr/drivers/solarflare/sfn5122f.h [new file with mode: 0644]
usr/drivers/solarflare/sfn5122f_cdriver.c [new file with mode: 0644]
usr/drivers/solarflare/sfn5122f_debug.h [new file with mode: 0644]
usr/drivers/solarflare/sfn5122f_qdriver.c [new file with mode: 0644]
usr/drivers/solarflare/sfn5122f_queue.h [new file with mode: 0644]
usr/skb/programs/device_db.pl

index 743ad4b..b6c1d2c 100644 (file)
            "vtd",
            "vtd_iotlb",
            "zynq7/zynq_uart",
-           "zynq7/zynq_slcr"
+           "zynq7/zynq_slcr",
+           "sfn5122f",
+           "sfn5122f_q"
          ], arch <- allArchitectures
 ] ++
 
diff --git a/devices/sfn5122f.dev b/devices/sfn5122f.dev
new file mode 100644 (file)
index 0000000..f0deb54
--- /dev/null
@@ -0,0 +1,1564 @@
+/*
+ * Copyright (c) 2011, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * sfn5211f.dev
+ *
+ * DESCRIPTION: Solarflare Solarstorm SFx902x Ethernet Controller family
+ *
+ * Numbers in comments refer to Solarstorm SFx902x Ethernet Controller family Controller Datasheet
+ * Product #: SF-103590-DS / Issue 3
+ */
+
+device sfn5122f msbfirst ( addr base ) 
+"Solarflare SFx902x Ethernet Controller Family"{
+
+  /************************************
+   *  5.1 Global CSR Block
+   ***********************************/
+  
+  // 5.3
+
+  register csr_spare_reg_hi rw addr(base, 0x00000318) "Spare register low"{
+    _                             32 rsvd;
+    memr_perr_en                  32 "Memory parity error enable bits";
+  };
+
+  register csr_spare_reg_lo rw addr(base, 0x00000310) "Spare register high"{
+    _                             32 rsvd;
+    csr_spare_bits                32 "Spare bits";
+  };
+
+  // 5.6
+ // reserved bits are not mapped
+  register cs_debug_reg_lo ro addr(base, 0x00000270) "Debug register" {
+    _                             22 rsvd;
+    cs_port_num                   2  type(cs_port_num)"Port number register";
+    _                             40 rsvd;
+  };
+
+ // reserved bits are not mapped
+  register cs_debug_reg_hi ro addr(base, 0x00000278) "Debug register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  constants cs_port_num "Port Number" {
+    port_0      = 0b01 "Port 0";
+    port_1      = 0b10 "Port 1";
+  };
+  
+  // 5.9
+  register dp_ctrl_reg_lo rw addr(base, 0x00000250) "Datapath control register" {
+    _                             52 rsvd;
+    fls_evq_id                    12 "Flush done event event queue ID";
+  };
+
+  register dp_ctrl_reg_hi rw addr(base, 0x00000258) "Datapath control register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.12 would be 128 bits
+  regarray driver_reg_lo rw addr(base, 0x00000280) [8; 0x10] "Driver scratch register" {
+    _                             32 rsvd;
+    driver_dw0                    32 "Driver scratch space dword";
+  };
+
+  regarray driver_reg_hi rw addr(base, 0x00000288) [8; 0x10] "Driver scratch register" {
+    _                             32 rsvd;
+    driver_dw0                    32 "Driver scratch";
+  };
+
+
+ // 5.15 would be 128 bits
+ // (bits rx_buf/txbuf_onw_int_ker not documented found in driver code)
+
+  register fatal_intr_reg_ker_lo rw addr(base, 0x00000230) 
+  "Fatal interrupt register for Kernel" {
+    _                             19 rsvd;
+    sram_perr_int_p_ker_en        1 
+    "SRAM memory parity error interrupt enable for opposite port";
+    mbu_perr_int_ker_en           1 "MBU memory parrity error interrupt enable";
+    _                             2  rsvd;
+    mem_perr_int_ker_en           1 
+    "Internal memory parity error interrupt enable";
+    rxbuf_own_int_ker_en          1  "RX buffer interrupt enable";
+    txbuf_own_int_ker_en          1  "TX buffer interrupt enable";
+    _                             3  rsvd;
+    evf_oflo_int_ker_en           1  "Event queue FIFO overflow interrupt enable";
+    ill_adr_int_ker_en            1  "Illegal address error interrupt enable";
+    srm_perr_int_ker_en           1  "SRAM parity error interrupt enable";
+    _                             19 rsvd;
+    sram_perr_int_p_ker           1  rc
+    "SRAM memory parity error occurred in opposite port";
+    mbu_perr_int_ker              1  rc "PCI MBU memory parity error";
+    _                             2  rsvd;
+    mem_perr_int_ker              1  rc "Internal memory parity error interrupt";
+    _                             5  rsvd;
+    evf_oflo_intker               1  rc "Event queue FIFO overlfow";
+    ill_adr_int_ker               1  rc "Illegal address error";
+    srm_perr_int_ker              1  rc "SRAM parity error";
+  };
+  register fatal_intr_reg_ker_hi rw addr(base, 0x00000238) "" {
+    bit                          64  "bit";
+  };
+
+ // 5.18 would be 128 bits
+  register mem_stat_reg_lo ro addr(base, 0x00000260) "Memory status register" {
+    _                             29 rsvd;
+    mem_perr_vec                  35 ro "Memory parity error vector";
+  };
+
+  register mem_stat_reg_hi ro addr(base, 0x00000268) "Memory status register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+// Not specified in documentation
+
+  register altera_build_reg_lo rw addr(base, 0x00000300) "Altera build register" {
+   _                              32 rsvd;
+   altera_build_ver               32 "Spare bits";
+  };
+
+  register altera_build_reg_hi rw addr(base, 0x00000308) "Altera build register" {
+   _                              63 rsvd;
+   bit                            1 "";
+  };
+
+  /************************************
+   *  Bus Interface Unit Block
+   ***********************************/
+
+
+  // 5.22
+  register adr_region_reg_hi rw addr(base, 0x00000008) 
+  "Address region register high bits" {
+    _                             14 rsvd;
+    adr_region1                   18 "Upper 18 bits of 46-bit address region #1";
+    _                             14 rsvd;
+    adr_region0                   18 "Upper 18 bits of 46-bit address region #0";
+  };
+
+  register adr_region_reg_lo rw addr(base, 0x00000000) 
+  "Address region register low bits" {
+    _                             14 rsvd;
+    adr_region1                   18 "Upper 18 bits of 46-bit address region #1";
+    _                             14 rsvd;
+    adr_region0                   18 "Upper 18 bits of 46-bit address region #0";
+  };
+
+
+
+  
+  // 5.25
+  register hw_init_reg_lo rw addr(base, 0x000000c0)
+  "Hardware initialization register low bits" {
+    _                             18 rsvd;
+    b2b_reg_en                    1  "Enables back to back request in bdmrq";
+    _                             1  rsvd;
+    post_wr_mask                  4    
+    "Space out every write to every target by this many cycles";
+    _                             3  rsvd;
+    tlp_tc                        3  "For testing read completion";
+    tlp_attr                      2  "For testing read completion";
+    _                             16 rsvd;
+    wd_timer                      8  
+    "Watch dog timer for reading non-mapped or non-implemented addresses";
+    _                             2  rsvd;
+    us_disable                    1  "Disable un-supported status return";
+    tlp_ep                        1  "Testing constructing posted write";
+    attr_sel                      1  
+    "For testing, when constructing a posted write TLP";
+    _                             1  rsvd;
+    tlp_sel                       1  "For testing, enables using TLP_TD";
+    tlp_td                        1  "For testing, write TLP";
+  };
+
+  register hw_init_reg_hi rw addr(base, 0x000000c8)
+  "Hardware initialization register high bits" {
+       _                         7  rsvd;
+       tx_mrg_tags               1  
+        "Tx Descriptor Read Requests can share/use TX DMA read tags";
+       _                         20 rsvd;
+       dorbell_drop              8  rc "Counter for dorbell with push dropped";
+       _                         28 rsvd;
+   };
+
+  // bits 0:63 would be legacy interrupt vecor or legacy_int_vec?
+  
+  register int_adr_reg_ker_hi rw addr(base, 0x00000038) 
+   "Interrupt host address for Kernel driver high bits" {
+    _                             63 rsvd;
+    norm_int_vec_dis_ker          1  "Normal interrupt vector write disable";
+  };
+
+  register int_adr_reg_ker_lo rw addr(base, 0x00000030) 
+   "Interrupt host address for Kernel driver low bits" {
+    net_ivec_fatal_int            1  "Interrupt Generator";
+    legacy_int_vec                63 "LEGACY_INT_VEC";
+  };
+
+  
+  // 5.31 would be 128 bits bit
+  register int_en_reg_ker_lo rw addr(base, 0x00000010) 
+   "Kernel driver Interrupt enable register" {
+    _                             50 rsvd;
+    ker_int_leve_sel              6     
+    "Should always be set to 0 when MSI-X interrupts are being used";
+    _                             4   rsvd;
+    ker_int_ker                   1   "not documented";
+    _                             2   rsvd;
+    drv_int_en_ker                1   "Interrupt enable";
+  };
+  
+  register int_en_reg_ker_hi rw addr(base, 0x00000018) 
+   "Kernel driver Interrupt enable register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.34 would be 128 bits (higher bits should never be read)
+  register int_isr0_reg_lo ro addr(base, 0x00000090) 
+   "Interrupt Acknowlege Status register" {
+    int_isr_reg                   32 ro
+    "Satus of pending interrupts of the function (non MSI/MSI-X)";
+  };
+
+  // 5.43 would be 128 bits 
+  
+  register usr_ev_cfg_lo rw addr(base, 0x00000100) 
+   "Documentaion to be written for usr_ev_config" {
+    _                             47 rsvd;
+    usrev_dis                     1  "";
+    _                             6  rsvd;
+    dflt_evq                      10 "";
+  };
+               
+  register usr_ev_cfg_hi rw addr(base, 0x00000108) 
+   "Documentaion to be written for usr_ev_config" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  /*
+  // 5.46 
+  regarray usr_ev_reg_lo wo addr(base, 0x00000540) [1024; 0x2000] "Table" {
+    _                            32 rsvd;
+    usr_ev_data                  32 wo "31 bits of data to be posted to USER_EV";
+  };
+
+  regarray usr_ev_reg_hi wo addr(base, 0x00000548) [1024; 0x2000] "Table" {
+    _                            63 rsvd;
+    bit                          1  "";
+  };
+  */
+  /************************************
+   *  SRAM Block
+   ***********************************/
+
+   //5.49 
+   
+//   regarray buf_full_tbl rw addr(base, 0x00800000) [147456; 0x8] "Buffer Table" {
+  regarray buf_full_tbl rw addr(base, 0x00800000) [1024; 0x8] "Buffer Table" {
+    buf_full_unused               13 "unused bits";
+    ip_dat_buf_size               1  type(ip_dat_buf_size)
+    "Buffer size";
+    buf_adr_region                2  type(buf_adr_region)
+    "Address region to be used for upper 18 bits";
+    buf_adr_fbuf                  34 "Buffer physical address middle bits [45:12]";
+    buf_owner_id_fbuf             14 "Buffer owner ID";
+  };
+
+  constants buf_adr_region "Address region" {
+    region_0      = 0b00 "Adress Region 0";
+    region_1      = 0b01 "Adress Region 1";
+    region_2      = 0b10 "Adress Region 2";
+    region_3      = 0b11 "Adress Region 3";
+  };
+  constants ip_dat_buf_size "Buffer size" {
+    buff_size_4k      = 0b00 "Buffer size 4k";
+    buff_size_8k      = 0b01 "Buffer size 8k, not supported";
+  };
+  
+  // 5.52 would be 128 bits
+  register buf_tbl_cfg_reg_lo addr(base, 0x00000600) 
+   "Buffer table configuration register" {
+    _                             61 rsvd;
+    buf_tbl_mode                  1   type(buf_tbl_mode)
+    "Buffer table mode";
+    _                             2   rsvd;
+  }; 
+  register buf_tbl_cfg_reg_hi addr(base, 0x00000608) 
+   "Buffer table configuration register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  }; 
+
+  constants buf_tbl_mode "Buffer table mode" {
+    half_mode_4b      = 0b00 "4 bytes per entry";
+    full_mobe_8b      = 0b01 "8 bytes per entry";
+  };
+  
+  // 5.55 would be 128 bits
+  
+  register buf_tbl_upd_reg_lo wo addr(base, 0x00000650) 
+   "Buffer table update register" {
+    buf_upd_cmd                   1  "Buffer table update command";
+    buf_clr_cmd                   1  
+    "Buffer table clear command. Cleared from start - end";
+    _                             10 rsvd;
+    buf_clr_end_id                20 "Starting buffer ID to be cleared";
+    _                             12 rsvd;
+    buf_clr_start_id              20 "Ending buffer ID to be cleared";
+  };
+  
+  register buf_tbl_upd_reg_hi wo addr(base, 0x00000658) 
+   "Buffer table update register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.58 would be 128 bits (bit 2 not documented)
+  register srm_parity_reg_lo rw addr(base, 0x00000670) "SRAM parity register" {
+    _                             61 rsvd;
+    bypass_ecc                    1  "Puts ECC into bypass mode";
+    sec_int                       1   
+    "Single/Double error corrects/detect contribute fatal interrupt register bits";
+    _                             1  rsvd;
+  }; 
+  
+  register srm_parity_reg_hi rw addr(base, 0x00000678) "SRAM parity register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+  // 5.61 would be 128 bits
+  register srm_cfg_reg_lo  rw addr(base, 0x00000630) 
+   "SRAM configuration register" {
+    _                             58 rsvd;
+    srn_oob_adr_inten             1   
+    "SRAM out-of-bound address checking interrupt enable";
+    srm_oob_buf_inten             1   
+    "SRAM out-of-bound buffer ID checking interrupt enable";     
+    srm_init_en                   1   "SRAM initialization enabled";
+    srm_num_bank                  1  type(srm_num_bank) 
+    "Number of SRAM banks";
+    srm_bank_size                 2  type(srm_bank_size)   
+    "On-board SRAM bank size";
+  };
+
+  register srm_cfg_reg_hi  rw addr(base, 0x00000638) 
+   "SRAM configuration register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+  
+  constants srm_bank_size "SRAM bank size" {
+    srm_size_72k    = 0b00 "72K deep SRAM";
+    reserved_0      = 0b01 "reserved0";
+    reserved_1      = 0b10 "reserved1";
+    reserved_2      = 0b11 "reserved2";
+  };
+  
+  constants srm_num_bank "SRAM bank size" {
+    srm_num_bank_1    = 0b0 "1 bank";
+    srm_num_bank_2    = 0b1 "2 bank";
+  };
+  
+  // 5.64 would be 128 bits
+  register srm_rx_dc_cfg_reg_lo  rw addr(base, 0x00000610) 
+   "SRAM receive descriptor cache configuration regsiter" {
+    _                             42  rsvd;
+    srm_clk_tmp_en                1   "undocumented field";
+    srm_rx_dc_base_adr            21  
+    "Receive descriptor cache startilng address in SRAM";
+  };
+   
+  register srm_rx_dc_cfg_reg_hi  rw addr(base, 0x00000618) 
+   "SRAM receive descriptor cache configuration regsiter" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+   
+  
+  // 5.67 would be 128 bits
+  register srm_tx_dc_cfg_reg_lo  rw addr(base, 0x00000620) 
+   "SRAM transmit descriptor cache configuration regsiter" {
+    _                             43 rsvd;
+    srm_tx_dc_base_adr            21  
+    "Transmit descriptor cache startilng address in SRAM";
+  };
+  register srm_tx_dc_cfg_reg_hi  rw addr(base, 0x00000628) 
+   "SRAM transmit descriptor cache configuration regsiter" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.70 would be 128 bits-
+  register srm_upd_evq_reg_lo  rw addr(base, 0x00000660) 
+   "Buffer talbe update register" {
+    _                             52 rsvd;
+    srm_upd_evq_id                12  
+    "Event queue to be used to return SRAM update done events";
+  };
+
+  register srm_upd_evq_reg_hi  rw addr(base, 0x00000668) 
+   "Buffer talbe update register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  /************************************
+   *  Event Time Block
+   ***********************************/
+
+  // 5.78 Must be written as DWORD
+  register drv_ev_reg_lo wo addr(base, 0x00000440) 
+  "Driver generated event register low bits" {
+    drv_ev_data                   64  
+    "Driver writes to this register to manufacture event";
+  };
+
+  register drv_ev_reg_hi wo addr(base, 0x00000448) 
+  "Driver generated event register high bits" {
+    _                             52 rsvd;
+    drv_ev_qid                    12  "Event queue ID";
+  };
+
+  // 5.81
+
+
+  register evq_cnt1_reg_lo  ro addr(base, 0x00000460) 
+  "Event counter 1 register low bits"{
+    evq_rx_req_cnt_lo             4  "Number of RX event requests bits 3:0";
+    evq_em_req_cnt                20 "Number of EM event requests";
+    evq_csr_req_cnt               20 "Number of CSR event requests";
+    evq_err_req_cnt               20 "Number of error event requests";
+  };
+
+  register evq_cnt1_reg_hi  ro addr(base, 0x00000468) 
+  "Event counter 1 register high bits"{
+    _                             1  rsvd;
+    evq_cnt_pre_fifo              7  "Number of entries in the event pre-FIFO";
+    evq_cnt_tobiu                 20 "Number of events delivered to the BIU";
+    evq_tx_req_cnt                20 "Number of TX event requests";
+    evq_rx_req_cnt_lo             16 "Number of RX event requests bits 19:4";
+  };
+  // 5.84 
+
+
+  register evq_cnt2_reg_lo  ro addr(base, 0x00000470)
+  "Event counter 2 register low bits"{
+    evq_wu_req_cnt                4  "Number of wake-up event requests bits 3:0";
+    evq_wet_req_cnt               20 "Number of write event timer requests";
+    evq_init_req_cnt              20 "Number of event init event requests";
+    evq_tm_req_cnt                20 "Number of timer event requests";
+  };
+
+
+  register evq_cnt2_reg_hi  ro addr(base, 0x00000478)
+  "Event counter 2 register high bits"{
+    _                             4  rsvd;
+    evq_upd_req_ctn               20 "Number of update requests";
+    evq_clr_req_cnt               20 "Number of clear requests";
+    evq_rdy_cnt                   4  "Number of entries in event post-FIFO";
+    evq_wu_req_cnt                16 "Number of wake-up event requests bits 19:4";
+  };
+
+  // 5.87 would be 128 bits
+  register evq_ctrl_reg_lo  rw addr(base, 0x00000450) 
+  "Event queue control register"{
+    _                             39  rsvd;
+    rx_evq_wakeup_mask            10 "Defines how wake-up events are delivered";
+    evq_ownerr_ctrl               1  "Ecent queue owner ID error control";
+    evq_fifo_at_th                7  
+    "Event queue FIFO almost full interrupt threshold";
+    evq_fifo_notaf_th             7 
+    "Event queue FIFO not almost full interrupt threshold";
+  };
+
+  register evq_ctrl_reg_hi  rw addr(base, 0x00000458) 
+  "Event queue control register"{
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+   // 5.90 would be 128 bits
+  regarray evq_ptr_tbl_lo  rw addr(base, 0x00f60000) [1024; 0x10] 
+  "Event queue pointer table"{
+    _                             23  rsvd;
+    evq_rptr_ign                  1  ro
+    "Hardware maintainend only (Prevents DOS attack)";
+    evq_dos_ptrotect_en           1  "Enables RPTP dos protection";
+    evq_nxt_wptr                  15 ro "Next event write pointer";
+    evq_en                        1  "Event queue enable";
+    evq_size                      3  type(evq_size)"Event queue size";
+    evq_buf_base_id               20 "Event queue buffer base ID";
+  };
+
+  regarray evq_ptr_tbl_hi  rw addr(base, 0x00f60008) [1024; 0x10] 
+  "Event queue pointer table"{
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  constants  evq_size "Event queue size" {
+    evq_size_512            = 0b000 "512 Entries";
+    evq_size_1k             = 0b001 "1k Entries";
+    evq_size_2k             = 0b010 "2k Entries";
+    evq_size_4k             = 0b011 "4k Entries";
+    evq_size_8k             = 0b100 "8k Entries";
+    evq_size_16k            = 0b101 "16k Entries";
+    evq_size_32k            = 0b110 "32k Entries";
+  };
+
+   // 5.93 
+  // TODO two addresses !
+  regarray evq_rptr_reg  wo addr(base, 0x00fa0000) [1024; 0x10] 
+  "Event queue read pointer register" {
+    _                             16  rsvd;
+    evq_rptr_vld                  1  "undocumented filed";
+    evq_rptr                      15 "If written queue's pointer is update";
+  };
+
+  regarray evq_rptr_reg_2  wo addr(base, 0x00000400) [1024; 0x2000] 
+  "Event queue read pointer register" {
+    _                             16 rsvd;
+    evq_rptr_vld                  1  "undocumented filed";
+    evq_rptr                      15 "If written queue's pointer is update";
+  };
+
+  // 5.102 would be 128 bits
+  regarray timer_command_reg_lo  wo addr(base, 0x00000420) [1024; 0x2000] 
+  "Timer command register table" {
+    _                              48  rsvd;
+    tc_timer_mode                  2   type(tc_timer_mode)"see TIMER_MODE";
+    tc_timer_val                   14  "see TIMER_VAL";
+  };
+
+  regarray timer_command_reg_hi  wo addr(base, 0x00000428) [1024; 0x2000] 
+  "Timer command register table" {
+    _                              63 rsvd;
+    bit                            1 "";
+  };
+  
+  constants  tc_timer_mode "Event queue size" {
+    timer_mode_dis          = 0b00 "Timer disabled";
+    timer_mode_immed_start  = 0b01 "Immediate start mode";
+    timer_mode_trig_start   = 0b10 "Receive trigger start mode";
+    timer_mode_int_hldoff   = 0b11 "Interrupt hold-off mode";
+  };
+
+  
+   // 5.105 would be 128 bits 
+  regarray timer_tbl_lo  rw addr(base, 0x00f70000) [1024; 0x10] "Timer table" {
+    _                             30 rsvd;
+    timer_q_en                    1  "tells timer logic that event queue is enabled";
+    int_armd                      1  "Used by HW";
+    int_pend                      1  "Used by HW";
+    host_notify_mode              1  "Controls what timer modes are available";
+    reload_timer_val              14 "Hold value to reload timer on expiration";
+    timer_mode                    2  "Timer counting mode";
+    timer_val                     14 "Timer value to be used for count-down";
+  }; 
+
+  regarray timer_tbl_hi  rw addr(base, 0x00f70008) [1024; 0x10] "Timer table" {
+    _                             63 rsvd;
+    bit                           1  "";
+  }; 
+  /************************************
+   *  Receive Datapath Block
+   ************************************/
+
+  // 5.110
+  // TODO constants for rx_ownerr_ctl
+
+  register rx_cfg_reg_lo  rw addr(base, 0x00000800) 
+  "Receive configuration register low bits" {
+    rx_hdr_split_pld_buf_size     2  
+    "Size of payload buffer(s) in 32-byte words bits 1:0";
+    rx_hdr_split_hdr_buf_size     9  
+    "Size of haeder buffer(s) in 32-byte words";
+    rx_pre_rff_ipg                4  
+    "Inter-packet gap between frames from Pre-RFF FIFO";
+    rx_tcp_sup                    1  
+    "Enable for TCP packets toeplitz has based 2-tuple IP addresses";
+    rx_ingr_en                    1  "undocumented field";
+    rx_ip_hash                    1  "Enable IPv4 toeplitz has support";
+    rx_hash_alg                   1  "Enables Toeplitz has algorithm";
+    rx_hash_insrt_hdr             1  
+    "Enables Toeplitz hash result and type insertion";
+    rx_desc_push_en               1  "undocumented field";
+    _                             4  rsvd;
+    rx_ownerr_ctl                 1  "Receive owner ID error control";
+    rx_xon_tx_th                  5  
+    "Receive Xon flow control threshold for status FIFO";
+    rx_xoff_tx_th                 5  
+    "Receive Xoff flow control threshold for status FIFO";
+    rx_usr_buf_size               9  "Receive user buffer size 32-byte units";
+    rx_xon_mac_th                 9  "Receive Xon flow control threshold";
+    rx_xoff_mac_th                9  "receive Xoff flow control threshold";
+    rx_xoff_mac_en                1  "Receive Xoff flow control enable";
+  };
+
+  register rx_cfg_reg_hi  rw addr(base, 0x00000808) 
+  "Receive configuration register high bits" {
+    _                             42 rsvd;
+    rx_min_kbuf_size              14 "Lower bound of kernel buffer size in bytes";
+    rx_hdr_split_en               1  "Global enable for header split feature";
+    rx_hdr_split_pld_buf_size     7  
+    "Size of payload buffer(s) in 32-byte words bits 8:2";
+  };
+
+  // 5.113 would be 128 bits
+  register rx_dc_cfg_reg_lo rw addr(base, 0x00000840) 
+  "Receive descriptor cache configuration register" {
+    _                             62 rsvd;
+    rx_dc_size                    2  type(rx_dc_size)
+    "Receive descriptor cache size";
+  };
+
+  register rx_dc_cfg_reg_hi  rw addr(base, 0x00000848) 
+  "Receive descriptor cache configuration register" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+
+  constants  rx_dc_size "Descriptor cache size" {
+     rx_dc_size_8              = 0b00 "8 descriptors";
+     rx_dc_size_16             = 0b01 "16 descriptors";
+     rx_dc_size_32             = 0b10 "32 descriptors";
+     rx_dc_size_64             = 0b11 "64 descriptors";
+  };
+
+  // 5.116
+  register rx_dc_pf_wm_reg_lo  rw addr(base, 0x00000850) 
+  "Receive descriptor cache pre-fetch watermark register" {
+    _                             52  rsvd;
+    rx_dc_pf_hwm                  6   "Receive descriptor pre-fetch high wm";
+    rx_dc_pf_lwm                  6   "Receive descriptor pre-fetch low wm";
+  };
+
+  register rx_dc_pf_wm_reg_hi  rw addr(base, 0x00000858) 
+  "Receive descriptor cache pre-fetch watermark register" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+
+  // 5.119
+  regarray rx_desc_ptr_tbl_hi  rw addr(base, 0x00f40008)  [1024; 0x10]
+  "Receive descriptor pointer table high bits" {
+    _                             37 rsvd;
+    rx_hdr_split                  1  "Queue is header queue of header-split pair";
+    _                             1  rsvd;
+    rx_iscsi_ddig_en              1  "Receive iSCSI data digest enable";
+    rx_iscsi_hdig_en              1  "Receive iSCSI header digest enable";
+    rx_desc_pref_act              1  ro 
+    "Receive descriptor pre-fetch request outstanding";
+    rx_dc_hw_rptr                 6  ro 
+    "Hardware read pointer to descriptor cache";
+    rx_descq_hw_rptr              12 ro 
+    "Hardware read pointer to descriptor ring";
+    rx_descq_sw_wptr              4 ro 
+    "Software write pointer to the descriptor ring bits 11:8";
+  };
+
+  regarray rx_desc_ptr_tbl_lo  rw addr(base, 0x00f40000)  [1024; 0x10]
+  "Receive descriptor pointer table low bits " {
+    rx_descq_sw_wptr              8 ro 
+    "Software write pointer to the descriptor ring bits 7:0";
+    rx_descq_buf_base_id          20 
+    "Queue buffer base ID programmed by software";
+    rx_descq_evq_id               12 "Event queue id for descriptor queue";
+    rx_descq_owner_id             14 "Owner of this DMA queue";
+    rx_descq_label                5  "Queue label to be returned to event queue";
+    rx_descq_size                 2  type(rx_descq_size) "Descriptor queue size";
+    rx_descq_type                 1  "Descriptor queue type";
+    rx_descq_jumbo                1  type(rx_descq_jumbo)
+    "Allow writing jumbo packets into memory";
+    rx_descq_en                   1  "Receive descriptor queue enable";
+  };
+
+
+  constants  rx_descq_size "Descriptor queue size" {
+     rx_descq_size_512         = 0b00 "512 descriptors";
+     rx_descq_size_1k          = 0b01 "1K descriptors";
+     rx_descq_size_2k          = 0b10 "2K descriptors";
+     rx_descq_size_4k          = 0b11 "4K descriptors";
+  };
+
+  constants  rx_descq_jumbo "Descriptor operatin in scatter mode " {
+     rx_descq_jumbo_non_scatter       = 0b0 "Operate in non-scatter mode";
+     rx_descq_jumbo_scatter           = 0b1 "Operate in scatter mode";
+  };
+   // 5.122
+  regarray rx_desc_upd_reg_lo  wo addr(base, 0x00000830) [1024; 0x2000] 
+  "Receive descriptor update register low bits" {
+    rx_desc                 64 "Receive descriptor";
+  }; 
+
+  regarray rx_desc_upd_reg_hi  wo addr(base, 0x00000838) [1024; 0x2000] 
+  "Receive descriptor update register high bits " {
+    _                       20 rsvd;
+    rx_desc_wptr            12 "Descriptor pointing to NEXT write descriptor";
+    rx_desc_push_cmd        1  type(rx_desc_push_cmd)
+    "Descriptor pushed along with pointer update";
+    _                       31 rsvd;
+  }; 
+  constants  rx_desc_push_cmd "Descriptor pushed" {
+     rx_desc_no_push        = 0b0 "Just write pointer";
+     rx_desc_push           = 0b1 "Descriptor to follow in next address";
+  };
+
+  // 5.125
+  register rx_filter_ctl_reg_lo  rw addr(base, 0x00000810) 
+  "Receive filter control registers low bits" {
+    multicast_nomatch_q_id_lo       7 "Resulting queue ID if no match low bits 6:0";
+    multicast_nomatch_rss_enabled   1  "Generate Toeplitz has if no match";
+    multicast_nomatch_ip_override   1  "Override RX IP filter if no match";
+    unicast_nomatch_q_id            12 "Default queue id if no match found";
+    unicast_nomatch_rss_enabled     1  "Generate Toeplitz has if no match found";
+    unicast_nomatch_ip_override     1  "Override RX IP Filter if no match found";
+    scatter_enbl_no_match_q         1  
+    "Enables buffer scatter for packets with no match in IP filter table";
+    udp_full_srch_limit             8  
+    "Limits the number of hops in full UDP searching";
+    _                               8 rsvd;
+    udp_wild_srch_limit             8  
+    "Limits the number of hops in wildcard UPD searching";
+    tcp_wild_srch_limit             8  
+    "Limits the number of hops in wildcard TCP searching";
+    tcp_full_srch_limit             8  
+    "Limits the number of hops in full TCP searching";
+  };
+
+  register rx_filter_ctl_reg_hi  rw addr(base, 0x00000818) 
+  "Receive filter control registers high bits" {
+    _                               26 rsvd;
+    ethernet_wildcard_search_limit  8  
+    "Number of table entries to examine during wildcard filter search";
+    ethernet_full_search_limit      8  
+    "Number of table entries to examine during full filter search";
+    rx_filter_all_vlan_ethertypes   1  "Filter VLAN IDs for all VLAN Ethertypes";
+    rx_vlan_match_ethertype         16 "Outer VLAN Ethertype"; 
+    multicast_nomatch_q_id_hi       5  "Resulting queue ID if no match high bits 11:7";
+  };
+
+  // 5.128
+  regarray rx_filter_tbl_lo  rw addr(base, 0x00f00000) [8192; 0x20]  
+  "Receive filter table low bits" {
+    dest_port_tcp                   16 
+    "Destination port number TCP full/wildcard";
+    src_ip                          32 "Source IP address";
+    src_tcp_dest_udp                16 
+    "Sourch port number of TCP full or destination UDP wildcard";
+  };
+
+  regarray rx_filter_tbl_hi  rw addr(base, 0x00f00008) [8192; 0x20]  
+  "Receive filter table high bits" {
+    _                               17 rsvd;
+    rss_en                          1  "Enable Indirection Table";
+    scatter_en                      1  "Enable buffer scatter";
+    tcp_udp                         1  "TCP or UDP indicator";
+    rxq_id                          12 "Receive queue ID";
+    dest_ip                         32 "Destination IP address";
+  };
+  constants  tcp_udp "TCP or UDP indicator" {
+     udp           = 0b0 "UDP";
+     tcp           = 0b1 "TCP";
+  };
+
+  // 5.1231 would be 128 bits
+  register rx_flush_descq_reg_lo  wo addr(base, 0x00000820) 
+  "Receive flush descriptor queue register" {
+    _                             39 rsvd;
+    rx_flush_descq_cmd            1  "Command to flush indicated descriptor queue";
+    _                             12 rsvd;
+    rx_flush_descq                12 "receive descriptor queue number to be flushed";
+  };
+
+  register rx_flush_descq_reg_hi  wo addr(base, 0x00000828) 
+  "Receive flush descriptor queue register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+  // 5.134
+  // padded to 8 bits documentation is 7 bits
+   regarray rx_indirection_tbl  rw addr(base, 0x00fb0000) [128; 0x10]
+  "RX indirection table"
+   type(it_queue);
+
+   regtype it_queue "Contains indirection result" {
+    _                             2 rsvd;
+    it_queue                      6 "Contains indirection result";
+   };
+
+  // 5.137
+  regarray rx_mac_filter_tbl_lo rw also addr(base, 0x00f00010) [512; 0x20]  
+  "Receive Ethernet filter table low bits" {
+    rmft_rxq_id_lo                3 "Receive queue ID low bits 2:0";
+    rmft_wildcard_match           1  "Entry matches in wildcard searches only";
+    rmft_dest_mac                 44 "Destination MAC address";
+    _                             4  rsvd; 
+    rmft_vlan_id                  12 "Destination VLAN ID";
+  };
+
+  regarray rx_mac_filter_tbl_hi rw also addr(base, 0x00f00018) [512; 0x20]  
+  "Receive Ethernet filter table low bits" {
+    _                             52 rsvd;
+    rmft_rss_en                   1  "Enable Indirection Table if match";
+    rmft_scatter_en               1  "Enable buffer scatter if match";
+    rmft_ip_override              1  
+    "Match in RX Ethernet filter table will override match in RX filter talbe";
+    rmft_rxq_id_hi                9  "Receive queue ID high bits 11:3";
+  };
+
+  // 5.140 would be 128 bits
+  register rx_nodesc_drop_reg_lo   rc addr(base, 0x00000880) 
+  "Receive dropped packet counter register" {
+    _                             32 rsvd;
+    rx_nodesc_drop_cnt            32 "Count of dropped packets by RX module";
+  };
+  register rx_nodesc_drop_reg_hi   rc addr(base, 0x00000888) 
+  "Receive dropped packet counter register" {
+    _                             63 rsvd;
+    bit                           1 "";
+  };
+  // 5.143 would be 128 bits
+  register rx_push_drop_reg_lo     rc addr(base, 0x000008b0) 
+  "Receive descriptor push droped count register" {
+    _                             32 rsvd;
+    rx_nodesc_drop_cnt            32 "Count of descriptor pushes dropped";
+  };
+
+  register rx_push_drop_reg_hi     rc addr(base, 0x000008b8) 
+  "Receive descriptor push droped count register" {
+    _                             63 rsvd;
+    bit                           1 "";
+  };
+
+ // 5.146
+  register rx_rss_ipv6_reg1_lo     rw addr(base, 0x000008d0) 
+  "IPv6 RSS Toeplitz has key bytes 63:0" {
+    rx_rss_ipv6_tkey_lo_lo        64 "IPv6 RSS Toeplitz hash key 63:0";
+  };
+  register rx_rss_ipv6_reg1_hi     rw addr(base, 0x000008d8) 
+  "IPv6 RSS Toeplitz has key bytes 127:64" {
+    rx_rss_ipv6_tkey_lo_hi        64 "IPv6 RSS Toeplitz hash key 127:64";
+  };
+  // 5.149
+  register rx_rss_ipv6_reg2_lo     rw addr(base, 0x000008e0) 
+  "IPv6 RSS Toeplitz has key bytes 191:128" {
+    rx_rss_ipv6_tkey_mid_lo       64 "IPv6 RSS Toeplitz hash key 191:128";
+  };
+
+  register rx_rss_ipv6_reg2_hi    rw addr(base, 0x000008e8) 
+  "IPv6 RSS Toeplitz has key bytes 255:192" {
+    rx_rss_ipv6_tkey_mid_hi       64 "IPv6 RSS Toeplitz hash key 255:128";
+  };
+
+  // 5.152
+  register rx_rss_ipv6_reg3_lo    rw addr(base, 0x000008f0) 
+  "IPv6 RSS Toeplitz has key bytes 320:256" {
+    rx_rss_ipv6_tkey_hi              64 "IPv6 RSS Toeplitz hash key 320:256";
+  };
+
+  register rx_rss_ipv6_reg3_hi    rw addr(base, 0x000008f8) 
+  "IPv6 RSS Toeplitz has key bytes 320:256" {
+    _                                61 rsvd;
+    rx_rss_ipv6_thash_enable         1  "Global enable IPv6 Toeplitz hash";
+    rx_rss_ipv6_ip_thash_enable      1  
+    "Enable generation of Toeplitz hash non-TCP IPv6";
+    rx_rss_ipv6_tcp_suppress         1  
+    "Force generation 2-tuple hash for IPv6/TCP";
+  };
+
+  // 5.155
+  register rx_rss_tkey_reg_lo    rw addr(base, 0x00000860) 
+  "RSS Toeplitz has key low bytes" {
+    rx_rss_tkey_lo              64 "RSS Toeplitz hash key low";
+  };
+
+  register rx_rss_tkey_reg_hi   rw addr(base, 0x00000868) 
+  "RSS Toeplitz has key high bytes" {
+    rx_rss_tkey_hi              64 "RSS Toeplitz hash key high";
+  };
+
+
+  /************************************
+   *  Transmit Datapath Block
+   ************************************/ 
+
+  // 5.160 
+  // TODO tx_ownerr_ctl constant ? 
+  register tx_cfg_reg_lo  rw addr(base, 0x00000a50) 
+  "Transmit configuration register low bits" {
+    tx_vlan_match_ethertype_range          16 "Outer VLAN Ethertype";
+    tx_filter_en_bit                       1  "Enable TX filtering";
+    _                                      16 rsvd;
+    tx_ip_id_p0_ofs                        15 "Transmit IP ID port 0 offset";
+    _                                      10 rsvd;
+    tx_no_eop_disc_en                      1  
+    "Enables discarding of corrupting TX packets";
+    _                                      2  rsvd;
+    tx_ownerr_ctl                          1  "Transmit owner ID error control";
+    _                                      1  rsvd;
+    tx_ip_id_rep_en                        1  
+    "Transmit IP identification field replacement enable";
+  };
+
+  register tx_cfg_reg_hi  rw addr(base, 0x00000a58) 
+  "Transmit configuration register high bits" {
+    _                                      6  rsvd;
+    tx_cont_lookup_thresh_range            8  
+    "TX control word buffer TX filter lookup buffer threshold";
+    tx_filter_test_mode                    1  "Forces full lookup on all packets";
+    tx_eth_filter_wild_search_range        8  
+    "Wildcard search depth Ethernet filter";
+    tx_eth_filter_full_search_range        8  "Full search depth Ethernet filter";
+    tx_udpip_filter_wild_search_range      8  
+    "Wildcard search depth for IPv4/UPD filter";
+    tx_udpip_filter_full_search_range      8  "Full search depth IPv4/UDP filter";
+    tx_tcpip_filter_wild_search_range      8  
+    "Wildcard search depth for IPv4/TCP filter";
+    tx_tcpip_filter_full_search_range      8  "Full search depth IPv4/TCP filter";
+    tx_filter_all_vlan_ethertype_range     1  
+    "Filter VLAN IDs for all VLAN Ethertypes";
+  };
+  // 5.163 would be 128 bits
+  register tx_dc_cfg_reg_lo  rw addr(base, 0x00000a20) 
+  "Transmit descriptor cache configuration register" {
+    _                             62  rsvd;
+    tx_dc_size                    2   type(tx_dc_size)
+    "Transmit descriptor cache size";
+  };
+
+  register tx_dc_cfg_reg_hi  rw addr(base, 0x00000a28) 
+  "Transmit descriptor cache configuration register" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+
+  constants  tx_dc_size " TX Descriptor cache size" {
+     tx_dc_size_8              = 0b00 "8 descriptors";
+     tx_dc_size_16             = 0b01 "16 descriptors";
+     tx_dc_size_32             = 0b10 "32 descriptors";
+     tx_dc_size_r              = 0b11 "reserved";
+  };
+
+  // 5.166
+  regarray tx_desc_ptr_tbl_lo  rw addr(base, 0x00f50000)  [1024; 0x10] 
+  "Transmit descriptor pointer table low bits" {
+    tx_descq_sw_wptr              8  ro
+    "Software write pointer to the descriptor ring bits 7:0";
+    tx_descq_buf_base_id          20 "Queue buffer base ID programmed by software";
+    tx_descq_evq_id               12 "Event queue id for descriptor queue";
+    tx_descq_owner_id             14 "Owner of this DMA queue";
+    tx_descq_label                5  "Queue label to be returned to event queue";
+    tx_descq_size                 2  "Descriptor queue size";
+    tx_descq_type                 2  type(tx_descq_size) 
+    "Descriptor adressing mode";
+    tx_descq_flush                1  "Descriptor queue flush";
+  };
+
+  regarray tx_desc_ptr_tbl_hi  rw addr(base, 0x00f50008)  [1024; 0x10] 
+  "Transmit descriptor pointer table high bits" {
+    _                             32  rsvd;
+    tx_dpt_q_mask_widht           2  
+    "Masks out the lower TX_DPT_Q_MAS_WIDHT bits";
+    tx_dtp_eth_filter_en          1  "Enable Ethernet filtering";
+    tx_dtp_ip_filter_en           1  "Enable IPv4 TCP/UDP filtering";
+    tx_non_ip_drop_dis            1  
+    "Disable IPv4 TCP/UDP filtering if 0 non-IPv4 TCP/UDP filter enable";
+    tx_ip_chksm_dis               1  "Disables IP checksum offload";
+    tx_tcp_chksm_dis              1  "Disables TCP/UDP checksum offload";
+    tx_descq_en                   1  "Transmit descriptor queue enable";
+    tx_iscsi_ddig_en              1  "Transmit iSCSI data digest enable";
+    tx_iscsi_hdig_en              1  "Transmit iSCSI header digest enable";
+    tx_dc_hw_rptr                 6  ro "Hardware read pointer to descriptor cache";
+    tx_descq_hw_rptr              12 ro "Hardware read pointer to descriptor ring";
+    tx_descq_sw_wptr              4  ro
+    "Software write pointer to the descriptor ring bits 11:8";
+
+  };
+
+  constants  tx_descq_size "Descriptor queue size" {
+     tx_descq_size_512         = 0b00 "512 descriptors";
+     tx_descq_size_1k          = 0b01 "1K descriptors";
+     tx_descq_size_2k          = 0b10 "2K descriptors";
+     tx_descq_size_4k          = 0b11 "4K descriptors";
+  };
+
+  // 5.169
+  regarray tx_desc_upd_reg_lo  wo addr(base, 0x00000a10)  [1024; 0x2000] 
+  "Char & user transmit descriptor update register low bits" {
+    tx_desc                       64 "Transmit descriptor bits 63:0";
+  };
+
+  regarray tx_desc_upd_reg_hi  wo addr(base, 0x00000a18)  [1024; 0x2000] 
+  "Char & user transmit descriptor update register" {
+    _                             20  rsvd;
+    tx_desc_wptr                  12 "Decriptor write pointer";
+    tx_desc_push_cmd              1  "push descriptor into next address";
+    tx_desc                       31 "Transmit descriptor bits 94:64";
+  };
+
+  // 5.172
+  /* Don't need it for now
+  regarray tx_filter_tbl_lo  rw addr(base, 0x00fc0000)  [8192; 0x10] 
+  "Transmit filter table low bits" {
+    tift_dest_port_tcp            16 
+    "Destination port number TCP full/wildcard";
+    tift_src_ip                   32 "Source IP address";
+    tift_src_tcp_dest_udp         16 
+    "Sourc port number TCP full or destination UDP wildcard";
+  };
+  */
+  /* TODO no support for transmit filtering in code yet
+  regarray tx_filter_tbl_hi  rw addr(base, 0x00fc0008)  [8192; 0x10] 
+  "Transmit filter table" {
+    _                             19  rsvd;
+    tift_tcp_udp                  1   type(tift_tcp_udp)
+    "TCP or UDP indicator";
+    tift_txq_id                   12 "Transmit queue ID";
+    tift_dest_ip                  32 "Destination IP address";
+  };
+
+  constants  tift_tcp_udp  "TCP or UDP indicator" {
+     tift_udp          = 0b0 "UDP";
+     tift_tcp          = 0b1 "TCP";
+  };
+  */
+
+  // 5.175 would be 128 bits
+  register tx_flush_descq_reg_lo  wo addr(base, 0x00000a00) 
+  "Transmit flush descriptor queue register" {
+    _                             51 rsvd;
+    tx_flush_descq_cmd            1   "Flush indicated Trasmit descriptor queue";
+    tx_flush_descq                12  "Transmit descriptor queue number flushed";
+  };
+  register tx_flush_descq_reg_hi  wo addr(base, 0x00000a08) 
+  "Transmit flush descriptor queue register" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+
+  // 5.178
+  /*
+  regarray tx_mac_filter_tbl_lo  rw also addr(base, 0x00fe0000) [512; 0x10] 
+  "Transmit Ethernet filter table low bits" {
+    tmft_txq_id                   3  "Transmit queue ID bits 2:0";
+    tmft_wildcard_match           1  "Match wildcard searches only";
+    tmft_src_mac                  44 "Source MAC address";
+    _                             4  rsvd;
+    tmft_vlan_id                  12 "Destination VLAN ID";
+  };
+
+  regarray tx_mac_filter_tbl_hi  rw also addr(base, 0x00fe0008) [512; 0x10] 
+  "Transmit Ethernet filter table high bits" {
+    _                             55 rsvd;
+    tmft_txq_id                   9  "Transmit queue ID bits 11:3";
+  };
+  */
+  // 5.181 would be 128 bits
+  register tx_pace_drop_qid_lo_reg  rc addr(base, 0x00000aa0) 
+  "PACE Drop QID Counter" {
+    _                             48 rsvd;
+    tx_pace_qid_drp_cnt           16 "Count of Dropped QIDs";
+  };
+
+  register tx_pace_drop_qid_hi_reg  rc addr(base, 0x00000aa8) 
+  "PACE Drop QID Counter" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.184 would be 128 bits
+  register tx_pace_reg_lo  rw addr(base, 0x00000a90) 
+  "Transmit pace control register" {
+    _                             55 rsvd;
+    tx_pace_fb_base               4  
+    "Transmit pace fast bin base starting location";
+    tx_pace_bin_th                5  "Transmit pacing binning threshold";
+  };
+
+  register tx_pace_reg_hi  rw addr(base, 0x00000a98) 
+  "Transmit pace control register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+
+  // 5.187 would be 128 bits
+  regarray tx_pace_tbl_lo  rw addr(base, 0x00f80000)  [1024; 0x10] "Transmit pacing table" {
+    _                             59  rsvd;
+    tx_pace                       5   "Descriptor queue flush";
+  };
+
+  regarray tx_pace_tbl_hi  rw addr(base, 0x00f80008)  [1024; 0x10] "Transmit pacing table" {
+    _                             63  rsvd;
+    bit                           1   "";
+  };
+  // TODO right constants ? problems with c code 
+ /*
+  constants  tx_pace "Descriptor queue size" {
+     tx_pace_00                 = 0b00000 "0 micro sec";
+     tx_pace_02                 = 0b00001 "0.2 micro sec";
+     tx_pace_04                 = 0b00010 "0.4 micro sec";
+     tx_pace_08                 = 0b00011 "0.8 micro sec";
+     tx_pace_1_6                = 0b00100 "1.6 micro sec";
+     tx_pace_3_2                = 0b00101 "3.2 micro sec";
+     tx_pace_6_4                = 0b00110 "6.4 micro sec";
+     tx_pace_12_8               = 0b00111 "12.8 micro sec";
+     tx_pace_25_6               = 0b01000 "25.6 micro sec";
+     tx_pace_51_2               = 0b01001 "51.2 micro sec";
+     tx_pace_100                = 0b01010 "100 micro sec";
+     tx_pace_200                = 0b01011 "200 micro sec";
+     tx_pace_400                = 0b01100 "400 micro sec";
+     tx_pace_800                = 0b01101 "800 micro sec";
+     tx_pace_1_6n               = 0b01110 "1.6 nano sec";
+     tx_pace_3_2n               = 0b01111 "3.2 nano sec";
+     tx_pace_6_4n               = 0b10000 "6.4 nano sec";
+     tx_pace_12_8n              = 0b10001 "12.8 nano sec";
+     tx_pace_25_6n              = 0b10010 "25.6 nano sec";
+     tx_pace_51_2n              = 0b10011 "51.2 nano sec";
+     tx_pace_100n               = 0b10100 "100 nano sec";
+     tx_pace_200n               = 0b10101 "200 nano sec";
+     tx_pace_400n               = 0b10110 "400 nano sec";
+     tx_pace_800n               = 0b10111 "800 nano sec";
+     tx_pace_1_6m               = 0b11000 "1.6 msec";
+     tx_pace_3_2m               = 0b11010 "3.2 msec";
+     tx_pace_50k                = 0b10011 "5 msec";
+     tx_pace_100k               = 0b10100 "10 msec ";
+  };
+  */
+  // 5.190 would be 128 bits
+  register tx_push_drop_reg_lo  rc addr(base, 0x00000a60) 
+  "Transmit push dropped register" {
+    _                             32 rsvd;
+    tx_push_drop_cnt              32 
+    "Number of pushed descriptor not taken by hw";
+  };
+
+  register tx_push_drop_reg_hi  rc addr(base, 0x00000a68) 
+  "Transmit push dropped register" {
+    _                             63 rsvd;
+    bit                           1  "";
+  };
+  // 5.193 
+  register tx_reserved_reg_lo  rw addr(base, 0x00000a80)
+  "Transmit configuration register low bits" {
+    _                             3  rsvd;
+    tx_drop_abort_en              1  "TX drop aborted DLLP enable";
+    tx_soft_evt_en                1  
+    "Software TX user per descriptor event enable";
+    _                             1  rsvd;
+    tx_rx_spacer_en               1  "TX DMA spacer enable when exceed threshold";
+    _                             5  rsvd;
+    tx_pref_spacer                8  "TX pre-fetch slowdown spacer";
+    tx_pref_wd_tmr                22 "Transmit pre-fetch watch-dog timer";          
+    tx_only1tag                   1  
+    "Transmit read limit to one outstanding request at a time";
+    tx_pref_threshold             2  type(tx_pref_threshold)
+    "Transmit pre_fetch threshold";
+    tx_one_pkt_per_q              1  "One packet per queue";
+    tx_dis_non_ip_ev              1  
+    "Disable generation of TX_PKT_NON_TCP_UDP event";
+    _                             1  rsvd;
+    tx_dma_spacer                 8  "Transmit DMA spacer (slow down DMA)";
+    tx_flush_min_len_en           1  "Transmit owner ID error control";
+    _                             3  rsvd;
+    tx_max_cpl                    2  type(tx_max_cpl)
+    "Number of transmit descriptor per batched transmit event";
+    tx_max_pref                   2  type(tx_max_pref)
+    "Max number of descriptor pre-fetches per queue";
+  };
+   
+    // Field tx_push_en not documentet (from linux driver)
+  register tx_reserved_reg_hi  rw addr(base, 0x00000a88)
+  "Transmit configuration register high bits" {
+    _                             7  rsvd;
+    tx_pref_age_cnt               2  ro "Count of pre-fetch aging occurances";
+    _                             28 rsvd;
+    tx_push_en                    1  "TX_PUSH_EN";
+    tx_push_chk_dis               1  "Push checksum disable";
+    _                             17  rsvd;
+    tx_rx_spacer                  8  "TX DMA spacer when exceeds high threshold";
+  };
+
+
+  constants  tx_max_pref "Max number of descriptor pre-fetches per queue" {
+     tx_max_pref_0           = 0b00 "no limit";
+     tx_max_pref_8           = 0b01 "8 descriptors";
+     tx_max_pref_16          = 0b10 "16 descriptors";
+     tx_max_pref_32          = 0b11 "32 descriptors";
+  };
+
+  constants  tx_max_cpl 
+  "Number of transmit descriptor per batched transmit event" {
+     tx_max_max_0                = 0b00 "no limit";
+     tx_max_max_8                = 0b01 "4 descriptors";
+     tx_max_max_16               = 0b10 "8 descriptors";
+     tx_max_max_32               = 0b11 "16 descriptors";
+  };
+
+  constants  tx_pref_threshold "Transmit pre-fetch threshold" {
+     tx_pre_threshold_0           = 0b00 "pre-fetch when <= 0 descriptors";
+     tx_pre_threshold_2           = 0b01 "pre-fetch when <= 2 descriptors";
+     tx_pre_threshold_4           = 0b10 "pre-fetch when <= 4 descriptors";
+     tx_pre_threshold_6           = 0b11 "pre-fetch when <= 6 descriptors";
+  };
+
+  /************************************
+   *  Sideband Management Block
+   ***********************************/
+
+  // 5.599 
+  regarray mc_dma_buf_state_0  ro addr(base, 0x0018c060) [4;0x4]
+  "Word 0 of buffer state (one for each buffer)" {
+    mc_dma_buf_state_rd_ptr       16 "Read pointer 16-byte words";
+    mc_dma_buf_state_wr_ptr       16 "Write pointer in 16-byte words";
+  };
+  
+  // 5.602
+  regarray mc_dma_buf_state_1  rw addr(base, 0x0018c070) [4;0x4]
+  "Word 1 of buffer state (one for each buffer)" {
+    _                             3  rsvd;
+    mc_dma_buf_state_fill         13 ro "Num. of 16 byte words in buffer";
+    _                             3  rsvd;
+    mc_dma_buf_state_af_wmark     13 
+    "Buffer almost full watermark (16-byte words)";
+  };
+    
+  // 5.605
+  regarray mc_dma_buf_state_2  rw addr(base, 0x0018c080) [4;0x4]
+  "Word 2 of buffer state (one for each buffer)" {
+    _                             1  rsvd;
+    mc_dma_buf_state_empty        1  ro "buffer is empty";
+    mc_dma_buf_state_full         1  ro "buffer is full";
+    mc_dma_buf_state_af           1  ro "buffer is almost full";
+    _                             16 rsvd;
+    mc_dma_buf_state_eaddr        6  "buffer end addr in 1K-byte words";
+    mc_dma_buf_state_saddr        6  "Buffer start addr in 1K-byte words";
+  };
+
+  // 5.608 
+  register mc_dma_buf_status_reg  rc addr(base, 0x0018c0a4)
+  "DMA buffer status register" {
+    _                             28 rsvd;
+    mc_dma_tx_cmd_cntr_decr       4  
+    "One bit for each DMA buffer, set when TX command completes for that buffer";
+  };
+
+  // 5.611
+  register mc_dma_indr_buf_acc_reg  rw addr(base, 0x0018c090)
+  "" {
+    _                             30 rsvd;
+    mc_dma_indr_buf_acc_val       2  type(buffer);
+  };
+
+  constants buffer "Selected Buffer" {
+    buffer_ncsi_mac      = 0b00 "Buffer 0/NCSI-MAC";
+    buffer_port_0        = 0b01 "Buffer 1/Network port 0";
+    buffer_port_1        = 0b10 "Buffer 2/Network port 1";
+    buffer_all           = 0b11 "Buffer 3 (all of packet memory)";
+  };
+
+  // 5.614
+  regarray mc_dma_pkt_drop_buf_full_cntr rc addr(base, 0x0018c040) [3;0x4]
+  "Packet drop count for each port due to buffer full" {
+    dma_pkt_drop_buf_full_cntr    32 
+    "Packet drop count for each port (buffer full)";
+  };
+
+  // 5.617
+  regarray mc_dma_pkt_drop_data_ff_full_cntr rc addr(base, 0x0018c030) [3;0x4]
+  "Packet drop count due to FIFO full" {
+    dma_pkt_drop_data_data_ff_full_cntr    32
+    "Packet drop count for each port (FIFO full)";
+  };
+
+  // 5.620
+  regarray mc_dma_pkt_drop_evq_full_cntr rc addr(base, 0x0018c050) [3;0x4]
+  "Packet drop count due to rx event queue full" {
+    dma_pkt_drop_evq_full_full_cntr    32
+    "Packet drop count for each port (RX event q full)";
+  };
+
+  // MC_DMA_PMEM not in yet -> too big
+
+  // 5.626
+  regarray mc_dma_rx_evq ro addr(base, 0x0018c010) [3;0x4]
+  "RX event queues" {
+    _                             3  rsvd;
+    mc_dma_rx_evq_len             16 "Packet length in bytes including padding";
+    mc_dma_rx_evq_addr            12 "Packet starts at this 16-byte address";
+    mc_dma_rx_evq_crc_err         1  "packet has MAC CRC error";
+  };
+
+  // 5.629
+  regarray mc_dma_rx_evq_checksum ro addr(base, 0x0018c094) [3;0x4]
+  "RX event queues" {
+    mc_dma_rx_evq_chksum          16  "";
+  };
+
+  // 5.632 padded to 8 bits documentation is 4
+  register mc_dma_status_reg ro addr(base, 0x0018c000)
+  "DMA command andevent queue statsu register" {
+    _                             4 rsvd;
+    mc_dma_status_rx_evq_vld2     1  
+    "RX event queue for port 2 (Network port 1) has event";
+    mc_dma_status_rx_evq_vld1     1  
+    "RX event queue for port 1 (Network port 0) has event";
+    mc_dma_status_rx_evq_vld0     1  
+    "RX event queue for port 0 (NCSI) has event";
+    mc_dma_status_tx_cmq_rdy      1  
+    "TX command queue has room for more commands";
+  };
+
+  // 5.635
+  regarray mc_dma_tx_cmd_cntr ro addr(base, 0x0018c020) [4;0x4]
+  "RX event queues" {
+    dma_tx_cmd_cntr               32  "";
+  };
+
+  // 5.638
+  register mc_dma_tx_cmq_reg wo addr(base, 0x0018c008)
+  "RX event queues" {
+    mc_dma_tx_cmq_prt_sel         2  type(interface)
+    "Select transmit interface";
+    mc_dma_tx_cmq_buf_sel         2  type(buffer)
+    "Selected source buffer (use 3 if op == 1)";
+    mc_dma_tx_cmq_len             14
+    "Number of bytes to transmit or to pop including 2 byte header";
+    mc_dma_tx_cmq_addr            12 "Address in 16-byte words (only optcode 1)";
+    mc_dma_tx_cmq_op              2  type(opcode) "Opcode";
+  };
+  
+  constants interface "Selected Interface" {
+    interface_ncsi_mac      = 0b00 "NCSI-MAC";
+    interface_port_0        = 0b01 "Network MAC port 0";
+    interface_port_1        = 0b10 "Network MAC port 1";
+  };
+
+  constants opcode "Selected Interface" {
+    transmit_circular_buffer      = 0b00 
+    "Transmit (len) bytes using circular buffer state";
+    supplied_address              = 0b01 
+    "Transmit (len) bytes starting from supplied address";
+    pop_circular_buffer           = 0b10 
+    "Pop (len) bytes using circular buffer state";
+  };
+
+  // 5.997 padded to 8 bits documentation is 3
+  register mc_rstctrl_reg  rw addr(base, 0x00480030) 
+  "Reset configuration Control register" {
+    _                             5  rsvd;
+    mc_swrst_slfclr_en_reset      1  "Enables global soft reset self clearing";
+    mc_swrst_mst_en_reset         1  "Enables global master soft reset";
+    mc_swrst_en_reset             1  "Enables global soft reset";
+  };
+
+  // 5.1003
+  register mc_rstvec_biu_mst_reg  rw addr(base, 0x00480038) 
+  "BIU and PCIE Reset control register (Master reset)" {
+    mc_pciesd_aux_mst_reset       1  "PCIE Serdes Aux reset";
+    mc_pciesd_mst_reset           1  "PCIE Serdes reset";
+    mc_biu_cs_mst_reset           1  "Not implemented";
+    mc_pcie_stky_mst_reset        1  "PCIE core Sticky reset";
+    mc_pcie_nstky_mst_reset       1  "PCIE core non-Sticky reset";
+    mc_pcie_core_mst_reset        1  "PCIE core reset if set";
+    mc_biu_mst_reset              1  "BIU reset";
+    mc_pcie_pwr_mst_reset         1  "PCIE core PWR reset if set";
+  };
+
+  // 5.1006
+  register mc_rstvec_biu_reg  rw addr(base, 0x00480028) 
+  "BIU and PCIE Reset control register (Soft reset)" {
+    mc_pciesd_aux_reset           1  "PCIE Serdes Aux reset";
+    mc_pciesd_reset               1  "PCIE Serdes reset";
+    mc_biu_cs_reset               1  "Not implemented";
+    mc_pcie_stky_reset            1  "PCIE core Sticky reset";
+    mc_pcie_nstky_reset           1  "PCIE core non-Sticky reset";
+    mc_pcie_core_reset            1  "PCIE core reset if set";
+    mc_biu_reset                  1  "BIU reset";
+    mc_pcie_pwr_reset             1  "PCIE core PWR reset if set";
+  };
+
+  // 5.1009
+  regtype mc_rstvec_bpx_mst_reg
+  "Reset Control register for BPX port (Master reset)" {
+    mc_autoneg_mst_reset          1  "Auto neg Port reset";
+    mc_sgmii_mst_reset            1  "SGMII Port reset";
+    mc_xgbr_mst_reset             1  "XGBR Port reset";
+    mc_xgxs_mst_reset             1  "XGXS Port reset";
+    mc_xfidp_mst_reset            1  "XFI Port digital reset";
+    mc_xfiap_mst_reset            1  "XFI Port analog reset";
+    mc_sdp_mst_reset              1  "XAUI Serdes Port reset";
+    mc_pbx_mst_reset              1  "BPX port reset";
+  };
+
+  register p0_mc_rstvec_bpx_mst_reg rw addr(base, 0x00480210)
+  "Port 0 Reset control register for BPX Port (Master reset)"
+    type(mc_rstvec_bpx_mst_reg);
+
+  register p1_mc_rstvec_bpx_mst_reg rw addr(base, 0x00480214)
+  "Port 1 Reset control register for BPX Port (Master reset)"
+    type(mc_rstvec_bpx_mst_reg);
+ // 5.1012
+  regtype mc_rstvec_bpx_reg
+  "Reset Control register for BPX port (Soft reset)" {
+    mc_autoneg_reset          1  "Auto neg Port reset";
+    mc_sgmii_reset            1  "SGMII Port reset";
+    mc_xgbr_reset             1  "XGBR Port reset";
+    mc_xgxs_reset             1  "XGXS Port reset";
+    mc_xfidp_reset            1  "XFI Port digital reset";
+    mc_xfiap_reset            1  "XFI Port analog reset";
+    mc_sdp_reset              1  "XAUI Serdes Port reset";
+    mc_pbx_reset              1  "BPX port reset";
+  };
+
+  register p0_mc_rstvec_bpx_reg rw addr(base, 0x00480200)
+  "Port 0 Reset control register for BPX Port (Soft reset)"
+    type(mc_rstvec_bpx_reg);
+
+  register p1_mc_rstvec_bpx_reg rw addr(base, 0x00480204)
+  "Port 1 Reset control register for BPX Port (Soft reset)"
+    type(mc_rstvec_bpx_reg);
+
+ // 5.1015 padded to 32 bits documentation is 21
+    register mc_rstvec_mc_mst_reg rw addr(base, 0x0048003c)
+  "Reset Control register for BPX port (Master reset)" {
+    _                             11 rsvd;
+    mc_flow_mngr_mst_reset        1  "MC FLOW_MNGR reset";
+    mc_mips_mst_reset             1  "MC MIPS 1 reset";
+    mc_mdio1_mst_reset            1  "MC MDIO 1 reset";
+    mc_mdio0_mst_reset            1  "MC MDIO 0 reset";
+    mc_rmii_gmac_mst_reset        1  "MC Management GMAC reset";
+    mc_spi_mst_reset              1  "MC SPI reset";
+    mc_i2c_mst_reset              1  "MC I2C reset";
+    mc_uart1_mst_reset            1  "MC UART 1 reset";
+    mc_uart0_mst_reset            1  "MC UART 0 reset";
+    mc_vmi_mst_reset              1  "MC VMI reset";
+    mc_dbi_mst_reset              1  "MC DBI reset";
+    mc_tlp_mst_reset              1  "MC TLP reset";
+    mc_ktchn_mst_reset            1  "MC PCIE Kitchen Sink reset";
+    mc_treg_mst_reset             1  "MC TREG reset";
+    mc_ireg1_mst_reset            1  "MC IREG 1 reset";
+    mc_ireg0_mst_reset            1  "MC IREG 0 reset";
+    mc_prsr1_mst_reset            1  "MC Parser 1 reset";
+    mc_prsr0_mst_reset            1  "MC Parser 0 reset";
+    mc_dma_mst_reset              1  "MC DMA reset";
+    mc_gpio_mst_reset             1  "MC GPIO reset";
+    mc_mc_mst_reset               1  "MC reset";
+  };
+
+ // 5.1018 padded to 32 bits documentation is 21
+    register mc_rstvec_mc_reg rw addr(base, 0x0048002c)
+  "Reset Control register for BPX port (Soft reset)" {
+    _                             11 rsvd;
+    mc_flow_mngr_reset            1  "MC FLOW_MNGR reset";
+    mc_mips_reset                 1  "MC MIPS 1 reset";
+    mc_mdio1_reset                1  "MC MDIO 1 reset";
+    mc_mdio0_reset                1  "MC MDIO 0 reset";
+    mc_rmii_gmac_reset            1  "MC Management GMAC reset";
+    mc_spi_reset                  1  "MC SPI reset";
+    mc_i2c_reset                  1  "MC I2C reset";
+    mc_uart1_reset                1  "MC UART 1 reset";
+    mc_uart0_reset                1  "MC UART 0 reset";
+    mc_vmi_reset                  1  "MC VMI reset";
+    mc_dbi_reset                  1  "MC DBI reset";
+    mc_tlp_reset                  1  "MC TLP reset";
+    mc_ktchn_reset                1  "MC PCIE Kitchen Sink reset";
+    mc_treg_reset                 1  "MC TREG reset";
+    mc_ireg1_reset                1  "MC IREG 1 reset";
+    mc_ireg0_reset                1  "MC IREG 0 reset";
+    mc_prsr1_reset                1  "MC Parser 1 reset";
+    mc_prsr0_reset                1  "MC Parser 0 reset";
+    mc_dma_reset                  1  "MC DMA reset";
+    mc_gpio_reset                 1  "MC GPIO reset";
+    mc_mc_reset                   1  "MC reset";
+  };
+
+ // 5.1021 padded to 32 bits documentation is 14
+  regtype mc_rstvec_ntwrkpt_mst_reg
+  "Reset Control register for BPX port (Master reset)" {
+    _                             18 rsvd;
+    mc_sr_mst_reset               1  "Global SRAM port reset";
+    mc_extphy_mst_reset           1  "MC external PHY port reset";
+    mc_xgtxfifo_mst_reset         1  "MC XG Async TX FIFO module port reset";
+    mc_xgrxfifo_mst_reset         1  "MC XG Async RX FIFO module port reset";
+    mc_1gfifo_mst_reset           1  "MC 1G Async FIFO module port reset";
+    mc_grmon_mst_reset            1  "MC 1G RMON module port reset";
+    mc_xgtx_mst_reset             1  "MC XG MAC TX module port reset ";
+    mc_xgrx_mst_reset             1  "MC XG MAC RX module port reset ";
+    mc_gmac_mst_reset             1  "MC 1G MAC module port reset";
+    mc_em_mst_reset               1  "MC EM module port reset";
+    mc_ev_mst_reset               1  "MC Event module port";
+    mc_rxdp_mst_reset             1  "MC RXDP port reset";
+    mc_txdp_mst_reset             1  "MC TXDP port reset";
+    mc_ntwrkpt_mst_reset          1  "MC Network port reset";
+  };
+
+  register p0_mc_rstvec_ntwrkpt_mst_reg rw addr(base, 0x00480218)
+  "Port 0 Reset Control register for BPX port (Master reset)"
+    type(mc_rstvec_ntwrkpt_mst_reg);
+
+  register p1_mc_rstvec_ntwrkpt_mst_reg rw addr(base, 0x0048021c)
+  "Port 1 Reset Control register for BPX port (Master reset)"
+    type(mc_rstvec_ntwrkpt_mst_reg);
+
+ // 5.1021 padded to 32 bits documentation is 14
+  regtype mc_rstvec_ntwrkpt_reg
+  "Reset Control register for BPX port (Soft reset)" {
+    _                             18 rsvd;
+    mc_sr_reset                   1  "Global SRAM port reset";
+    mc_extphy_reset               1  "MC external PHY port reset";
+    mc_xgtxfifo_reset             1  "MC XG Async TX FIFO module port reset";
+    mc_xgrxfifo_reset             1  "MC XG Async RX FIFO module port reset";
+    mc_1gfifo_reset               1  "MC 1G Async FIFO module port reset";
+    mc_grmon_reset                1  "MC 1G RMON module port reset";
+    mc_xgtx_reset                 1  "MC XG MAC TX module port reset ";
+    mc_xgrx_reset                 1  "MC XG MAC RX module port reset ";
+    mc_gmac_reset                 1  "MC 1G MAC module port reset";
+    mc_em_reset                   1  "MC EM module port reset";
+    mc_ev_reset                   1  "MC Event module port";
+    mc_rxdp_reset                 1  "MC RXDP port reset";
+    mc_txdp_reset                 1  "MC TXDP port reset";
+    mc_ntwrkpt_reset              1  "MC Network port reset";
+  };
+
+
+  register p0_mc_rstvec_ntwrkpt_reg rw addr(base, 0x00480208)
+  "Port 0 Reset Control register for BPX port (Soft reset)"
+    type(mc_rstvec_ntwrkpt_reg);
+
+  register p1_mc_rstvec_ntwrkpt_reg rw addr(base, 0x0048020c)
+  "Port 1 Reset Control register for BPX port (Soft reset)"
+    type(mc_rstvec_ntwrkpt_reg);
+
+   // 5.1062
+  regarray mc_treg_smem  rw addr(base, 0x00ff0000) [512;0x4] 
+  "Shared memory" {
+    mc_treg_smem_row              32;
+  };
+
+};
diff --git a/devices/sfn5122f_q.dev b/devices/sfn5122f_q.dev
new file mode 100644 (file)
index 0000000..3939461
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2011, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * sfn5122f_q.dev
+ *
+ * DESCRIPTION: Solarflare Solarstorm SFx902x Ethernet Controller Queues
+ *
+ * Numbers in comments refer to Solarstorm SFx902x Ethernet Controller family Controller Datasheet
+ * Product #: SF-103590-DS / Issue 3
+ */
+
+device sfn5122f_q msbfirst () 
+"Solarflare Solarstorm SFx902x Ethernet Controller Queues" {
+  // 5.156
+  datatype tx_ker_desc msbfirst(64) "Transmit physical mode descriptor" {
+    _                         1   rsvd;
+    tx_ker_cont               1   "Packet data continuation";
+    tx_ker_byte_count         14  "Number of valid bytes in this buffer";
+    tx_ker_buf_region         2   type(tx_ker_buf_region)
+    "Indicates which address region register should be used (upper 18 bits)";
+    tx_ker_buf_addr           46  "Lower 46 bits of buffer's address";
+  };
+  
+  constants  tx_ker_buf_region "Address region register of buffer" {
+    tx_ker_buf_region0          = 0b00 "Address region register 0";
+    tx_ker_buf_region1          = 0b01 "Address region register 1";
+    tx_ker_buf_region2          = 0b10 "Address region register 2";
+    tx_ker_buf_region3          = 0b11 "Address region register 3";
+  };
+
+  // 5.106
+  datatype rx_ker_desc msbfirst(64) "Receive physical mode descriptor" {
+    _                         2   rsvd;
+    rx_ker_buf_size           14  "Buffer size in bytes";
+    rx_ker_buf_region         2   type(rx_ker_buf_region)
+    "Indicates which address region register should be used (upper 18 bits)";
+    rx_ker_buf_addr           46  "Lower 46 bits of buffer's address";
+  };
+
+  constants  rx_ker_buf_region "Address region register of buffer" {
+    rx_ker_buf_region0          = 0b00 "Address region register 0";
+    rx_ker_buf_region1          = 0b01 "Address region register 1";
+    rx_ker_buf_region2          = 0b10 "Address region register 2";
+    rx_ker_buf_region3          = 0b11 "Address region register 3";
+  };
+
+
+  // advanced descriptors
+ // 5.157
+  datatype tx_user_desc msbfirst(64) "Transmit buffer mode descriptor" {
+    _                         15  rsvd;
+    tx_user_sw_ev_en          1   "Software event enable";
+    _                         1   rsvd;
+    tx_user_cont              1   "Packet data continuation";
+    tx_user_byte_cnt          13  "Number of valid bytes";
+    tx_user_buf_id            20  "Buffer ID to index the buffer table";
+    tx_user_byte_ofs          13  "Byte offset from base address";
+  };
+
+  // 5.107
+  datatype rx_user_desc msbfirst(32) "Receive buffer mode descriptor" {
+    rx_user_2byte_offset       12  "2-byte offset from base address of buffer";
+    rx_user_buf_id             20  "Buffer ID to index the buffer table";
+  };
+
+
+   // Evevent queue 
+  // 5.72
+  datatype event_entry msbfirst(64)  "Event entry" {
+    ev_code                    4  "Event code";
+    ev_data                    60 "Event data";
+  };
+
+  constants ev_code "Event code" {
+    rx_ev            = 0b0000 "RX event";
+    tx_ev            = 0b0010 "TX event";
+    driver_ev        = 0b0101 "Driver event";
+    global_ev        = 0b0110 "Global event";
+    drv_gen_ev       = 0b0111 "DRV_GEN_EV";
+    user_ev          = 0b1000 "User event";
+    mcdi_val         = 0b1010 "Value used by MCDI protocol";
+  };
+
+    // 5.71
+  datatype driver_ev msbfirst(64) "Char or Kernel driver events" {
+    _                        4  rsvd;
+    driver_ev_subcode        4  type(driver_ev_subcode)
+    "Driver event sub-code";
+    _                        42   rsvd;
+    driver_ev_subdata        14 "Driver event sub-data";
+  };
+  
+  constants driver_ev_subcode "SRAM bank size" {
+    fls_evq_id         = 0b0000 "FLS_EVQ_ID";
+    rcv_desc_q_flush   = 0b0001 "Receive descriptor queue flush done";
+    event_q_init       = 0b0010 "Event queue initialization done";
+    srm_upd_           = 0b0101 "SRAM update done";
+    wakeup_ev          = 0b0110 "Wake up event";
+    error_packet_type  = 0b1001 "Packet is neither TCP nor UDP";
+    timer_event        = 0b1010 
+    "Timer event happens (triggerd/immedate start mode)";
+    rx_desc_err_event  = 0b1110 "RX Descriptor Error Event";
+    tx_desc_err_event  = 0b1111 "TX Descriptor Error Event";
+  };
+  
+  // 5.73
+  datatype rx_ev msbfirst(64) "Receive Completion event" {
+    _                         5  rsvd;
+    rx_ev_pkt_not_parsed      1  "Receive packet not parsed";
+    rx_ev_ipv6_pkt            1  "Receive packet is IPv6";
+    rx_ev_pkt_ok              1  "Receive packet contains no error";
+    rx_ev_pause_frm_err       1  "Undocumented bit";
+    rx_ev_buf_owner_id        1 
+    "Receive buffer owner ID missmatch with buffer table";
+    rx_ev_ip_frag_err         1  "Receive packet IP header checksum error";
+    rx_ev_ip_hdr_chksum_err   1  "Receive packet IP header checksum error";
+    rx_ev_tcp_udp_chksum_err  1  "Receive packet TCP/UDP checksum error";
+    rx_ev_eth_crc_err         1  "Receive Ethernet CRC error";
+    rx_ev_frm_trunc           1  "Receive frame truncated";
+    _                         1  rsvd;
+    rx_ev_tobe_disc           1  "Receive packet to be discarded by software";
+    rx_ev_pkt_type            3  type(rx_ev_pkt_type)
+    "Receive packet type";
+    rx_ev_hdr_type            2  type(rx_ev_hdr_type)
+    "Receive packet header type";
+    rx_ev_desc_q_empty        1  "Receive descriptor queue is empty";
+    rx_ev_mcast_hask_match    1  "Receive multicast has match";
+    rx_ev_mcast_ptk           1  "Receive packet is multicast";
+    _                         2  rsvd;
+    rx_ev_q_label             5  "Queue label";
+    rx_ev_jumbo_cont          1  "Receive jumbo packet (not end-of-packet)";
+    rx_ev_port                1  "Port number of packet";
+    rx_ev_byte_ctn            14 "Receive packet byte count";
+    rx_ev_sop                 1  "Buffer for Start of packet";
+    rx_ev_iscsi_pkt_ok        1  "iSCSI packet no error";
+    rx_ev_iscsi_ddig_er       1  "iSCSI data digest error";
+    rx_ev_iscsi_hdig_err      1  "iSCSI header digest error";
+    rx_ev_desc_ptr            12 "Receive descriptor pointer";
+  };
+  
+  constants  rx_ev_hdr_type "Receive packet header type" {
+    rx_header_tcp           = 0b00 "IPv4/IPv6 TCP packet";
+    rx_header_udp           = 0b01 "IPv4/IPv6 UDP packet";
+    rx_header_neither       = 0b10 "IPv4/IPv6 neither TCP nor UDP packet";
+    rx_header_none          = 0b11 "Not IPv4/IPv6";
+  };
+  
+  constants  rx_ev_pkt_type "Receive packet type" {
+    rx_ptype_ethr           = 0b000 "Plain Ethernet";
+    rx_ptype_llc_snap       = 0b001 "LLC/SNAP";
+    rx_ptype_jumbo          = 0b010 "Jumbo";
+    rx_ptype_vlan           = 0b011 "VLAN";
+    rx_ptype_vlan_llc_snap  = 0b100 "VLAN w/LLC/SNAP";
+    rx_ptype_vlan_jumbo     = 0b101 "VLAN Jumbo";
+  };
+  
+  // 5.74 would be 128 bits
+ datatype tx_ev msbfirst(64) "Receive Completion event" {
+    _                        25  rsvd;
+    tx_ev_pkt_err            1  "Error while reading TX data";
+    tx_ev_pkt_too_big        1  "Packet too big to fit trasnmit FIFO";
+    tx_ev_q_label            5  
+    "Queue label programmed in trasmit descriptor point table";
+    _                        16 rsvd;
+    tx_ev_wq_ff_full         1  "TX pacing queue full";
+    tx_ev_buf_owner_id_err   1  
+    "Indicates current descriptor that has the error";
+    _                        1  rsvd;
+    tx_ev_comp               1  "Transmit completion event";
+    tx_ev_desc_ptr           12 "Transmit descriptor pointer";
+  };
+
+  // 5.75 
+  // TODO user_ev_reg_value ??
+  datatype usr_ev msbfirst(64) "User event" {
+    _                       22  rsvd;
+    user_qid                10 "Originating quid";
+    user_ev_reg_value       32 "USR_EV_REG";
+  };
+
+
+
+
+};
index 20c4578..c2b4953 100755 (executable)
@@ -1231,3 +1231,15 @@ errors cpuid DEVQ_ERR_ {
     failure DESCQ_INIT              "Failure in descriptor queue init",
 };
 
+// errors generated by solarflare cards
+errors sfn SFN_ERR_{
+    failure IO                   "Error during card IO",
+    failure INTR                 "Interrupted system call",
+    failure NOSYS                "Not implemented",
+    failure UNKNOWN              "Uknown error",
+    failure TX_PKT               "Error sending packet",
+    failure RX_PKT               "Error receiving packet",
+    failure RX_DISCARD           "Error, packet needs to be discared",
+    failure ALLOC_BUF            "Error allocating buffer",
+};
+
index d167c8a..b2fff71 100644 (file)
@@ -244,8 +244,10 @@ MODULES_x86_64= \
        sbin/e1000n \
        sbin/NGD_mng \
        sbin/e10k \
+    sbin/sfn5122f \
        sbin/sfxge \
        sbin/e10k_queue \
+    sbin/sfn5122f_queue \
        sbin/rtl8029 \
        sbin/netd \
        sbin/echoserver \
@@ -282,7 +284,7 @@ MODULES_x86_64= \
        sbin/bulk_shm \
        sbin/corectrl \
        sbin/megaraid \
-       lib/libmegaraid.a
+       lib/libmegaraid.a 
 
 MODULES_k1om= \
        sbin/weever \
index 0b7435d..b6fcf21 100644 (file)
                "xmplrpc",
                "xmplthc",
                "xomp",
-               "devif"
-               "xomp_gateway"
+               "devif_ctrl",
+               "devif_data",
+               "xomp_gateway",
+               "sfn5122f"
            ],
              arch <- allArchitectures
 ] ++
diff --git a/if/sfn5122f.if b/if/sfn5122f.if
new file mode 100644 (file)
index 0000000..ef51a47
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * This interface is used in the sfn5122f driver for the device specific
+ * communication between the device manager and the queue manager. It is
+ * exposed by the device manager, and every queue manager connects to it.
+ */
+interface sfn5122f "sfn5122f queue management interface" {
+    typedef enum {PORT_TCP, PORT_UDP} port_type;
+    alias qid uint16;
+
+    message request_device_info();
+    message queue_init_data(cap registers, uint64 macaddr, cap mac_stat);
+
+    /* Upon initialization the queue driver registers its memory with
+       the device manager. */
+    message register_queue_memory(qid    id,
+                               cap    tx,
+                               cap    rx,
+                               cap    ev,
+                               uint32 rxbufsz,
+                               bool   use_irq, 
+                               bool   userspace,
+                               uint8 vector,
+                               uint16 core);
+    message queue_memory_registered();
+
+    /* FIXME: this is not technically a response, but a request by the server,
+              hope this works anyway... I'd like the dev mgr to be server. */
+    /* Tells queue driver to write the tail pointers for the rx and
+       tx queues after initialization or reset */
+    message write_queue_tails();
+
+    /* Called by queue manager if it is done, and is going to terminate. */
+    message terminate_queue(qid id);
+    message queue_terminated();
+
+    /*****************************************************
+     * Filter management (used by device  manager library)
+     *****************************************************/
+
+    message register_port_filter(uint64    buf_id_rx,
+                              uint64    buf_id_tx,
+                              qid       queue,
+                              port_type type,
+                              uint16    port);
+    message filter_registered(uint64    buf_id_rx,
+                              uint64    buf_id_tx,
+                              errval err,
+                              uint64 filter);
+
+    message unregister_filter(uint64 filter);
+    message filter_unregistered(uint64 filter, errval err);
+
+    /*****************************************************
+     * Control path for userspace networking
+     * (used by  interface_raw.c)
+     *****************************************************/
+ /*     
+    call get_queue(uint16 qid);
+    response get_queue_response(cap rx, 
+                                cap tx,
+                                cap registers,
+                                uint32 rx_size,
+                                uint32 tx_size,
+                                bool userspace);
+*/
+};
index e60e41f..9fa7a60 100644 (file)
@@ -22,6 +22,7 @@
 #define PCI_VENDOR_ATI          0x1002
 #define PCI_VENDOR_LSI         0x1000
 #define PCI_VENDOR_FISH         0xdada
+#define PCI_VENDOR_SOLARFLARE   0x1924
 
 #define PCI_CLASS_MASS_STORAGE  0x1
 #define PCI_SUB_RAID           0x4
index 7198427..81730fb 100644 (file)
 
 [ build library { target = "net_device_manager",
                   cFiles = [ "port_service_impl.c", "device_manager.c",
-                  "soft_filt_cl_impl.c", "e10k_filt_cl_impl.c", "portalloc.c" ],
+                  "soft_filt_cl_impl.c", "e10k_filt_cl_impl.c", 
+                  "sfn5122f_filt_cl_impl.c", "portalloc.c" ],
                   flounderBindings = [ "net_soft_filters", "net_ports",
-                                       "e10k" ],
+                                       "e10k", "sfn5122f" ],
                   addLibraries = [ "contmng", "bfdmuxtools", "trace"
 -- try to get rid of "lwip" as it is only used for hton[s/l]
                     , "lwip"
index 989c906..c98a269 100644 (file)
@@ -38,11 +38,10 @@ static struct filters_tx_vtbl *lookup_filt_mng(uint8_t filt_mng_type)
         case 1: // e10K hardware filter manager
                 return get_e10k_filt_mng_sign();
                 break;
-/*
+
         case 2: // Solarflare filter manager
-                return NULL;
+                return get_sfn5122f_filt_mng_sign();
                 break;
-*/
 
         default: // Unknown filter manager
                 USER_PANIC("Filter Manager type %"PRIu8" not supported\n",
index c6274f7..8b6e632 100755 (executable)
@@ -52,6 +52,9 @@ struct filters_tx_vtbl *get_soft_filt_mng_sign(void);
 // Get the signature for e10k hardware filter manager
 struct filters_tx_vtbl *get_e10k_filt_mng_sign(void);
 
+// Get the signature for sfn5122f hardware filter manager
+struct filters_tx_vtbl *get_sfn5122f_filt_mng_sign(void);
+
 // Initialize the port number management service
 int init_ports_service(char *dev_name);
 
diff --git a/lib/net_device_manager/sfn5122f_filt_cl_impl.c b/lib/net_device_manager/sfn5122f_filt_cl_impl.c
new file mode 100644 (file)
index 0000000..9ec92ed
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2007-12 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/waitset.h>
+#include <barrelfish/nameservice_client.h>
+#include <contmng/contmng.h>
+#include <ipv4/lwip/inet.h>
+
+#include <if/sfn5122f_defs.h>
+
+#include "port_management_support.h"
+#include "device_manager_debug.h"
+
+
+
+/******************************************************************************
+ * Local state
+ ******************************************************************************/
+
+/** Connection to sfn5122f management service */
+struct sfn5122f_binding *sfn5122f_binding = NULL;
+
+struct cont_queue *sfn5122f_c_queue = NULL;
+
+
+/******************************************************************************
+ * Operations for filter interface
+ ******************************************************************************/
+
+// Callback from sfn5122f
+static void idc_filter_registered(struct sfn5122f_binding *b,
+                                  uint64_t buf_id_rx,
+                                  uint64_t buf_id_tx,
+                                  errval_t err,
+                                  uint64_t filter)
+{
+    NDM_DEBUG("sfn5122f_idc_filter_registered(f=%"PRIu64" rx=%"PRIu64" tx=%"PRIu64
+            ")\n", filter, buf_id_rx, buf_id_tx);
+    handle_filter_response(filter, err, filter, buf_id_rx, buf_id_tx, 1);
+}
+
+// Callback from sfn5122f
+static void idc_filter_unregistered(struct sfn5122f_binding *b,
+                                    uint64_t filter,
+                                    errval_t err)
+{
+    NDM_DEBUG("sfn5122f_idc_filter_unregistered(%"PRIu64")\n", filter);
+}
+
+static errval_t send_register_port_filter(struct q_entry e)
+{
+    if (sfn5122f_binding->can_send(sfn5122f_binding)) {
+        return sfn5122f_binding->tx_vtbl.register_port_filter(
+                sfn5122f_binding, MKCONT(cont_queue_callback, sfn5122f_c_queue),
+                e.plist[0], e.plist[1], e.plist[2], e.plist[3], e.plist[4]);
+    } else {
+        return FLOUNDER_ERR_TX_BUSY;
+    }
+}
+
+/** Register filter with sfn5122f card driver */
+static void idc_register_port_filter(uint64_t buf_id_rx,
+                                     uint64_t buf_id_tx,
+                                     uint16_t queue,
+                                     sfn5122f_port_type_t type,
+                                     uint16_t port)
+{
+    struct q_entry entry;
+    NDM_DEBUG("sfn5122f_idc_register_port_filter(q=%d p=%d rx=%"PRIu64" tx=%"
+            PRIu64")\n", queue, port, buf_id_rx, buf_id_tx);
+
+    memset(&entry, 0, sizeof(struct q_entry));
+
+    entry.handler = send_register_port_filter;
+    entry.binding_ptr = sfn5122f_binding;
+    entry.plist[0] = buf_id_rx;
+    entry.plist[1] = buf_id_tx;
+    entry.plist[2] = queue;
+    entry.plist[3] = type;
+    entry.plist[4] = port;
+
+    enqueue_cont_q(sfn5122f_c_queue, &entry);
+}
+
+static errval_t send_unregister_filter(struct q_entry e)
+{
+    if (sfn5122f_binding->can_send(sfn5122f_binding)) {
+        return sfn5122f_binding->tx_vtbl.unregister_filter(
+                sfn5122f_binding, MKCONT(cont_queue_callback, sfn5122f_c_queue),
+                e.plist[0]);
+    } else {
+        return FLOUNDER_ERR_TX_BUSY;
+    }
+}
+
+/** Unregister filter with sfn5122f card driver */
+static void idc_unregister_filter(uint64_t filter)
+{
+    struct q_entry entry;
+    memset(&entry, 0, sizeof(struct q_entry));
+
+    entry.handler = send_unregister_filter;
+    entry.binding_ptr = sfn5122f_binding;
+    entry.plist[0] = filter;
+
+    enqueue_cont_q(sfn5122f_c_queue, &entry);
+}
+
+static struct sfn5122f_rx_vtbl rx_vtbl = {
+    .filter_registered = idc_filter_registered,
+    .filter_unregistered = idc_filter_unregistered,
+};
+
+// Callback for bind
+static void bind_cb(void *st, errval_t err, struct sfn5122f_binding *b)
+{
+    assert(err_is_ok(err));
+
+    NDM_DEBUG("Sucessfully connected to management interface\n");
+
+    b->rx_vtbl = rx_vtbl;
+
+    sfn5122f_binding = b;
+    sfn5122f_c_queue = create_cont_q("sfn5122f_filters");
+}
+
+/** Open connection to management interface */
+static void connect_to_mngif(char *dev_name)
+{
+    errval_t r;
+    iref_t iref;
+    const char *suffix = "_sfn5122fmng";
+    char name[strlen(dev_name) + strlen(suffix) + 1];
+
+    // Build label for management service
+    sprintf(name, "%s%s", dev_name, suffix);
+
+    // Connect to service
+    r = nameservice_blocking_lookup(name, &iref);
+    assert(err_is_ok(r));
+
+    r = sfn5122f_bind(iref, bind_cb, NULL, get_default_waitset(),
+            IDC_BIND_FLAGS_DEFAULT);
+    assert(err_is_ok(r));
+}
+
+/******************************************************************************
+ * Operations for filter interface
+ ******************************************************************************/
+
+static void init_filters(char *dev_name, qid_t qid)
+{
+    NDM_DEBUG("sfn5122f_flt: init %s %d\n", dev_name, (int) qid);
+
+    // Check if we are already initialized from another queue
+    if (sfn5122f_binding != NULL) {
+        return;
+    }
+
+    connect_to_mngif(dev_name);
+
+    // waiting for connection to succeed.
+    NDM_DEBUG("sfn5122f_init_filters: wait connection\n");
+    while (sfn5122f_binding == NULL) {
+        messages_wait_and_handle_next();
+    }
+}
+
+static void reg_arp_filters(uint64_t id, uint64_t len_rx,
+                            uint64_t len_tx)
+{
+    USER_PANIC("reg_arp_filters() not supported yet in sfn5122f filters");
+}
+
+static errval_t reg_filters(uint16_t port,
+                            port_type_t type,
+                            bufid_t buffer_id_rx,
+                            bufid_t buffer_id_tx,
+                            appid_t appid,
+                            qid_t qid)
+{
+    sfn5122f_port_type_t t;
+    assert(sfn5122f_binding != NULL);
+
+    NDM_DEBUG("sfn5122f_reg_filters()\n");
+
+    if (type == net_ports_PORT_TCP) {
+        t = sfn5122f_PORT_TCP;
+    } else {
+        t = sfn5122f_PORT_UDP;
+    }
+
+    idc_register_port_filter(buffer_id_rx, buffer_id_tx, qid, t, port);
+
+    return SYS_ERR_OK;
+}
+
+static void unreg_filters(uint64_t filter_id, qid_t qid)
+{
+    assert(sfn5122f_binding != NULL);
+
+    NDM_DEBUG("sfn5122f_unreg_filters()\n");
+    idc_unregister_filter(filter_id);
+}
+
+
+/******************************************************************************
+ * Get signature of this service
+ ******************************************************************************/
+
+static struct filters_tx_vtbl sfn5122f_filts_mng = {
+    .type = "sfn5122f_filters",
+    .init_filters = init_filters,
+    .reg_arp_filters = reg_arp_filters,
+    .reg_filters = reg_filters,
+    .unreg_filters = unreg_filters,
+};
+
+struct filters_tx_vtbl *get_sfn5122f_filt_mng_sign(void)
+{
+    return &sfn5122f_filts_mng;
+}
+
+
diff --git a/usr/drivers/solarflare/Hakefile b/usr/drivers/solarflare/Hakefile
new file mode 100644 (file)
index 0000000..e00c4a9
--- /dev/null
@@ -0,0 +1,32 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2009, 2011, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for sbin/solarflare
+--
+--------------------------------------------------------------------------
+
+  [ build application { target = "sfn5122f_queue",
+                    cFiles = ["sfn5122f_qdriver.c", "helper.c", 
+                              "mcdi_rpc.c", "buffer_tbl.c"],
+                    flounderBindings = [ "net_queue_manager", "sfn5122f" ],
+                    mackerelDevices = ["sfn5122f", "sfn5122f_q"],
+                    addLibraries = libDeps ["netQmng", "pci", "net_device_manager",
+                                            "skb"]
+                  },
+
+  build application { target = "sfn5122f",
+                      cFiles = [ "sfn5122f_cdriver.c", "sfn5122f_qdriver.c", "mcdi_rpc.c", 
+                                 "helper.c", "buffer_tbl.c"],
+                      flounderBindings = [ "sfn5122f", "net_ARP" ],
+                      mackerelDevices = [ "sfn5122f"],
+                      addLibraries = libDeps["netQmng", "pci", "contmng", 
+                                             "net_device_manager", "bench", "trace", "skb" ]
+                    }
+  ]
+
+
diff --git a/usr/drivers/solarflare/buffer_tbl.c b/usr/drivers/solarflare/buffer_tbl.c
new file mode 100644 (file)
index 0000000..97a5931
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include "buffer_tbl.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+#include "sfn5122f_debug.h"
+
+
+
+
+static uint64_t buffer_offset = 0;
+static uint64_t userspace_offset = 512;
+
+// add a buffer to the buffer table
+uint64_t alloc_buf_tbl_entries(uint64_t phys_addr,
+                               uint32_t num_buf,
+                               uint16_t qid,
+                               bool userspace,
+                               sfn5122f_t *d)
+{
+    uint64_t reg = 0;
+    if (buffer_offset + num_buf > MAX_BUF_TBL_ENTRIES) {
+        return -1;
+    }
+
+    for (int i = 0; i < num_buf; i++){
+        reg = 0;
+        reg = sfn5122f_buf_full_tbl_buf_adr_region_insert(reg, 0 );
+        reg = sfn5122f_buf_full_tbl_buf_adr_fbuf_insert(reg,
+                                    ((phys_addr+i*4096) >> 12));
+        if (userspace) {
+            reg = sfn5122f_buf_full_tbl_buf_owner_id_fbuf_insert(reg, qid+1);
+            DEBUG("Buffer user address %lx o_id %d buf_id %ld \n", 
+                   phys_addr+i*4096, qid+1, userspace_offset+i);
+        } else {
+            DEBUG("Buffer address %lx o_id %d buf_id %ld \n", 
+                   phys_addr+i*4096, 0, buffer_offset+i);
+            reg = sfn5122f_buf_full_tbl_buf_owner_id_fbuf_insert(reg, 0);
+        }
+
+        if (userspace) {
+            sfn5122f_buf_full_tbl_wr(d, userspace_offset + i, reg);
+        } else {
+            sfn5122f_buf_full_tbl_wr(d, buffer_offset + i, reg);
+        }
+    }
+  
+    reg = 0;
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_upd_cmd_insert(reg, 1);
+    sfn5122f_buf_tbl_upd_reg_lo_wr(d, reg); 
+    sfn5122f_buf_tbl_upd_reg_hi_wr(d, 0); 
+
+    if (userspace) {
+        userspace_offset += num_buf;
+    } else {
+        buffer_offset += num_buf;
+    }
+
+    if (userspace) {
+        return (userspace_offset - num_buf);
+    }
+
+    return (buffer_offset - (num_buf));
+}
+
diff --git a/usr/drivers/solarflare/buffer_tbl.h b/usr/drivers/solarflare/buffer_tbl.h
new file mode 100644 (file)
index 0000000..cb1521e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef BUFFER_TBL_H_
+#define BUFFER_TBL_H_
+
+#include <barrelfish/barrelfish.h>
+#include "sfn5122f.h"
+
+/**
+ * @brief adds one or several 4k buffer to the buffer table
+ * 
+ * @param phys_addr     the physical address of the buffer
+ * @param num_buf       the number of buffers to add
+ * @param qid           for descriptor queue (RX/TX/EV) queues
+ *                      the qid should be 0 (used as owner id)
+ *                      otherwise for send/recv buffers for userlvl
+ *                      networking != 0
+ * @param userpsace     is userlvl networking enabled
+ * @param d             handle to device registers
+ *
+ * @return the id of of the added buffer in the table
+ */
+uint64_t alloc_buf_tbl_entries(uint64_t phys_addr,
+                               uint32_t num_buf, 
+                               uint16_t qid ,
+                               bool userspace, 
+                               sfn5122f_t *d);
+
+#endif // ndef BUFFER_TBL_H_
diff --git a/usr/drivers/solarflare/helper.c b/usr/drivers/solarflare/helper.c
new file mode 100644 (file)
index 0000000..9f3bd1b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include "helper.h"
+
+#include <skb/skb.h>
+#include <stdio.h>
+#include <stdint.h>
+
+
+/* allocate a single frame, mapping it into our vspace with given attributes */
+void* alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap)
+{
+    struct capref frame;
+    errval_t r;
+
+    r = frame_alloc(&frame, size, NULL);
+    assert(err_is_ok(r));
+    void *va;
+    r = vspace_map_one_frame_attr(&va, size, frame, attr,
+                                  NULL, NULL);
+    if (err_is_fail(r)) {
+        DEBUG_ERR(r, "vspace_map_one_frame failed");
+        return NULL;
+    }
+
+    if (retcap != NULL) {
+        *retcap = frame;
+    }
+
+    return va;
+}
+
+/* Get APIC id for specified core */
+errval_t get_apicid_from_core(coreid_t cid, uint8_t *apicid)
+{
+    static bool connected = false;
+    errval_t err;
+    unsigned int i;
+
+    if (!connected) {
+        err = skb_client_connect();
+        if (err_is_fail(err)) {
+            return err;
+        }
+        connected = true;
+    }
+
+    err = skb_execute_query("corename(%d,_,apic(ApicID)),write(ApicID).",
+                            cid);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    err = skb_read_output("%u.", &i);
+    *apicid = i;
+    return err;
+}
+
+
+/*****************************************************************************/
+/* Bitmap based allocator */
+
+
+/** Init allocator for n objects. */
+bool bmallocator_init(struct bmallocator *alloc, size_t n)
+{
+    alloc->count = n;
+    alloc->bitmap = calloc((n + BMALLOCATOR_BITS - 1) / BMALLOCATOR_BITS,
+                           BMALLOCATOR_BITS / 8);
+    return alloc->bitmap != NULL;
+}
+
+/** Release memory associated with allocator. */
+void bmallocator_destroy(struct bmallocator *alloc)
+{
+    free(alloc->bitmap);
+    alloc->bitmap = NULL;
+}
+
+/** Allocate object, return index in *n if successful (return true). */
+bool bmallocator_alloc(struct bmallocator *alloc, size_t *n)
+{
+    size_t i;
+    BMALLOCATOR_TYPE bit;
+    size_t idx;
+
+    // This could be improved
+    for (i = 0; i < alloc->count; i++) {
+        bit = 1 << (i % BMALLOCATOR_BITS);
+        idx = i / BMALLOCATOR_BITS;
+
+        if (!(alloc->bitmap[idx] & bit)) {
+            alloc->bitmap[idx] |= bit;
+            *n = i;
+            return true;
+        }
+    }
+    return false;
+}
+
+/** Free object n, return value indicates if it was allocated before. */
+bool bmallocator_free(struct bmallocator *alloc, size_t n)
+{
+    bool result;
+    BMALLOCATOR_TYPE bit;
+    size_t idx;
+
+    if (n >= alloc->count) {
+        return false;
+    }
+
+    bit = (1 << (n % BMALLOCATOR_BITS));
+    idx = n / BMALLOCATOR_BITS;
+
+    result = alloc->bitmap[idx] & bit;
+    alloc->bitmap[idx] &= ~bit;
+
+    return result;
+}
diff --git a/usr/drivers/solarflare/helper.h b/usr/drivers/solarflare/helper.h
new file mode 100644 (file)
index 0000000..be8f6c7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef HELPER_H_
+#define HELPER_H_
+
+#include <errors/errno.h>
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/vregion.h>
+
+void* alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap);
+
+errval_t get_apicid_from_core(coreid_t cid, uint8_t *apicid);
+
+/* Simple bitmap-based allocator */
+#define BMALLOCATOR_BITS 8
+#define BMALLOCATOR_TYPE uint8_t
+struct bmallocator {
+    BMALLOCATOR_TYPE *bitmap;
+    size_t count;
+};
+
+/** Init allocator for n objects. */
+bool bmallocator_init(struct bmallocator *alloc, size_t n);
+/** Release memory associated with allocator. */
+void bmallocator_destroy(struct bmallocator *alloc);
+/** Allocate object, return index in *n if successful (return true). */
+bool bmallocator_alloc(struct bmallocator *alloc, size_t *n);
+/** Free object n, return value indicates if it was allocated before. */
+bool bmallocator_free(struct bmallocator *alloc, size_t n);
+
+#endif // ndef HELPER_H_
diff --git a/usr/drivers/solarflare/mcdi_rpc.c b/usr/drivers/solarflare/mcdi_rpc.c
new file mode 100644 (file)
index 0000000..d0e8690
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+
+#include "sfn5122f.h"
+#include "mcdi_rpc.h"
+#include "sfn5122f_debug.h"
+
+static uint32_t seqno = 0;
+
+static struct thread_mutex mcdi;
+
+void init_mcdi_mutex(void)
+{
+     thread_mutex_init(&mcdi);
+}
+
+
+/* Function to issue MCDI calls
+ *****************************************************************
+ * Each MCDI request starts with an MCDI_HEADER, which is a 32byte
+ * structure, filled in by the client.
+ *
+ *       0       7  8     16    20     22  23  24    31
+ *      | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS |
+ *               |                      |   |
+ *               |                      |   \--- Response
+ *               |                      \------- Error
+ *               \------------------------------ Resync (always set)
+*/
+
+errval_t mcdi_rpc(unsigned cmd, const uint8_t *in, uint32_t inlen,
+                     uint8_t *out, uint32_t outlen, uint32_t *outlen_actual, 
+                     bool port, sfn5122f_t *d)
+{
+    uint32_t rlen = 0;
+    uint32_t hdr = 0; 
+    uint32_t reg = 0;
+    uint32_t offset = MCDI_PDU(port);
+    uint32_t offset2 = MCDI_DORBELL(port);
+    unsigned error; 
+    uint32_t* pointer = (uint32_t*) in;
+
+    thread_mutex_lock(&mcdi);
+
+    seqno++;
+
+    // Code
+    hdr |= cmd;
+    // Resync
+    hdr |= 1 << 7;
+    // Len  
+    hdr |= inlen << 8;
+    // SEQ
+    hdr |= seqno << 16;
+
+    // write command 
+    sfn5122f_mc_treg_smem_wr(d,offset,hdr);
+    // write arguments
+    for (int i = 0; i < inlen/4; i++) {   
+        sfn5122f_mc_treg_smem_wr(d, offset+1+i, (uint32_t) pointer[i]);
+        __sync_synchronize();
+    }
+
+    // from driver
+    // ring dorbell with distinct value
+    offset2 = MCDI_DORBELL(port);
+    sfn5122f_mc_treg_smem_wr(d, offset2, 0x45789abc);
+    // Poll for completion
+    while(1){
+        // TODO add backoff ? 
+        reg = sfn5122f_mc_treg_smem_rd(d, offset);
+        // If the reg is 0xffffffff the memory resets
+        if (reg != 0xffffffff && ((reg >> 23) & 0x001))
+            break;
+    }
+
+    error = (reg >> 22) & 0x001;
+    rlen = (reg >> 8) & 0x0FF;
+
+    if (cmd == CMD_REBOOT && error && !rlen) {
+        DEBUG("CARD REBOOTED \n");
+    } else if(error && !(cmd == CMD_REBOOT)){
+        // TODO ERROR HANDLING
+        reg = sfn5122f_mc_treg_smem_rd(d,offset+1);
+        DEBUG("AN ERROR OCCURRED: CMD %d, ERROR %d \n",cmd , reg);
+        switch(reg){
+        case 4:
+            return SFN_ERR_INTR;
+        case 5:
+            return SFN_ERR_IO;
+        case 37:
+            return SFN_ERR_NOSYS;
+        default:
+            return SFN_ERR_UNKNOWN;
+        }
+    }
+    // read result
+    // outlen computation from driver 
+    outlen = (outlen < rlen+3) ? outlen : rlen+3;
+    outlen = outlen & ~0x3;
+
+    if (outlen_actual != NULL) {
+        *outlen_actual = rlen;
+    }
+
+    memset(&out, outlen, 0);
+
+    for (int i = 0; i < outlen; i+=4 ){
+        reg = sfn5122f_mc_treg_smem_rd(d, offset+1+i/4);
+        memcpy(out+i, &reg, 4);
+    }
+
+    __sync_synchronize();
+    thread_mutex_unlock(&mcdi);
+    return SYS_ERR_OK;
+} 
+
+
+
+
+
+
diff --git a/usr/drivers/solarflare/mcdi_rpc.h b/usr/drivers/solarflare/mcdi_rpc.h
new file mode 100644 (file)
index 0000000..10fa063
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef MCDI_RPC_H_
+#define MCDI_RPC_H_
+
+// MCDI Constant Offsets
+#define MCDI_REBOOT_OFFSET(a) (a? 0x7fc/4 :0x7f8/4)
+#define MCDI_PDU(a) (a? 0x108/4 : 0x008/4)
+#define MCDI_DORBELL(a) (a? 0x004/4: 0x000)
+#define MCDI_MAC_PORT_OFFSET(a) (a? 50 : 44)
+// CMD for getting assertions
+#define CMD_GET_ASSERTS 0x6
+#define CMD_GET_ASSERTS_IN_LEN 4
+#define CMD_GET_ASSERTS_IN_CLEAR_OFFSET 0
+#define CMD_GET_ASSERTS_OUT_LEN 140
+#define CMD_GET_ASSERTS_FLAG_THR_FAIL 0x2
+#define CMD_GET_ASSERTS_FLAG_SYS_FAIL 0x3
+#define CMD_GET_ASSERTS_FLAG_WDOG_FAIL 0x4
+// CMD for Driver attaching
+#define CMD_DRV_ATTACH 0x1c
+#define CMD_DRV_ATTACH_IN_LEN 8
+#define CMD_DRV_ATTACH_OUT_LEN 4
+// CMD for Reboot
+#define CMD_REBOOT 0x3d
+#define CMD_REBOOT_IN_LEN 4
+// CMD fetting firmware version
+#define CMD_GET_VERSION 0x8
+#define CMD_GET_VERSION_OUT_LEN 32
+// CMD for Port reset
+#define CMD_PORT_RESET 0x20
+// CMD for WoL Filter get
+#define CMD_WOL_FILTER_GET 0x45
+#define CMD_WOL_FILTER_RESET 0x34
+#define CMD_WOL_FILTER_GET_OUT_LEN 4
+// CMD for getting Board config
+#define CMD_GET_BOARD_CONFIG 0x18
+#define CMD_GET_BOARD_CONFIG_OUT_LEN 136
+#define CMD_GET_BOARD_CONFIG_OUT_CAPABILITIES(a) (a? 40: 36)
+// CMD SRIOV
+#define SRIOV_BASE 0x40
+#define CMD_SRIOV 0x30
+#define CMD_SRIOV_IN_LEN 12
+#define CMD_SRIOV_OUT_LEN 8
+// CMD PTP
+#define CMD_PTP 0xb
+#define CMD_PTP_IN_LEN 4
+#define PTP_DISABLE 0x2
+// CMD get resource limits
+#define CMD_GET_RESOURCE_LIMITS 0x4f
+#define CMD_GET_RESOURCE_LIMITS_OUT_LEN 16
+// CMD for ports setup
+#define CMD_GET_LINK 0x29
+#define CMD_GET_LINK_OUT_LEN 28
+#define CMD_GET_LINK_OUT_SPEED_OFFSET 8
+#define CMD_GET_LINK_OUT_FLAGS_OFFSET 16
+#define CMD_GET_LINK_OUT_FCNTL_OFFSET 20
+#define CMD_GET_LINK_OUT_MAC_FAULT_OFFSET 24
+
+#define CMD_GET_LOOPBACK_MODES 0x28
+#define CMD_GET_LOOPBACK_MODES_OUT_LEN 32
+#define CMD_GET_LOOPBACK_MODES_SUGGESTED_OFFSET 24
+// CMD for setting link
+#define CMD_SET_LINK 0x2a
+#define CMD_SET_LINK_IN_LEN 16
+#define CMD_SET_LINK_IN_CAP_OFFSET 0
+#define CMD_SET_LINK_IN_FLAGS_OFFSET 4
+#define CMD_SET_LINK_IN_LOOPBACK_MODE_OFFSET 8
+#define CMD_SET_LINK_IN_LOOPBACK_SPEED_OFFSET 12
+// CMD for enable logging
+#define CMD_LOG_CTRL 0x7
+#define CMD_LOG_CTRL_IN_LEN 8
+// CMD for setting mac address
+#define CMD_SET_MAC 0x2c
+#define CMD_SET_MAC_IN_LEN 24
+#define CMD_SET_MAC_IN_ADR_OFFSET 8
+#define CMD_SET_MAC_IN_MTU_OFFSET 0
+#define CMD_SET_MAC_IN_DRAIN_OFFSET 4
+#define CMD_SET_MAC_IN_REJECT_OFFSET 16
+#define CMD_SET_MAC_IN_FCTNL_OFFSET 20
+// CMD for setting multicast hash
+#define CMD_SET_MCAST_HASH 0x35
+#define CMD_SET_MCAST_HASH_IN_LEN 32
+#define CMD_SET_MCAST_IN_HASH0_OFFSET 0
+#define CMD_SET_MCAST_IN_HASH1_OFFSET 16
+// CMD for getting phy config
+#define CMD_GET_PHY_CFG 0x24
+#define CMD_GET_PHY_CFG_OUT_LEN 72
+#define CMD_GET_PHY_CFG_OUT_FLAGS_OFFSET 0
+#define CMD_GET_PHY_CFG_OUT_TYPE_OFFSET 4
+#define CMD_GET_PHY_CFG_OUT_CAP_OFFSET 8
+#define CMD_GET_PHY_CFG_OUT_MEDIA_OFFSET 44
+// CMD for getting phy state out
+#define CMD_GET_PHY_STATE 0x43
+#define CMD_GET_PHY_STATE_OUT_LEN 4
+// CMD for mon probe
+#define CMD_SENSOR_INFO 0x41
+#define CMD_SENSOR_INFO_OUT_LEN 252
+#define CMD_SENSOR_INFO_OUT_MASK 0
+// CMD for BIST test
+#define CMD_START_BIST 0x25
+#define CMD_START_BIST_IN_LEN 4
+#define CMD_PHY_BIST 5
+#define CMD_POLL_BIST 0x26
+#define CMD_POLL_BIST_RUNNING 1
+#define CMD_POLL_BIST_PASSED  2
+#define CMD_POLL_BIST_FAILED  3
+#define CMD_POLL_BIST_OUT_LEN 8
+// CMD for MAC stats
+#define CMD_MAC_STATS_IN_LEN 16
+#define CMD_MAC_STATS 0x2e
+#define CMD_MAC_STATS_IN_CMD_OFFSET 8
+#define CMD_MAC_STATS_IN_ADDR_LO_OFFSET 0
+#define CMD_MAC_STATS_IN_ADDR_HI_OFFSET 4
+#define CMD_MAC_STATS_IN_DMA_LEN_OFFSET 12
+// CMD for PHY stats
+#define CMD_PHY_STATS 0x2d
+#define CMD_PHY_STATS_IN_LEN 8
+#define CMD_PHY_STATS_IN_ADDR_OFFSET 0
+// CMD for info about virtual NVRAM partition
+#define CMD_NVRAM_INFO 0x37
+#define CMD_NVRAM_INFO_IN_LEN 4
+#define CMD_NVRAM_INFO_IN_TYPE_OFFSET 0
+#define CMD_NVRAM_INFO_OUT_LEN 24
+//CMD 
+#define CMD_NVRAM_TYPES 0x36
+#define CMD_NVRAM_TYPES_OUT_LEN 4
+errval_t mcdi_rpc(unsigned cmd, const uint8_t *in, uint32_t inlen,
+             uint8_t *out, uint32_t outlen, uint32_t *outlen_actual,
+             bool port, sfn5122f_t *d);
+void init_mcdi_mutex(void);
+
+
+#endif 
+
+
diff --git a/usr/drivers/solarflare/sfn5122f.h b/usr/drivers/solarflare/sfn5122f.h
new file mode 100644 (file)
index 0000000..c7bef82
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * \file
+ * \brief Solarflare sfn5122f driver: Constants
+ *
+ *
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef SFN5122F_H_
+#define SFN5122F_H_
+
+#include <dev/sfn5122f_dev.h>
+#include <dev/sfn5122f_q_dev.h>
+#include "mcdi_rpc.h"
+#include "helper.h"
+
+#define BUF_SIZE 4096
+#define DEVICE_ID 0x803
+// TX Queue
+#define TX_DESC_CACHE_SIZE 16
+#define TX_ENTRIES 1024
+#define TX_DC_BASE 0x11000
+// Event Queue
+#define EV_CODE_RX 0
+#define EV_CODE_TX 2
+#define EV_CODE_DRV 5
+#define EV_CODE_DRV_GEN 7
+#define EV_CODE_USER 8
+#define EV_CODE_MCDI 12
+#define EV_CODE_GLOBAL 6
+
+/* for each TX/RX entry one entry plus an additonal 2 for mcdi completion
+and link state events */
+#define EV_ENTRIES 4096
+
+// RX Queue
+#define RX_DESC_CACHE_SIZE 64
+#define RX_ENTRIES 2048
+#define RX_DC_BASE 0xD000
+// calculcat max frame length
+#define MTU 1500
+#define MTU_MAX 2048
+/* PHY and MAC stats       */
+#define NUM_MAC_STATS 0x61
+// Numer of buffer table entries for each type of queue
+#define NUM_ENT_EVQ ((EV_ENTRIES*8)/BUF_SIZE)
+#define NUM_ENT_RX ((RX_ENTRIES*8)/BUF_SIZE)
+#define NUM_ENT_TX ((TX_ENTRIES*8) / BUF_SIZE)
+#define NUM_ENT_RX_USR  ((RX_ENTRIES*4) / BUF_SIZE)
+#define MAX_BUF_TBL_ENTRIES 147456
+
+// Filters
+#define NUM_FILTERS_IP 8192
+#define NUM_FILTERS_MAC 512
+
+
+#endif /* SFN5122F_H_ */
diff --git a/usr/drivers/solarflare/sfn5122f_cdriver.c b/usr/drivers/solarflare/sfn5122f_cdriver.c
new file mode 100644 (file)
index 0000000..38cbada
--- /dev/null
@@ -0,0 +1,1578 @@
+/*
+ * Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net_queue_manager/net_queue_manager.h>
+#include <barrelfish/nameservice_client.h>
+#include <pci/pci.h>
+#include <ipv4/lwip/inet.h>
+#include <barrelfish/debug.h>
+#include <if/sfn5122f_defs.h>
+#include <if/net_ARP_rpcclient_defs.h>
+#include <if/net_ARP_defs.h>
+
+
+#include "sfn5122f.h"
+#include "sfn5122f_debug.h"
+#include "buffer_tbl.h"
+
+struct queue_state {
+    bool enabled;
+    bool userspace;
+    bool use_irq;
+
+    struct sfn5122f_binding *binding;
+    struct capref tx_frame;
+    struct capref rx_frame;
+    struct capref ev_frame;
+    uint32_t rxbufsz;
+
+    //bool userspace;
+    uint64_t rx_head;
+    uint64_t tx_head;
+    uint64_t ev_head;
+
+    // first entries of the buffer table to make up queue
+    uint32_t rx_buf_tbl;
+    uint32_t tx_buf_tbl;
+    uint32_t ev_buf_tbl;
+
+    // MSI-X information
+    size_t msix_index;
+    int16_t msix_intvec;
+    uint8_t msix_intdest;
+};
+
+
+static bool use_msix = false;
+static const char *service_name = "sfn5122f";
+static sfn5122f_t *d = NULL;
+//static sfn5122f_msix_t *d_msix = NULL;
+static uint64_t d_mac[2];
+static int initialized = 0;
+static struct capref *regframe;
+/* Interrupt state  */
+static struct capref int_ker;
+static void* int_ker_virt;
+/*  MAC stats  */
+static struct capref mac_stats;
+static void* mac_virt;
+static uint64_t mac_phys;
+/*        */
+static uint8_t pci_function = 0;
+// Port  info
+static uint32_t cap[2];
+static uint32_t speed[2];
+static uint32_t flags[2];
+static uint32_t fcntl [2];
+
+// Phy info
+static uint32_t phy_caps[2];
+static uint32_t phy_flags[2];
+static uint32_t phy_media[2];
+/* Loopback mode none and speed */
+static uint32_t phy_loopback_mode = 0;
+//static uint32_t phy_loopback_speed = 0;
+//WoL Filter id
+static uint32_t wol_filter_id = 0;
+
+// ARP rpc client
+static struct net_ARP_rpc_client arp_rpc;
+static bool net_arp_connected = false;
+static struct waitset rpc_ws;
+
+static bool csum_offload = 1;
+// TX / RX
+static uint32_t rx_indir_tbl[128];
+
+// Queues
+static struct queue_state queues[1024];
+/* PCI device address passed on command line */
+static uint32_t pci_bus = PCI_DONT_CARE;
+static uint32_t pci_device = PCI_DONT_CARE;
+static struct bmallocator msix_alloc;
+static size_t cdriver_msix = -1;
+static uint8_t cdriver_vector;
+
+// first to start everything
+static bool first = 1;
+
+/* Hash key */
+uint8_t rx_hash_key[40];
+uint8_t mc_hash[32];
+
+// Filters
+static uint32_t ip = 0;
+
+enum filter_type_ip {
+    OTHER,
+    UDP_FULL,
+    TCP_FULL,
+    TCP_WILDCARD,
+    UDP_WILDCARD
+};
+
+/*
+enum filter_type_mac {
+    OTHER,
+    MAC_FULL,
+    MAC_WILDCARD
+};
+*/
+
+struct sfn5122f_filter_ip {
+    bool enabled;
+    bool scatter;
+    bool rss;
+
+    uint8_t queue;
+
+    uint32_t src_ip;
+    uint32_t dst_ip;
+    uint16_t src_port;
+    uint16_t dst_port;
+
+    uint16_t type_ip;
+    uint16_t hash;   
+};
+
+/*
+struct sfn5122f_filter_mac {
+    bool enabled;
+    bool wildcard_match;
+    bool scatter;
+    bool rss;
+    bool ip_override;    
+
+    uint8_t queue;
+
+    uint64_t dst_mac;
+    uint16_t vlan_id;
+
+    uint16_t type_mac;
+    uint16_t hash;   
+};
+*/
+
+/* scatter and rss enable */
+static bool rss_en = 0;
+static bool scatter_en = 0;
+static struct sfn5122f_filter_ip filters_rx_ip[NUM_FILTERS_IP];
+//static struct sfn5122f_filter_ip filters_tx_ip[NUM_FILTERS_IP];
+
+/*
+static struct sfn5122f_filter_mac filters_rx_ip[NUM_FILTERS_MAC];
+static struct sfn5122f_filter_mac filters_tx_ip[NUM_FILTERS_MAC];
+*/
+
+
+/******************************************************************************/
+/* Prototypes */
+void qd_main(void) __attribute__((weak));
+void qd_argument(const char *arg) __attribute__((weak));
+void qd_interrupt(void) __attribute__((weak));
+void qd_queue_init_data(struct sfn5122f_binding *b, struct capref registers,
+        uint64_t macaddr, struct capref mac_stat) __attribute__((weak));
+void qd_queue_memory_registered(struct sfn5122f_binding *b) __attribute__((weak));
+void qd_write_queue_tails(struct sfn5122f_binding *b) __attribute__((weak));
+
+
+void cd_request_device_info(struct sfn5122f_binding *b);
+void cd_register_queue_memory(struct sfn5122f_binding *b,
+                              uint16_t queue,
+                              struct capref tx,
+                              struct capref rx,
+                              struct capref ev,
+                              uint32_t rxbufsz,
+                              bool use_interrupts,
+                              bool userspace,
+                              uint8_t vector,
+                              uint16_t core);
+
+static void idc_write_queue_tails(struct sfn5122f_binding *b);
+
+static void device_init(void);
+static void start_all(void);
+static void probe_all(void);
+static uint32_t init_txq(uint16_t n, bool csum, bool userspace);
+static uint32_t init_rxq(uint16_t n, bool userspace);
+static uint32_t init_evq(uint16_t n);
+static void queue_hw_stop(uint16_t n);
+
+static void setup_interrupt(size_t *msix_index, uint8_t core, uint8_t vector);
+static void interrupt_handler(void* arg);
+
+static void bind_arp(struct waitset *ws);
+static errval_t arp_ip_info(void);
+/***************************************************************************/
+/* Filters */
+
+static void sfn5122f_filter_port_setup(int idx, struct sfn5122f_filter_ip* filter)
+{
+    sfn5122f_rx_filter_tbl_lo_t filter_lo = 0;
+    sfn5122f_rx_filter_tbl_hi_t filter_hi = 0;
+
+    if (filter->type_ip == sfn5122f_PORT_UDP) {
+
+        // Add destination IP
+        filter_hi = sfn5122f_rx_filter_tbl_hi_dest_ip_insert(filter_hi, 
+                                                             filter->dst_ip);
+        filter_lo = sfn5122f_rx_filter_tbl_lo_src_ip_insert(filter_lo, 
+                                                            0);
+        filter_hi = sfn5122f_rx_filter_tbl_hi_tcp_udp_insert(filter_hi, 1);
+        filter_lo = sfn5122f_rx_filter_tbl_lo_src_tcp_dest_udp_insert(
+                                                filter_lo, filter->dst_port);
+
+        filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, 0);
+        filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, 0);
+        DEBUG("UPD filter index %d: ip_dst %x port_dst %d ip_src %x port_src %d"
+               " queue %d \n", 
+               idx, filter->dst_ip, filter->dst_port, 
+               filter->src_ip, filter->src_port, filter->queue);
+    }
+
+    if (filter->type_ip == sfn5122f_PORT_TCP) {
+        // Add dst IP and port
+        filter_hi = sfn5122f_rx_filter_tbl_hi_dest_ip_insert(filter_hi,
+                                                             filter->dst_ip);
+        filter_lo = sfn5122f_rx_filter_tbl_lo_src_ip_insert(filter_lo, 
+                                                            filter->src_ip);
+        filter_lo = sfn5122f_rx_filter_tbl_lo_dest_port_tcp_insert(filter_lo, 
+                                                                   filter->dst_port);
+        filter_hi = sfn5122f_rx_filter_tbl_hi_tcp_udp_insert(filter_hi, 0);
+        filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, 0);
+        filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, 0);
+        DEBUG("TCP filter index %d: ip_dst %x port_dst %d ip_src %x port_src %d"
+               " queue %d \n", 
+               idx, filter->dst_ip, filter->dst_port, 
+               filter->src_ip, filter->src_port, filter->queue);
+    }
+
+    filter_hi = sfn5122f_rx_filter_tbl_hi_rxq_id_insert(filter_hi, filter->queue);
+    filter_hi = sfn5122f_rx_filter_tbl_hi_rss_en_insert(filter_hi, rss_en);
+    filter_hi = sfn5122f_rx_filter_tbl_hi_scatter_en_insert(filter_hi, scatter_en);
+
+    sfn5122f_rx_filter_tbl_lo_wr(d, idx, filter_lo);
+    sfn5122f_rx_filter_tbl_hi_wr(d, idx, filter_hi);
+}
+
+static uint32_t build_key(struct sfn5122f_filter_ip* f)
+{
+    uint32_t data[4] = {0,0,0,0};
+    uint32_t host1;
+    uint32_t host2;
+    uint16_t port1;
+    uint16_t port2;
+    host1 = f->src_ip;
+    host2 = f->dst_ip;
+    
+    if (f->type_ip == sfn5122f_PORT_UDP) {
+       port1 = f->dst_port;
+       port2 = f->src_port;
+       data[3] = 1;
+    } else {
+       port1 = f->src_port;
+       port2 = f->dst_port;
+       data[3] = 0;
+    }
+
+    data[0] = host1 << 16 | port1;
+    data[1] = port2 << 16 | host1 >> 16;
+    data[2] = host2;
+
+    return data[0] ^ data[1] ^ data[2] ^ data[3];
+}
+
+static uint16_t filter_hash(uint32_t key)
+{
+    uint16_t tmp;
+
+    /* First 16 rounds */
+    tmp = 0x1fff ^ key >> 16;
+    tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
+    tmp = tmp ^ tmp >> 9;
+    /* Last 16 rounds */
+    tmp = tmp ^ tmp << 13 ^ key;
+    tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
+    return tmp ^ tmp >> 9;
+}
+
+static bool filter_equals(struct sfn5122f_filter_ip* f1, 
+                          struct sfn5122f_filter_ip* f2)
+{
+    if (f1->type_ip != f2->type_ip) {
+        return false;
+    } else if ((f1->src_ip != f2->src_ip) ||
+               (f1->dst_ip != f2->dst_ip) || 
+               (f1->queue != f2->queue)) {
+        return false;
+    } else if ((f1->src_port != f2->src_port) && 
+               (f2->dst_port != f1->dst_port)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static uint16_t filter_increment(uint32_t key)
+{
+    return key * 2 - 1;
+}
+
+static int ftqf_alloc(struct sfn5122f_filter_ip* f)
+{
+    // Documentation suggest hashing using a certain algorithm
+    int key = 0;
+    uint16_t hash = 0;
+    unsigned int incr = 0;
+    uint16_t depth = 0;
+    key = build_key(f);
+    hash = filter_hash(key);
+    incr = filter_increment(key);
+    
+    key = hash & (NUM_FILTERS_IP - 1);
+
+    while (true) {
+        if (filters_rx_ip[key].enabled == false) {
+            return key;
+        } else if (filter_equals(&filters_rx_ip[key], f)){
+            return key;
+        } 
+        
+        if (depth > 3) {
+            return -1;
+        }
+            
+        key = (key + incr) & (NUM_FILTERS_IP - 1);
+        depth++;
+    }
+
+    return key;
+}
+
+
+static errval_t reg_port_filter(struct sfn5122f_filter_ip* f, uint64_t* fid)
+{
+    int filt_ind;
+
+    DEBUG("reg_port_filter: called\n");
+
+    if ((filt_ind=ftqf_alloc(f)) < 0) {
+        return FILTER_ERR_NOT_ENOUGH_MEMORY;
+    }
+
+    filters_rx_ip[filt_ind] = *f;
+    filters_rx_ip[filt_ind].enabled = true;
+
+    sfn5122f_filter_port_setup(filt_ind, f);
+
+    // TODO +1 needed?
+    *fid = filt_ind;
+
+    return SYS_ERR_OK;
+}
+
+
+/***************************************************************************/
+/* Helper functions*/
+static void decode_link(uint32_t fcntl1 , uint32_t flags1 , uint32_t speed1)
+{
+    switch(fcntl1){
+    case 0x3:
+        DEBUG("LINK MODE: AUTO \n");
+        break;
+    case 0x2:
+        DEBUG("LINK MODE: RX/TX \n");
+        break;
+    case 0x1:
+        DEBUG("LINK MODE: RESPOND \n");
+        break;
+    case 0x0:
+        DEBUG("LINK MODE: NONE \n");
+        break;
+    }
+    DEBUG("LINK SPEED: %"PRIu32" \n", speed1);
+    DEBUG("LINK FLAGS: %8lX \n", (long unsigned int) flags1);
+    if (!!(flags1 & 1)) {
+       DEBUG("LINK IS UP \n");
+    }
+
+    if (!!(flags1 & 1 << 0x1)) {
+       DEBUG("LINK IS FULL DUPLEX \n");
+    }
+
+}
+
+static void handle_assertions(void)
+{
+    uint8_t in[4];
+    uint8_t out[140];
+    uint32_t outlen = 0;
+    errval_t err;   
+
+    memset(in, 0, sizeof(in));
+    in[CMD_GET_ASSERTS_IN_CLEAR_OFFSET] = 0;
+
+    err = mcdi_rpc(CMD_GET_ASSERTS, in , CMD_GET_ASSERTS_IN_LEN, out,
+                   CMD_GET_ASSERTS_OUT_LEN, &outlen, pci_function, d);    
+    assert(err_is_ok(err));
+
+    if(out[0] != 0x1){
+          /* TODO handle assertions */
+         printf("THERE WERE ASSERTIONS: %"PRIu8" \n ", out[0]);
+         /* exit assertions -> special reboot*/
+         in[0] = 0x1;
+         err = mcdi_rpc(CMD_REBOOT, in, CMD_REBOOT_IN_LEN , 
+                        NULL, 0, NULL, pci_function, d);
+         assert(err_is_ok(err));
+    }
+
+}
+
+/* Get Link and write settings into global variables  */
+static void get_link(uint8_t port)
+{
+    uint8_t out[CMD_GET_LINK_OUT_LEN];
+    errval_t err;
+
+    err = mcdi_rpc(CMD_GET_LINK, NULL, 0 , out, CMD_GET_LINK_OUT_LEN, NULL, port,d);
+    assert(err_is_ok(err));
+
+    memcpy(&cap[port], out, 4);
+    memcpy(&speed[port], out+CMD_GET_LINK_OUT_SPEED_OFFSET, 4);
+    memcpy(&fcntl[port], out+CMD_GET_LINK_OUT_FCNTL_OFFSET, 4);
+    memcpy(&flags[port], out+CMD_GET_LINK_OUT_FLAGS_OFFSET, 4);
+   
+    decode_link(fcntl[port], flags[port], speed[port]);     
+
+}
+
+
+/* Init port */
+static void init_port(uint8_t port)
+{
+    uint8_t in[CMD_SET_MAC_IN_LEN];
+    uint32_t reg;
+    errval_t err;
+
+    memcpy(in + CMD_SET_MAC_IN_ADR_OFFSET, &d_mac[port], 6 );
+    /* linux driver sets these bits */
+    in[14] = 0xFF;
+    in[15] = 0xFF; 
+    /* set MTU */
+    reg = MTU_MAX;
+    memcpy(in + CMD_SET_MAC_IN_MTU_OFFSET , &reg, 4);
+    
+    in[CMD_SET_MAC_IN_DRAIN_OFFSET] = 0;
+    /* Reject unicast packets?   */
+    in[CMD_SET_MAC_IN_REJECT_OFFSET] = 1;
+    /* Set wanted flow control of the card 2 -> bidirectional*/
+    in[CMD_SET_MAC_IN_FCTNL_OFFSET] = 2;
+    err = mcdi_rpc(CMD_SET_MAC, in, CMD_SET_MAC_IN_LEN, NULL, 0, NULL, port, d);
+    assert(err_is_ok(err));
+
+    memset(mc_hash, 0, sizeof(mc_hash));
+    err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
+                   NULL, 0 , NULL, port, d);
+    assert(err_is_ok(err));
+
+    memset(in, 0 , sizeof(in));
+    memcpy(in + CMD_SET_LINK_IN_CAP_OFFSET, &cap[pci_function], 4);
+    
+    err = mcdi_rpc(CMD_SET_LINK, in, CMD_SET_LINK_IN_LEN, NULL, 0, NULL, 0, d);
+    assert(err_is_ok(err));
+}
+/*  start port        */
+static void start_port(uint8_t port)
+{
+    uint8_t in[CMD_SET_MAC_IN_LEN];
+    uint64_t reg;
+    errval_t err;
+
+    memset(&in, 0, sizeof(in));
+
+    err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
+                   NULL, 0 , NULL, port, d);
+    assert(err_is_ok(err));
+
+    /* mac address */
+    memcpy(in + CMD_SET_MAC_IN_ADR_OFFSET, &d_mac[port], 6 ); 
+    /* seems like the linux driver sets all bits not set 
+       from the MAC address to 1*/
+    in[14] = 0xFF;
+    in[15] = 0xFF; 
+    /* set MTU*/
+    reg = MTU_MAX; 
+    memcpy(in + CMD_SET_MAC_IN_MTU_OFFSET , &reg, 4);
+    in[CMD_SET_MAC_IN_DRAIN_OFFSET] = 0;
+    /* Reject unicast packets ?  */
+    in[CMD_SET_MAC_IN_REJECT_OFFSET] = 1;
+    /* Set wanted functionality (flow control) of card -> set to 2 for RX/TX 
+       And on*/
+    in[CMD_SET_MAC_IN_FCTNL_OFFSET] = 2;
+    err = mcdi_rpc(CMD_SET_MAC, in, CMD_SET_MAC_IN_LEN, NULL, 0, NULL, port, d);
+    assert(err_is_ok(err));   
+
+    err = mcdi_rpc(CMD_SET_MCAST_HASH, mc_hash , CMD_SET_MCAST_HASH_IN_LEN,
+                   NULL, 0 , NULL, port, d);
+
+    assert(err_is_ok(err));   
+}
+
+/******************************************************************************
+ * Device init
+ *****************************************************************************/
+
+static void probe_all(void)
+{   
+    uint32_t offset = 0;
+    uint32_t outlen = 0;
+    
+    uint64_t reg = 0;
+    
+    uint8_t in[16];
+    uint8_t out[252];
+     
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    errval_t r;
+
+    // init MCDI
+    init_mcdi_mutex();  
+    // Test and clear MC-reboot flag for port/function
+    offset = MCDI_REBOOT_OFFSET(pci_function);
+    reg =  sfn5122f_mc_treg_smem_rd(d,offset);
+    if (reg != 0) {
+        sfn5122f_mc_treg_smem_wr(d,offset,0);
+    }
+
+    /*print out any assertions */
+    handle_assertions();
+    // Let BMC know that driver is in charg of filter/link setttings
+    // before we can restet NIC
+    memset(&in, 0, sizeof(in));
+    memset(&out, 0 , sizeof(out));
+    
+    r = mcdi_rpc(CMD_GET_VERSION, NULL, 0, out, CMD_GET_VERSION_OUT_LEN,
+                 &outlen, pci_function, d);
+    assert(err_is_ok(r));
+
+
+    memset(&out, 0 , sizeof(out));
+
+    // driver is operating / + update
+    in[0] = 0x1;
+    in[4] = 0x1;
+    r = mcdi_rpc(CMD_DRV_ATTACH, in, CMD_DRV_ATTACH_IN_LEN, out, 
+                 CMD_DRV_ATTACH_OUT_LEN, &outlen, pci_function, d);
+    assert(err_is_ok(r));
+
+    /* reset card */
+    r = mcdi_rpc(CMD_PORT_RESET, NULL, 0, NULL, 0, NULL, pci_function, d);
+    assert(err_is_ok(r));
+
+    // init WoL Filter 
+    if(mcdi_rpc(CMD_WOL_FILTER_GET, NULL, 0, out, CMD_WOL_FILTER_GET_OUT_LEN, 
+       &outlen, pci_function, d) == SYS_ERR_OK) {
+        memcpy(&wol_filter_id, out , 4);
+    } else {
+      // Reset filter of card
+      mcdi_rpc(CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL, pci_function, d);
+    }
+    //  memory for INT_KER 
+    int_ker_virt = alloc_map_frame(VREGION_FLAGS_READ_WRITE, 
+                                   2*sizeof(uint64_t), &int_ker);
+    memset(int_ker_virt, 0, 2*sizeof(uint64_t));
+    // Read in non volatile configuration
+    memset(&out, 0, sizeof(out));
+    r = mcdi_rpc(CMD_GET_BOARD_CONFIG, NULL, 0, out,
+                 CMD_GET_BOARD_CONFIG_OUT_LEN, &outlen, pci_function, d); 
+    assert(err_is_ok(r));
+
+    memcpy(&d_mac[0], out+MCDI_MAC_PORT_OFFSET(0) ,6);  
+    memcpy(&d_mac[1], out+MCDI_MAC_PORT_OFFSET(1) ,6);  
+    
+    // read phy configuration  
+    r = mcdi_rpc(CMD_GET_PHY_CFG, NULL, 0, out, CMD_GET_PHY_CFG_OUT_LEN, &outlen, 
+                 pci_function, d);
+    assert(err_is_ok(r));
+
+    memcpy(&phy_caps[pci_function], out+CMD_GET_PHY_CFG_OUT_CAP_OFFSET, 4);
+    memcpy(&phy_flags[pci_function], out+CMD_GET_PHY_CFG_OUT_FLAGS_OFFSET, 4);
+    memcpy(&phy_media[pci_function], out+CMD_GET_PHY_CFG_OUT_MEDIA_OFFSET, 4);
+
+    // get loopback modes
+    r = mcdi_rpc(CMD_GET_LOOPBACK_MODES, NULL, 0, out, 
+                 CMD_GET_LOOPBACK_MODES_OUT_LEN, &outlen, pci_function, d);
+    assert(err_is_ok(r));
+    memcpy(&phy_loopback_mode, out+CMD_GET_LOOPBACK_MODES_SUGGESTED_OFFSET,4);
+    // loopback mode NONE is no valid condition
+    phy_loopback_mode &= ~(1);
+   
+
+    // MAC STATS INIT
+    mac_virt = alloc_map_frame(VREGION_FLAGS_READ_WRITE, 
+                               NUM_MAC_STATS*sizeof(uint64_t), 
+                               &mac_stats);
+
+    assert(mac_virt != NULL);
+    r = invoke_frame_identify(mac_stats, &frameid);
+    assert(err_is_ok(r));
+    mac_phys = frameid.base;
+    memset(mac_virt, 0, NUM_MAC_STATS*sizeof(uint64_t));
+
+
+    memset(&in, 0, sizeof(in));
+    memcpy(in, &mac_phys, 8);
+
+     // Settings for DMA of MAC stats
+    in[CMD_MAC_STATS_IN_CMD_OFFSET] = 0x6;    
+    in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET] = 8;
+    in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET+1] = 3;
+    r = mcdi_rpc(CMD_MAC_STATS, in, CMD_MAC_STATS_IN_LEN, NULL, 0, NULL, 
+                pci_function, d); 
+    assert(err_is_ok(r));
+
+}
+
+
+
+// Init card IP filters
+static void init_rx_filter_config(void)
+{
+    uint64_t reg_hi, reg_lo;
+
+    for (int i = 0; i < NUM_FILTERS_IP; i++) {   
+        sfn5122f_rx_filter_tbl_lo_wr(d, i, 0);
+        sfn5122f_rx_filter_tbl_hi_wr(d, i, 0);
+    }
+
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_rd(d);
+    reg_hi = sfn5122f_rx_filter_ctl_reg_hi_rd(d);
+
+    reg_hi = sfn5122f_rx_filter_ctl_reg_hi_ethernet_full_search_limit_insert(reg_hi, 1);
+    reg_hi = sfn5122f_rx_filter_ctl_reg_hi_ethernet_wildcard_search_limit_insert(reg_hi, 3);
+
+    // TODO set to 0
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_multicast_nomatch_q_id_lo_insert(reg_lo, 0);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_unicast_nomatch_q_id_insert(reg_lo, 0);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_unicast_nomatch_rss_enabled_insert(reg_lo, 0);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_multicast_nomatch_rss_enabled_insert(reg_lo, 0);
+
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_udp_full_srch_limit_insert(reg_lo, 1);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_udp_wild_srch_limit_insert(reg_lo, 3);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_tcp_full_srch_limit_insert(reg_lo, 1);
+    reg_lo = sfn5122f_rx_filter_ctl_reg_lo_tcp_wild_srch_limit_insert(reg_lo, 3);
+
+
+    sfn5122f_rx_filter_ctl_reg_lo_wr(d,reg_lo);
+    sfn5122f_rx_filter_ctl_reg_hi_wr(d,reg_hi);
+
+}
+
+static void device_init(void)
+{
+    errval_t r;
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    uint64_t reg, reg2; // tmp_key = 0;
+    uint8_t in[24]; // set length to biggest in length needed 
+
+    memset(&in, 0, sizeof(in));
+
+    // recover from failed assertion post-reset
+    handle_assertions();
+
+    /* ignore TX of packets 16 bytes and less */
+    reg = sfn5122f_tx_reserved_reg_lo_rd(d);
+    reg = sfn5122f_tx_reserved_reg_lo_tx_flush_min_len_en_insert(reg, 1);
+    sfn5122f_tx_reserved_reg_lo_wr(d, reg);
+    sfn5122f_tx_reserved_reg_hi_wr(d, sfn5122f_tx_reserved_reg_hi_rd(d));
+    //Disable TX_NO_EOP_DISC_EN because else would limit packets to 16
+    reg = sfn5122f_tx_cfg_reg_lo_rd(d);
+    reg = sfn5122f_tx_cfg_reg_lo_tx_no_eop_disc_en_insert(reg, 0);
+    reg = sfn5122f_tx_cfg_reg_lo_tx_ownerr_ctl_insert(reg, 1);
+    reg = sfn5122f_tx_cfg_reg_lo_tx_filter_en_bit_insert(reg, 1);
+    sfn5122f_tx_cfg_reg_lo_wr(d, reg);
+    sfn5122f_tx_cfg_reg_hi_wr(d, sfn5122f_tx_cfg_reg_hi_rd(d));
+
+    reg = sfn5122f_rx_cfg_reg_lo_rd(d);
+    // unset bit and set other bit which are not in documentation (43 and 47)
+    reg = sfn5122f_rx_cfg_reg_lo_rx_desc_push_en_insert(reg, 0) ;
+    reg = sfn5122f_rx_cfg_reg_lo_rx_ingr_en_insert(reg, 1); 
+    reg = sfn5122f_rx_cfg_reg_lo_rx_usr_buf_size_insert(reg, (MTU_MAX-256) >> 5);
+    //reg = sfn5122f_rx_cfg_reg_lo_rx_ownerr_ctl_insert(reg, 1);
+    reg = sfn5122f_rx_cfg_reg_lo_rx_ip_hash_insert(reg, 1);
+    //reg = sfn5122f_rx_cfg_reg_lo_rx_hash_insrt_hdr_insert(reg, 1);
+    reg = sfn5122f_rx_cfg_reg_lo_rx_hash_alg_insert(reg, 1);
+    sfn5122f_rx_cfg_reg_lo_wr(d, reg);
+    sfn5122f_rx_cfg_reg_hi_wr(d, sfn5122f_rx_cfg_reg_hi_rd(d));
+    /* enable event logging, no UART
+      Event destination is queue 0 */
+    in[0] = 0x2;
+    r = mcdi_rpc(CMD_LOG_CTRL, in, CMD_LOG_CTRL_IN_LEN, 
+                 NULL, 0, NULL, pci_function, d);    
+    assert(err_is_ok(r));
+
+    /* Set destination of TX/RX flush event */
+    
+    sfn5122f_dp_ctrl_reg_lo_fls_evq_id_wrf(d, 0);
+    sfn5122f_dp_ctrl_reg_hi_wr(d, sfn5122f_dp_ctrl_reg_hi_rd(d));
+  
+    /* Disalbe user events for now     */
+    sfn5122f_usr_ev_cfg_lo_usrev_dis_wrf(d , 1);  
+    sfn5122f_usr_ev_cfg_hi_wr(d, sfn5122f_usr_ev_cfg_hi_rd(d));    
+
+
+    // This seems to be not device specific i.e. works for other 
+    // Solarflare cards
+    /* Set position of descriptor caches in SRAM */
+    sfn5122f_srm_tx_dc_cfg_reg_lo_wr(d, TX_DC_BASE);
+    sfn5122f_srm_tx_dc_cfg_reg_hi_wr(d, sfn5122f_srm_tx_dc_cfg_reg_hi_rd(d));
+    sfn5122f_srm_rx_dc_cfg_reg_lo_srm_rx_dc_base_adr_wrf(d, RX_DC_BASE);
+    sfn5122f_srm_rx_dc_cfg_reg_hi_wr(d, sfn5122f_srm_rx_dc_cfg_reg_hi_rd(d));
+
+    /* Set TX descriptor cache size to 16 */
+    sfn5122f_tx_dc_cfg_reg_lo_tx_dc_size_wrf(d, 1);
+    sfn5122f_tx_dc_cfg_reg_hi_wr(d, sfn5122f_tx_dc_cfg_reg_hi_rd(d));
+
+    /* Set RX descriptor cache size to 64 and low watermark */
+    sfn5122f_rx_dc_cfg_reg_lo_rx_dc_size_wrf(d, 3);
+    sfn5122f_rx_dc_cfg_reg_hi_wr(d, sfn5122f_rx_dc_cfg_reg_hi_rd(d));
+
+    reg = 0;
+    reg = sfn5122f_rx_dc_pf_wm_reg_lo_rx_dc_pf_lwm_insert(reg, RX_DESC_CACHE_SIZE -8);
+    sfn5122f_rx_dc_pf_wm_reg_lo_wr(d, reg);
+    sfn5122f_rx_dc_pf_wm_reg_hi_wr(d, sfn5122f_rx_dc_pf_wm_reg_hi_rd(d));
+   
+   /*programm init ker address for interrupts */
+    r = invoke_frame_identify(int_ker, &frameid);
+    assert(err_is_ok(r));
+
+    sfn5122f_int_adr_reg_ker_lo_wr(d, frameid.base);
+    reg = sfn5122f_int_adr_reg_ker_hi_rd(d);
+
+    // disable vector write if we use MSI-X
+    if (use_msix) {
+        reg = sfn5122f_int_adr_reg_ker_hi_norm_int_vec_dis_ker_insert(reg, 1);
+        if (cdriver_msix == -1) {
+            r = pci_setup_inthandler(interrupt_handler, NULL, &cdriver_vector);
+            assert(err_is_ok(r));
+            setup_interrupt(&cdriver_msix, disp_get_core_id(), cdriver_vector);
+        }
+    } else {
+        reg = sfn5122f_int_adr_reg_ker_hi_norm_int_vec_dis_ker_insert(reg, 0);
+    }
+    sfn5122f_int_adr_reg_ker_hi_wr(d, reg);
+   
+    /* Enable all the genuinley fatal interrupts */
+    reg = sfn5122f_fatal_intr_reg_ker_lo_ill_adr_int_ker_en_insert(reg, 1);
+    /* Enable rxbuf/txbuf interrupt  fields not documented. 
+       Set bits 39 and 38*/           
+    reg = sfn5122f_fatal_intr_reg_ker_lo_rxbuf_own_int_ker_en_insert(reg, 1);
+    reg = sfn5122f_fatal_intr_reg_ker_lo_txbuf_own_int_ker_en_insert(reg, 1);
+    
+    //reg = sfn5122f_fatal_intr_reg_ker_lo_sram_perr_int_p_ker_en_insert(reg, 1);
+    sfn5122f_fatal_intr_reg_ker_lo_wr(d, ~reg);
+    sfn5122f_fatal_intr_reg_ker_hi_wr(d, 0XFFFFFFFFFFFFFFFF);
+
+    /* Setup RSS indirection table (maps from hash value to packet to RXQ) */
+    for (int i = 0; i < 128; i++) {
+        rx_indir_tbl[i] = 0;
+        sfn5122f_rx_indirection_tbl_wr( d, i, rx_indir_tbl[i]);
+    }
+
+    /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+     * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+      (from linux driver) */
+    reg = sfn5122f_tx_reserved_reg_lo_rd(d);
+    reg = sfn5122f_tx_reserved_reg_lo_tx_rx_spacer_en_insert(reg, 1);  
+    reg = sfn5122f_tx_reserved_reg_lo_tx_one_pkt_per_q_insert(reg, 1);
+    reg = sfn5122f_tx_reserved_reg_lo_tx_dis_non_ip_ev_insert(reg, 1);
+
+    /* Enable software events */
+    reg = sfn5122f_tx_reserved_reg_lo_tx_soft_evt_en_insert(reg, 1);
+    /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+    reg = sfn5122f_tx_reserved_reg_lo_tx_pref_threshold_insert(reg, 2);
+    /* Disable hardware watchdog which can misfire */
+    reg = sfn5122f_tx_reserved_reg_lo_tx_pref_wd_tmr_insert(reg, 0x3fffff);
+    /* Squash TX of packets of 16 bytes or less */
+    reg = sfn5122f_tx_reserved_reg_lo_tx_flush_min_len_en_insert(reg, 1);
+    reg2 = sfn5122f_tx_reserved_reg_hi_rd(d);
+    reg2 = sfn5122f_tx_reserved_reg_hi_tx_push_en_insert(reg2, 0);
+    reg2 = sfn5122f_tx_reserved_reg_hi_tx_push_chk_dis_insert(reg2, 0);
+    reg2 = sfn5122f_tx_reserved_reg_hi_tx_rx_spacer_insert(reg2, 0xfe); 
+    sfn5122f_tx_reserved_reg_lo_wr(d, reg);
+    sfn5122f_tx_reserved_reg_hi_wr(d, reg2);
+
+    init_port(pci_function);
+    get_link(pci_function);
+    DEBUG("BASIC CARD INIT DONE  \n");
+}
+
+static void start_all(void)
+{
+    uint64_t reg;
+    uint8_t in[CMD_MAC_STATS_IN_LEN];
+    unsigned long long* stats = (unsigned long long *) mac_virt;    
+    uint8_t* pointer;
+    start_port(pci_function);
+
+    memset(int_ker_virt, 0, 2*sizeof(uint64_t));
+    /*  Enable interrupts   */
+    /* Use an interrupt level unused by event queues */
+    reg = sfn5122f_int_en_reg_ker_lo_rd(d);
+    if (use_msix) {
+        reg = sfn5122f_int_en_reg_ker_lo_ker_int_leve_sel_insert(reg, 0);
+    } else {
+        // legacy
+        reg = sfn5122f_int_en_reg_ker_lo_ker_int_leve_sel_insert(reg, 0x1f);
+    }
+    reg = sfn5122f_int_en_reg_ker_lo_drv_int_en_ker_insert(reg, 1);
+
+    /*   undocumented field   */
+    reg = sfn5122f_int_en_reg_ker_lo_ker_int_ker_insert(reg, 0);
+    sfn5122f_int_en_reg_ker_lo_wr(d, reg);
+    sfn5122f_int_en_reg_ker_hi_wr(d, sfn5122f_int_en_reg_ker_hi_rd(d));
+
+    /* Start MAC stats            */
+    memset(in, 0, sizeof(in));
+    stats[0x60] = (unsigned long long) (-1);
+    memcpy(in, &mac_phys, 8);  
+    pointer = (uint8_t *) &mac_phys;
+    in[CMD_MAC_STATS_IN_CMD_OFFSET] = 0xD;
+    in[10] = 0xE8;
+    in[11] = 3;
+    in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET] = 8;
+    in[CMD_MAC_STATS_IN_DMA_LEN_OFFSET+1] = 3;
+    errval_t err = mcdi_rpc(CMD_MAC_STATS, in, CMD_MAC_STATS_IN_LEN, 
+                            NULL, 0, NULL, pci_function, d); 
+
+    assert(err_is_ok(err));
+}
+
+/**************************************************************************
+ Queue init and stop
+***************************************************************************/
+
+
+static void queue_hw_stop(uint16_t n)
+{
+
+    uint64_t reg = 0;
+    /* flush TX queue */
+    reg = sfn5122f_tx_flush_descq_reg_lo_rd(d);
+    reg = sfn5122f_tx_flush_descq_reg_lo_tx_flush_descq_insert(reg, n);
+    reg = sfn5122f_tx_flush_descq_reg_lo_tx_flush_descq_cmd_insert(reg, 1);
+    sfn5122f_tx_flush_descq_reg_lo_wr(d, reg);
+    sfn5122f_tx_flush_descq_reg_hi_wr(d, sfn5122f_tx_flush_descq_reg_hi_rd(d));
+    /* flush RX queue */
+    reg = sfn5122f_rx_flush_descq_reg_lo_rd(d);
+    reg = sfn5122f_rx_flush_descq_reg_lo_rx_flush_descq_insert(reg, n);
+    reg = sfn5122f_rx_flush_descq_reg_lo_rx_flush_descq_cmd_insert(reg, 1);
+    sfn5122f_rx_flush_descq_reg_lo_wr(d, reg);
+    sfn5122f_rx_flush_descq_reg_hi_wr(d, sfn5122f_rx_flush_descq_reg_hi_rd(d));
+
+    /*   TODO Wait for DRIVER_EVENT    */
+    /* clear pointer table entries */
+    sfn5122f_tx_desc_ptr_tbl_lo_wr(d, n, 0);
+    sfn5122f_tx_desc_ptr_tbl_hi_wr(d, n, 0);
+    sfn5122f_rx_desc_ptr_tbl_lo_wr(d, n, 0);
+    sfn5122f_rx_desc_ptr_tbl_hi_wr(d, n, 0);
+
+    /*Free RX queue tbl entries*/
+    reg = 0;
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg, 
+                                              queues[n].rx_buf_tbl);
+
+    if (queues[n].userspace) {
+       reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg, 
+                                  queues[n].rx_buf_tbl + NUM_ENT_RX_USR);
+    } else {
+        reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg, 
+                                       queues[n].rx_buf_tbl + NUM_ENT_RX);
+    }
+
+
+    /*Free TX queue tbl entries*/
+    reg = 0;
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
+                              queues[n].tx_buf_tbl + NUM_ENT_TX );
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg, 
+                                              queues[n].tx_buf_tbl);
+
+    /*Free EV queue tbl entries*/
+    reg = 0;
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_cmd_insert(reg, 1);
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_end_id_insert(reg,
+                              queues[n].ev_buf_tbl + NUM_ENT_EVQ );
+    reg = sfn5122f_buf_tbl_upd_reg_lo_buf_clr_start_id_insert(reg, 
+                                             queues[n].ev_buf_tbl);
+}
+
+
+
+static uint32_t init_evq(uint16_t n)
+{
+
+    errval_t r; 
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    uint64_t ev_phys, reg, buffer_offset;
+    size_t ev_size;
+    reg = 0;
+
+    reg = sfn5122f_timer_tbl_lo_timer_q_en_insert(reg, 1);
+    // set to 0 if interrupts for receives/sends should be generated
+    if (use_msix) {
+        reg = sfn5122f_timer_tbl_lo_host_notify_mode_insert(reg, 0);
+    } else {
+        reg = sfn5122f_timer_tbl_lo_int_pend_insert(reg, 0);
+        reg = sfn5122f_timer_tbl_lo_int_armd_insert(reg, 0);
+        reg = sfn5122f_timer_tbl_lo_host_notify_mode_insert(reg, 1);
+    }
+    // timer mode disabled 
+    reg = sfn5122f_timer_tbl_lo_timer_mode_insert(reg, 0);
+    sfn5122f_timer_tbl_lo_wr(d, n, reg);
+    sfn5122f_timer_tbl_hi_wr(d, n, sfn5122f_timer_tbl_hi_rd(d, n));
+
+    r = invoke_frame_identify(queues[n].ev_frame, &frameid);
+    assert(err_is_ok(r));
+    ev_phys = frameid.base;
+    ev_size = frameid.bytes;  
+
+    buffer_offset = alloc_buf_tbl_entries(ev_phys, NUM_ENT_EVQ, 0, 0, d);
+    if (buffer_offset == -1) {
+        return -1;
+    }
+
+    DEBUG("EV_QUEUE_%d: buf_off %ld, phys 0x%lx\n",n , buffer_offset, ev_phys);
+    //  setup EV queue
+    reg = sfn5122f_evq_ptr_tbl_lo_rd(d, n);
+    reg = sfn5122f_evq_ptr_tbl_lo_evq_en_insert(reg, 1);
+    reg = sfn5122f_evq_ptr_tbl_lo_evq_size_insert(reg, 3);
+    reg = sfn5122f_evq_ptr_tbl_lo_evq_buf_base_id_insert(reg,
+           buffer_offset);   
+
+    sfn5122f_evq_ptr_tbl_lo_wr(d, n, reg);
+    sfn5122f_evq_ptr_tbl_hi_wr(d, n, sfn5122f_evq_ptr_tbl_hi_rd(d, n));
+
+    /* No write collection for this register   */ 
+    reg = sfn5122f_timer_command_reg_lo_rd(d,n);
+    reg = sfn5122f_timer_command_reg_lo_tc_timer_val_insert(reg, 0);
+    if (use_msix) {
+        reg = sfn5122f_timer_command_reg_lo_tc_timer_mode_insert(reg, 0); 
+    } else {
+        reg = sfn5122f_timer_command_reg_lo_tc_timer_mode_insert(reg, 0); 
+    }
+    sfn5122f_timer_command_reg_lo_wr(d, n, reg);
+
+    sfn5122f_evq_rptr_reg_wr(d, n, queues[n].ev_head);
+
+    return buffer_offset;
+}
+
+static uint32_t init_rxq(uint16_t n, bool userspace)
+{
+
+    errval_t r;
+    size_t rx_size;
+    size_t num_ent_rx;
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    uint64_t rx_phys, reg_lo, reg_hi,  buffer_offset;
+   /*
+    * This will define a buffer in the buffer table, allowing
+    * it to be used for event queues, descriptor rings etc.
+    */
+    /* Get physical addresses for rx/tx rings and event queue */
+  
+    r = invoke_frame_identify(queues[n].rx_frame, &frameid);
+    assert(err_is_ok(r));
+    rx_phys = frameid.base;
+    rx_size = frameid.bytes;  
+    if (userspace) {
+        num_ent_rx = NUM_ENT_RX_USR;
+    } else {
+        num_ent_rx = NUM_ENT_RX;
+    }
+
+    /* RX   */
+    buffer_offset = alloc_buf_tbl_entries(rx_phys, num_ent_rx, 0, 0, d);
+
+    if (buffer_offset == -1) {
+       return -1;
+    }
+
+    DEBUG("RX_QUEUE_%d: buf_off %ld, phys %lx, size %lx \n", n, 
+          buffer_offset, rx_phys, rx_size);
+    /* setup RX queue */
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rd(d, n);
+    reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rd(d, n);
+    /*  Which buffer table entries are used (which is the first entry) */
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_buf_base_id_insert(reg_lo, buffer_offset);
+    /*  Which event queue is associated with this queue*/
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_evq_id_insert(reg_lo, n);
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_owner_id_insert(reg_lo, 0);
+
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_label_insert(reg_lo, n);
+
+    /*  1024 entries = 1   (512 = 0; 2048 = 2 ; 4096 = 3)   */
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_size_insert(reg_lo, 1);
+
+    if (!userspace) {
+        reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_type_insert(reg_lo, 0);
+    } else {
+        reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_type_insert(reg_lo, 1);
+    }
+    /*   No scatter */
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_jumbo_insert(reg_lo, 0);
+    /*  Enable queue */
+    reg_lo = sfn5122f_rx_desc_ptr_tbl_lo_rx_descq_en_insert(reg_lo, 1);
+   
+    /*   Hardware verifies data digest  */
+    reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rx_iscsi_ddig_en_insert(reg_hi, 1);
+    reg_hi = sfn5122f_rx_desc_ptr_tbl_hi_rx_iscsi_hdig_en_insert(reg_hi, 1);  
+
+    sfn5122f_rx_desc_ptr_tbl_lo_wr(d, n, reg_lo);
+    sfn5122f_rx_desc_ptr_tbl_hi_wr(d, n, reg_hi);
+
+    return buffer_offset;
+}
+
+static uint32_t init_txq(uint16_t n, bool csum, bool userspace)
+{
+
+    errval_t r;
+    size_t tx_size;
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    uint64_t tx_phys, reg, reg1, buffer_offset;    
+    /* Get physical addresses for rx/tx rings and event queue */
+    r = invoke_frame_identify(queues[n].tx_frame, &frameid);
+    assert(err_is_ok(r));
+    tx_phys = frameid.base;
+    tx_size = frameid.bytes;
+  
+    buffer_offset = alloc_buf_tbl_entries(tx_phys, NUM_ENT_TX, 0, 0, d);
+    
+    if (buffer_offset == -1) {
+       return -1;
+    }
+
+    DEBUG("TX_QUEUE_%d: buf_off %ld, phys %lx\n",n , buffer_offset, tx_phys);
+    /* setup TX queue */
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_rd(d, n);
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_rd(d, n);
+    /*  Which buffer table entries are used (which is the first entry) */
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_buf_base_id_insert(reg,
+                        buffer_offset);
+    /*  Which event queue is associated with this queue */
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_evq_id_insert(reg , n);
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_owner_id_insert(reg, 0);
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_label_insert(reg , n);
+    /*  1024 entries = 1   (512 = 0; 2048 = 2 ; 4096 = 3)   */
+    reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_size_insert(reg , 1);
+
+    /*  No user lvl networking   */
+    if (!userspace) {
+        reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_type_insert(reg, 0);
+    } else {
+        reg = sfn5122f_tx_desc_ptr_tbl_lo_tx_descq_type_insert(reg, 1);
+    }
+
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_iscsi_ddig_en_insert(reg1, 0);
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_iscsi_hdig_en_insert(reg1, 0);
+   
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_non_ip_drop_dis_insert(reg1, 1);
+    /*   Enable queue  */
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_descq_en_insert(reg1 , 1);
+
+    /* Enable offload of checksum */
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_ip_chksm_dis_insert(reg1, !csum);
+    reg1 = sfn5122f_tx_desc_ptr_tbl_hi_tx_tcp_chksm_dis_insert(reg1, !csum);
+    sfn5122f_tx_desc_ptr_tbl_lo_wr(d, n, reg);
+    sfn5122f_tx_desc_ptr_tbl_hi_wr(d, n, reg1);
+    return buffer_offset; 
+}
+
+
+static void setup_interrupt(size_t *msix_index, uint8_t core, uint8_t vector)
+{
+    bool res;
+    errval_t err;
+    uint8_t dest;
+
+    res = bmallocator_alloc(&msix_alloc, msix_index);
+    assert(res);
+
+    err = get_apicid_from_core(core, &dest);
+    assert(err_is_ok(err));
+
+    err = pci_msix_vector_init(*msix_index, dest, vector);
+    assert(err_is_ok(err));
+
+    DEBUG("MSI-X vector setup index=%"PRIx64", core=%d apic=%d swvec=%x\n",
+            *msix_index, core, dest, vector);
+}
+
+/** Here are the global interrupts handled. */
+static void interrupt_handler(void* arg)
+{
+    //uint64_t reg;
+    uint32_t queue;
+    errval_t syserr;
+    uint8_t* net_ivec_fatal = (uint8_t *) int_ker_virt;    
+
+    // bit 64 is indicator for a fatal event 
+    syserr = (net_ivec_fatal[8] & 0x1);
+    if (syserr) {
+        // TODO handle fatal interrupt
+        USER_PANIC("FATAL INTERRUPT");   
+    } else {
+
+    }
+
+    queue = sfn5122f_int_isr0_reg_lo_rd(d);
+    DEBUG("AN INTERRUPT OCCURED %d \n", queue);
+    // Don't need to start event queues because we're already polling 
+
+} 
+/******************************************************************************/
+/* Management interface implemetation */
+
+static void idc_queue_init_data(struct sfn5122f_binding *b,
+                                struct capref registers,
+                                uint64_t macaddr,
+                                struct capref mac_stat)
+                                  
+{
+    errval_t r;
+
+    r = sfn5122f_queue_init_data__tx(b, NOP_CONT, registers, macaddr, mac_stat);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Tell queue driver that we are done initializing the queue. */
+static void idc_queue_memory_registered(struct sfn5122f_binding *b)
+{
+    errval_t r;
+    r = sfn5122f_queue_memory_registered__tx(b, NOP_CONT);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Send request to queue driver to rewrite the tail pointers of its queues. */
+static void idc_write_queue_tails(struct sfn5122f_binding *b)
+{
+    errval_t r;
+    if (b == NULL) {
+        qd_write_queue_tails(b);
+        return;
+    }
+
+    r = sfn5122f_write_queue_tails__tx(b, NOP_CONT);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Signal queue driver that the queue is stopped. */
+static void idc_queue_terminated(struct sfn5122f_binding *b)
+{
+    errval_t r;
+    r = sfn5122f_queue_terminated__tx(b, NOP_CONT);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Request from queue driver for register memory cap */
+void cd_request_device_info(struct sfn5122f_binding *b)
+{
+    if (b == NULL) {
+        qd_queue_init_data(b, *regframe, d_mac[pci_function], mac_stats);
+        return;
+    }
+    idc_queue_init_data(b, *regframe, d_mac[pci_function], mac_stats);
+}
+
+/** Request from queue driver to initialize hardware queue. */
+void cd_register_queue_memory(struct sfn5122f_binding *b,
+                              uint16_t n,
+                              struct capref tx_frame,
+                              struct capref rx_frame,
+                              struct capref ev_frame,
+                              uint32_t rxbufsz,
+                              bool use_irq, 
+                              bool userspace,
+                              uint8_t vector,
+                              uint16_t core)
+{
+    // Save state so we can restore the configuration in case we need to do a
+    // reset
+
+    bool failed = 0;
+    queues[n].enabled = false;
+    queues[n].tx_frame = tx_frame;
+    queues[n].rx_frame = rx_frame;
+    queues[n].ev_frame = ev_frame;
+    queues[n].tx_head = 0;
+    queues[n].rx_head = 0;
+    queues[n].ev_head = 0;
+    queues[n].rxbufsz = rxbufsz;
+    queues[n].binding = b;
+    queues[n].use_irq = use_irq;
+    queues[n].userspace = userspace;
+    queues[n].msix_index = -1;
+    queues[n].msix_intvec = vector;
+    queues[n].msix_intdest = core;
+
+    queues[n].ev_buf_tbl = init_evq(n);
+    // enable checksums
+    queues[n].tx_buf_tbl = init_txq(n, csum_offload, userspace);
+    queues[n].rx_buf_tbl = init_rxq(n, userspace);
+
+    if(queues[n].ev_buf_tbl == -1 ||
+       queues[n].tx_buf_tbl == -1 ||
+       queues[n].rx_buf_tbl == -1){
+       failed = 1;
+       DEBUG("Allocating queue failed \n");
+       return;
+    }      
+
+    if (queues[n].use_irq) {
+        if (queues[n].msix_intvec != 0) {
+            if (queues[n].msix_index == -1) {
+                setup_interrupt(&queues[n].msix_index, queues[n].msix_intdest,
+                                queues[n].msix_intvec);
+            }
+        } 
+    }
+
+    queues[n].enabled = true;
+
+    idc_write_queue_tails(queues[n].binding);     
+
+    if (b == NULL) {
+        qd_queue_memory_registered(b);
+        return;
+    }
+
+    idc_queue_memory_registered(b);
+
+    if (first){
+       start_all();
+       first = 0;
+    }
+}
+
+static void idc_terminate_queue(struct sfn5122f_binding *b, uint16_t n)
+{
+  DEBUG("idc_terminate_queue(q=%d) \n", n);
+  
+  queue_hw_stop(n);
+  
+  queues[n].enabled = false;
+  queues[n].binding = NULL;
+
+// TODO: Do we have to free the frame caps, or destroy the binding?
+  idc_queue_terminated(b);
+
+}
+
+
+
+/** Send response about filter registration to device manager */
+static void idc_filter_registered(struct sfn5122f_binding *b,
+                                  uint64_t buf_id_rx,
+                                  uint64_t buf_id_tx,
+                                  errval_t err,
+                                  uint64_t filter)
+{
+    errval_t r;
+    r = sfn5122f_filter_registered__tx(b, NOP_CONT, buf_id_rx, buf_id_tx, err,
+                                   filter);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Send response about filter deregistration to device manager */
+static void idc_filter_unregistered(struct sfn5122f_binding *b,
+                                    uint64_t filter,
+                                    errval_t err)
+{
+    errval_t r;
+    r = sfn5122f_filter_unregistered__tx(b, NOP_CONT, filter, err);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+
+static void idc_register_port_filter(struct sfn5122f_binding *b,
+                                     uint64_t buf_id_rx,
+                                     uint64_t buf_id_tx,
+                                     uint16_t queue,
+                                     sfn5122f_port_type_t type,
+                                     uint16_t port)
+{
+    DEBUG("idc_register_port_filter: called (q=%d t=%d p=%d)\n",
+            queue, type, port);
+
+    if (ip == 0) {
+        /* Get cards IP */
+        waitset_init(&rpc_ws);
+        bind_arp(&rpc_ws);
+        arp_ip_info();
+    }
+
+    struct sfn5122f_filter_ip f = {
+            .dst_port = port,
+            .dst_ip = htonl(ip),
+            .src_ip = 0,
+            .src_port = 0,
+            .type_ip = type,
+            .queue = queue,
+    };
+
+    errval_t err;
+    uint64_t fid = -1ULL;
+
+    err = reg_port_filter(&f, &fid);
+    DEBUG("filter registered: err=%"PRIu64", fid=%"PRIu64"\n", err, fid);
+
+    idc_filter_registered(b, buf_id_rx, buf_id_tx, err, fid);
+}
+
+
+static void idc_unregister_filter(struct sfn5122f_binding *b,
+                                  uint64_t filter)
+{
+    DEBUG("unregister_filter: called (%"PRIx64")\n", filter);
+    idc_filter_unregistered(b, filter, LIB_ERR_NOT_IMPLEMENTED);
+}
+
+
+static struct sfn5122f_rx_vtbl rx_vtbl = {
+    .request_device_info = cd_request_device_info,
+    .register_queue_memory = cd_register_queue_memory,
+    .terminate_queue = idc_terminate_queue,
+    .register_port_filter = idc_register_port_filter,
+    .unregister_filter = idc_unregister_filter, 
+};
+
+
+static void export_cb(void *st, errval_t err, iref_t iref)
+{
+    const char *suffix = "_sfn5122fmng";
+    char name[strlen(service_name) + strlen(suffix) + 1];
+
+    assert(err_is_ok(err));
+
+    // Build label for interal management service
+    sprintf(name, "%s%s", service_name, suffix);
+
+    err = nameservice_register(name, iref);
+    assert(err_is_ok(err));
+    DEBUG("Management interface exported\n");
+}
+
+
+static errval_t connect_cb(void *st, struct sfn5122f_binding *b)
+{
+    DEBUG("New connection on management interface\n");
+    b->rx_vtbl = rx_vtbl;
+    return SYS_ERR_OK;
+}
+
+/**
+ * Initialize management interface for queue drivers.
+ * This has to be done _after_ the hardware is initialized.
+ */
+static void initialize_mngif(void)
+{
+    errval_t r;
+
+    r = sfn5122f_export(NULL, export_cb, connect_cb, get_default_waitset(),
+                    IDC_BIND_FLAGS_DEFAULT);
+    assert(err_is_ok(r));
+
+}
+
+/*****************************************************************************/
+/* ARP service client */
+
+/** Get information about the local TCP/IP configuration*/
+static errval_t arp_ip_info(void)
+{
+    errval_t err, msgerr;
+
+    uint32_t gw;
+    uint32_t mask;
+    err = arp_rpc.vtbl.ip_info(&arp_rpc, 0, &msgerr, &ip, &gw, &mask);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return msgerr;
+}
+
+static void a_bind_cb(void *st, errval_t err, struct net_ARP_binding *b)
+{
+    assert(err_is_ok(err));
+    err = net_ARP_rpc_client_init(&arp_rpc, b);
+    assert(err_is_ok(err));
+    net_arp_connected = true;
+}
+
+/** Bind to ARP service (currently blocking) */
+static void bind_arp(struct waitset *ws)
+{
+    errval_t err;
+    iref_t iref;
+
+    DEBUG("bind_arp()\n");
+    err = nameservice_blocking_lookup("sfn5122f_ARP", &iref);
+    assert(err_is_ok(err));
+    DEBUG("resolved\n");
+
+    err = net_ARP_bind(iref, a_bind_cb, NULL, ws, IDC_BIND_FLAGS_DEFAULT);
+    assert(err_is_ok(err));
+    DEBUG("binding initiated\n");
+
+    while (!net_arp_connected) {
+        event_dispatch_non_block(ws);
+        event_dispatch_non_block(get_default_waitset());
+    }
+    DEBUG("bound_arp\n");
+}
+
+
+/******************************************************************************/
+/* Initialization code for driver */
+
+/** Callback from pci to initialize a specific PCI device. */
+static void pci_init_card(struct device_mem* bar_info, int bar_count)
+{
+    errval_t err;
+    bool res;
+
+    d = malloc(sizeof(*d));
+    /* Map first BAR for register access */
+    assert(bar_count >= 1);
+    DEBUG("BAR count %d \n", bar_count);
+    map_device(&bar_info[0]);
+    regframe = bar_info[0].frame_cap;
+    DEBUG("BAR[0] mapped (v=%llx p=%llx l=%llx)\n",
+            (unsigned long long) bar_info[0].vaddr,
+            (unsigned long long) bar_info[0].paddr,
+            (unsigned long long) bar_info[0].bytes);
+
+    /* Initialize Mackerel binding */
+    sfn5122f_initialize(d, (void*) bar_info[0].vaddr);
+
+    // Initialize manager for MSI-X vectors
+    if (use_msix) {
+        //d_msix = malloc(sizeof(*d_msix));
+        //map_device(&bar_info[1]);
+        //sfn5122f_msix_initialize(d_msix, (void*) bar_info[1].vaddr);
+        DEBUG("Enabling MSI-X interrupts\n");
+        uint16_t msix_count = 0;
+        err = pci_msix_enable(&msix_count);
+        assert(err_is_ok(err));
+        assert(msix_count > 0);
+        DEBUG("MSI-X #vecs=%d\n", msix_count);
+
+        res = bmallocator_init(&msix_alloc, msix_count);
+        assert(res);
+    } else {
+        DEBUG("Using legacy interrupts\n");
+    }
+
+    /* Get all information needed  */
+    probe_all();
+    /* Initialize hardware registers etc. */
+    /* Start interrups / mac_stats etc.  */   
+    device_init();
+    /* Init rx filters */
+    init_rx_filter_config();
+    /* initalize managemnt interface   */
+    initialize_mngif();  
+}
+
+static void parse_cmdline(int argc, char **argv)
+{
+    int i;
+
+    for (i = 1; i < argc; i++) {
+        if (strncmp(argv[i], "cardname=", strlen("cardname=") - 1) == 0) {
+            service_name = argv[i] + strlen("cardname=");
+        } else if (strncmp(argv[i], "bus=", strlen("bus=") - 1) == 0) {
+            pci_bus = atol(argv[i] + strlen("bus="));
+        } else if (strncmp(argv[i], "device=", strlen("device=") - 1) == 0) {
+            pci_device = atol(argv[i] + strlen("device="));
+        } else if (strncmp(argv[i], "function=", strlen("function=") - 1) == 0){
+            pci_function = atol(argv[i] + strlen("function="));
+            if (pci_function != 0) {
+                USER_PANIC("Second port not implemented, please use function=0")
+            }
+        } else if (strncmp(argv[i], "msix=", strlen("msix=") - 1) == 0){
+            USER_PANIC("MSI-X not fully supported yet");
+            use_msix = !!atol(argv[i] + strlen("msix="));
+            //qd_rgument(argv[i]);
+        } else {
+            qd_argument(argv[i]);
+        }
+    }
+}
+
+static void eventloop(void)
+{
+    struct waitset *ws;
+
+    ws = get_default_waitset();
+    DEBUG("SFN5122F enter event loop \n");
+    while (1) {
+        event_dispatch(ws);
+    }
+}
+
+void qd_main(void)
+{
+    eventloop();
+}
+
+int main(int argc, char** argv)
+{
+    DEBUG("SFN5122F driver started \n");
+    errval_t r;
+
+    parse_cmdline(argc, argv);
+    /* Register our device driver */
+    printf("SFN5122F register PCI\n");
+    r = pci_client_connect();
+    printf("SFN5122F register PCI end \n");
+    assert(err_is_ok(r));
+    r = pci_register_driver_irq(pci_init_card, PCI_CLASS_ETHERNET,
+                                PCI_DONT_CARE, PCI_DONT_CARE, 
+                                PCI_VENDOR_SOLARFLARE, DEVICE_ID,
+                                pci_bus, pci_device, pci_function, 
+                                interrupt_handler, NULL);
+
+    printf("SFN5122F register driver end \n");
+    while (!initialized) {
+        event_dispatch(get_default_waitset());
+    }
+    /* loop myself */
+    qd_main();
+}
diff --git a/usr/drivers/solarflare/sfn5122f_debug.h b/usr/drivers/solarflare/sfn5122f_debug.h
new file mode 100644 (file)
index 0000000..7b5dc0e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * \file
+ * \brief Solarflare sfn5122f debug function
+ *
+ *
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef SFN5122F_DEBUG_H_
+#define SFN5122F_DEBUG_H_
+
+//#define DEBUG_SFN
+
+#ifdef DEBUG_SFN
+    #define DEBUG_QUEUE(x...) printf("sfn5122f_q : " x)
+#else
+    #define DEBUG_QUEUE(x...) do {} while (0)
+#endif
+
+#ifdef DEBUG_SFN
+    #define DEBUG(x...) printf("sfn5122f: " x)
+#else
+    #define DEBUG(x...) do {} while (0)
+#endif
+
+#endif /* SFN5122F_DEBUG_H_ */
diff --git a/usr/drivers/solarflare/sfn5122f_qdriver.c b/usr/drivers/solarflare/sfn5122f_qdriver.c
new file mode 100644 (file)
index 0000000..03ee301
--- /dev/null
@@ -0,0 +1,626 @@
+/* Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <net_queue_manager/net_queue_manager.h>
+#include <barrelfish/nameservice_client.h>
+#include <barrelfish/spawn_client.h>
+#include <barrelfish/debug.h>
+#include <barrelfish/deferred.h>
+#include <pci/pci.h>
+
+
+#include <if/sfn5122f_defs.h>
+#include <dev/sfn5122f_dev.h>
+#include <dev/sfn5122f_q_dev.h>
+
+#include "helper.h"
+#include "sfn5122f.h"
+#include "sfn5122f_queue.h"
+#include "sfn5122f_debug.h"
+#include "buffer_tbl.h"
+
+/******************************************************************************/
+/* Prototypes */
+
+static void idc_register_queue_memory(uint8_t queue,
+                                      struct capref tx_frame,
+                                      struct capref ev_frame,
+                                      struct capref rx_frame,
+                                      uint32_t rxbufsz,
+                                      uint8_t vector,
+                                      coreid_t core);
+
+static void idc_terminate_queue(void);
+
+void qd_queue_init_data(struct sfn5122f_binding *b, struct capref registers,
+        uint64_t macaddr, struct capref mac_stat);
+void qd_queue_memory_registered(struct sfn5122f_binding *b);
+void qd_write_queue_tails(struct sfn5122f_binding *b);
+
+void qd_argument(const char *arg);
+void qd_main(void);
+int main(int argc, char **argv) __attribute__((weak));
+
+/* Global state */
+static const char* service_name = "sfn5122f";
+
+/** Binding to the internal sfn5122f management service */
+static struct sfn5122f_binding *binding = NULL;
+
+/** Queue index for this manager instance */
+static int qi = -1;
+
+/** Mackerel handle for device */
+static sfn5122f_t *d = NULL;
+
+/** Queue handle for queue management library */
+static sfn5122f_queue_t *q;
+
+/** MAC address to be used */
+static uint64_t mac_address = 0;
+
+/** Indicates if the initialization is done */
+static int initialized = 0;
+
+/**
+ * Indicates whether we should rely on cache coherence for the descriptor
+ * rings.
+ */
+static bool cache_coherence = true;
+
+/** Indicates whether Interrupts should be used */
+static bool use_interrupts = false;
+static bool use_msix = false;
+static coreid_t core = 0;
+static uint8_t vector = 0;
+
+/** Capability for hardware TX ring */
+static struct capref tx_frame;
+
+/** Capability for hardware RX ring */
+static struct capref rx_frame;
+
+/** Capability for hardware EV ring */
+static struct capref ev_frame;
+
+/** Capability for MAC statistics */
+static struct capref mac_stats;
+//static void* mac_virt;
+uint64_t mac_stats_array[NUM_MAC_STATS];
+
+/**  Userspace networking enable  */
+static bool userspace = 0;
+
+/******************************************************************************/
+/* Transmit path */
+static uint64_t find_tx_free_slot_count_fn(void)
+{
+    return sfn5122f_queue_free_txslots(q);
+}
+
+static errval_t transmit_pbuf_list_fn(struct driver_buffer *buffers,
+                                      size_t                count)
+{
+    size_t i;
+    
+    if (find_tx_free_slot_count_fn() < count) {
+        return ETHERSRV_ERR_CANT_TRANSMIT;
+    }
+
+    for (i = 0; i < count; i++) {
+        sfn5122f_queue_add_txbuf(q, buffers[i].pa,
+                                 buffers[i].len, buffers[i].opaque, 
+                                 (i == count - 1)); 
+    }
+
+    sfn5122f_queue_bump_txtail(q);
+
+    return SYS_ERR_OK;
+}
+
+static bool handle_free_tx_slot_fn(void)
+{
+    return false;
+}
+
+
+
+/******************************************************************************/
+/* Receive path */
+
+static uint64_t find_rx_free_slot_count_fn(void)
+{
+   return sfn5122f_queue_free_rxslots(q);
+}
+
+static errval_t register_rx_buffer_fn(uint64_t paddr, void *vaddr, void *opaque)
+{
+    if (find_rx_free_slot_count_fn() == 0) {
+        printf("SFN5122F_%d: Not enough space in RX ring, not adding buffer\n", 
+                qi);
+        return ETHERSRV_ERR_TOO_MANY_BUFFERS;
+    }
+
+    sfn5122f_queue_add_rxbuf(q, paddr, opaque);
+    sfn5122f_queue_bump_rxtail(q);
+    
+    return SYS_ERR_OK;
+}
+
+
+/*  polling event queue for new events         */
+static size_t check_for_new_events(void)
+{
+    size_t len = 0;
+    size_t count = 0;
+    uint8_t ev_code;
+    // TODO add constant
+    struct driver_rx_buffer buf[16];
+
+    // need to block until initalized
+    if (!initialized) {
+        return 0;
+    }
+    ev_code = sfn5122f_get_event_code(q);
+    while (ev_code != 15 && count < 100){
+          void *op = NULL;
+          ev_code = sfn5122f_get_event_code(q);
+          switch(ev_code){
+   
+              case EV_CODE_RX:
+                   // TODO multiple packets
+                   if (sfn5122f_queue_handle_rx_ev(q, &op, &len) == SYS_ERR_OK) {
+                        buf[0].len = len;
+                        buf[0].opaque = op;
+                        process_received_packet(buf, 1, 0);
+                   } else {
+                        // TODO how to tell the the upper layer that it can reuse
+                        // the rx buffer
+                   }
+
+                   DEBUG_QUEUE(" RX_EV Q_ID: %d len %ld \n", qi, len);
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_TX:
+                   if (sfn5122f_queue_handle_tx_ev(q, &op) == SYS_ERR_OK) {
+                        DEBUG_QUEUE("TX EVENT OK %d \n", qi);
+                        handle_tx_done(op); 
+                   } else {
+                        DEBUG_QUEUE("TX EVENT ERR %d \n", qi);
+                   }
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_DRV:
+                   //DEBUG_QUEUE("DRIVER EVENT %d\n", qi);
+                   sfn5122f_handle_drv_ev(q, qi);
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_DRV_GEN:
+                   DEBUG_QUEUE("DRIVER GENERATED EVENT \n");
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_USER:
+                   DEBUG_QUEUE("USER EVENT \n");
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_MCDI:
+                   //DEBUG_QUEUE("MCDI EVENT \n");
+                   sfn5122f_queue_handle_mcdi_event(q);
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+              case EV_CODE_GLOBAL:
+                   DEBUG_QUEUE("GLOBAL EVENT \n");
+                   sfn5122f_queue_bump_evhead(q);
+                   break;
+          }
+          count++;
+    }
+    /* update event queue tail */
+    //if (count > 0) {
+        sfn5122f_evq_rptr_reg_wr(d, qi, q->ev_head);
+    //}
+
+    return count-1;
+}
+
+/**  Misc             */
+static errval_t update_rxtail(void *opaque, size_t tail)
+{
+    assert(d != NULL);
+    uint64_t reg = 0;
+
+    reg = sfn5122f_rx_desc_upd_reg_hi_rx_desc_wptr_insert(reg, tail);
+    /* don't want to push an additional rx descriptor with the write pointer */
+    reg = sfn5122f_rx_desc_upd_reg_hi_rx_desc_push_cmd_insert(reg, 0);
+    /* the lower register will be ignored   */
+    sfn5122f_rx_desc_upd_reg_lo_wr(d, qi, 0);
+    sfn5122f_rx_desc_upd_reg_hi_wr(d, qi, reg);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t update_txtail(void *opaque, size_t tail)
+{
+    assert(d != NULL);
+    uint64_t reg = 0;
+    reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_wptr_insert(reg, tail);
+    /* don't want to push an additional tx descriptor with the write pointer */
+    reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_push_cmd_insert(reg, 0);
+    reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_insert(reg, 0);
+
+    /*  the lower register will be ignored  */
+    sfn5122f_tx_desc_upd_reg_lo_wr(d, qi, 0);
+    sfn5122f_tx_desc_upd_reg_hi_wr(d, qi, reg);
+    return SYS_ERR_OK;
+}
+
+/** Callback to get card's MAC address */
+static void get_mac_address_fn(uint8_t* mac)
+{
+    memcpy(mac, &mac_address, 6);
+}
+/******************************************************************************/
+/* Interrupts */
+
+static void qd_interrupt(void)
+{
+    size_t count;
+    
+    count = check_for_new_events();
+    if (count <= 0) {
+        DEBUG_QUEUE("qd_int_%d: qid=%d no events \n", disp_get_core_id(), qi);
+    } else {
+        DEBUG_QUEUE("qd_int_%d: qid=%d events processed=%ld \n", disp_get_core_id(), 
+                    qi, count);
+    }
+
+}
+
+static void interrupt_handler(void *data)
+{
+    qd_interrupt();
+}
+
+/******************************************************************************/
+/* Device/queue initialization */
+
+/** Allocate queue n and return handle for queue manager */
+
+static void setup_queue(void)
+{
+    size_t tx_size, rx_size, ev_size;
+    void *tx_virt, *rx_virt, *ev_virt;
+    vregion_flags_t flags_vreg;
+    
+    struct sfn5122f_queue_ops ops = {
+        .update_txtail = update_txtail,
+        .update_rxtail = update_rxtail
+     };
+
+    // Decide on which flags to use for the mappings
+    flags_vreg = (cache_coherence ? VREGION_FLAGS_READ_WRITE :
+                               VREGION_FLAGS_READ_WRITE_NOCACHE);
+
+   
+    /* Allocate memory for descriptor rings  
+       No difference for userspace networking*/
+    tx_size = sfn5122f_q_tx_ker_desc_size * TX_ENTRIES;
+    tx_virt = alloc_map_frame(flags_vreg, tx_size, &tx_frame);
+
+    assert(tx_virt != NULL);
+
+    if (!userspace) {
+         rx_size = sfn5122f_q_rx_ker_desc_size * RX_ENTRIES;
+    } else {
+         rx_size = sfn5122f_q_rx_user_desc_size * RX_ENTRIES;
+    }
+
+    rx_virt = alloc_map_frame(flags_vreg, rx_size, &rx_frame);
+    assert(rx_virt != NULL);
+
+    ev_size = sfn5122f_q_event_entry_size * EV_ENTRIES;
+    ev_virt = alloc_map_frame(flags_vreg, ev_size, &ev_frame);
+    assert(ev_virt != NULL);
+
+    if (use_interrupts && use_msix) {
+        DEBUG_QUEUE("Enabling MSI-X interrupts\n");
+        errval_t err = pci_setup_inthandler(interrupt_handler, NULL, &vector);
+        assert(err_is_ok(err));
+        core = disp_get_core_id();
+    } else {
+        if (use_interrupts) {
+            DEBUG_QUEUE("Enabling legacy interrupts\n");
+        }
+        vector = 0;
+        core = 0;
+    }
+
+
+    // Initialize queue manager
+    q = sfn5122f_queue_init(tx_virt, TX_ENTRIES, rx_virt, RX_ENTRIES,
+                            ev_virt, EV_ENTRIES, &ops,  NULL, userspace);
+    idc_register_queue_memory(qi, tx_frame, rx_frame,
+                              ev_frame, MTU_MAX, vector, core);
+
+}
+
+/** Terminate this queue driver */
+static void terminate_queue_fn(void)
+{
+    idc_terminate_queue();
+}
+
+/******************************************************************************/
+/* Management interface implemetation */
+
+/** Request device register cap from card driver */
+
+static void idc_request_device_info(void)
+{
+
+    errval_t r;
+    DEBUG_QUEUE("idc_request_device_info()\n");
+
+    r = sfn5122f_request_device_info__tx(binding, NOP_CONT);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+/** Send memory caps to card driver */
+static void idc_register_queue_memory(uint8_t queue,
+                                      struct capref tx,
+                                      struct capref rx,
+                                      struct capref ev,
+                                      uint32_t rxbufsz,
+                                      uint8_t vec,
+                                      coreid_t cid)
+{
+
+    errval_t r;
+    DEBUG_QUEUE("idc_register_queue_memory()\n");
+
+    r = sfn5122f_register_queue_memory__tx(binding, NOP_CONT, queue,
+                                           tx, rx, ev, rxbufsz, 
+                                           use_interrupts, userspace,
+                                           vec, cid);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+// Callback from device manager
+void qd_queue_init_data(struct sfn5122f_binding *b, struct capref registers,
+                        uint64_t macaddr, struct capref mac_stat)
+{
+    struct frame_identity frameid = { .base = 0, .bytes = 0 };
+    errval_t err;
+    void *virt;
+
+    DEBUG_QUEUE("idc_queue_init_data\n");
+
+    mac_address = macaddr;
+    mac_stats = mac_stat;
+
+    // Map device registers
+    invoke_frame_identify(registers, &frameid);
+    err = vspace_map_one_frame_attr(&virt, frameid.bytes, registers,
+            VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL);
+
+    assert(err_is_ok(err));
+
+    // Initialize mackerel device
+    d = malloc(sizeof(*d));
+    sfn5122f_initialize(d, virt);
+    // Initialize queue
+    setup_queue();
+}
+
+/** Tell card driver to stop this queue. */
+static void idc_terminate_queue(void)
+{
+    errval_t r;
+    DEBUG_QUEUE("idc_terminate_queue()\n");
+
+    r = sfn5122f_terminate_queue__tx(binding, NOP_CONT, qi);
+    // TODO: handle busy
+    assert(err_is_ok(r));
+}
+
+// Callback from device manager
+void qd_queue_memory_registered(struct sfn5122f_binding *b)
+{
+    initialized = 1;
+    // Register queue with queue_mgr library
+    DEBUG_QUEUE("Called ethersrv_init() \n");
+    ethersrv_init((char*) service_name, qi, 
+                  get_mac_address_fn, 
+                  terminate_queue_fn,
+                  transmit_pbuf_list_fn, 
+                  find_tx_free_slot_count_fn,
+                  handle_free_tx_slot_fn, 
+                  MTU_MAX, 
+                  register_rx_buffer_fn,
+                  find_rx_free_slot_count_fn);
+}
+
+// Callback from device manager
+void qd_write_queue_tails(struct sfn5122f_binding *b)
+{
+    DEBUG_QUEUE("idc_write_queue_tails()\n");
+
+    sfn5122f_queue_bump_rxtail(q);
+    sfn5122f_queue_bump_txtail(q);
+}
+
+
+// Callback from device manager
+static void idc_queue_terminated(struct sfn5122f_binding *b)
+{
+    errval_t err;
+
+    DEBUG_QUEUE("idc_queue_terminated()\n");
+
+    // Free memory for hardware ring buffers
+    if (q->userspace) {
+        err = vspace_unmap(q->tx_ring.user);
+        assert(err_is_ok(err));
+        err = vspace_unmap(q->rx_ring.user);
+        assert(err_is_ok(err));
+    } else {
+        err = vspace_unmap(q->tx_ring.ker);
+        assert(err_is_ok(err));
+        err = vspace_unmap(q->rx_ring.ker);
+        assert(err_is_ok(err));
+    }
+
+    err = vspace_unmap(q->ev_ring);
+    assert(err_is_ok(err));
+    err = cap_delete(tx_frame);
+    assert(err_is_ok(err));
+    err = cap_delete(rx_frame);
+    assert(err_is_ok(err));
+    err = cap_delete(ev_frame);
+    assert(err_is_ok(err));
+
+    exit(0);
+}
+
+static struct sfn5122f_rx_vtbl rx_vtbl = {
+    .queue_init_data = qd_queue_init_data,
+    .queue_memory_registered = qd_queue_memory_registered,
+    .write_queue_tails = qd_write_queue_tails,
+    .queue_terminated = idc_queue_terminated,
+};
+
+static void bind_cb(void *st, errval_t err, struct sfn5122f_binding *b)
+{
+    assert(err_is_ok(err));
+
+    DEBUG_QUEUE("Sucessfully connected to management interface\n");
+
+    b->rx_vtbl = rx_vtbl;
+    binding = b;
+
+    idc_request_device_info();
+}
+
+/** Connect to the management interface */
+static void connect_to_mngif(void)
+{
+    errval_t r;
+    iref_t iref;
+    const char *suffix = "_sfn5122fmng";
+    char name[strlen(service_name) + strlen(suffix) + 1];
+
+    // Build label for interal management service
+    sprintf(name, "%s%s", service_name, suffix);
+
+    // Connect to service
+    DEBUG_QUEUE("Looking up management interface (%s)\n", name);
+    r = nameservice_blocking_lookup(name, &iref);
+    assert(err_is_ok(r));
+
+    DEBUG_QUEUE("Binding to management interface\n");
+    r = sfn5122f_bind(iref, bind_cb, NULL, get_default_waitset(),
+            IDC_BIND_FLAGS_DEFAULT);
+    assert(err_is_ok(r));
+}
+
+void qd_argument(const char *arg)
+{
+    if (strncmp(arg, "cardname=", strlen("cardname=") - 1) == 0) {
+        service_name = arg + strlen("cardname=");
+        ethersrv_argument(arg);
+
+    } else if (strncmp(arg, "queue=", strlen("queue=") - 1) == 0) {
+        qi = atol(arg + strlen("queue="));
+        ethersrv_argument(arg);
+
+    } else if (strncmp(arg, "cache_coherence=", 
+                       strlen("cache_coherence=") - 1) == 0) {
+        cache_coherence = !!atol(arg + strlen("cache_coherence="));
+
+    } else if (strncmp(arg, "interrupts=", strlen("interrupts=") - 1) == 0) {
+        use_interrupts = !!atol(arg + strlen("interrupts="));
+        DEBUG_QUEUE("Interrupts enabled: legacy interrupts for fatal device errors\n");
+    } else if (strncmp(arg, "msix=", strlen("msix=") - 1) == 0) {
+        USER_PANIC("MSI-X not fully implemented yet!");
+        use_msix = !!atol(arg + strlen("msix="));
+        DEBUG_QUEUE("Using msix \n");
+    } else if (strncmp(arg, "userspace=", strlen("userspace=") - 1) == 0) {
+       USER_PANIC("Userspace networking for SFN5122F not implemented!");
+       /*
+        userspace = atol(arg + strlen("userspace="));
+        ethersrv_argument(arg);
+       */
+    } else {
+        ethersrv_argument(arg);
+    }
+}
+
+static void parse_cmdline(int argc, char **argv)
+{
+    int i;
+    for (i = 1; i < argc; i++) {
+        qd_argument(argv[i]);
+    }
+}
+
+static void eventloop(void)
+{
+    struct waitset *ws;
+    errval_t err;
+
+    DEBUG_QUEUE("eventloop()\n");
+
+    ws = get_default_waitset();
+    while (1) {
+        err = event_dispatch_non_block(ws);
+        do_pending_work_for_all();
+        check_for_new_events();
+    }
+}
+
+static void eventloop_ints(void)
+{
+    struct waitset *ws;
+    DEBUG_QUEUE("eventloop_ints()\n");
+
+    ws = get_default_waitset();
+    while (1) {
+        event_dispatch(ws);
+        do_pending_work_for_all();
+    }
+}
+
+void qd_main(void)
+{
+    // Validate some settings
+    if (qi == -1) {
+        USER_PANIC("For queue driver the queue= parameter has to be specified "
+                   "on the command line!");
+    }
+
+    connect_to_mngif();
+    if (use_interrupts) {
+        eventloop_ints();
+    } else {
+        eventloop();
+    }
+}
+
+int main(int argc, char **argv)
+{
+    DEBUG_QUEUE("Started\n");
+    parse_cmdline(argc, argv);
+    qd_main();
+}
diff --git a/usr/drivers/solarflare/sfn5122f_queue.h b/usr/drivers/solarflare/sfn5122f_queue.h
new file mode 100644 (file)
index 0000000..5d46916
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ *Copyright (c) 2007-2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef SFN5122F_CHANNEL_H_
+#define SFN5122F_CHANNEL_H_
+
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <dev/sfn5122f_q_dev.h>
+#include "helper.h"
+
+#define MTU_MAX 2048
+
+struct sfn5122f_queue_ops {
+    errval_t (*update_txtail)(void*, size_t);
+    errval_t (*update_rxtail)(void*, size_t);
+};
+
+struct sfn5122f_queue {
+
+    
+    union {
+        sfn5122f_q_tx_user_desc_array_t* user;
+        sfn5122f_q_tx_ker_desc_array_t* ker;
+    } tx_ring;
+    void**                          tx_opaque;
+    uint16_t                        tx_head;
+    uint16_t                        tx_tail;
+    size_t                          tx_size;
+
+    union {
+        sfn5122f_q_rx_user_desc_array_t* user;
+        sfn5122f_q_rx_ker_desc_array_t* ker;
+    } rx_ring;
+    void**                          rx_opaque;
+    uint16_t                        rx_head;
+    uint16_t                        rx_tail;
+    uint16_t                        rx_size;
+
+    sfn5122f_q_event_entry_array_t* ev_ring;
+    void**                          ev_opaque;
+    uint32_t                        ev_head;
+    uint32_t                        ev_tail;
+    size_t                          ev_size;
+
+    struct sfn5122f_queue_ops       ops;
+    void*                           opaque;
+    bool                            userspace;
+};
+
+typedef struct sfn5122f_queue sfn5122f_queue_t;
+
+static inline sfn5122f_queue_t* sfn5122f_queue_init(void* tx, 
+                                                    size_t tx_size,
+                                                    void* rx, 
+                                                    size_t rx_size, 
+                                                    void* ev, 
+                                                    size_t ev_size,
+                                                    struct sfn5122f_queue_ops* ops, 
+                                                    void* opaque, bool userspace)
+{
+
+    sfn5122f_queue_t* q = malloc(sizeof(*q));
+
+    if (userspace) {
+        q->tx_ring.user = tx;
+    } else {
+        q->tx_ring.ker = tx;
+    }
+    q->tx_opaque = malloc(sizeof(void*) * tx_size);
+    q->tx_head = 0;
+    q->tx_tail = 0;
+    q->tx_size = tx_size;
+
+    if (userspace) {
+        q->rx_ring.user = rx;
+    } else {
+        q->rx_ring.ker = rx;
+    }
+    q->rx_opaque = malloc(sizeof(void*) * rx_size);
+    q->rx_head = 0;
+    q->rx_tail = 0;
+    q->rx_size = rx_size;
+  
+    q->ev_ring = ev;
+    q->ev_head = 0;
+    q->ev_tail = 0;
+    q->ev_size = ev_size;
+    q->userspace = userspace; 
+
+    q -> ops = *ops;
+    if(!userspace) {
+        q->opaque = opaque;
+    }
+
+    // Initialize ring memory with 0xff
+    if(!userspace){
+       memset(tx, 0xff, tx_size * sfn5122f_q_tx_ker_desc_size);
+       memset(rx, 0xff, rx_size * sfn5122f_q_rx_ker_desc_size);
+    }else{
+       memset(tx, 0xff, tx_size * sfn5122f_q_tx_user_desc_size);
+       memset(rx, 0xff, rx_size * sfn5122f_q_rx_user_desc_size);
+    }
+    /* all 0 is potential valid event */
+    memset(ev, 0xff, ev_size * sfn5122f_q_event_entry_size);
+    return q;
+}
+
+static inline uint8_t sfn5122f_get_event_code(sfn5122f_queue_t* queue)
+{             
+       sfn5122f_q_event_entry_t ev;
+       ev = queue->ev_ring[queue->ev_head];
+       return sfn5122f_q_event_entry_ev_code_extract(ev);
+}
+
+
+static inline errval_t sfn5122f_queue_bump_txtail(sfn5122f_queue_t* q)
+{
+    return q->ops.update_txtail(q->opaque, q->tx_tail);
+}
+
+
+static inline errval_t sfn5122f_queue_bump_rxtail(sfn5122f_queue_t* q)
+{
+    return q->ops.update_rxtail(q->opaque, q->rx_tail);
+}
+
+
+static inline errval_t sfn5122f_handle_drv_ev(sfn5122f_queue_t* q, uint16_t n)
+{   
+    size_t ev_head = q->ev_head;
+
+    sfn5122f_q_event_entry_t code;
+    code = q->ev_ring[ev_head]; 
+
+    if (sfn5122f_q_driver_ev_driver_ev_subcode_extract(code) == 2) {
+        printf("Event queue init done %d \n", n);
+    }
+
+    if (sfn5122f_q_driver_ev_driver_ev_subcode_extract(code) == 9) {
+        printf("Packet neither TCP nor UPD %d \n", n);
+    }
+    
+    if (sfn5122f_q_driver_ev_driver_ev_subcode_extract(code) == 14) {
+        printf("RX error %d \n", n);
+        return SFN_ERR_RX_PKT;
+    }
+
+    if (sfn5122f_q_driver_ev_driver_ev_subcode_extract(code) == 15) {
+        printf("TX error %d \n", n);
+        return SFN_ERR_TX_PKT;
+    }
+
+    memset(code, 0xff, sfn5122f_q_event_entry_size);
+    return SYS_ERR_OK;
+
+}
+
+
+
+static inline errval_t sfn5122f_queue_handle_mcdi_event(sfn5122f_queue_t* q)
+{
+    // TODO handle different events    
+    size_t ev_head = q->ev_head;
+    sfn5122f_q_event_entry_t ev;
+    uint64_t reg;
+    ev = q->ev_ring[ev_head]; 
+    reg = sfn5122f_q_event_entry_ev_data_extract(ev);
+    memset(ev, 0xff, sfn5122f_q_event_entry_size);
+
+    return SYS_ERR_OK;
+
+}
+
+/*    RX      */
+static inline int sfn5122f_queue_add_rxbuf(sfn5122f_queue_t* q, 
+                                           uint64_t phys,
+                                           void* opaque)
+{
+    sfn5122f_q_rx_ker_desc_t d;
+    size_t tail = q->rx_tail;
+
+    q->rx_opaque[tail] = opaque;
+    d = q->rx_ring.ker[tail];
+
+    sfn5122f_q_rx_ker_desc_rx_ker_buf_addr_insert(d, phys);
+    sfn5122f_q_rx_ker_desc_rx_ker_buf_region_insert(d, 0);
+    // TODO: Check size
+    sfn5122f_q_rx_ker_desc_rx_ker_buf_size_insert(d, MTU_MAX);
+    q->rx_tail = (tail + 1) % q->rx_size;
+    return 0;
+}
+
+static inline int sfn5122f_queue_add_user_rxbuf(sfn5122f_queue_t* q, 
+                                                uint32_t buf_id,
+                                                uint16_t offset)
+{
+    sfn5122f_q_rx_user_desc_t d;
+    size_t tail = q->rx_tail;
+
+    d = q->rx_ring.user[tail];
+
+    sfn5122f_q_rx_user_desc_rx_user_buf_id_insert(d, buf_id);
+    sfn5122f_q_rx_user_desc_rx_user_2byte_offset_insert(d, offset);
+    q->rx_tail = (tail + 1) % q->rx_size;
+    return 0;
+}
+
+static inline errval_t sfn5122f_queue_handle_rx_ev(sfn5122f_queue_t* q, 
+                                                   void** opaque, 
+                                                   size_t* len)
+{   
+    /*  Only one event is generated even if there is more than one
+        descriptor per packet  */
+    size_t ev_head = q->ev_head;
+    size_t rx_head;
+    sfn5122f_q_rx_ev_t ev;
+    sfn5122f_q_rx_ker_desc_t d = 0;
+    sfn5122f_q_rx_user_desc_t d_user = 0;
+
+    ev = q->ev_ring[ev_head];
+
+    if(!sfn5122f_q_rx_ev_rx_ev_pkt_ok_extract(ev)) {   
+         // TODO error handling
+         if (sfn5122f_q_rx_ev_rx_ev_tobe_disc_extract(ev)) {
+            // packet discared by softare -> ok
+            return SFN_ERR_RX_DISCARD;
+         }
+
+         printf("Packet not ok \n");
+         return SFN_ERR_RX_PKT;
+    }
+
+    *len = sfn5122f_q_rx_ev_rx_ev_byte_ctn_extract(ev);
+    /* Length of 0 is treated as 16384 bytes */
+    if (*len == 0) {
+        *len = 16384;
+    }
+
+    rx_head = sfn5122f_q_rx_ev_rx_ev_desc_ptr_extract(ev);
+    if (q->userspace) {
+        d_user = q->rx_ring.user[rx_head];  
+    } else {
+        d = q->rx_ring.ker[rx_head];
+    }
+
+    *opaque = q->rx_opaque[rx_head]; 
+
+    memset(ev, 0xff, sfn5122f_q_event_entry_size);
+    if (q->userspace) {
+        memset(d_user, 0 , sfn5122f_q_rx_user_desc_size);
+    } else {
+        memset(d, 0 , sfn5122f_q_rx_ker_desc_size);
+    }
+
+    q->rx_head = (rx_head + 1) % q->rx_size;
+    return SYS_ERR_OK;
+
+}
+
+
+static inline void sfn5122f_queue_bump_evhead(sfn5122f_queue_t* q)
+{     
+     q->ev_head = (q->ev_head +1) % q->ev_size;
+}
+
+static inline size_t sfn5122f_queue_free_rxslots(sfn5122f_queue_t* q)
+{
+    size_t head = q->rx_head;
+    size_t tail = q->rx_tail;
+    size_t size = q->rx_size;
+
+    if (tail >= head) {
+        return size - (tail - head) -1; 
+    } else {
+        return size - (tail + size - head) -1; 
+    }
+}
+
+
+/*   TX       */
+static inline size_t sfn5122f_queue_free_txslots(sfn5122f_queue_t* q)
+{
+    size_t head = q->tx_head;
+    size_t tail = q->tx_tail;
+    size_t size = q->tx_size;
+
+    if (tail >= head) {
+        return size - (tail - head) - 1; 
+    } else {
+        return size - (tail + size - head) - 1; 
+    }
+
+}
+
+
+static inline errval_t sfn5122f_queue_handle_tx_ev(sfn5122f_queue_t* q, void** opaque)
+{   
+    /*  Only one event is generated even if there is more than one
+        descriptor per packet  */
+    size_t ev_head = q->ev_head;
+    size_t tx_head;
+    sfn5122f_q_tx_ev_t ev;
+    sfn5122f_q_tx_ker_desc_t d = 0;
+    sfn5122f_q_tx_user_desc_t d_user= 0;
+    
+    ev = q->ev_ring[ev_head];
+    if(sfn5122f_q_tx_ev_tx_ev_pkt_err_extract(ev)){     
+           //TODO error handling
+           return SFN_ERR_TX_PKT;
+    }
+
+    if (sfn5122f_q_tx_ev_tx_ev_comp_extract(ev) == 1){  
+        tx_head = sfn5122f_q_tx_ev_tx_ev_desc_ptr_extract(ev);
+        if (q->userspace) {
+            d_user = q->tx_ring.user[tx_head];  
+        } else {
+            d = q->tx_ring.ker[tx_head];  
+        }
+
+        *opaque = q->tx_opaque[tx_head]; 
+
+        // reset entry event in queue
+        memset(ev, 0xff, sfn5122f_q_event_entry_size);
+        if (q->userspace) {
+            memset(d_user, 0 , sfn5122f_q_tx_user_desc_size);
+        } else {
+           memset(d, 0 , sfn5122f_q_tx_ker_desc_size);
+        }
+        q->tx_head = (tx_head +1) % q->tx_size;
+    }
+
+    return SYS_ERR_OK;
+}
+static inline int sfn5122f_queue_add_txbuf(sfn5122f_queue_t* q, 
+                                           uint64_t phys,
+                                           size_t len, 
+                                           void* opaque, 
+                                           int last)
+{
+    sfn5122f_q_tx_ker_desc_t d;
+    size_t tail = q->tx_tail;
+
+    q->tx_opaque[tail] = opaque;
+    d = q->tx_ring.ker[tail];
+   
+    sfn5122f_q_tx_ker_desc_tx_ker_buf_addr_insert(d, phys);
+    sfn5122f_q_tx_ker_desc_tx_ker_byte_count_insert(d, len);
+    sfn5122f_q_tx_ker_desc_tx_ker_cont_insert(d, !(last == 1));
+    sfn5122f_q_tx_ker_desc_tx_ker_buf_region_insert(d, 0);
+
+    __sync_synchronize();
+    q->tx_tail = (tail + 1) % q->tx_size;
+    return 0;
+}
+
+#endif //ndef SFN5122F_CHANNEL_H_
+
index 838ce3f..80b9e83 100644 (file)
@@ -57,6 +57,18 @@ pci_driver{
     platforms: ['x86_64', 'x86_32']
 }.
 
+
+pci_driver{
+    binary: "sfn5122f",
+    supported_cards:
+    [ pci_card{ vendor: 16'1924, device: 16'0803, function: _, subvendor: _, subdevice: _ }],
+    core_hint: 0,
+    core_offset: 0,
+    multi_instance: 0,
+    interrupt_load: 0.5,
+    platforms: ['x86_64']
+}.
+
 pci_driver{
     binary: "rtl8029",
     supported_cards: