From 4887258ef5425fb3e3c4dd99ea9f7c1d01990c6e Mon Sep 17 00:00:00 2001 From: Mykyta Iziumtsev Date: Thu, 19 Oct 2017 16:35:31 +0200 Subject: Work in progress: 2017-10-19 --- drivers/e1000e.c | 63 +++++++++++++++++++++++++++-------------- drivers/r8169.c | 4 +-- include/common.h | 4 +-- include/drivers/driver_ops.h | 4 +-- kernel/4.13.0/e1000e/e1000.h | 2 ++ kernel/4.13.0/e1000e/netdev.c | 23 ++++++++------- kernel/4.13.0/e1000e/vfio-net.c | 30 ++++++++++++++++---- run_e1000e.sh | 2 +- src/userspace_io.c | 5 +++- 9 files changed, 91 insertions(+), 46 deletions(-) diff --git a/drivers/e1000e.c b/drivers/e1000e.c index f3e4cf6..1b30a32 100644 --- a/drivers/e1000e.c +++ b/drivers/e1000e.c @@ -128,40 +128,46 @@ static void print_packet(unsigned char *buffer) } #endif -static void e1000e_rx_desc_push(e1000e_rx_desc_t *rx_ring, int idx, dma_addr_t dma_addr, volatile void *ioaddr) -{ - rx_ring[idx].read.buffer_addr = odpdrv_cpu_to_le_64(dma_addr); - dma_wmb(); - - io_write32(odpdrv_cpu_to_le_32(idx), ioaddr + E1000_RDT_OFFSET); -} - static int e1000e_rx_fill(int device, void *rxring, struct iomem data, - char *rx_buff[], volatile void *ioaddr) + volatile char *rx_buff[], volatile void *ioaddr) { - e1000e_rx_desc_t *rx_ring = (e1000e_rx_desc_t *)rxring; + volatile e1000e_rx_desc_t *rx_ring = (e1000e_rx_desc_t *) rxring; int i; + memset((void *)rx_ring, 0, E1000E_RX_RING_SIZE_DEFAULT * sizeof(e1000e_rx_desc_t)); + /* TODO: support variable rx_ring size, configuration via ethtool */ - for (i = 0; i < E1000E_RX_RING_SIZE_DEFAULT; i++) { - rx_buff[i] = (char *)(data.vaddr + i * E1000E_RX_BUF_SIZE); - e1000e_rx_desc_push(rx_ring, i, data.iova + i * E1000E_RX_BUF_SIZE, ioaddr); + for (i = 0; i < E1000E_RX_RING_SIZE_DEFAULT - 1; i++) { + rx_buff[i] = + (char *) (data.vaddr + i * E1000E_RX_BUF_SIZE); + memset((void *) rx_buff[i], 0xa5, E1000E_RX_BUF_SIZE); + rx_ring[i].read.buffer_addr = + odpdrv_cpu_to_le_64(data.iova + + i * E1000E_RX_BUF_SIZE); + if (!(i & 15)) { + dma_wmb(); + io_write32(odpdrv_cpu_to_le_32(i), + ioaddr + E1000_RDT_OFFSET); + } } return 0; } -static void e1000e_recv(void *rxring, char *rx_buff[], volatile void *ioaddr) +static void e1000e_recv(void *rxring, volatile char *rx_buff[], volatile void *ioaddr) { - e1000e_rx_desc_t *rx_ring = (e1000e_rx_desc_t *)rxring; + volatile e1000e_rx_desc_t *rx_ring = (e1000e_rx_desc_t *)rxring; int i = 0; while (1) { if (i >= E1000E_RX_RING_SIZE_DEFAULT) i = 0; for (; i < E1000E_RX_RING_SIZE_DEFAULT; i++) { - e1000e_rx_desc_t *rx_desc = rx_ring + i; - uint32_t status = odpdrv_le_to_cpu_32(rx_desc->wb.upper.status_error); + volatile e1000e_rx_desc_t *rx_desc = rx_ring + i; + uint32_t status; + + dma_rmb(); + status = odpdrv_le_to_cpu_32(rx_desc->wb.upper.status_error); if (!(status & E1000E_RX_DESC_STAT_DONE)) { usleep(100*1000); @@ -179,6 +185,13 @@ static void e1000e_recv(void *rxring, char *rx_buff[], volatile void *ioaddr) } else { int pkt_size = odpdrv_le_to_cpu_16(rx_desc->wb.upper.length); +#if 0 + while ((unsigned char)rx_buff[i][0] == 0xa5U) { + printf("Packet payload is garbage, waiting ...\n"); + usleep(1000); + printf("Done waiting\n"); + } +#endif printf("desc[%03d]: size= %5d ", i, pkt_size); print_packet((unsigned char *)rx_buff[i]); printf("\n"); @@ -197,9 +210,9 @@ void *e1000e_map_mmio(int device) void e1000e_xmit(void *txring, struct iomem data, volatile void *ioaddr) { /* test udp packet */ - static const char pkt_udp[] = { + static const unsigned char pkt_udp[] = { 0x02, 0x50, 0x43, 0xff, 0xff, 0x01, /* mac dst */ - 0x00, 0x60, 0xdd, 0x45, 0xe5, 0x67, /* mac src */ + 0xf4, 0x4d, 0x30, 0x64, 0x43, 0xf7, /* mac src */ 0x08, 0x00, 0x45, 0x00, 0x00, 0x32, 0x38, 0xb8, 0x40, 0x00, 0x40, 0x11, 0x1e, 0xae, 0xc0, 0xa8, 0x31, 0x03, /* ip src: 192.168.49.3 and dst 192.168.49.1 */ @@ -216,12 +229,12 @@ void e1000e_xmit(void *txring, struct iomem data, volatile void *ioaddr) E1000_TXD_CMD_IDE; for (idx = 0; idx < 100; idx++) { - e1000_tx_desc_t *tx_desc = + volatile e1000_tx_desc_t *tx_desc = (e1000_tx_desc_t *) txring + idx; - char *tx_buff = (char *) (data.vaddr + idx * 2048); + volatile unsigned char *tx_buff = (unsigned char *) (data.vaddr + idx * 2048); /* XXX FIXME need proper packet size and sizeof(src) *NOT* dst */ - memcpy(tx_buff, pkt_udp, sizeof(pkt_udp)); + memcpy((void *)tx_buff, pkt_udp, sizeof(pkt_udp)); tx_desc->buffer_addr = odpdrv_cpu_to_le_64(data.iova + idx * 2048); tx_desc->lower.data = @@ -231,6 +244,8 @@ void e1000e_xmit(void *txring, struct iomem data, volatile void *ioaddr) dma_wmb(); printf("Triggering xmit of dummy packet\n"); + print_packet((void *)tx_buff); + printf("tx_desc->buffer_addr == 0x%016lx\n", tx_desc->buffer_addr); printf("tx_desc->lower == 0x%08x\n", tx_desc->lower.data); @@ -247,6 +262,10 @@ void e1000e_xmit(void *txring, struct iomem data, volatile void *ioaddr) printf("TDT == 0x%08x\n", io_read32(ioaddr + E1000_TDT_OFFSET)); printf("TDH == 0x%08x\n", io_read32(ioaddr + E1000_TDH_OFFSET)); + printf("tx_desc->buffer_addr == 0x%016lx\n", + tx_desc->buffer_addr); + printf("tx_desc->lower == 0x%08x\n", tx_desc->lower.data); + printf("tx_desc->upper == 0x%08x\n", tx_desc->upper.data); } return; diff --git a/drivers/r8169.c b/drivers/r8169.c index e90ed7b..dd34b82 100644 --- a/drivers/r8169.c +++ b/drivers/r8169.c @@ -63,7 +63,7 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) } static int r8169_rx_fill(int device, void *rx_data, struct iomem data, - char *rx_buff[], volatile void *ioaddr) + volatile char *rx_buff[], volatile void *ioaddr) { int i; struct RxDesc *r8169_rxring = (struct RxDesc *) rx_data; @@ -77,7 +77,7 @@ static int r8169_rx_fill(int device, void *rx_data, struct iomem data, return 0; } -void r8169_recv(void *rxring, char *rx_buff[], volatile void *ioaddr) +void r8169_recv(void *rxring, volatile char *rx_buff[], volatile void *ioaddr) { int i = 0; struct RxDesc *r8169_rxring = (struct RxDesc *)rxring; diff --git a/include/common.h b/include/common.h index 38570d7..a3adc66 100644 --- a/include/common.h +++ b/include/common.h @@ -12,7 +12,7 @@ static inline int uio_quirks(const struct driver_ops *e) } static inline int uio_rx_fill(const struct driver_ops *e, int device, - void *rxring, struct iomem data, char *rx_buf[], + void *rxring, struct iomem data, volatile char *rx_buf[], volatile void *ioaddr) { if (e && e->rx_fill) @@ -22,7 +22,7 @@ static inline int uio_rx_fill(const struct driver_ops *e, int device, } static inline void uio_recv(const struct driver_ops *e, void *rxring, - char *rxbuffers[], volatile void *iomem) + volatile char *rxbuffers[], volatile void *iomem) { if (e && e->recv) e->recv(rxring, rxbuffers, iomem); diff --git a/include/drivers/driver_ops.h b/include/drivers/driver_ops.h index 4ab973d..9da5312 100644 --- a/include/drivers/driver_ops.h +++ b/include/drivers/driver_ops.h @@ -9,9 +9,9 @@ struct driver_ops { int (*vfio_quirks)(void); /* prepare Rx descriptors */ int (*rx_fill)(int device, void *rxring, struct iomem data, - char *rx_buf[], volatile void *iomem); + volatile char *rx_buf[], volatile void *iomem); /* receive */ - void (*recv)(void *rxring, char *rxbuffers[], volatile void *iomem); + void (*recv)(void *rxring, volatile char *rxbuffers[], volatile void *iomem); /* xmit */ void (*xmit)(void *txring, struct iomem data, volatile void *iomem); /* map MMIO */ diff --git a/kernel/4.13.0/e1000e/e1000.h b/kernel/4.13.0/e1000e/e1000.h index 06ad27f..1955604 100644 --- a/kernel/4.13.0/e1000e/e1000.h +++ b/kernel/4.13.0/e1000e/e1000.h @@ -319,6 +319,7 @@ struct e1000_adapter { struct msix_entry *msix_entries; int int_mode; u32 eiac_mask; + u32 irq_mask; u32 eeprom_wol; u32 wol; @@ -507,6 +508,7 @@ void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); void e1000e_get_hw_control(struct e1000_adapter *adapter); void e1000e_release_hw_control(struct e1000_adapter *adapter); void e1000e_write_itr(struct e1000_adapter *adapter, u32 itr); +void e1000e_trigger_lsc(struct e1000_adapter *adapter); extern unsigned int copybreak; diff --git a/kernel/4.13.0/e1000e/netdev.c b/kernel/4.13.0/e1000e/netdev.c index 5892d07..fd28d38 100644 --- a/kernel/4.13.0/e1000e/netdev.c +++ b/kernel/4.13.0/e1000e/netdev.c @@ -2246,11 +2246,11 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); - ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC); + ew32(IMS, ~adapter->irq_mask & (adapter->eiac_mask | E1000_IMS_LSC)); } else if (hw->mac.type >= e1000_pch_lpt) { - ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER); + ew32(IMS, ~adapter->irq_mask & (IMS_ENABLE_MASK | E1000_IMS_ECCER)); } else { - ew32(IMS, IMS_ENABLE_MASK); + ew32(IMS, ~adapter->irq_mask & IMS_ENABLE_MASK); } e1e_flush(); } @@ -4202,7 +4202,7 @@ void e1000e_reset(struct e1000_adapter *adapter) * * Fire a link status change interrupt to start the watchdog. **/ -static void e1000e_trigger_lsc(struct e1000_adapter *adapter) +void e1000e_trigger_lsc(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; @@ -4219,13 +4219,12 @@ void e1000e_up(struct e1000_adapter *adapter) clear_bit(__E1000_DOWN, &adapter->state); - if (!test_bit(__E1000_VFIO_NET, &adapter->state)) { - if (adapter->msix_entries) - e1000_configure_msix(adapter); - e1000_irq_enable(adapter); + if (adapter->msix_entries) + e1000_configure_msix(adapter); + e1000_irq_enable(adapter); + if (!test_bit(__E1000_VFIO_NET, &adapter->state)) { netif_start_queue(adapter->netdev); - e1000e_trigger_lsc(adapter); } } @@ -5926,8 +5925,10 @@ static void e1000_tx_timeout(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - adapter->tx_timeout_count++; - schedule_work(&adapter->reset_task); + if (!test_bit(__E1000_VFIO_NET, &adapter->state)) { + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + } } static void e1000_reset_task(struct work_struct *work) diff --git a/kernel/4.13.0/e1000e/vfio-net.c b/kernel/4.13.0/e1000e/vfio-net.c index 6a16f25..dd829af 100644 --- a/kernel/4.13.0/e1000e/vfio-net.c +++ b/kernel/4.13.0/e1000e/vfio-net.c @@ -87,6 +87,12 @@ static int e1000e_vfio_net_open(struct mdev_device *mdev) dev_hold(adapter->netdev); set_bit(__E1000_VFIO_NET, &adapter->state); + adapter->irq_mask = + E1000_IMS_RXT0 | + E1000_IMS_TXDW | + E1000_IMS_RXDMT0 | + E1000_IMS_RXSEQ; + if (netif_running(adapter->netdev)) e1000e_reinit_locked(adapter); else @@ -108,6 +114,8 @@ static void e1000e_vfio_net_release(struct mdev_device *mdev) struct e1000_adapter *adapter = netdev_priv(netdev); clear_bit(__E1000_VFIO_NET, &adapter->state); + adapter->irq_mask = 0; + if (netif_running(adapter->netdev)) e1000e_reinit_locked(adapter); else @@ -319,6 +327,7 @@ static long e1000e_vfio_net_ioctl(struct mdev_device *mdev, unsigned int cmd, /* return ret? */ return -ENOMEM; +#if 0 printk(KERN_INFO"VFIO_IOMMU_MAP_DMA: about to dma_map_single(%p, %p, %lld, DMA_FROM_DEVICE)\n", parent_dev, data, map.size); mapping = dma_map_single(parent_dev, data, map.size, @@ -329,11 +338,18 @@ static long e1000e_vfio_net_ioctl(struct mdev_device *mdev, unsigned int cmd, kfree(data); goto out; } +#else + data = dma_alloc_coherent(parent_dev, map.size, &mapping, GFP_KERNEL); + if (!data) { + if (net_ratelimit()) + printk(KERN_ERR"Failed to dma_alloc_coherent buffer for userland!\n"); + goto out; + } + +#endif map.iova = mapping; - ret = io_remap_pfn_range(vma, map.vaddr, - virt_to_phys(data) >> PAGE_SHIFT, - map.size, vma->vm_page_prot); - printk(KERN_INFO"VFIO_IOMMU_MAP_DMA: io_remap_pfn_range %llx -> physmem <- @%llx, %lld:%d\n", + ret = dma_mmap_coherent(parent_dev, vma, data, mapping, map.size); + printk(KERN_INFO"VFIO_IOMMU_MAP_DMA: dma_map_coherent %llx -> physmem <- @%llx, %lld:%d\n", map.vaddr, map.iova, map.size, ret); if (ret != 0) { dma_unmap_single(parent_dev, mapping, map.size, @@ -347,7 +363,7 @@ static long e1000e_vfio_net_ioctl(struct mdev_device *mdev, unsigned int cmd, netmdev->mappings_count); netmdev->mappings[netmdev->mappings_count].dev = parent_dev; netmdev->mappings[netmdev->mappings_count].vaddr = data; - netmdev->mappings[netmdev->mappings_count].iova = mapping; + netmdev->mappings[netmdev->mappings_count].iova = map.iova; netmdev->mappings[netmdev->mappings_count].size = map.size; netmdev->mappings_count++; @@ -370,6 +386,10 @@ out: return 0; + case 500: + e1000e_trigger_lsc(adapter); + return 0; + default: return -EOPNOTSUPP; } diff --git a/run_e1000e.sh b/run_e1000e.sh index 4a74a20..844fb5a 100755 --- a/run_e1000e.sh +++ b/run_e1000e.sh @@ -7,4 +7,4 @@ insmod kernel/4.13.0/e1000e/e1000e.ko sleep 1 ifconfig $intf up ./run.sh create $intf -./uio -i 0 -d $(basename /sys/bus/mdev/devices/*) -n e1000e +./uio -i 12 -d $(basename /sys/bus/mdev/devices/*) -n e1000e diff --git a/src/userspace_io.c b/src/userspace_io.c index 4677409..46fc21b 100644 --- a/src/userspace_io.c +++ b/src/userspace_io.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) int ret, c, group_id; char group_uuid[64]; /* 37 should be enough */ char drv_name[64]; - char *rx_buff[256]; + volatile char *rx_buff[256]; __u32 opts = 0; memset(group_uuid, 0, sizeof(group_uuid)); @@ -164,6 +164,9 @@ int main(int argc, char *argv[]) } ioctl(device, 500, NULL); + + // usleep(30 * 1000 * 1000); + uio_xmit(exec_ops, txring, tx_data, mmio); uio_recv(exec_ops, rxring, rx_buff, mmio); -- cgit v1.2.3