目录

1 ixgbe_netdev_ops 类函数列表

2 接口 ixgbe_open()

2.1 发送环形队列描述符分配 ixgbe_setup_all_tx_resources

2.2 接收环形队列描述符分配 ixgbe_setup_all_rx_resources

2.3 网卡配置 ixgbe_configure()

2.3.1 网卡接收队列配置 ixgbe_configure_rx()

2.3.2 网卡发送队列配置 ixgbe_configure_tx()

2.4 注册中断 ixgbe_request_irq()

2.4.1 MSIX 硬中断请求 ixgbe_request_msix_irqs()


1 ixgbe_netdev_ops 类函数列表

static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{...netdev->netdev_ops = &ixgbe_netdev_ops;...
}   static const struct net_device_ops ixgbe_netdev_ops = {.ndo_open       = ixgbe_open,.ndo_stop     = ixgbe_close,.ndo_start_xmit      = ixgbe_xmit_frame,.ndo_select_queue   = ixgbe_select_queue,.ndo_set_rx_mode  = ixgbe_set_rx_mode,.ndo_validate_addr = eth_validate_addr,.ndo_set_mac_address   = ixgbe_set_mac,.ndo_change_mtu        = ixgbe_change_mtu,.ndo_tx_timeout     = ixgbe_tx_timeout,.ndo_set_tx_maxrate = ixgbe_tx_maxrate,.ndo_vlan_rx_add_vid    = ixgbe_vlan_rx_add_vid,.ndo_vlan_rx_kill_vid  = ixgbe_vlan_rx_kill_vid,.ndo_do_ioctl     = ixgbe_ioctl,.ndo_set_vf_mac      = ixgbe_ndo_set_vf_mac,.ndo_set_vf_vlan    = ixgbe_ndo_set_vf_vlan,.ndo_set_vf_rate   = ixgbe_ndo_set_vf_bw,.ndo_set_vf_spoofchk = ixgbe_ndo_set_vf_spoofchk,.ndo_set_vf_rss_query_en = ixgbe_ndo_set_vf_rss_query_en,.ndo_set_vf_trust    = ixgbe_ndo_set_vf_trust,.ndo_get_vf_config    = ixgbe_ndo_get_vf_config,.ndo_get_stats64 = ixgbe_get_stats64,.ndo_setup_tc      = __ixgbe_setup_tc,
#ifdef CONFIG_NET_POLL_CONTROLLER.ndo_poll_controller   = ixgbe_netpoll,
#endif
#ifdef IXGBE_FCOE.ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get,.ndo_fcoe_ddp_target = ixgbe_fcoe_ddp_target,.ndo_fcoe_ddp_done = ixgbe_fcoe_ddp_put,.ndo_fcoe_enable = ixgbe_fcoe_enable,.ndo_fcoe_disable = ixgbe_fcoe_disable,.ndo_fcoe_get_wwn = ixgbe_fcoe_get_wwn,.ndo_fcoe_get_hbainfo = ixgbe_fcoe_get_hbainfo,
#endif /* IXGBE_FCOE */.ndo_set_features = ixgbe_set_features,.ndo_fix_features = ixgbe_fix_features,.ndo_fdb_add     = ixgbe_ndo_fdb_add,.ndo_bridge_setlink    = ixgbe_ndo_bridge_setlink,.ndo_bridge_getlink = ixgbe_ndo_bridge_getlink,.ndo_dfwd_add_station   = ixgbe_fwd_add,.ndo_dfwd_del_station  = ixgbe_fwd_del,.ndo_udp_tunnel_add    = ixgbe_add_udp_tunnel_port,.ndo_udp_tunnel_del    = ixgbe_del_udp_tunnel_port,.ndo_features_check    = ixgbe_features_check,.ndo_xdp        = ixgbe_xdp,.ndo_xdp_xmit      = ixgbe_xdp_xmit,.ndo_xdp_flush        = ixgbe_xdp_flush,
};

2 接口 ixgbe_open()

