"...composable_kernel_rocm.git" did not exist on "8a4253baafd1bb130eb9db88ca91aaa1984af28d"
Commit e5d21a24 authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

scripts to generate VM image

parent 37890e12
*.o *.o
*.a *.a
*.ko
.*.cmd
_vimrc_local.vim _vimrc_local.vim
dummy_nic/dummy_nic dummy_nic/dummy_nic
corundum/obj_dir corundum/obj_dir
corundum/corundum_verilator corundum/corundum_verilator
net_wire/net_wire net_wire/net_wire
net_tap/net_tap net_tap/net_tap
images/mqnic/Module.symvers
images/mqnic/modules.order
images/mqnic/mqnic.mod*
images/vmlinux
images/bzImage
images/output-ubuntu1804
images/packer
images/packer_cache
images/kernel/linux-*/
PACKER_VERSION := 1.6.0
KERNEL_VERSION := 5.4.46
IMAGE := output-ubuntu1804/ubuntu1804
all: $(IMAGE) $(IMAGE).raw vmlinux bzImage mqnic/mqnic.ko
clean:
rm -rf packer packer_cache output-ubuntu1804 vmlinux bzImage \
mqnic/mqnic.ko mqnic/*.o mqnic/.*.cmd mqnic/mqnic.mod.c \
mqnic/Module.symvers mqnic/modules.order \
kernel/linux-5.4.46/
################################################
# Disk image
$(IMAGE).raw: $(IMAGE)
qemu-img convert -f qcow2 -O raw $< $@
$(IMAGE): $(wildcard scripts/*) packer ubuntu1804.json
rm -rf output-ubuntu1804
./packer build ubuntu1804.json
packer:
wget https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip
unzip packer_$(PACKER_VERSION)_linux_amd64.zip
rm -f packer_$(PACKER_VERSION)_linux_amd64.zip
################################################
# Kernel
vmlinux bzImage &: kernel/linux-$(KERNEL_VERSION)
$(MAKE) -C kernel/linux-$(KERNEL_VERSION)
cp kernel/linux-$(KERNEL_VERSION)/vmlinux vmlinux
cp kernel/linux-$(KERNEL_VERSION)/arch/x86_64/boot/bzImage bzImage
kernel/linux-$(KERNEL_VERSION):
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-$(KERNEL_VERSION).tar.xz
tar xf linux-$(KERNEL_VERSION).tar.xz
rm -f linux-$(KERNEL_VERSION).tar.xz
mv linux-$(KERNEL_VERSION) kernel/
cd kernel/linux-$(KERNEL_VERSION) && patch -p1 < ../linux-$(KERNEL_VERSION)-timers-gem5.patch
cp kernel/config-$(KERNEL_VERSION) kernel/linux-$(KERNEL_VERSION)/.config
################################################
# mqnic kernel module
mqnic/mqnic.ko: vmlinux
$(MAKE) -C kernel/linux-$(KERNEL_VERSION) M=`pwd`/mqnic/ modules
touch $@
This diff is collapsed.
diff -ur linux-5.4.46/arch/x86/kernel/apic/apic.c linux-5.4.46.our/arch/x86/kernel/apic/apic.c
--- linux-5.4.46/arch/x86/kernel/apic/apic.c 2020-06-10 20:24:58.000000000 +0200
+++ linux-5.4.46.our/arch/x86/kernel/apic/apic.c 2020-06-16 20:26:58.697157257 +0200
@@ -1034,6 +1034,8 @@
return -1;
}
+
+ printk(KERN_ERR " calibrated lapic_timer_period=%u\n", lapic_timer_period);
return 0;
}
@@ -2916,3 +2918,13 @@
return 0;
}
early_param("apic_extnmi", apic_set_extnmi);
+
+static int __init lapic_set_timer_period(char *arg)
+{
+ if (!arg || kstrtouint(arg, 10, &lapic_timer_period)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+early_param("lapic_timer_period", lapic_set_timer_period);
diff -ur linux-5.4.46/arch/x86/kernel/tsc.c linux-5.4.46.our/arch/x86/kernel/tsc.c
--- linux-5.4.46/arch/x86/kernel/tsc.c 2020-06-10 20:24:58.000000000 +0200
+++ linux-5.4.46.our/arch/x86/kernel/tsc.c 2020-06-16 21:07:12.652251545 +0200
@@ -51,6 +51,8 @@
static u64 art_to_tsc_offset;
struct clocksource *art_related_clocksource;
+static unsigned long tsc_override_freq = 0;
+
struct cyc2ns {
struct cyc2ns_data data[2]; /* 0 + 2*16 = 32 */
seqcount_t seq; /* 32 + 4 = 36 */
@@ -862,6 +864,8 @@
{
unsigned long flags, fast_calibrate = cpu_khz_from_cpuid();
+ if (tsc_override_freq)
+ return tsc_override_freq;
if (!fast_calibrate)
fast_calibrate = cpu_khz_from_msr();
if (!fast_calibrate) {
@@ -869,6 +873,7 @@
fast_calibrate = quick_pit_calibrate();
local_irq_restore(flags);
}
+ pr_warn("calibrated TSC: tsc_freq=%lu\n", fast_calibrate);
return fast_calibrate;
}
@@ -1534,3 +1539,14 @@
return 0;
}
#endif
+
+
+static int __init tsc_set_override_freq(char *arg)
+{
+ if (!arg || kstrtoul(arg, 10, &tsc_override_freq)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+early_param("tsc_override_freq", tsc_set_override_freq);
obj-m += mqnic.o
mqnic-objs += mqnic_main.o mqnic_dev.o mqnic_netdev.o mqnic_port.o mqnic_ethtool.o mqnic_i2c.o mqnic_ptp.o mqnic_tx.o mqnic_rx.o mqnic_cq.o mqnic_eq.o
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#ifndef MQNIC_H
#define MQNIC_H
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/miscdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#define DRIVER_NAME "mqnic"
#define DRIVER_VERSION "0.1"
#include "mqnic_hw.h"
struct mqnic_i2c_priv
{
struct mqnic_dev *mqnic;
u8 __iomem *scl_in_reg;
u8 __iomem *scl_out_reg;
u8 __iomem *sda_in_reg;
u8 __iomem *sda_out_reg;
uint32_t scl_in_mask;
uint32_t scl_out_mask;
uint32_t sda_in_mask;
uint32_t sda_out_mask;
};
struct mqnic_dev {
struct pci_dev *pdev;
size_t hw_regs_size;
phys_addr_t hw_regs_phys;
u8 __iomem *hw_addr;
u8 __iomem *phc_hw_addr;
struct mutex state_lock;
u8 base_mac[ETH_ALEN];
char name[16];
int msi_nvecs;
unsigned int id;
struct list_head dev_list_node;
struct miscdevice misc_dev;
u32 fw_id;
u32 fw_ver;
u32 board_id;
u32 board_ver;
u32 phc_count;
u32 phc_offset;
u32 if_count;
u32 if_stride;
u32 if_csr_offset;
struct net_device *ndev[MQNIC_MAX_IF];
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
struct i2c_algo_bit_data if_i2c_algo[MQNIC_MAX_IF];
struct i2c_adapter if_i2c_adap[MQNIC_MAX_IF];
struct mqnic_i2c_priv if_i2c_priv[MQNIC_MAX_IF];
struct i2c_algo_bit_data eeprom_i2c_algo;
struct i2c_adapter eeprom_i2c_adap;
struct mqnic_i2c_priv eeprom_i2c_priv;
struct i2c_client *eeprom_i2c_client;
};
struct mqnic_frag {
dma_addr_t dma_addr;
u32 len;
};
struct mqnic_tx_info {
struct sk_buff *skb;
DEFINE_DMA_UNMAP_ADDR(dma_addr);
DEFINE_DMA_UNMAP_LEN(len);
u32 frag_count;
struct mqnic_frag frags[MQNIC_MAX_FRAGS-1];
int ts_requested;
};
struct mqnic_rx_info {
struct page *page;
u32 page_order;
u32 page_offset;
dma_addr_t dma_addr;
u32 len;
};
struct mqnic_ring {
// written on enqueue (i.e. start_xmit)
u32 head_ptr;
u64 bytes;
u64 packets;
u64 dropped_packets;
struct netdev_queue *tx_queue;
// written from completion
u32 tail_ptr ____cacheline_aligned_in_smp;
u32 clean_tail_ptr;
u64 ts_s;
u8 ts_valid;
// mostly constant
u32 size;
u32 full_size;
u32 size_mask;
u32 stride;
u32 cpl_index;
u32 mtu;
u32 page_order;
u32 desc_block_size;
u32 log_desc_block_size;
size_t buf_size;
u8 *buf;
dma_addr_t buf_dma_addr;
union {
struct mqnic_tx_info *tx_info;
struct mqnic_rx_info *rx_info;
};
u32 hw_ptr_mask;
u8 __iomem *hw_addr;
u8 __iomem *hw_head_ptr;
u8 __iomem *hw_tail_ptr;
} ____cacheline_aligned_in_smp;
struct mqnic_cq_ring {
u32 head_ptr;
u32 tail_ptr;
u32 size;
u32 size_mask;
u32 stride;
size_t buf_size;
u8 *buf;
dma_addr_t buf_dma_addr;
struct net_device *ndev;
struct napi_struct napi;
int ring_index;
int eq_index;
void (*handler) (struct mqnic_cq_ring *);
u32 hw_ptr_mask;
u8 __iomem *hw_addr;
u8 __iomem *hw_head_ptr;
u8 __iomem *hw_tail_ptr;
};
struct mqnic_eq_ring {
u32 head_ptr;
u32 tail_ptr;
u32 size;
u32 size_mask;
u32 stride;
size_t buf_size;
u8 *buf;
dma_addr_t buf_dma_addr;
struct net_device *ndev;
int int_index;
int irq;
void (*handler) (struct mqnic_eq_ring *);
u32 hw_ptr_mask;
u8 __iomem *hw_addr;
u8 __iomem *hw_head_ptr;
u8 __iomem *hw_tail_ptr;
};
struct mqnic_port {
struct device *dev;
struct net_device *ndev;
int index;
u32 tx_queue_count;
u32 port_id;
u32 port_features;
u32 port_mtu;
u32 sched_count;
u32 sched_offset;
u32 sched_stride;
u32 sched_type;
u8 __iomem *hw_addr;
};
struct mqnic_priv {
struct device *dev;
struct net_device *ndev;
struct mqnic_dev *mdev;
spinlock_t stats_lock;
bool registered;
int port;
bool port_up;
u32 if_id;
u32 if_features;
u32 event_queue_count;
u32 event_queue_offset;
u32 tx_queue_count;
u32 tx_queue_offset;
u32 tx_cpl_queue_count;
u32 tx_cpl_queue_offset;
u32 rx_queue_count;
u32 rx_queue_offset;
u32 rx_cpl_queue_count;
u32 rx_cpl_queue_offset;
u32 port_count;
u32 port_offset;
u32 port_stride;
u32 max_desc_block_size;
u8 __iomem *hw_addr;
u8 __iomem *csr_hw_addr;
struct mqnic_eq_ring *event_ring[MQNIC_MAX_EVENT_RINGS];
struct mqnic_ring *tx_ring[MQNIC_MAX_TX_RINGS];
struct mqnic_cq_ring *tx_cpl_ring[MQNIC_MAX_TX_CPL_RINGS];
struct mqnic_ring *rx_ring[MQNIC_MAX_RX_RINGS];
struct mqnic_cq_ring *rx_cpl_ring[MQNIC_MAX_RX_CPL_RINGS];
struct mqnic_port *ports[MQNIC_MAX_PORTS];
struct hwtstamp_config hwts_config;
};
// mqnic_main.c
extern struct mqnic_dev *mqnic_find_by_minor(unsigned minor);
// mqnic_dev.c
extern const struct file_operations mqnic_fops;
// mqnic_netdev.c
void mqnic_update_stats(struct net_device *ndev);
int mqnic_init_netdev(struct mqnic_dev *mdev, int port, u8 __iomem *hw_addr);
void mqnic_destroy_netdev(struct net_device *ndev);
// mqnic_port.c
int mqnic_create_port(struct mqnic_priv *priv, struct mqnic_port **port_ptr, int index, u8 __iomem *hw_addr);
void mqnic_destroy_port(struct mqnic_priv *priv, struct mqnic_port **port_ptr);
int mqnic_activate_port(struct mqnic_port *port);
void mqnic_deactivate_port(struct mqnic_port *port);
u32 mqnic_port_get_rss_mask(struct mqnic_port *port);
void mqnic_port_set_rss_mask(struct mqnic_port *port, u32 rss_mask);
// mqnic_ptp.c
void mqnic_register_phc(struct mqnic_dev *mdev);
void mqnic_unregister_phc(struct mqnic_dev *mdev);
ktime_t mqnic_read_cpl_ts(struct mqnic_dev *mdev, struct mqnic_ring *ring, const struct mqnic_cpl *cpl);
// mqnic_i2c.c
int mqnic_init_i2c(struct mqnic_dev *mqnic);
void mqnic_remove_i2c(struct mqnic_dev *mqnic);
// mqnic_eq.c
int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr);
void mqnic_destroy_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr);
int mqnic_activate_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring *ring, int int_index);
void mqnic_deactivate_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring *ring);
bool mqnic_is_eq_ring_empty(const struct mqnic_eq_ring *ring);
bool mqnic_is_eq_ring_full(const struct mqnic_eq_ring *ring);
void mqnic_eq_read_head_ptr(struct mqnic_eq_ring *ring);
void mqnic_eq_write_tail_ptr(struct mqnic_eq_ring *ring);
void mqnic_arm_eq(struct mqnic_eq_ring *ring);
void mqnic_process_eq(struct net_device *ndev, struct mqnic_eq_ring *eq_ring);
// mqnic_cq.c
int mqnic_create_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr);
void mqnic_destroy_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring **ring_ptr);
int mqnic_activate_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring *ring, int eq_index);
void mqnic_deactivate_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring *ring);
bool mqnic_is_cq_ring_empty(const struct mqnic_cq_ring *ring);
bool mqnic_is_cq_ring_full(const struct mqnic_cq_ring *ring);
void mqnic_cq_read_head_ptr(struct mqnic_cq_ring *ring);
void mqnic_cq_write_tail_ptr(struct mqnic_cq_ring *ring);
void mqnic_arm_cq(struct mqnic_cq_ring *ring);
// mqnic_tx.c
int mqnic_create_tx_ring(struct mqnic_priv *priv, struct mqnic_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr);
void mqnic_destroy_tx_ring(struct mqnic_priv *priv, struct mqnic_ring **ring_ptr);
int mqnic_activate_tx_ring(struct mqnic_priv *priv, struct mqnic_ring *ring, int cpl_index);
void mqnic_deactivate_tx_ring(struct mqnic_priv *priv, struct mqnic_ring *ring);
bool mqnic_is_tx_ring_empty(const struct mqnic_ring *ring);
bool mqnic_is_tx_ring_full(const struct mqnic_ring *ring);
void mqnic_tx_read_tail_ptr(struct mqnic_ring *ring);
void mqnic_tx_write_head_ptr(struct mqnic_ring *ring);
void mqnic_free_tx_desc(struct mqnic_priv *priv, struct mqnic_ring *ring, int index, int napi_budget);
int mqnic_free_tx_buf(struct mqnic_priv *priv, struct mqnic_ring *ring);
int mqnic_process_tx_cq(struct net_device *ndev, struct mqnic_cq_ring *cq_ring, int napi_budget);
void mqnic_tx_irq(struct mqnic_cq_ring *cq);
int mqnic_poll_tx_cq(struct napi_struct *napi, int budget);
netdev_tx_t mqnic_start_xmit(struct sk_buff *skb, struct net_device *dev);
// mqnic_rx.c
int mqnic_create_rx_ring(struct mqnic_priv *priv, struct mqnic_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr);
void mqnic_destroy_rx_ring(struct mqnic_priv *priv, struct mqnic_ring **ring_ptr);
int mqnic_activate_rx_ring(struct mqnic_priv *priv, struct mqnic_ring *ring, int cpl_index);
void mqnic_deactivate_rx_ring(struct mqnic_priv *priv, struct mqnic_ring *ring);
bool mqnic_is_rx_ring_empty(const struct mqnic_ring *ring);
bool mqnic_is_rx_ring_full(const struct mqnic_ring *ring);
void mqnic_rx_read_tail_ptr(struct mqnic_ring *ring);
void mqnic_rx_write_head_ptr(struct mqnic_ring *ring);
void mqnic_free_rx_desc(struct mqnic_priv *priv, struct mqnic_ring *ring, int index);
int mqnic_free_rx_buf(struct mqnic_priv *priv, struct mqnic_ring *ring);
int mqnic_prepare_rx_desc(struct mqnic_priv *priv, struct mqnic_ring *ring, int index);
void mqnic_refill_rx_buffers(struct mqnic_priv *priv, struct mqnic_ring *ring);
int mqnic_process_rx_cq(struct net_device *ndev, struct mqnic_cq_ring *cq_ring, int napi_budget);
void mqnic_rx_irq(struct mqnic_cq_ring *cq);
int mqnic_poll_rx_cq(struct napi_struct *napi, int budget);
// mqnic_ethtool.c
extern const struct ethtool_ops mqnic_ethtool_ops;
#endif /* MQNIC_H */
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
int mqnic_create_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr)
{
struct device *dev = priv->dev;
struct mqnic_cq_ring *ring;
int ret;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
{
dev_err(dev, "Failed to allocate CQ ring");
return -ENOMEM;
}
ring->ndev = priv->ndev;
ring->size = roundup_pow_of_two(size);
ring->size_mask = ring->size-1;
ring->stride = roundup_pow_of_two(stride);
ring->buf_size = ring->size*ring->stride;
ring->buf = dma_alloc_coherent(dev, ring->buf_size, &ring->buf_dma_addr, GFP_KERNEL);
if (!ring->buf)
{
dev_err(dev, "Failed to allocate CQ ring DMA buffer");
ret = -ENOMEM;
goto fail_ring;
}
ring->hw_addr = hw_addr;
ring->hw_ptr_mask = 0xffff;
ring->hw_head_ptr = hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG;
ring->hw_tail_ptr = hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG;
ring->head_ptr = 0;
ring->tail_ptr = 0;
// deactivate queue
iowrite32(0, ring->hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG);
// set base address
iowrite32(ring->buf_dma_addr, ring->hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+0);
iowrite32(ring->buf_dma_addr >> 32, ring->hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+4);
// set interrupt index
iowrite32(0, ring->hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG);
// set pointers
iowrite32(ring->head_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG);
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG);
// set size
iowrite32(ilog2(ring->size), ring->hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG);
*ring_ptr = ring;
return 0;
fail_ring:
kfree(ring);
*ring_ptr = NULL;
return ret;
}
void mqnic_destroy_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring **ring_ptr)
{
struct device *dev = priv->dev;
struct mqnic_cq_ring *ring = *ring_ptr;
*ring_ptr = NULL;
mqnic_deactivate_cq_ring(priv, ring);
dma_free_coherent(dev, ring->buf_size, ring->buf, ring->buf_dma_addr);
kfree(ring);
}
int mqnic_activate_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring *ring, int eq_index)
{
ring->eq_index = eq_index;
// deactivate queue
iowrite32(0, ring->hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG);
// set base address
iowrite32(ring->buf_dma_addr, ring->hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+0);
iowrite32(ring->buf_dma_addr >> 32, ring->hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+4);
// set interrupt index
iowrite32(eq_index, ring->hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG);
// set pointers
iowrite32(ring->head_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG);
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG);
// set size and activate queue
iowrite32(ilog2(ring->size) | MQNIC_CPL_QUEUE_ACTIVE_MASK, ring->hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG);
return 0;
}
void mqnic_deactivate_cq_ring(struct mqnic_priv *priv, struct mqnic_cq_ring *ring)
{
// deactivate queue
iowrite32(ilog2(ring->size), ring->hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG);
// disarm queue
iowrite32(ring->eq_index, ring->hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG);
}
bool mqnic_is_cq_ring_empty(const struct mqnic_cq_ring *ring)
{
return ring->head_ptr == ring->tail_ptr;
}
bool mqnic_is_cq_ring_full(const struct mqnic_cq_ring *ring)
{
return ring->head_ptr - ring->tail_ptr >= ring->size;
}
void mqnic_cq_read_head_ptr(struct mqnic_cq_ring *ring)
{
ring->head_ptr += (ioread32(ring->hw_head_ptr) - ring->head_ptr) & ring->hw_ptr_mask;
}
void mqnic_cq_write_tail_ptr(struct mqnic_cq_ring *ring)
{
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_tail_ptr);
}
void mqnic_arm_cq(struct mqnic_cq_ring *ring)
{
iowrite32(ring->eq_index | MQNIC_CPL_QUEUE_ARM_MASK, ring->hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG);
}
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
#include "mqnic_ioctl.h"
static int mqnic_open(struct inode *inode, struct file *filp)
{
struct mqnic_dev *mqnic;
mqnic = mqnic_find_by_minor(iminor(inode));
if (mqnic == NULL)
{
pr_err("Failed to locate mqnic for minor = %u.\n", iminor(inode));
return -ENODEV;
}
filp->private_data = mqnic;
return 0;
}
static int mqnic_release(struct inode *inode, struct file *filp)
{
//struct mqnic_dev *mqnic = filp->private_data;
return 0;
}
static int mqnic_map_registers(struct mqnic_dev *mqnic, struct vm_area_struct *vma)
{
struct device *dev = &mqnic->pdev->dev;
size_t map_size = vma->vm_end - vma->vm_start;
int ret;
if (map_size > mqnic->hw_regs_size)
{
dev_err(dev, "mqnic_map_registers: Tried to map registers region with wrong size %lu (expected <=%zu)", vma->vm_end - vma->vm_start, mqnic->hw_regs_size);
return -EINVAL;
}
ret = remap_pfn_range(vma, vma->vm_start, mqnic->hw_regs_phys >> PAGE_SHIFT, map_size, pgprot_noncached(vma->vm_page_prot));
if (ret)
{
dev_err(dev, "mqnic_map_registers: remap_pfn_range failed for registers region");
}
else
{
dev_dbg(dev, "mqnic_map_registers: Mapped registers region at phys: 0x%pap, virt: 0x%p", &mqnic->hw_regs_phys, (void *)vma->vm_start);
}
return ret;
}
static int mqnic_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct mqnic_dev *mqnic = filp->private_data;
struct device *dev = &mqnic->pdev->dev;
int ret;
if (vma->vm_pgoff == 0)
{
ret = mqnic_map_registers(mqnic, vma);
}
else
{
goto fail_invalid_offset;
}
return ret;
fail_invalid_offset:
dev_err(dev, "mqnic_mmap: Tried to map an unknown region at page offset %lu", vma->vm_pgoff);
return -EINVAL;
}
static long mqnic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct mqnic_dev *mqnic = filp->private_data;
if (_IOC_TYPE(cmd) != MQNIC_IOCTL_TYPE)
return -ENOTTY;
switch (cmd) {
case MQNIC_IOCTL_INFO:
{
struct mqnic_ioctl_info ctl;
ctl.fw_id = mqnic->fw_id;
ctl.fw_ver = mqnic->fw_ver;
ctl.board_id = mqnic->board_id;
ctl.board_ver = mqnic->board_ver;
ctl.regs_size = mqnic->hw_regs_size;
if (copy_to_user((void *)arg, &ctl, sizeof(ctl)) != 0)
return -EFAULT;
return 0;
}
default:
return -ENOTTY;
}
}
const struct file_operations mqnic_fops = {
.owner = THIS_MODULE,
.open = mqnic_open,
.release = mqnic_release,
.mmap = mqnic_mmap,
.unlocked_ioctl = mqnic_ioctl,
};
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr)
{
struct device *dev = priv->dev;
struct mqnic_eq_ring *ring;
int ret;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
{
dev_err(dev, "Failed to allocate EQ ring");
return -ENOMEM;
}
ring->ndev = priv->ndev;
ring->size = roundup_pow_of_two(size);
ring->size_mask = ring->size-1;
ring->stride = roundup_pow_of_two(stride);
ring->buf_size = ring->size*ring->stride;
ring->buf = dma_alloc_coherent(dev, ring->buf_size, &ring->buf_dma_addr, GFP_KERNEL);
if (!ring->buf)
{
dev_err(dev, "Failed to allocate EQ ring DMA buffer");
ret = -ENOMEM;
goto fail_ring;
}
ring->hw_addr = hw_addr;
ring->hw_ptr_mask = 0xffff;
ring->hw_head_ptr = hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG;
ring->hw_tail_ptr = hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG;
ring->head_ptr = 0;
ring->tail_ptr = 0;
// deactivate queue
iowrite32(0, ring->hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
// set base address
iowrite32(ring->buf_dma_addr, ring->hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+0);
iowrite32(ring->buf_dma_addr >> 32, ring->hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4);
// set interrupt index
iowrite32(0, ring->hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
// set pointers
iowrite32(ring->head_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG);
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG);
// set size
iowrite32(ilog2(ring->size), ring->hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
*ring_ptr = ring;
return 0;
fail_ring:
kfree(ring);
*ring_ptr = NULL;
return ret;
}
void mqnic_destroy_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr)
{
struct device *dev = priv->dev;
struct mqnic_eq_ring *ring = *ring_ptr;
*ring_ptr = NULL;
mqnic_deactivate_eq_ring(priv, ring);
dma_free_coherent(dev, ring->buf_size, ring->buf, ring->buf_dma_addr);
kfree(ring);
}
int mqnic_activate_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring *ring, int int_index)
{
ring->int_index = int_index;
// deactivate queue
iowrite32(0, ring->hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
// set base address
iowrite32(ring->buf_dma_addr, ring->hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+0);
iowrite32(ring->buf_dma_addr >> 32, ring->hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4);
// set interrupt index
iowrite32(int_index, ring->hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
// set pointers
iowrite32(ring->head_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG);
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG);
// set size and activate queue
iowrite32(ilog2(ring->size) | MQNIC_EVENT_QUEUE_ACTIVE_MASK, ring->hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
return 0;
}
void mqnic_deactivate_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring *ring)
{
// deactivate queue
iowrite32(ilog2(ring->size), ring->hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG);
// disarm queue
iowrite32(ring->int_index, ring->hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
}
bool mqnic_is_eq_ring_empty(const struct mqnic_eq_ring *ring)
{
return ring->head_ptr == ring->tail_ptr;
}
bool mqnic_is_eq_ring_full(const struct mqnic_eq_ring *ring)
{
return ring->head_ptr - ring->tail_ptr >= ring->size;
}
void mqnic_eq_read_head_ptr(struct mqnic_eq_ring *ring)
{
ring->head_ptr += (ioread32(ring->hw_head_ptr) - ring->head_ptr) & ring->hw_ptr_mask;
}
void mqnic_eq_write_tail_ptr(struct mqnic_eq_ring *ring)
{
iowrite32(ring->tail_ptr & ring->hw_ptr_mask, ring->hw_tail_ptr);
}
void mqnic_arm_eq(struct mqnic_eq_ring *ring)
{
iowrite32(ring->int_index | MQNIC_EVENT_QUEUE_ARM_MASK, ring->hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG);
}
void mqnic_process_eq(struct net_device *ndev, struct mqnic_eq_ring *eq_ring)
{
struct mqnic_priv *priv = netdev_priv(ndev);
struct mqnic_event *event;
u32 eq_index;
u32 eq_tail_ptr;
int done = 0;
if (unlikely(!priv->port_up))
{
return;
}
// read head pointer from NIC
mqnic_eq_read_head_ptr(eq_ring);
eq_tail_ptr = eq_ring->tail_ptr;
eq_index = eq_tail_ptr & eq_ring->size_mask;
while (eq_ring->head_ptr != eq_tail_ptr)
{
event = (struct mqnic_event *)(eq_ring->buf + eq_index*eq_ring->stride);
if (event->type == MQNIC_EVENT_TYPE_TX_CPL)
{
// transmit completion event
if (unlikely(event->source > priv->tx_cpl_queue_count))
{
dev_err(&priv->mdev->pdev->dev, "mqnic_process_eq on port %d: unknown event source %d (index %d, type %d)", priv->port, event->source, eq_index, event->type);
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 1, event, MQNIC_EVENT_SIZE, true);
}
else
{
struct mqnic_cq_ring *cq_ring = priv->tx_cpl_ring[event->source];
if (likely(cq_ring && cq_ring->handler))
{
cq_ring->handler(cq_ring);
}
}
}
else if (event->type == MQNIC_EVENT_TYPE_RX_CPL)
{
// receive completion event
if (unlikely(event->source > priv->rx_cpl_queue_count))
{
dev_err(&priv->mdev->pdev->dev, "mqnic_process_eq on port %d: unknown event source %d (index %d, type %d)", priv->port, event->source, eq_index, event->type);
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 1, event, MQNIC_EVENT_SIZE, true);
}
else
{
struct mqnic_cq_ring *cq_ring = priv->rx_cpl_ring[event->source];
if (likely(cq_ring && cq_ring->handler))
{
cq_ring->handler(cq_ring);
}
}
}
else
{
dev_err(&priv->mdev->pdev->dev, "mqnic_process_eq on port %d: unknown event type %d (index %d, source %d)", priv->port, event->type, eq_index, event->source);
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 1, event, MQNIC_EVENT_SIZE, true);
}
done++;
eq_tail_ptr++;
eq_index = eq_tail_ptr & eq_ring->size_mask;
}
// update eq tail
eq_ring->tail_ptr = eq_tail_ptr;
mqnic_eq_write_tail_ptr(eq_ring);
}
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
static void mqnic_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *drvinfo)
{
struct mqnic_priv *priv = netdev_priv(ndev);
struct mqnic_dev *mdev = priv->mdev;
strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, DRIVER_VERSION, sizeof(drvinfo->version));
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d", mdev->fw_ver >> 16, mdev->fw_ver & 0xffff);
strlcpy(drvinfo->bus_info, pci_name(mdev->pdev), sizeof(drvinfo->bus_info));
}
static int mqnic_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info)
{
struct mqnic_priv *priv = netdev_priv(ndev);
struct mqnic_dev *mdev = priv->mdev;
int ret;
ret = ethtool_op_get_ts_info(ndev, info);
if (ret)
return ret;
info->so_timestamping |=
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
info->rx_filters =
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_ALL);
if (mdev->ptp_clock)
info->phc_index = ptp_clock_index(mdev->ptp_clock);
return ret;
}
const struct ethtool_ops mqnic_ethtool_ops = {
.get_drvinfo = mqnic_get_drvinfo,
.get_ts_info = mqnic_get_ts_info
};
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#ifndef MQNIC_HW_H
#define MQNIC_HW_H
#include <linux/types.h>
#define MQNIC_MAX_IF 8
#define MQNIC_MAX_PORTS 8
#define MQNIC_MAX_SCHED 8
#define MQNIC_MAX_FRAGS 8
#define MQNIC_MAX_EVENT_RINGS 256
#define MQNIC_MAX_TX_RINGS 8192
#define MQNIC_MAX_TX_CPL_RINGS 8192
#define MQNIC_MAX_RX_RINGS 8192
#define MQNIC_MAX_RX_CPL_RINGS 8192
#define MQNIC_BOARD_ID_NETFPGA_SUME 0x10ee7028
#define MQNIC_BOARD_ID_VCU108 0x10ee806c
#define MQNIC_BOARD_ID_VCU118 0x10ee9076
#define MQNIC_BOARD_ID_VCU1525 0x10ee95f5
#define MQNIC_BOARD_ID_EXANIC_X10 0x1ce40003
#define MQNIC_BOARD_ID_EXANIC_X25 0x1ce40009
#define MQNIC_BOARD_ID_ADM_PCIE_9V3 0x41449003
// NIC CSRs
#define MQNIC_REG_FW_ID 0x0000
#define MQNIC_REG_FW_VER 0x0004
#define MQNIC_REG_BOARD_ID 0x0008
#define MQNIC_REG_BOARD_VER 0x000C
#define MQNIC_REG_PHC_COUNT 0x0010
#define MQNIC_REG_PHC_OFFSET 0x0014
#define MQNIC_REG_PHC_STRIDE 0x0018
#define MQNIC_REG_IF_COUNT 0x0020
#define MQNIC_REG_IF_STRIDE 0x0024
#define MQNIC_REG_IF_CSR_OFFSET 0x002C
#define MQNIC_REG_FPGA_ID 0x0040
#define MQNIC_REG_GPIO_OUT 0x0100
#define MQNIC_REG_GPIO_IN 0x0104
#define MQNIC_PHC_REG_FEATURES 0x0000
#define MQNIC_PHC_REG_PTP_CUR_FNS 0x0010
#define MQNIC_PHC_REG_PTP_CUR_NS 0x0014
#define MQNIC_PHC_REG_PTP_CUR_SEC_L 0x0018
#define MQNIC_PHC_REG_PTP_CUR_SEC_H 0x001C
#define MQNIC_PHC_REG_PTP_GET_FNS 0x0020
#define MQNIC_PHC_REG_PTP_GET_NS 0x0024
#define MQNIC_PHC_REG_PTP_GET_SEC_L 0x0028
#define MQNIC_PHC_REG_PTP_GET_SEC_H 0x002C
#define MQNIC_PHC_REG_PTP_SET_FNS 0x0030
#define MQNIC_PHC_REG_PTP_SET_NS 0x0034
#define MQNIC_PHC_REG_PTP_SET_SEC_L 0x0038
#define MQNIC_PHC_REG_PTP_SET_SEC_H 0x003C
#define MQNIC_PHC_REG_PTP_PERIOD_FNS 0x0040
#define MQNIC_PHC_REG_PTP_PERIOD_NS 0x0044
#define MQNIC_PHC_REG_PTP_NOM_PERIOD_FNS 0x0048
#define MQNIC_PHC_REG_PTP_NOM_PERIOD_NS 0x004C
#define MQNIC_PHC_REG_PTP_ADJ_FNS 0x0050
#define MQNIC_PHC_REG_PTP_ADJ_NS 0x0054
#define MQNIC_PHC_REG_PTP_ADJ_COUNT 0x0058
#define MQNIC_PHC_REG_PTP_ADJ_ACTIVE 0x005C
#define MQNIC_PHC_PEROUT_OFFSET 0x60
#define MQNIC_PHC_PEROUT_STRIDE 0x40
#define MQNIC_PHC_REG_PEROUT_CTRL 0x0000
#define MQNIC_PHC_REG_PEROUT_STATUS 0x0004
#define MQNIC_PHC_REG_PEROUT_START_FNS 0x0010
#define MQNIC_PHC_REG_PEROUT_START_NS 0x0014
#define MQNIC_PHC_REG_PEROUT_START_SEC_L 0x0018
#define MQNIC_PHC_REG_PEROUT_START_SEC_H 0x001C
#define MQNIC_PHC_REG_PEROUT_PERIOD_FNS 0x0020
#define MQNIC_PHC_REG_PEROUT_PERIOD_NS 0x0024
#define MQNIC_PHC_REG_PEROUT_PERIOD_SEC_L 0x0028
#define MQNIC_PHC_REG_PEROUT_PERIOD_SEC_H 0x002C
#define MQNIC_PHC_REG_PEROUT_WIDTH_FNS 0x0030
#define MQNIC_PHC_REG_PEROUT_WIDTH_NS 0x0034
#define MQNIC_PHC_REG_PEROUT_WIDTH_SEC_L 0x0038
#define MQNIC_PHC_REG_PEROUT_WIDTH_SEC_H 0x003C
// Interface CSRs
#define MQNIC_IF_REG_IF_ID 0x0000
#define MQNIC_IF_REG_IF_FEATURES 0x0004
#define MQNIC_IF_REG_EVENT_QUEUE_COUNT 0x0010
#define MQNIC_IF_REG_EVENT_QUEUE_OFFSET 0x0014
#define MQNIC_IF_REG_TX_QUEUE_COUNT 0x0020
#define MQNIC_IF_REG_TX_QUEUE_OFFSET 0x0024
#define MQNIC_IF_REG_TX_CPL_QUEUE_COUNT 0x0028
#define MQNIC_IF_REG_TX_CPL_QUEUE_OFFSET 0x002C
#define MQNIC_IF_REG_RX_QUEUE_COUNT 0x0030
#define MQNIC_IF_REG_RX_QUEUE_OFFSET 0x0034
#define MQNIC_IF_REG_RX_CPL_QUEUE_COUNT 0x0038
#define MQNIC_IF_REG_RX_CPL_QUEUE_OFFSET 0x003C
#define MQNIC_IF_REG_PORT_COUNT 0x0040
#define MQNIC_IF_REG_PORT_OFFSET 0x0044
#define MQNIC_IF_REG_PORT_STRIDE 0x0048
#define MQNIC_IF_FEATURE_RSS (1 << 0)
#define MQNIC_IF_FEATURE_PTP_TS (1 << 4)
#define MQNIC_IF_FEATURE_TX_CSUM (1 << 8)
#define MQNIC_IF_FEATURE_RX_CSUM (1 << 9)
#define MQNIC_IF_FEATURE_RX_HASH (1 << 10)
// Port CSRs
#define MQNIC_PORT_REG_PORT_ID 0x0000
#define MQNIC_PORT_REG_PORT_FEATURES 0x0004
#define MQNIC_PORT_REG_PORT_MTU 0x0008
#define MQNIC_PORT_REG_SCHED_COUNT 0x0010
#define MQNIC_PORT_REG_SCHED_OFFSET 0x0014
#define MQNIC_PORT_REG_SCHED_STRIDE 0x0018
#define MQNIC_PORT_REG_SCHED_TYPE 0x001C
#define MQNIC_PORT_REG_SCHED_ENABLE 0x0040
#define MQNIC_PORT_REG_RSS_MASK 0x0080
#define MQNIC_PORT_REG_TDMA_CTRL 0x0100
#define MQNIC_PORT_REG_TDMA_STATUS 0x0104
#define MQNIC_PORT_REG_TDMA_TIMESLOT_COUNT 0x0108
#define MQNIC_PORT_REG_TDMA_SCHED_START_FNS 0x0110
#define MQNIC_PORT_REG_TDMA_SCHED_START_NS 0x0114
#define MQNIC_PORT_REG_TDMA_SCHED_START_SEC_L 0x0118
#define MQNIC_PORT_REG_TDMA_SCHED_START_SEC_H 0x011C
#define MQNIC_PORT_REG_TDMA_SCHED_PERIOD_FNS 0x0120
#define MQNIC_PORT_REG_TDMA_SCHED_PERIOD_NS 0x0124
#define MQNIC_PORT_REG_TDMA_SCHED_PERIOD_SEC_L 0x0128
#define MQNIC_PORT_REG_TDMA_SCHED_PERIOD_SEC_H 0x012C
#define MQNIC_PORT_REG_TDMA_TIMESLOT_PERIOD_FNS 0x0130
#define MQNIC_PORT_REG_TDMA_TIMESLOT_PERIOD_NS 0x0134
#define MQNIC_PORT_REG_TDMA_TIMESLOT_PERIOD_SEC_L 0x0138
#define MQNIC_PORT_REG_TDMA_TIMESLOT_PERIOD_SEC_H 0x013C
#define MQNIC_PORT_REG_TDMA_ACTIVE_PERIOD_FNS 0x0140
#define MQNIC_PORT_REG_TDMA_ACTIVE_PERIOD_NS 0x0144
#define MQNIC_PORT_REG_TDMA_ACTIVE_PERIOD_SEC_L 0x0148
#define MQNIC_PORT_REG_TDMA_ACTIVE_PERIOD_SEC_H 0x014C
#define MQNIC_PORT_FEATURE_RSS (1 << 0)
#define MQNIC_PORT_FEATURE_PTP_TS (1 << 4)
#define MQNIC_PORT_FEATURE_TX_CSUM (1 << 8)
#define MQNIC_PORT_FEATURE_RX_CSUM (1 << 9)
#define MQNIC_PORT_FEATURE_RX_HASH (1 << 10)
#define MQNIC_QUEUE_STRIDE 0x00000020
#define MQNIC_CPL_QUEUE_STRIDE 0x00000020
#define MQNIC_EVENT_QUEUE_STRIDE 0x00000020
#define MQNIC_QUEUE_BASE_ADDR_REG 0x00
#define MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG 0x08
#define MQNIC_QUEUE_CPL_QUEUE_INDEX_REG 0x0C
#define MQNIC_QUEUE_HEAD_PTR_REG 0x10
#define MQNIC_QUEUE_TAIL_PTR_REG 0x18
#define MQNIC_QUEUE_ACTIVE_MASK 0x80000000
#define MQNIC_CPL_QUEUE_BASE_ADDR_REG 0x00
#define MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG 0x08
#define MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG 0x0C
#define MQNIC_CPL_QUEUE_HEAD_PTR_REG 0x10
#define MQNIC_CPL_QUEUE_TAIL_PTR_REG 0x18
#define MQNIC_CPL_QUEUE_ACTIVE_MASK 0x80000000
#define MQNIC_CPL_QUEUE_ARM_MASK 0x80000000
#define MQNIC_CPL_QUEUE_CONT_MASK 0x40000000
#define MQNIC_EVENT_QUEUE_BASE_ADDR_REG 0x00
#define MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG 0x08
#define MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG 0x0C
#define MQNIC_EVENT_QUEUE_HEAD_PTR_REG 0x10
#define MQNIC_EVENT_QUEUE_TAIL_PTR_REG 0x18
#define MQNIC_EVENT_QUEUE_ACTIVE_MASK 0x80000000
#define MQNIC_EVENT_QUEUE_ARM_MASK 0x80000000
#define MQNIC_EVENT_QUEUE_CONT_MASK 0x40000000
#define MQNIC_EVENT_TYPE_TX_CPL 0x0000
#define MQNIC_EVENT_TYPE_RX_CPL 0x0001
#define MQNIC_DESC_SIZE 16
#define MQNIC_CPL_SIZE 32
#define MQNIC_EVENT_SIZE 32
struct mqnic_desc {
__u16 rsvd0;
__u16 tx_csum_cmd;
__u32 len;
__u64 addr;
};
struct mqnic_cpl {
__u16 queue;
__u16 index;
__u16 len;
__u16 rsvd0;
__u32 ts_ns;
__u16 ts_s;
__u16 rx_csum;
__u32 rx_hash;
__u8 rx_hash_type;
__u8 rsvd1;
__u8 rsvd2;
__u8 rsvd3;
__u32 rsvd4;
__u32 rsvd5;
};
struct mqnic_event {
__u16 type;
__u16 source;
};
#endif /* MQNIC_HW_H */
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
void mqnic_i2c_set_scl(void *data, int state)
{
struct mqnic_i2c_priv *priv = data;
if (state)
{
iowrite32(ioread32(priv->scl_out_reg) | priv->scl_out_mask, priv->scl_out_reg);
}
else
{
iowrite32(ioread32(priv->scl_out_reg) & ~priv->scl_out_mask, priv->scl_out_reg);
}
}
void mqnic_i2c_set_sda(void *data, int state)
{
struct mqnic_i2c_priv *priv = data;
if (state)
{
iowrite32(ioread32(priv->sda_out_reg) | priv->sda_out_mask, priv->sda_out_reg);
}
else
{
iowrite32(ioread32(priv->sda_out_reg) & ~priv->sda_out_mask, priv->sda_out_reg);
}
}
int mqnic_i2c_get_scl(void *data)
{
struct mqnic_i2c_priv *priv = data;
return !!(ioread32(priv->scl_in_reg) & priv->scl_in_mask);
}
int mqnic_i2c_get_sda(void *data)
{
struct mqnic_i2c_priv *priv = data;
return !!(ioread32(priv->sda_in_reg) & priv->sda_in_mask);
}
static const struct i2c_algo_bit_data mqnic_i2c_algo = {
.setsda = mqnic_i2c_set_sda,
.setscl = mqnic_i2c_set_scl,
.getsda = mqnic_i2c_get_sda,
.getscl = mqnic_i2c_get_scl,
.udelay = 5,
.timeout = 20
};
static struct i2c_board_info mqnic_eeprom_info = {
I2C_BOARD_INFO("24c02", 0x50),
};
int mqnic_init_i2c(struct mqnic_dev *mqnic)
{
int ret = 0;
// interface i2c interfaces
// TODO
// eeprom i2c interface
switch (mqnic->board_id) {
case MQNIC_BOARD_ID_EXANIC_X10:
case MQNIC_BOARD_ID_EXANIC_X25:
case MQNIC_BOARD_ID_ADM_PCIE_9V3:
mqnic->eeprom_i2c_adap.owner = THIS_MODULE;
mqnic->eeprom_i2c_priv.mqnic = mqnic;
mqnic->eeprom_i2c_priv.scl_in_reg = mqnic->hw_addr+MQNIC_REG_GPIO_IN;
mqnic->eeprom_i2c_priv.scl_out_reg = mqnic->hw_addr+MQNIC_REG_GPIO_OUT;
mqnic->eeprom_i2c_priv.sda_in_reg = mqnic->hw_addr+MQNIC_REG_GPIO_IN;
mqnic->eeprom_i2c_priv.sda_out_reg = mqnic->hw_addr+MQNIC_REG_GPIO_OUT;
mqnic->eeprom_i2c_priv.scl_in_mask = 1 << 24;
mqnic->eeprom_i2c_priv.scl_out_mask = 1 << 24;
mqnic->eeprom_i2c_priv.sda_in_mask = 1 << 25;
mqnic->eeprom_i2c_priv.sda_out_mask = 1 << 25;
mqnic->eeprom_i2c_algo = mqnic_i2c_algo;
mqnic->eeprom_i2c_algo.data = &mqnic->eeprom_i2c_priv;
mqnic->eeprom_i2c_adap.algo_data = &mqnic->eeprom_i2c_algo;
mqnic->eeprom_i2c_adap.dev.parent = &mqnic->pdev->dev;
iowrite32(ioread32(mqnic->hw_addr+MQNIC_REG_GPIO_OUT) & ~(1 << 26), mqnic->hw_addr+MQNIC_REG_GPIO_OUT); // WP disable
strlcpy(mqnic->eeprom_i2c_adap.name, "mqnic EEPROM", sizeof(mqnic->eeprom_i2c_adap.name));
ret = i2c_bit_add_bus(&mqnic->eeprom_i2c_adap);
if (ret)
{
return ret;
}
mqnic->eeprom_i2c_client = i2c_new_device(&mqnic->eeprom_i2c_adap, &mqnic_eeprom_info);
if (mqnic->eeprom_i2c_client == NULL)
{
ret = -ENODEV;
}
break;
}
return ret;
}
void mqnic_remove_i2c(struct mqnic_dev *mqnic)
{
// eeprom i2c interface
if (mqnic->eeprom_i2c_client)
{
i2c_unregister_device(mqnic->eeprom_i2c_client);
mqnic->eeprom_i2c_client = NULL;
}
if (mqnic->eeprom_i2c_adap.owner)
{
i2c_del_adapter(&mqnic->eeprom_i2c_adap);
}
memset(&mqnic->eeprom_i2c_adap, 0, sizeof(mqnic->eeprom_i2c_adap));
}
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#ifndef MQNIC_IOCTL_H
#define MQNIC_IOCTL_H
#include <linux/types.h>
#define MQNIC_IOCTL_TYPE 0x88
#define MQNIC_IOCTL_INFO _IOR(MQNIC_IOCTL_TYPE, 0xf0, struct mqnic_ioctl_info)
struct mqnic_ioctl_info {
__u32 fw_id;
__u32 fw_ver;
__u32 board_id;
__u32 board_ver;
size_t regs_size;
};
#endif /* MQNIC_IOCTL_H */
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
#include "mqnic.h"
#include <linux/module.h>
#include <linux/version.h>
#include <linux/delay.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
#include <linux/pci-aspm.h>
#endif
MODULE_DESCRIPTION("mqnic driver");
MODULE_AUTHOR("Alex Forencich");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION(DRIVER_VERSION);
MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(0x1234, 0x1001) },
{ PCI_DEVICE(0x5543, 0x1001) },
{ 0 /* end */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static LIST_HEAD(mqnic_devices);
static DEFINE_SPINLOCK(mqnic_devices_lock);
static unsigned int mqnic_get_free_id(void)
{
struct mqnic_dev *mqnic;
unsigned int id = 0;
bool available = false;
while (!available)
{
available = true;
list_for_each_entry(mqnic, &mqnic_devices, dev_list_node)
{
if (mqnic->id == id)
{
available = false;
id++;
break;
}
}
}
return id;
}
struct mqnic_dev *mqnic_find_by_minor(unsigned minor)
{
struct mqnic_dev *mqnic;
spin_lock(&mqnic_devices_lock);
list_for_each_entry(mqnic, &mqnic_devices, dev_list_node)
if (mqnic->misc_dev.minor == minor)
goto done;
mqnic = NULL;
done:
spin_unlock(&mqnic_devices_lock);
return mqnic;
}
static irqreturn_t mqnic_interrupt(int irq, void *data)
{
struct mqnic_dev *mqnic = data;
struct mqnic_priv *priv;
int k, l;
for (k = 0; k < MQNIC_MAX_IF; k++)
{
if (!mqnic->ndev[k])
continue;
priv = netdev_priv(mqnic->ndev[k]);
if (unlikely(!priv->port_up))
continue;
for (l = 0; l < priv->event_queue_count; l++)
{
if (unlikely(!priv->event_ring[l]))
continue;
if (priv->event_ring[l]->irq == irq)
{
mqnic_process_eq(priv->ndev, priv->event_ring[l]);
mqnic_arm_eq(priv->event_ring[l]);
}
}
}
return IRQ_HANDLED;
}
static int mqnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret = 0;
struct mqnic_dev *mqnic;
struct device *dev = &pdev->dev;
int k = 0;
dev_info(dev, "mqnic probe");
if (!(mqnic = devm_kzalloc(dev, sizeof(*mqnic), GFP_KERNEL)))
{
return -ENOMEM;
}
mqnic->pdev = pdev;
pci_set_drvdata(pdev, mqnic);
mqnic->misc_dev.minor = MISC_DYNAMIC_MINOR;
// assign ID and add to list
spin_lock(&mqnic_devices_lock);
mqnic->id = mqnic_get_free_id();
list_add_tail(&mqnic->dev_list_node, &mqnic_devices);
spin_unlock(&mqnic_devices_lock);
snprintf(mqnic->name, sizeof(mqnic->name), DRIVER_NAME "%d", mqnic->id);
// Disable ASPM
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
// Enable device
ret = pci_enable_device_mem(pdev);
if (ret)
{
dev_err(dev, "Failed to enable PCI device");
goto fail_enable_device;
}
// Set mask
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret)
{
dev_warn(dev, "Warning: failed to set 64 bit PCI DMA mask");
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
{
dev_err(dev, "Failed to set PCI DMA mask");
goto fail_regions;
}
}
// Set max segment size
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
// Reserve regions
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret)
{
dev_err(dev, "Failed to reserve regions");
goto fail_regions;
}
mqnic->hw_regs_size = pci_resource_end(pdev, 0) - pci_resource_start(pdev, 0) + 1;
mqnic->hw_regs_phys = pci_resource_start(pdev, 0);
// Map BAR
mqnic->hw_addr = pci_ioremap_bar(pdev, 0);
if (!mqnic->hw_addr)
{
ret = -ENOMEM;
dev_err(dev, "Failed to map BARs");
goto fail_map_bars;
}
// Check if device needs to be reset
if (ioread32(mqnic->hw_addr) == 0xffffffff)
{
ret = -EIO;
dev_err(dev, "Deivce needs to be reset");
goto fail_map_bars;
}
// Read ID registers
mqnic->fw_id = ioread32(mqnic->hw_addr+MQNIC_REG_FW_ID);
dev_info(dev, "FW ID: 0x%08x", mqnic->fw_id);
mqnic->fw_ver = ioread32(mqnic->hw_addr+MQNIC_REG_FW_VER);
dev_info(dev, "FW version: %d.%d", mqnic->fw_ver >> 16, mqnic->fw_ver & 0xffff);
mqnic->board_id = ioread32(mqnic->hw_addr+MQNIC_REG_BOARD_ID);
dev_info(dev, "Board ID: 0x%08x", mqnic->board_id);
mqnic->board_ver = ioread32(mqnic->hw_addr+MQNIC_REG_BOARD_VER);
dev_info(dev, "Board version: %d.%d", mqnic->board_ver >> 16, mqnic->board_ver & 0xffff);
mqnic->phc_count = ioread32(mqnic->hw_addr+MQNIC_REG_PHC_COUNT);
dev_info(dev, "PHC count: %d", mqnic->phc_count);
mqnic->phc_offset = ioread32(mqnic->hw_addr+MQNIC_REG_PHC_OFFSET);
dev_info(dev, "PHC offset: 0x%08x", mqnic->phc_offset);
if (mqnic->phc_count)
mqnic->phc_hw_addr = mqnic->hw_addr+mqnic->phc_offset;
mqnic->if_count = ioread32(mqnic->hw_addr+MQNIC_REG_IF_COUNT);
dev_info(dev, "IF count: %d", mqnic->if_count);
mqnic->if_stride = ioread32(mqnic->hw_addr+MQNIC_REG_IF_STRIDE);
dev_info(dev, "IF stride: 0x%08x", mqnic->if_stride);
mqnic->if_csr_offset = ioread32(mqnic->hw_addr+MQNIC_REG_IF_CSR_OFFSET);
dev_info(dev, "IF CSR offset: 0x%08x", mqnic->if_csr_offset);
// Allocate MSI IRQs
mqnic->msi_nvecs = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
if (mqnic->msi_nvecs < 0)
{
dev_err(dev, "Failed to allocate IRQs");
goto fail_map_bars;
}
// Set up interrupts
for (k = 0; k < mqnic->msi_nvecs; k++)
{
ret = pci_request_irq(pdev, k, mqnic_interrupt, 0, mqnic, "mqnic%d-%d", mqnic->id, k);
if (ret < 0)
{
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
}
}
// Set up I2C interfaces
ret = mqnic_init_i2c(mqnic);
if (ret)
{
dev_err(dev, "Failed to register I2C interfaces");
goto fail_i2c;
}
// Read MAC from EEPROM
if (mqnic->eeprom_i2c_client)
{
ret = i2c_smbus_read_i2c_block_data(mqnic->eeprom_i2c_client, 0x00, 6, mqnic->base_mac);
if (ret < 0)
{
dev_warn(dev, "Failed to read MAC from EEPROM");
}
}
else
{
dev_warn(dev, "Failed to read MAC from EEPROM; no EEPROM I2C client registered");
}
// Enable bus mastering for DMA
pci_set_master(pdev);
// register PHC
if (mqnic->phc_count)
{
mqnic_register_phc(mqnic);
}
// Set up interfaces
if (mqnic->if_count > MQNIC_MAX_IF)
mqnic->if_count = MQNIC_MAX_IF;
for (k = 0; k < mqnic->if_count; k++)
{
dev_info(dev, "Creating interface %d", k);
ret = mqnic_init_netdev(mqnic, k, mqnic->hw_addr + k*mqnic->if_stride);
if (ret)
{
dev_err(dev, "Failed to create net_device");
goto fail_init_netdev;
}
}
mqnic->misc_dev.name = mqnic->name;
mqnic->misc_dev.fops = &mqnic_fops;
mqnic->misc_dev.parent = dev;
ret = misc_register(&mqnic->misc_dev);
if (ret)
{
dev_err(dev, "misc_register failed: %d\n", ret);
goto fail_miscdev;
}
pci_save_state(pdev);
mutex_init(&mqnic->state_lock);
// probe complete
return 0;
// error handling
fail_miscdev:
fail_init_netdev:
for (k = 0; k < MQNIC_MAX_IF; k++)
{
if (mqnic->ndev[k])
{
mqnic_destroy_netdev(mqnic->ndev[k]);
}
}
mqnic_unregister_phc(mqnic);
pci_clear_master(pdev);
fail_i2c:
mqnic_remove_i2c(mqnic);
for (k = 0; k < mqnic->msi_nvecs; k++)
{
pci_free_irq(pdev, k, mqnic);
}
fail_irq:
pci_free_irq_vectors(pdev);
fail_map_bars:
pci_iounmap(pdev, mqnic->hw_addr);
pci_release_regions(pdev);
fail_regions:
pci_disable_device(pdev);
fail_enable_device:
spin_lock(&mqnic_devices_lock);
list_del(&mqnic->dev_list_node);
spin_unlock(&mqnic_devices_lock);
return ret;
}
static void mqnic_remove(struct pci_dev *pdev)
{
struct mqnic_dev *mqnic;
struct device *dev = &pdev->dev;
int k = 0;
dev_info(dev, "mqnic remove");
if (!(mqnic = pci_get_drvdata(pdev))) {
return;
}
misc_deregister(&mqnic->misc_dev);
spin_lock(&mqnic_devices_lock);
list_del(&mqnic->dev_list_node);
spin_unlock(&mqnic_devices_lock);
for (k = 0; k < MQNIC_MAX_IF; k++)
{
if (mqnic->ndev[k])
{
mqnic_destroy_netdev(mqnic->ndev[k]);
}
}
mqnic_unregister_phc(mqnic);
pci_clear_master(pdev);
mqnic_remove_i2c(mqnic);
for (k = 0; k < mqnic->msi_nvecs; k++)
{
pci_free_irq(pdev, k, mqnic);
}
pci_free_irq_vectors(pdev);
pci_iounmap(pdev, mqnic->hw_addr);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static void mqnic_shutdown(struct pci_dev *pdev)
{
struct mqnic_dev *mqnic = pci_get_drvdata(pdev);
struct device *dev = &pdev->dev;
dev_info(dev, "mqnic shutdown");
if (!mqnic) {
return;
}
// ensure DMA is disabled on shutdown
pci_clear_master(pdev);
}
static struct pci_driver pci_driver = {
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = mqnic_probe,
.remove = mqnic_remove,
.shutdown = mqnic_shutdown
};
static int __init mqnic_init(void)
{
return pci_register_driver(&pci_driver);
}
static void __exit mqnic_exit(void)
{
pci_unregister_driver(&pci_driver);
}
module_init(mqnic_init);
module_exit(mqnic_exit);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/bin/bash -eux
SSH_USER=${SSH_USERNAME:-vagrant}
# Make sure udev does not block our network - http://6.ptmc.org/?p=164
echo "==> Cleaning up udev rules"
rm -rf /dev/.udev/
rm /lib/udev/rules.d/75-persistent-net-generator.rules
echo "==> Cleaning up leftover dhcp leases"
# Ubuntu 10.04
if [ -d "/var/lib/dhcp3" ]; then
rm /var/lib/dhcp3/*
fi
# Ubuntu 12.04 & 14.04
if [ -d "/var/lib/dhcp" ]; then
rm /var/lib/dhcp/*
fi
UBUNTU_VERSION=$(lsb_release -sr)
if [[ ${UBUNTU_VERSION} == 16.04 ]] || [[ ${UBUNTU_VERSION} == 16.10 ]]; then
# Modified version of
# https://github.com/cbednarski/packer-ubuntu/blob/master/scripts-1604/vm_cleanup.sh#L9-L15
# Instead of eth0 the interface is now called ens5 to mach the PCI
# slot, so we need to change the networking scripts to enable the
# correct interface.
#
# NOTE: After the machine is rebooted Packer will not be able to reconnect
# (Vagrant will be able to) so make sure this is done in your final
# provisioner.
sed -i "s/ens3/ens5/g" /etc/network/interfaces
fi
# Add delay to prevent "vagrant reload" from failing
echo "pre-up sleep 2" >> /etc/network/interfaces
echo "==> Cleaning up tmp"
rm -rf /tmp/*
# Cleanup apt cache
apt-get -y autoremove --purge
apt-get -y clean
apt-get -y autoclean
echo "==> Installed packages"
dpkg --get-selections | grep -v deinstall
DISK_USAGE_BEFORE_CLEANUP=$(df -h)
# Remove Bash history
unset HISTFILE
rm -f /root/.bash_history
rm -f /home/${SSH_USER}/.bash_history
# Clean up log files
find /var/log -type f | while read f; do echo -ne '' > "${f}"; done;
echo "==> Clearing last login information"
>/var/log/lastlog
>/var/log/wtmp
>/var/log/btmp
# NOTE: Shrinking is not part of the build process
# so this will only grow the image...
# # Whiteout root
# count=$(df --sync -kP / | tail -n1 | awk -F ' ' '{print $4}')
# let count--
# dd if=/dev/zero of=/tmp/whitespace bs=1024 count=$count
# rm /tmp/whitespace
# # Whiteout /boot
# count=$(df --sync -kP /boot | tail -n1 | awk -F ' ' '{print $4}')
# let count--
# dd if=/dev/zero of=/boot/whitespace bs=1024 count=$count
# rm /boot/whitespace
# echo '==> Clear out swap and disable until reboot'
# set +e
# swapuuid=$(/sbin/blkid -o value -l -s UUID -t TYPE=swap)
# case "$?" in
# 2|0) ;;
# *) exit 1 ;;
# esac
# set -e
# if [ "x${swapuuid}" != "x" ]; then
# # Whiteout the swap partition to reduce box size
# # Swap is disabled till reboot
# swappart=$(readlink -f /dev/disk/by-uuid/$swapuuid)
# /sbin/swapoff "${swappart}"
# dd if=/dev/zero of="${swappart}" bs=1M || echo "dd exit code $? is suppressed"
# /sbin/mkswap -U "${swapuuid}" "${swappart}"
# fi
# # Zero out the free space to save space in the final image
# dd if=/dev/zero of=/EMPTY bs=1M || echo "dd exit code $? is suppressed"
# rm -f /EMPTY
# # Make sure we wait until all the data is written to disk, otherwise
# # Packer might quite too early before the large files are deleted
# sync
# echo "==> Disk usage before cleanup"
# echo ${DISK_USAGE_BEFORE_CLEANUP}
# echo "==> Disk usage after cleanup"
# df -h
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment