Example #1
0
SET_FIELD(SIOCSIFFLAGS, siocsifflags_c, ifr.ifr_flags = Int_val(caml_val))
SET_FIELD(SIOCSIFPFLAGS, siocsifpflags_c, ifr.ifr_flags = Int_val(caml_val))
SET_FIELD(SIOCSIFMTU, siocsifmtu_c, ifr.ifr_mtu = Int_val(caml_val))
SET_FIELD(SIOCSIFTXQLEN, siocsiftxqlen_c, ifr.ifr_qlen = Int_val(caml_val))

SET_FIELD(SIOCSIFNAME, siocsifname_c, copyifname(ifr.ifr_newname, String_val(caml_val)))

static void
set_hwaddr(struct sockaddr *sa, value hwaddr)
{
  /* quick and dirty checks */
  if (caml_string_length(hwaddr) != ETHERNET_MAC_LEN) caml_failwith("Expected 6 byte ethernet MAC");
  memcpy(sa->sa_data, String_val(hwaddr), ETHERNET_MAC_LEN);
  return;
}

SET_FIELD(SIOCSIFHWADDR, siocsifhwaddr_c, set_hwaddr(&ifr.ifr_hwaddr, caml_val))

static void
set_ipaddr(struct sockaddr *sa, value ipaddr)
{
  struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  sin->sin_family = AF_INET;
  sin->sin_addr.s_addr = Int32_val(ipaddr);
  return;
}