/*** ixgbe_open - Called when a network interface is made active* @netdev: network interface device structure** Returns 0 on success, negative value on failure** The open entry point is called when a network interface is made* active by the system (IFF_UP).  At this point all resources needed* for transmit and receive operations are allocated, the interrupt* handler is registered with the OS, the watchdog timer is started,* and the stack is notified that the interface is ready.**/
int ixgbe_open(struct net_device *netdev)
{struct ixgbe_adapter *adapter = netdev_priv(netdev);struct ixgbe_hw *hw = &adapter->hw;int err, queues;/* disallow open during test */if (test_bit(__IXGBE_TESTING, &adapter->state))return -EBUSY;netif_carrier_off(netdev);/* allocate transmit descriptors */// 为adapter->tx_ring[i]分配1024个ixgbe_tx_buffer,地址赋给adapter->tx_ring[i].tx_buffer_info  err = ixgbe_setup_all_tx_resources(adapter);if (err)goto err_setup_tx;/* allocate receive descriptors */// 为adapter->rx_ring[i]分配1024个ixgbe_rx_buffer,地址赋给adapter->rx_ring[i].rx_buffer_info  err = ixgbe_setup_all_rx_resources(adapter);if (err)goto err_setup_rx;ixgbe_configure(adapter);// 配置网卡err = ixgbe_request_irq(adapter);// 注册中断if (err)goto err_req_irq;/* Notify the stack of the actual queue counts. */if (adapter->num_rx_pools > 1)queues = adapter->num_rx_queues_per_pool;elsequeues = adapter->num_tx_queues;err = netif_set_real_num_tx_queues(netdev, queues);if (err)goto err_set_queues;if (adapter->num_rx_pools > 1 &&adapter->num_rx_queues > IXGBE_MAX_L2A_QUEUES)queues = IXGBE_MAX_L2A_QUEUES;elsequeues = adapter->num_rx_queues;err = netif_set_real_num_rx_queues(netdev, queues);if (err)goto err_set_queues;ixgbe_ptp_init(adapter);/* ixgbe_up_complete() -> ixgbe_configure_msix() -> ixgbe_set_ivar()ixgbe_napi_enable_all() -> napi_enable()ixgbe_irq_enable() -> ixgbe_irq_enable_queues()netif_tx_start_all_queues() -> netif_tx_start_queue()设置网卡寄存器IVAR清除napi->state的NAPI_STATE_SCHED标志打开中断清除所有发送队列的__QUEUE_STATE_XOFF标志 */ixgbe_up_complete(adapter);ixgbe_clear_udp_tunnel_port(adapter, IXGBE_VXLANCTRL_ALL_UDPPORT_MASK);udp_tunnel_get_rx_info(netdev);return 0;err_set_queues:ixgbe_free_irq(adapter);
err_req_irq:ixgbe_free_all_rx_resources(adapter);if (hw->phy.ops.set_phy_power && !adapter->wol)hw->phy.ops.set_phy_power(&adapter->hw, false);
err_setup_rx:ixgbe_free_all_tx_resources(adapter);
err_setup_tx:ixgbe_reset(adapter);return err;
}

2.1 发送环形队列描述符分配 ixgbe_setup_all_tx_resources

/*** ixgbe_setup_all_tx_resources - allocate all queues Tx resources* @adapter: board private structure** If this function returns with an error, then it's possible one or* more of the rings is populated (while the rest are not).  It is the* callers duty to clean those orphaned rings.** Return 0 on success, negative on failure**/
static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
{int i, j = 0, err = 0;for (i = 0; i < adapter->num_tx_queues; i++) {err = ixgbe_setup_tx_resources(adapter->tx_ring[i]); //遍历每个tx_ringif (!err)continue;e_err(probe, "Allocation for Tx Queue %u failed\n", i);goto err_setup_tx;}for (j = 0; j < adapter->num_xdp_queues; j++) {err = ixgbe_setup_tx_resources(adapter->xdp_ring[j]);// 遍历每个xdp_ringif (!err)continue;e_err(probe, "Allocation for Tx Queue %u failed\n", j);goto err_setup_tx;}return 0;
err_setup_tx:/* rewind the index freeing the rings as we go */while (j--)ixgbe_free_tx_resources(adapter->xdp_ring[j]);while (i--)ixgbe_free_tx_resources(adapter->tx_ring[i]);return err;
}/*** ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)* @tx_ring:    tx descriptor ring (for a specific queue) to setup** Return 0 on success, negative on failure**/
int ixgbe_setup_tx_resources(struct ixgbe_ring *tx_ring)
{struct device *dev = tx_ring->dev;int orig_node = dev_to_node(dev);int ring_node = -1;int size;size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;if (tx_ring->q_vector)ring_node = tx_ring->q_vector->numa_node;// 分配 tx_ring->count 个ixgbe_tx_buffer,地址赋给tx_ring->tx_buffer_infotx_ring->tx_buffer_info = vmalloc_node(size, ring_node);if (!tx_ring->tx_buffer_info)tx_ring->tx_buffer_info = vmalloc(size);if (!tx_ring->tx_buffer_info)goto err;/* round up to nearest 4K */tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);tx_ring->size = ALIGN(tx_ring->size, 4096);set_dev_node(dev, ring_node);tx_ring->desc = dma_alloc_coherent(dev,tx_ring->size,&tx_ring->dma,GFP_KERNEL);set_dev_node(dev, orig_node);//分配 tx_ring->size 个ixgbe_adv_tx_desc(一致性DMA内存),内存地址赋给tx_ring->desc,总线地址赋给tx_ring->dmaif (!tx_ring->desc)tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,&tx_ring->dma, GFP_KERNEL);if (!tx_ring->desc)goto err;tx_ring->next_to_use = 0;tx_ring->next_to_clean = 0;return 0;err:vfree(tx_ring->tx_buffer_info);tx_ring->tx_buffer_info = NULL;dev_err(dev, "Unable to allocate memory for the Tx descriptor ring\n");return -ENOMEM;
}

2.2 接收环形队列描述符分配 ixgbe_setup_all_rx_resources

同2.1小节发送环配置

2.3 网卡配置 ixgbe_configure()

static void ixgbe_configure(struct ixgbe_adapter *adapter)
{struct ixgbe_hw *hw = &adapter->hw;ixgbe_configure_pb(adapter);
#ifdef CONFIG_IXGBE_DCBixgbe_configure_dcb(adapter);
#endif/** We must restore virtualization before VLANs or else* the VLVF registers will not be populated*/ixgbe_configure_virtualization(adapter);ixgbe_set_rx_mode(adapter->netdev);ixgbe_restore_vlan(adapter);switch (hw->mac.type) {case ixgbe_mac_82599EB:case ixgbe_mac_X540:hw->mac.ops.disable_rx_buff(hw);break;default:break;}if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {ixgbe_init_fdir_signature_82599(&adapter->hw,adapter->fdir_pballoc);} else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {ixgbe_init_fdir_perfect_82599(&adapter->hw,adapter->fdir_pballoc);ixgbe_fdir_filter_restore(adapter);}switch (hw->mac.type) {case ixgbe_mac_82599EB:case ixgbe_mac_X540:hw->mac.ops.enable_rx_buff(hw);break;default:break;}#ifdef CONFIG_IXGBE_DCA/* configure DCA */if (adapter->flags & IXGBE_FLAG_DCA_CAPABLE)ixgbe_setup_dca(adapter);
#endif /* CONFIG_IXGBE_DCA */#ifdef IXGBE_FCOE/* configure FCoE L2 filters, redirection table, and Rx control */ixgbe_configure_fcoe(adapter);#endif /* IXGBE_FCOE */ixgbe_configure_tx(adapter);// 配置发送队列ixgbe_configure_rx(adapter);// 配置接收队列ixgbe_configure_dfwd(adapter);
}

2.3.1 网卡接收队列配置 ixgbe_configure_rx()

/*** ixgbe_configure_rx - Configure 8259x Receive Unit after Reset* @adapter: board private structure** Configure the Rx unit of the MAC after a reset.**/
static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
{struct ixgbe_hw *hw = &adapter->hw;int i;u32 rxctrl, rfctl;/* disable receives while setting up the descriptors */hw->mac.ops.disable_rx(hw);ixgbe_setup_psrtype(adapter);ixgbe_setup_rdrxctl(adapter);/* RSC Setup */rfctl = IXGBE_READ_REG(hw, IXGBE_RFCTL);rfctl &= ~IXGBE_RFCTL_RSC_DIS;if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))rfctl |= IXGBE_RFCTL_RSC_DIS;/* disable NFS filtering */rfctl |= (IXGBE_RFCTL_NFSW_DIS | IXGBE_RFCTL_NFSR_DIS);IXGBE_WRITE_REG(hw, IXGBE_RFCTL, rfctl);/* Program registers for the distribution of queues */ixgbe_setup_mrqc(adapter);/* set_rx_buffer_len must be called before ring initialization */ixgbe_set_rx_buffer_len(adapter);/** Setup the HW Rx Head and Tail Descriptor Pointers and* the Base and Length of the Rx Descriptor Ring*/for (i = 0; i < adapter->num_rx_queues; i++)ixgbe_configure_rx_ring(adapter, adapter->rx_ring[i]);// rx_ring 配置rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);/* disable drop enable for 82598 parts */if (hw->mac.type == ixgbe_mac_82598EB)rxctrl |= IXGBE_RXCTRL_DMBYPS;/* enable all receives */rxctrl |= IXGBE_RXCTRL_RXEN;hw->mac.ops.enable_rx_dma(hw, rxctrl);
}void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,struct ixgbe_ring *ring)
{struct ixgbe_hw *hw = &adapter->hw;union ixgbe_adv_rx_desc *rx_desc;u64 rdba = ring->dma; // ixgbe_adv_rx_desc数组的总线地址u32 rxdctl;u8 reg_idx = ring->reg_idx;/* 将ixgbe_adv_rx_desc数组的总线地址写入网卡寄存器RDBAL(RX Descriptor Base Address Low)RDBAH(RX Descriptor Base Address High)RDLEN(RX Descriptor Length)RDH(RX Descriptor Head)RDL(RX Descriptor Tail) */// #define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : \(0x0D000 + ((_i - 64) * 0x40)))// #define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : \(0x0D004 + ((_i - 64) * 0x40)))// #define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : \(0x0D008 + ((_i - 64) * 0x40)))// #define IXGBE_RDH(_i)   (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : \(0x0D010 + ((_i - 64) * 0x40)))// #define IXGBE_RDT(_i)   (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : \/* disable queue to avoid issues while updating state */rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));ixgbe_disable_rx_queue(adapter, ring);IXGBE_WRITE_REG(hw, IXGBE_RDBAL(reg_idx), (rdba & DMA_BIT_MASK(32)));IXGBE_WRITE_REG(hw, IXGBE_RDBAH(reg_idx), (rdba >> 32));IXGBE_WRITE_REG(hw, IXGBE_RDLEN(reg_idx),ring->count * sizeof(union ixgbe_adv_rx_desc));/* Force flushing of IXGBE_RDLEN to prevent MDD */IXGBE_WRITE_FLUSH(hw);IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx);ixgbe_configure_srrctl(adapter, ring);ixgbe_configure_rscctl(adapter, ring);if (hw->mac.type == ixgbe_mac_82598EB) {/** enable cache line friendly hardware writes:* PTHRESH=32 descriptors (half the internal cache),* this also removes ugly rx_no_buffer_count increment* HTHRESH=4 descriptors (to minimize latency on fetch)* WTHRESH=8 burst writeback up to two cache lines*/rxdctl &= ~0x3FFFFF;rxdctl |=  0x080420;
#if (PAGE_SIZE < 8192)/* RXDCTL.RLPML does not work on 82599 */} else if (hw->mac.type != ixgbe_mac_82599EB) {rxdctl &= ~(IXGBE_RXDCTL_RLPMLMASK |IXGBE_RXDCTL_RLPML_EN);/* Limit the maximum frame size so we don't overrun the skb.* This can happen in SRIOV mode when the MTU of the VF is* higher than the MTU of the PF.*/if (ring_uses_build_skb(ring) &&!test_bit(__IXGBE_RX_3K_BUFFER, &ring->state))rxdctl |= IXGBE_MAX_2K_FRAME_BUILD_SKB |IXGBE_RXDCTL_RLPML_EN;
#endif}/* initialize rx_buffer_info */memset(ring->rx_buffer_info, 0,sizeof(struct ixgbe_rx_buffer) * ring->count);/* initialize Rx descriptor 0 */rx_desc = IXGBE_RX_DESC(ring, 0);rx_desc->wb.upper.length = 0;/* enable receive descriptor ring */rxdctl |= IXGBE_RXDCTL_ENABLE;IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);ixgbe_rx_desc_queue_enable(adapter, ring);ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}

2.3.2 网卡发送队列配置 ixgbe_configure_tx()

参见 2.3.1 小节

2.4 注册中断 ixgbe_request_irq()

在 ixgbe_request_irq() 中申请并设置硬中断函数:

  • 使用MSIX,硬中断处理入口函数为 ixgbe_msix_clean_rings()
  • 使用MSI或其它,硬中断处理入口函数为 ixgbe_intr()
/*** ixgbe_request_irq - initialize interrupts* @adapter: board private structure** Attempts to configure interrupts using the best available* capabilities of the hardware and kernel.**/
static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
{struct net_device *netdev = adapter->netdev;int err;if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)err = ixgbe_request_msix_irqs(adapter);// 使用 MSIX 中断函数为 ixgbe_msix_clean_rings()else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED)err = request_irq(adapter->pdev->irq, ixgbe_intr, 0,netdev->name, adapter);   //中断函数为ixgbe_intr()elseerr = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED,netdev->name, adapter);if (err)e_err(probe, "request_irq failed, Error %d\n", err);return err;
}