SET_FIELD(SIOCSIFADDR, siocsifaddr_c, set_ipaddr(&ifr.ifr_addr, caml_val))
SET_FIELD(SIOCSIFBRDADDR, siocsifbrdaddr_c, set_ipaddr(&ifr.ifr_broadaddr, caml_val))
SET_FIELD(SIOCSIFNETMASK, siocsifnetmask_c, set_ipaddr(&ifr.ifr_netmask, caml_val))
Example #2
0
vmxnet3::vmxnet3(hw::PCI_Device& d, const uint16_t mtu) :
    Link(Link_protocol{{this, &vmxnet3::transmit}, mac()}, bufstore_),
    m_pcidev(d), m_mtu(mtu), bufstore_{1024, buffer_size_for_mtu(mtu)}
{
  INFO("vmxnet3", "Driver initializing (rev=%#x)", d.rev_id());
  assert(d.rev_id() == REVISION_ID);

  // find and store capabilities
  d.parse_capabilities();
  // find BARs etc.
  d.probe_resources();

  if (d.msix_cap())
  {
    d.init_msix();
    uint8_t msix_vectors = d.get_msix_vectors();
    INFO2("[x] Device has %u MSI-X vectors", msix_vectors);
    assert(msix_vectors >= 3);
    if (msix_vectors > 2 + NUM_RX_QUEUES) msix_vectors = 2 + NUM_RX_QUEUES;

    for (int i = 0; i < msix_vectors; i++)
    {
      auto irq = Events::get().subscribe(nullptr);
      this->irqs.push_back(irq);
      d.setup_msix_vector(SMP::cpu_id(), IRQ_BASE + irq);
    }

    Events::get().subscribe(irqs[0], {this, &vmxnet3::msix_evt_handler});
    Events::get().subscribe(irqs[1], {this, &vmxnet3::msix_xmit_handler});
    for (int q = 0; q < NUM_RX_QUEUES; q++)
    Events::get().subscribe(irqs[2 + q], {this, &vmxnet3::msix_recv_handler});
  }
  else {
    assert(0 && "This driver does not support legacy IRQs");
  }

  // dma areas
  this->iobase = d.get_bar(PCI_BAR_VD);
  assert(this->iobase);
  this->ptbase = d.get_bar(PCI_BAR_PT);
  assert(this->ptbase);

  // verify and select version
  bool ok = check_version();
  assert(ok);

  // reset device
  ok = reset();
  assert(ok);

  // get mac address
  retrieve_hwaddr();

  // check link status
  auto link_spd = check_link();
  if (link_spd) {
    INFO2("Link up at %u Mbps", link_spd);
  }
  else {
    INFO2("LINK DOWN! :(");
    return;
  }

  // set MAC
  set_hwaddr(this->hw_addr);

  // initialize DMA areas
  this->dma = (vmxnet3_dma*) memalign(VMXNET3_DMA_ALIGN, sizeof(vmxnet3_dma));
  memset(this->dma, 0, sizeof(vmxnet3_dma));

  auto& queues = dma->queues;
  // setup tx queues
  queues.tx.cfg.desc_address = (uintptr_t) &dma->tx_desc;
  queues.tx.cfg.comp_address = (uintptr_t) &dma->tx_comp;
  queues.tx.cfg.num_desc     = vmxnet3::NUM_TX_DESC;
  queues.tx.cfg.num_comp     = VMXNET3_NUM_TX_COMP;
  queues.tx.cfg.intr_index   = 1;
  // temp rxq buffer storage
  memset(tx.buffers, 0, sizeof(tx.buffers));

  // setup rx queues
  for (int q = 0; q < NUM_RX_QUEUES; q++)
  {
    memset(rx[q].buffers, 0, sizeof(rx[q].buffers));
    rx[q].desc0 = &dma->rx0_desc[0];
    rx[q].desc1 = &dma->rx1_desc[0];
    rx[q].comp  = &dma->rx_comp[0];
    rx[q].index = q;

    auto& queue = queues.rx[q];
    queue.cfg.desc_address[0] = (uintptr_t) rx[q].desc0;
    queue.cfg.desc_address[1] = (uintptr_t) rx[q].desc1;
    queue.cfg.comp_address    = (uintptr_t) rx[q].comp;
    queue.cfg.num_desc[0]  = vmxnet3::NUM_RX_DESC;
    queue.cfg.num_desc[1]  = vmxnet3::NUM_RX_DESC;
    queue.cfg.num_comp     = VMXNET3_NUM_RX_COMP;
    queue.cfg.driver_data_len = sizeof(vmxnet3_rx_desc)
                          + 2 * sizeof(vmxnet3_rx_desc);
    queue.cfg.intr_index = 2 + q;
  }

  auto& shared = dma->shared;
  // setup shared physical area
  shared.magic = VMXNET3_REV1_MAGIC;
  shared.misc.guest_info.arch =
      (sizeof(void*) == 4) ? GOS_BITS_32_BITS : GOS_BITS_64_BITS;
  shared.misc.guest_info.type = GOS_TYPE_LINUX;
  shared.misc.version         = VMXNET3_VERSION_MAGIC;
  shared.misc.version_support     = 1;
  shared.misc.upt_version_support = 1;
  shared.misc.upt_features        = UPT1_F_RXVLAN;
  shared.misc.driver_data_address = (uintptr_t) &dma;
  shared.misc.queue_desc_address  = (uintptr_t) &dma->queues;
  shared.misc.driver_data_len     = sizeof(vmxnet3_dma);
  shared.misc.queue_desc_len      = sizeof(vmxnet3_queues);
  shared.misc.mtu = packet_len(); // 60-9000
  shared.misc.num_tx_queues  = 1;
  shared.misc.num_rx_queues  = NUM_RX_QUEUES;
  shared.interrupt.mask_mode = VMXNET3_IT_AUTO | (VMXNET3_IMM_AUTO << 2);
  shared.interrupt.num_intrs = 2 + NUM_RX_QUEUES;
  shared.interrupt.event_intr_index = 0;
  memset(shared.interrupt.moderation_level, UPT1_IML_ADAPTIVE, VMXNET3_MAX_INTRS);
  shared.interrupt.control   = 0x1; // disable all
  shared.rx_filter.mode =
      VMXNET3_RXM_UCAST | VMXNET3_RXM_BCAST | VMXNET3_RXM_ALL_MULTI;

  // location of shared area to device
  uintptr_t shabus = (uintptr_t) &shared;
  mmio_write32(this->iobase + 0x10, shabus); // shared low
  mmio_write32(this->iobase + 0x18, 0x0);    // shared high

  // activate device
  int status = command(VMXNET3_CMD_ACTIVATE_DEV);
  if (status) {
    assert(0 && "Failed to activate device");
  }

  // initialize and fill RX queue...
  for (int q = 0; q < NUM_RX_QUEUES; q++)
  {
    refill(rx[q]);
  }

  // deferred transmit
  this->deferred_irq = Events::get().subscribe(handle_deferred);

  // enable interrupts
  enable_intr(0);
  enable_intr(1);
  for (int q = 0; q < NUM_RX_QUEUES; q++)
      enable_intr(2 + q);
}