2.4.1 MSIX 硬中断请求 ixgbe_request_msix_irqs()

/*** ixgbe_request_msix_irqs - Initialize MSI-X interrupts* @adapter: board private structure** ixgbe_request_msix_irqs allocates MSI-X vectors and requests* interrupts from the kernel.**/
static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
{struct net_device *netdev = adapter->netdev;unsigned int ri = 0, ti = 0;int vector, err;for (vector = 0; vector < adapter->num_q_vectors; vector++) {struct ixgbe_q_vector *q_vector = adapter->q_vector[vector];struct msix_entry *entry = &adapter->msix_entries[vector];// 通过cat /proc/interrupts可以看到xgbe0-TxRx-0等if (q_vector->tx.ring && q_vector->rx.ring) {snprintf(q_vector->name, sizeof(q_vector->name),"%s-TxRx-%u", netdev->name, ri++);ti++;} else if (q_vector->rx.ring) {snprintf(q_vector->name, sizeof(q_vector->name),"%s-rx-%u", netdev->name, ri++);} else if (q_vector->tx.ring) {snprintf(q_vector->name, sizeof(q_vector->name),"%s-tx-%u", netdev->name, ti++);} else {/* skip this unused q_vector */continue;}err = request_irq(entry->vector, &ixgbe_msix_clean_rings, 0,q_vector->name, q_vector);if (err) {e_err(probe, "request_irq failed for MSIX interrupt ""Error: %d\n", err);goto free_queue_irqs;}/* If Flow Director is enabled, set interrupt affinity */if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {/* assign the mask for this irq */irq_set_affinity_hint(entry->vector,&q_vector->affinity_mask);}}err = request_irq(adapter->msix_entries[vector].vector,ixgbe_msix_other, 0, netdev->name, adapter);if (err) {e_err(probe, "request_irq for msix_other failed: %d\n", err);goto free_queue_irqs;}return 0;free_queue_irqs:while (vector) {vector--;irq_set_affinity_hint(adapter->msix_entries[vector].vector,NULL);free_irq(adapter->msix_entries[vector].vector,adapter->q_vector[vector]);}adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;pci_disable_msix(adapter->pdev);kfree(adapter->msix_entries);adapter->msix_entries = NULL;return err;
}

ixgbe网卡驱动 Ⅲ----收发队列资源分配相关推荐

  1. linux网卡发送数据包流程,linux内核Ethernet以太网卡驱动收发数据过程

    linux内核Ethernet以太网卡驱动收发数据过程 linux内核Ethernet以太网卡驱动收发数据过程 下图简单描述了网卡驱动与Linux内核之间的联系: 关于上图的一些说明: 系统初始化: ...

  2. 网卡驱动和队列层中的数据包接收

    一.从网卡说起 这并非是一个网卡驱动分析的专门文档,只是对网卡处理数据包的流程进行一个重点的分析.这里以Intel的e100驱动为例进行分析. 大多数网卡都是一个PCI设备,PCI设备都包含了一个标准 ...

  3. 了解ixgbe网卡驱动— 驱动注册(纯代码分享)

    1 ixgbe 网卡注册驱动 和大部分设备驱动一样,网卡驱动是作为一个 module 注册到 kernel 的 通过 module_init() -> ixgbe_init_module() - ...

  4. ixgbe网卡驱动Ⅱ---- 驱动注册

    目录 1 ixgbe 网卡注册驱动 1.1 ixgbe_driver 类 1.2 ixgbe_driver 注册/注销 2 ixgbe 的 PCI 注册驱动流程 pci_register_driver ...

  5. DPDK — 网卡初始化流程(Intel 82599 ixgbe 网卡驱动示例)

    目录 文章目录 目录 总览 rte_eth_dev/rte_eth_dev_data 数据结构 rte_eth_dev_count 函数 rte_eth_dev_configure 函数 ixgbe_ ...

  6. ixgbe网卡驱动(一)

    注册网卡驱动 和大部分设备驱动一样,网卡驱动是作为一个module注册到kernel的 通过module_init() -> ixgbe_init_module() -> pci_regi ...

  7. ixgbe网卡驱动 Ⅳ----收发包流程详解

    目录 1 网卡队列收包流程概述 2 ixgbe_ring 结构 3 ixgbe 驱动收包流程 3.1 硬件中断入口 ixgbe_msix_clean_rings/ixgbe_intr 3.2 软中断入 ...

  8. DPDK — 网卡驱动初始化流程

    目录 文章目录 目录 Intel 82599 ixgbe 网卡驱动示例 rte_eth_dev/rte_eth_dev_data 数据结构 rte_eth_dev_count 函数 rte_eth_d ...

  9. linux内核网络协议栈--网卡报文收发(十六)

    版本说明 Linux版本: 3.10.103 网卡驱动: ixgbev 报文收发简单流程 网卡驱动默认采用的是NAPI的报文处理方式.即中断+轮询的方式,网卡收到一个报文之后会产生接收中断,并且屏蔽中 ...

最新文章

  1. Udacity机器人软件工程师课程笔记(二十八) - 卷积神经网络实例 - Fashion-MNIST数据集
  2. 形态学边缘提取matlab,在Matlab平台下基于形态学方法对LIDAR数据进行建筑物边缘提取...
  3. 计算机网络原理第二章笔记,计算机网络原理笔记 第三章 数据链路层(一)
  4. 运维人员如何最大限度避免误删除文件
  5. 斩断亏损,让利润奔跑
  6. java中对事件的监听事件,详谈Java中的事件监听机制
  7. 解析eas webservice
  8. css 彩虹色渐变色,纯CSS实现颜色渐变效果(包含环形渐变、线性渐变、彩虹效果等)...
  9. Epicor客制化 - RowRule使用示例
  10. Caffe_stu03_小训练
  11. SAP发票校验中支付条件中的基准日期缺省值的配置及控制逻辑测试
  12. 微信服务商子商户支付
  13. swift Toast
  14. Python+selenium+360浏览器实现自动测试
  15. 动漫头像修复高清,提高分辨率、提高清晰度的模型处理
  16. OneNote只能通过键盘左右上下键改变位置,鼠标点击没反应,鼠标无法选重文字,鼠标无法移动光标
  17. 网络空间安全专业,全国大学排名!猜猜谁排第一?
  18. JSoup快速入门-java解析html源码
  19. 一款聚合音乐播放器,可播放很多音乐资源,开源且完全免费。
  20. 华为腾讯游戏因分成开“撕“,“内容“与“渠道“谁能称王?

热门文章

  1. 系统驱动单元测试知识点总结
  2. Linux进程崩溃排查方法
  3. IDEA常用快捷键和debug常用调试技巧
  4. web3.js中的Glossary
  5. 【性能调优】应用系统性能画像
  6. 求分数和的最简形式(c++)
  7. 【Unity3D】场景切换、全屏/恢复切换、退出游戏、截屏
  8. Python实现热力图
  9. Linux核心的汉字
  10. 关于 小米平板 触摸事件响应不正常 ontouchend touchend