Add LingYao

Change-Id: Iae6634ce565940904ee320c678d0f77473bebb90
This commit is contained in:
Jintao 2025-01-03 16:08:55 +08:00
parent 7e20319bfc
commit 50c46e6857
106 changed files with 75311 additions and 0 deletions

BIN
LingYaoSNIC/.DS_Store vendored

Binary file not shown.

1
LingYaoSNIC/HW/README.md Normal file
View File

@ -0,0 +1 @@
适配对接中移网络云华为虚拟层版本

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
{
"vswitch_cfg": {
"flow_merge_enable": 1,
"bond_info": {
"bus_name": "pci",
"prefix": "jmnd",
"linux-device": [],
"dpdk-device": "b1:00.0"
},
"vport_info": {
"bus_name": "vdev",
"prefix": "jmnd_vdpa_net_"
},
"upcall-queue": {
"vm-queue-total-num": 1020
},
"reinject-queue": {
"vm-queue-total-num": 1020
}
},
"global_cfg": {
"nic_type": "smart_nic",
"vnic_max_num": 255,
"vnic_queue_num": 2040,
"nic_driver_path": "/usr/lib64/librte_jmnd.so",
"vdpa_status": 2
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
890073cae9c0fae3edf42938e3dfd010 imu_flash_snic_cqaca.img
3c1d9cbab63b4aae0f406c706a307681 scp_flash_cqaca_n2_2.0g_cmn_1.65g.img

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
obj-m += vdpa.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/vdpa.Module.symvers
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod *.mod .*.cmd .tmp_versions .crete* -rf

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
obj-m += vhost_vdpa.o
vhost_vdpa-y := vdpa.o
obj-m += vhost.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
# # KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/vdpa.Module.symvers
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod *.mod .*.cmd .tmp_versions .crete* -rf

View File

@ -0,0 +1,325 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _VHOST_H
#define _VHOST_H
#include <linux/eventfd.h>
#include <linux/vhost.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/uio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
#include <linux/atomic.h>
#include <linux/vhost_iotlb.h>
#include <linux/irqbypass.h>
struct vhost_work;
typedef void (*vhost_work_fn_t)(struct vhost_work *work);
#define VHOST_WORK_QUEUED 1
struct vhost_work {
struct llist_node node;
vhost_work_fn_t fn;
unsigned long flags;
};
/* Poll a file (eventfd or socket) */
/* Note: there's nothing vhost specific about this structure. */
struct vhost_poll {
poll_table table;
wait_queue_head_t *wqh;
wait_queue_entry_t wait;
struct vhost_work work;
__poll_t mask;
struct vhost_dev *dev;
};
void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn);
void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work);
bool vhost_has_work(struct vhost_dev *dev);
void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
__poll_t mask, struct vhost_dev *dev);
int vhost_poll_start(struct vhost_poll *poll, struct file *file);
void vhost_poll_stop(struct vhost_poll *poll);
void vhost_poll_flush(struct vhost_poll *poll);
void vhost_poll_queue(struct vhost_poll *poll);
void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work);
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp);
struct vhost_log {
u64 addr;
u64 len;
};
enum vhost_uaddr_type {
VHOST_ADDR_DESC = 0,
VHOST_ADDR_AVAIL = 1,
VHOST_ADDR_USED = 2,
VHOST_NUM_ADDRS = 3,
};
struct vhost_vring_call {
struct eventfd_ctx *ctx;
struct irq_bypass_producer producer;
};
/* The virtqueue structure describes a queue attached to a device. */
struct vhost_virtqueue {
struct vhost_dev *dev;
/* The actual ring of buffers. */
struct mutex mutex;
unsigned int num;
vring_desc_t __user *desc;
vring_avail_t __user *avail;
vring_used_t __user *used;
const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS];
struct file *kick;
struct vhost_vring_call call_ctx;
struct eventfd_ctx *error_ctx;
struct eventfd_ctx *log_ctx;
struct vhost_poll poll;
/* The routine to call when the Guest pings us, or timeout. */
vhost_work_fn_t handle_kick;
/* Last available index we saw. */
u16 last_avail_idx;
/* Caches available index value from user. */
u16 avail_idx;
/* Last index we used. */
u16 last_used_idx;
/* Used flags */
u16 used_flags;
/* Last used index value we have signalled on */
u16 signalled_used;
/* Last used index value we have signalled on */
bool signalled_used_valid;
/* Log writes to used structure. */
bool log_used;
u64 log_addr;
struct iovec iov[UIO_MAXIOV];
struct iovec iotlb_iov[64];
struct iovec *indirect;
struct vring_used_elem *heads;
/* Protected by virtqueue mutex. */
struct vhost_iotlb *umem;
struct vhost_iotlb *iotlb;
void *private_data;
u64 acked_features;
u64 acked_backend_features;
/* Log write descriptors */
void __user *log_base;
struct vhost_log *log;
struct iovec log_iov[64];
/* Ring endianness. Defaults to legacy native endianness.
* Set to true when starting a modern virtio device. */
bool is_le;
#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
/* Ring endianness requested by userspace for cross-endian support. */
bool user_be;
#endif
u32 busyloop_timeout;
};
struct vhost_msg_node {
union {
struct vhost_msg msg;
struct vhost_msg_v2 msg_v2;
};
struct vhost_virtqueue *vq;
struct list_head node;
};
struct vhost_dev {
struct mm_struct *mm;
struct mutex mutex;
struct vhost_virtqueue **vqs;
int nvqs;
struct eventfd_ctx *log_ctx;
struct llist_head work_list;
struct task_struct *worker;
struct vhost_iotlb *umem;
struct vhost_iotlb *iotlb;
spinlock_t iotlb_lock;
struct list_head read_list;
struct list_head pending_list;
wait_queue_head_t wait;
int iov_limit;
int weight;
int byte_weight;
u64 kcov_handle;
bool use_worker;
int (*msg_handler)(struct vhost_dev *dev, u32 asid,
struct vhost_iotlb_msg *msg);
};
bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs,
int nvqs, int iov_limit, int weight, int byte_weight,
bool use_worker,
int (*msg_handler)(struct vhost_dev *dev, u32 asid,
struct vhost_iotlb_msg *msg));
long vhost_dev_set_owner(struct vhost_dev *dev);
bool vhost_dev_has_owner(struct vhost_dev *dev);
long vhost_dev_check_owner(struct vhost_dev *);
struct vhost_iotlb *vhost_dev_reset_owner_prepare(void);
void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_iotlb *iotlb);
void vhost_dev_cleanup(struct vhost_dev *);
void vhost_dev_stop(struct vhost_dev *);
long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp);
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp);
bool vhost_vq_access_ok(struct vhost_virtqueue *vq);
bool vhost_log_access_ok(struct vhost_dev *);
int vhost_get_vq_desc(struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
void vhost_discard_vq_desc(struct vhost_virtqueue *, int n);
bool vhost_vq_is_setup(struct vhost_virtqueue *vq);
int vhost_vq_init_access(struct vhost_virtqueue *);
int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
unsigned count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
unsigned int id, int len);
void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
struct vring_used_elem *heads, unsigned count);
void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_dev *, struct vhost_virtqueue *);
bool vhost_vq_avail_empty(struct vhost_dev *, struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
unsigned int log_num, u64 len,
struct iovec *iov, int count);
int vq_meta_prefetch(struct vhost_virtqueue *vq);
struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type);
void vhost_enqueue_msg(struct vhost_dev *dev,
struct list_head *head,
struct vhost_msg_node *node);
struct vhost_msg_node *vhost_dequeue_msg(struct vhost_dev *dev,
struct list_head *head);
void vhost_set_backend_features(struct vhost_dev *dev, u64 features);
__poll_t vhost_chr_poll(struct file *file, struct vhost_dev *dev,
poll_table *wait);
ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
int noblock);
ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
struct iov_iter *from);
int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled);
void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
struct vhost_iotlb_map *map);
#define vq_err(vq, fmt, ...) do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
if ((vq)->error_ctx) \
eventfd_signal((vq)->error_ctx, 1);\
} while (0)
enum {
VHOST_FEATURES = (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
(1ULL << VIRTIO_RING_F_EVENT_IDX) |
(1ULL << VHOST_F_LOG_ALL) |
(1ULL << VIRTIO_F_ANY_LAYOUT) |
(1ULL << VIRTIO_F_VERSION_1)
};
/**
* vhost_vq_set_backend - Set backend.
*
* @vq Virtqueue.
* @private_data The private data.
*
* Context: Need to call with vq->mutex acquired.
*/
static inline void vhost_vq_set_backend(struct vhost_virtqueue *vq,
void *private_data)
{
vq->private_data = private_data;
}
/**
* vhost_vq_get_backend - Get backend.
*
* @vq Virtqueue.
*
* Context: Need to call with vq->mutex acquired.
* Return: Private data previously set with vhost_vq_set_backend.
*/
static inline void *vhost_vq_get_backend(struct vhost_virtqueue *vq)
{
return vq->private_data;
}
static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit)
{
return vq->acked_features & (1ULL << bit);
}
static inline bool vhost_backend_has_feature(struct vhost_virtqueue *vq, int bit)
{
return vq->acked_backend_features & (1ULL << bit);
}
#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
{
return vq->is_le;
}
#else
static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
{
return virtio_legacy_is_little_endian() || vq->is_le;
}
#endif
/* Memory accessors */
static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val)
{
return __virtio16_to_cpu(vhost_is_little_endian(vq), val);
}
static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val)
{
return __cpu_to_virtio16(vhost_is_little_endian(vq), val);
}
static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val)
{
return __virtio32_to_cpu(vhost_is_little_endian(vq), val);
}
static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val)
{
return __cpu_to_virtio32(vhost_is_little_endian(vq), val);
}
static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val)
{
return __virtio64_to_cpu(vhost_is_little_endian(vq), val);
}
static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val)
{
return __cpu_to_virtio64(vhost_is_little_endian(vq), val);
}
#endif

View File

@ -0,0 +1,362 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_VDPA_H
#define _LINUX_VDPA_H
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/vhost_iotlb.h>
/**
* vDPA callback definition.
* @callback: interrupt callback function
* @private: the data passed to the callback function
*/
struct vdpa_callback {
irqreturn_t (*callback)(void *data);
void *private;
};
/**
* vDPA notification area
* @addr: base address of the notification area
* @size: size of the notification area
*/
struct vdpa_notification_area {
resource_size_t addr;
resource_size_t size;
};
/**
* struct vdpa_vq_state_split - vDPA split virtqueue state
* @avail_index: available index
*/
struct vdpa_vq_state_split {
u16 avail_index;
};
/**
* struct vdpa_vq_state_packed - vDPA packed virtqueue state
* @last_avail_counter: last driver ring wrap counter observed by device
* @last_avail_idx: device available index
* @last_used_counter: device ring wrap counter
* @last_used_idx: used index
*/
struct vdpa_vq_state_packed {
u16 last_avail_counter:1;
u16 last_avail_idx:15;
u16 last_used_counter:1;
u16 last_used_idx:15;
};
struct vdpa_vq_state {
union {
struct vdpa_vq_state_split split;
struct vdpa_vq_state_packed packed;
};
};
/**
* vDPA device - representation of a vDPA device
* @dev: underlying device
* @dma_dev: the actual device that is performing DMA
* @config: the configuration ops for this device.
* @index: device index
* @features_valid: were features initialized? for legacy guests
*/
struct vdpa_device {
struct device dev;
struct device *dma_dev;
const struct vdpa_config_ops *config;
unsigned int index;
bool features_valid;
int nvqs;
};
/**
* vDPA IOVA range - the IOVA range support by the device
* @first: start of the IOVA range
* @last: end of the IOVA range
*/
struct vdpa_iova_range {
u64 first;
u64 last;
};
/**
* vDPA_config_ops - operations for configuring a vDPA device.
* Note: vDPA device drivers are required to implement all of the
* operations unless it is mentioned to be optional in the following
* list.
*
* @set_vq_address: Set the address of virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @desc_area: address of desc area
* @driver_area: address of driver area
* @device_area: address of device area
* Returns integer: success (0) or error (< 0)
* @set_vq_num: Set the size of virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @num: the size of virtqueue
* @kick_vq: Kick the virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @set_vq_cb: Set the interrupt callback function for
* a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @cb: virtio-vdev interrupt callback structure
* @set_vq_ready: Set ready status for a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @ready: ready (true) not ready(false)
* @get_vq_ready: Get ready status for a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* Returns boolean: ready (true) or not (false)
* @set_vq_state: Set the state for a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @state: pointer to set virtqueue state (last_avail_idx)
* Returns integer: success (0) or error (< 0)
* @get_vq_state: Get the state for a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* @state: pointer to returned state (last_avail_idx)
* @get_vq_notification: Get the notification area for a virtqueue
* @vdev: vdpa device
* @idx: virtqueue index
* Returns the notifcation area
* @get_vq_irq: Get the irq number of a virtqueue (optional,
* but must implemented if require vq irq offloading)
* @vdev: vdpa device
* @idx: virtqueue index
* Returns int: irq number of a virtqueue,
* negative number if no irq assigned.
* @get_vq_align: Get the virtqueue align requirement
* for the device
* @vdev: vdpa device
* Returns virtqueue algin requirement
* @get_features: Get virtio features supported by the device
* @vdev: vdpa device
* Returns the virtio features support by the
* device
* @set_features: Set virtio features supported by the driver
* @vdev: vdpa device
* @features: feature support by the driver
* Returns integer: success (0) or error (< 0)
* @set_config_cb: Set the config interrupt callback
* @vdev: vdpa device
* @cb: virtio-vdev interrupt callback structure
* @get_vq_num_max: Get the max size of virtqueue
* @vdev: vdpa device
* Returns u16: max size of virtqueue
* @get_device_id: Get virtio device id
* @vdev: vdpa device
* Returns u32: virtio device id
* @get_vendor_id: Get id for the vendor that provides this device
* @vdev: vdpa device
* Returns u32: virtio vendor id
* @get_status: Get the device status
* @vdev: vdpa device
* Returns u8: virtio device status
* @set_status: Set the device status
* @vdev: vdpa device
* @status: virtio device status
* @get_config: Read from device specific configuration space
* @vdev: vdpa device
* @offset: offset from the beginning of
* configuration space
* @buf: buffer used to read to
* @len: the length to read from
* configuration space
* @set_config: Write to device specific configuration space
* @vdev: vdpa device
* @offset: offset from the beginning of
* configuration space
* @buf: buffer used to write from
* @len: the length to write to
* configuration space
* @get_generation: Get device config generation (optional)
* @vdev: vdpa device
* Returns u32: device generation
* @get_iova_range: Get supported iova range (optional)
* @vdev: vdpa device
* Returns the iova range supported by
* the device.
* @set_map: Set device memory mapping (optional)
* Needed for device that using device
* specific DMA translation (on-chip IOMMU)
* @vdev: vdpa device
* @iotlb: vhost memory mapping to be
* used by the vDPA
* Returns integer: success (0) or error (< 0)
* @dma_map: Map an area of PA to IOVA (optional)
* Needed for device that using device
* specific DMA translation (on-chip IOMMU)
* and preferring incremental map.
* @vdev: vdpa device
* @iova: iova to be mapped
* @size: size of the area
* @pa: physical address for the map
* @perm: device access permission (VHOST_MAP_XX)
* Returns integer: success (0) or error (< 0)
* @dma_unmap: Unmap an area of IOVA (optional but
* must be implemented with dma_map)
* Needed for device that using device
* specific DMA translation (on-chip IOMMU)
* and preferring incremental unmap.
* @vdev: vdpa device
* @iova: iova to be unmapped
* @size: size of the area
* Returns integer: success (0) or error (< 0)
* @free: Free resources that belongs to vDPA (optional)
* @vdev: vdpa device
*/
struct vdpa_config_ops {
/* Virtqueue ops */
int (*set_vq_address)(struct vdpa_device *vdev,
u16 idx, u64 desc_area, u64 driver_area,
u64 device_area);
void (*set_vq_num)(struct vdpa_device *vdev, u16 idx, u32 num);
void (*kick_vq)(struct vdpa_device *vdev, u16 idx);
void (*set_vq_cb)(struct vdpa_device *vdev, u16 idx,
struct vdpa_callback *cb);
void (*set_vq_ready)(struct vdpa_device *vdev, u16 idx, bool ready);
bool (*get_vq_ready)(struct vdpa_device *vdev, u16 idx);
int (*set_vq_state)(struct vdpa_device *vdev, u16 idx,
const struct vdpa_vq_state *state);
int (*get_vq_state)(struct vdpa_device *vdev, u16 idx,
struct vdpa_vq_state *state);
struct vdpa_notification_area
(*get_vq_notification)(struct vdpa_device *vdev, u16 idx);
/* vq irq is not expected to be changed once DRIVER_OK is set */
int (*get_vq_irq)(struct vdpa_device *vdv, u16 idx);
/* Device ops */
u32 (*get_vq_align)(struct vdpa_device *vdev);
u64 (*get_features)(struct vdpa_device *vdev);
int (*set_features)(struct vdpa_device *vdev, u64 features);
void (*set_config_cb)(struct vdpa_device *vdev,
struct vdpa_callback *cb);
u16 (*get_vq_num_max)(struct vdpa_device *vdev);
u32 (*get_device_id)(struct vdpa_device *vdev);
u32 (*get_vendor_id)(struct vdpa_device *vdev);
u8 (*get_status)(struct vdpa_device *vdev);
void (*set_status)(struct vdpa_device *vdev, u8 status);
void (*get_config)(struct vdpa_device *vdev, unsigned int offset,
void *buf, unsigned int len);
void (*set_config)(struct vdpa_device *vdev, unsigned int offset,
const void *buf, unsigned int len);
u32 (*get_generation)(struct vdpa_device *vdev);
struct vdpa_iova_range (*get_iova_range)(struct vdpa_device *vdev);
/* Migration ops */
int (*set_log_base)(struct vdpa_device *vdev, u64 log_base, u64 log_size);
/* DMA ops */
int (*set_map)(struct vdpa_device *vdev, struct vhost_iotlb *iotlb);
int (*dma_map)(struct vdpa_device *vdev, u64 iova, u64 size,
u64 pa, u32 perm);
int (*dma_unmap)(struct vdpa_device *vdev, u64 iova, u64 size);
/* Free device resources */
void (*free)(struct vdpa_device *vdev);
};
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
const struct vdpa_config_ops *config,
int nvqs,
size_t size);
#define vdpa_alloc_device(dev_struct, member, parent, config, nvqs) \
container_of(__vdpa_alloc_device( \
parent, config, nvqs, \
sizeof(dev_struct) + \
BUILD_BUG_ON_ZERO(offsetof( \
dev_struct, member))), \
dev_struct, member)
int vdpa_register_device(struct vdpa_device *vdev);
void vdpa_unregister_device(struct vdpa_device *vdev);
/**
* vdpa_driver - operations for a vDPA driver
* @driver: underlying device driver
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
*/
struct vdpa_driver {
struct device_driver driver;
int (*probe)(struct vdpa_device *vdev);
void (*remove)(struct vdpa_device *vdev);
};
#define vdpa_register_driver(drv) \
__vdpa_register_driver(drv, THIS_MODULE)
int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner);
void vdpa_unregister_driver(struct vdpa_driver *drv);
#define module_vdpa_driver(__vdpa_driver) \
module_driver(__vdpa_driver, vdpa_register_driver, \
vdpa_unregister_driver)
static inline struct vdpa_driver *drv_to_vdpa(struct device_driver *driver)
{
return container_of(driver, struct vdpa_driver, driver);
}
static inline struct vdpa_device *dev_to_vdpa(struct device *_dev)
{
return container_of(_dev, struct vdpa_device, dev);
}
static inline void *vdpa_get_drvdata(const struct vdpa_device *vdev)
{
return dev_get_drvdata(&vdev->dev);
}
static inline void vdpa_set_drvdata(struct vdpa_device *vdev, void *data)
{
dev_set_drvdata(&vdev->dev, data);
}
static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev)
{
return vdev->dma_dev;
}
static inline void vdpa_reset(struct vdpa_device *vdev)
{
const struct vdpa_config_ops *ops = vdev->config;
vdev->features_valid = false;
ops->set_status(vdev, 0);
}
static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features)
{
const struct vdpa_config_ops *ops = vdev->config;
vdev->features_valid = true;
return ops->set_features(vdev, features);
}
static inline void vdpa_get_config(struct vdpa_device *vdev, unsigned offset,
void *buf, unsigned int len)
{
const struct vdpa_config_ops *ops = vdev->config;
/*
* Config accesses aren't supposed to trigger before features are set.
* If it does happen we assume a legacy guest.
*/
if (!vdev->features_valid)
vdpa_set_features(vdev, 0);
ops->get_config(vdev, offset, buf, len);
}
#endif /* _LINUX_VDPA_H */

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
obj-m += vdpa.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/vdpa.Module.symvers
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install:
install -D -m 644 Module.symvers /lib/modules/$(shell uname -r)/extern-symvers/vdpa.symvers
clean:
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod *.mod .*.cmd .tmp_versions .crete* -rf

View File

@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* vDPA bus.
*
* Copyright (c) 2020, Red Hat. All rights reserved.
* Author: Jason Wang <jasowang@redhat.com>
*
*/
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/vdpa.h>
static DEFINE_IDA(vdpa_index_ida);
static int vdpa_dev_probe(struct device *d)
{
struct vdpa_device *vdev = dev_to_vdpa(d);
struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
int ret = 0;
if (drv && drv->probe)
ret = drv->probe(vdev);
return ret;
}
static int vdpa_dev_remove(struct device *d)
{
struct vdpa_device *vdev = dev_to_vdpa(d);
struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
if (drv && drv->remove)
drv->remove(vdev);
return 0;
}
static struct bus_type vdpa_bus = {
.name = "vdpa",
.probe = vdpa_dev_probe,
.remove = vdpa_dev_remove,
};
static void vdpa_release_dev(struct device *d)
{
struct vdpa_device *vdev = dev_to_vdpa(d);
const struct vdpa_config_ops *ops = vdev->config;
if (ops->free)
ops->free(vdev);
ida_simple_remove(&vdpa_index_ida, vdev->index);
kfree(vdev);
}
/**
* __vdpa_alloc_device - allocate and initilaize a vDPA device
* This allows driver to some prepartion after device is
* initialized but before registered.
* @parent: the parent device
* @config: the bus operations that is supported by this device
* @nvqs: number of virtqueues supported by this device
* @size: size of the parent structure that contains private data
*
* Driver should use vdpa_alloc_device() wrapper macro instead of
* using this directly.
*
* Returns an error when parent/config/dma_dev is not set or fail to get
* ida.
*/
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
const struct vdpa_config_ops *config,
int nvqs,
size_t size)
{
struct vdpa_device *vdev;
int err = -EINVAL;
if (!config)
goto err;
if (!!config->dma_map != !!config->dma_unmap)
goto err;
err = -ENOMEM;
vdev = kzalloc(size, GFP_KERNEL);
if (!vdev)
goto err;
err = ida_simple_get(&vdpa_index_ida, 0, 0, GFP_KERNEL);
if (err < 0)
goto err_ida;
vdev->dev.bus = &vdpa_bus;
vdev->dev.parent = parent;
vdev->dev.release = vdpa_release_dev;
vdev->index = err;
vdev->config = config;
vdev->features_valid = false;
vdev->nvqs = nvqs;
err = dev_set_name(&vdev->dev, "vdpa%u", vdev->index);
if (err)
goto err_name;
device_initialize(&vdev->dev);
return vdev;
err_name:
ida_simple_remove(&vdpa_index_ida, vdev->index);
err_ida:
kfree(vdev);
err:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(__vdpa_alloc_device);
/**
* vdpa_register_device - register a vDPA device
* Callers must have a succeed call of vdpa_alloc_device() before.
* @vdev: the vdpa device to be registered to vDPA bus
*
* Returns an error when fail to add to vDPA bus
*/
int vdpa_register_device(struct vdpa_device *vdev)
{
return device_add(&vdev->dev);
}
EXPORT_SYMBOL_GPL(vdpa_register_device);
/**
* vdpa_unregister_device - unregister a vDPA device
* @vdev: the vdpa device to be unregisted from vDPA bus
*/
void vdpa_unregister_device(struct vdpa_device *vdev)
{
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL_GPL(vdpa_unregister_device);
/**
* __vdpa_register_driver - register a vDPA device driver
* @drv: the vdpa device driver to be registered
* @owner: module owner of the driver
*
* Returns an err when fail to do the registration
*/
int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner)
{
drv->driver.bus = &vdpa_bus;
drv->driver.owner = owner;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(__vdpa_register_driver);
/**
* vdpa_unregister_driver - unregister a vDPA device driver
* @drv: the vdpa device driver to be unregistered
*/
void vdpa_unregister_driver(struct vdpa_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(vdpa_unregister_driver);
static int vdpa_init(void)
{
return bus_register(&vdpa_bus);
}
static void __exit vdpa_exit(void)
{
bus_unregister(&vdpa_bus);
ida_destroy(&vdpa_index_ida);
}
core_initcall(vdpa_init);
module_exit(vdpa_exit);
MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
obj-m += vhost_vdpa.o
vhost_vdpa-y := vdpa.o
obj-m += vhost.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/
# KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
# # KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/vdpa.Module.symvers
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod *.mod .*.cmd .tmp_versions .crete* -rf

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
kernel-crete-front-driver 目录:
说明:
云豹内核pf驱动+vdpa驱动
编译方式:
sh build_nic.sh anolis_kernel龙蜥系统编译
sh build_nic.sh openeuler_kernel 欧拉系统编译
sh build_nic.sh all 编译所有驱动
编译产出物:
crete_core.ko 基础通道驱动
crete_pnic.ko pf驱动
jm_auxiliary.ko auxiliary驱动
crete_vdpa.ko vdpa驱动

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2023, Jaguar Micro. All rights reserved.
#!/usr/bin/env bash
function build_core() {
pushd crete-core
make clean
make
make install
popd
}
function build_vnet() {
pushd crete-vnet
make clean
make
popd
}
build_core
build_vnet

View File

@ -0,0 +1,136 @@
# SPDX-License-Identifier: GPL-2.0
#!/bin/bash
# common build rules useful for out-of-tree Linux driver builds
#
distro_info_dict=(/etc/anolis-release \
/etc/bclinux-release \
/etc/openEuler-release)
OS_KEY=""
distro_version=""
exit_not_found_failure() { exit 3; }
find_distro_info()
{
# Save the first valid kernel source path
for file in "${distro_info_dict[@]}"; do
if [ -f ${file} ]; then
distro_version=${file}
break
fi
done
}
get_os_key()
{
if [ -z "${distro_version}" ]; then
CFLAGS_KEY=""
return
fi
distro_info=`cat ${distro_version}`
if [ -z "${distro_info}" ]; then
echo "cat ${distro_info} is null"
fi
case $distro_info in
"Anolis OS release 8.8")
echo "You system is Anolis OS release 8.8"
OS_KEY="anolis-8.8"
CFLAGS_KEY="-DSNIC_ANOLIS_VERSION14"
;;
"Anolis OS release 8.6")
echo "You system is Anolis OS release 8.6"
OS_KEY="anolis-8.6"
CFLAGS_KEY="-DSNIC_ANOLIS_VERSION14"
;;
"BigCloud Enterprise Linux release 21.10U4 LTS")
echo "You system is BigCloud Enterprise Linux release 21.10U4 LTS"
OS_KEY="bclinux-21.10U4"
CFLAGS_KEY="-DBCLINUX2110U4"
;;
*)
echo "You system is $distro_info"
CFLAGS_KEY=""
OS_KEY="default"
;;
esac
}
usage() {
echo "Usage: $0 [all | anolis_kernel | openeuler_kernel | clean]"
echo "all : build all kernels"
echo "anolis_kernel : build snic with anolis 5.10.134-14"
echo "openeuler_kernel : build snic with openeuler 5.10.0-136.12"
echo "clean : clean the anolis the kernel"
exit 1
}
if [ $# -eq 0 ]; then
usage
fi
find_distro_info
get_os_key
case "$1" in
anolis_kernel)
echo "Build nic modules"
echo "build crete core modules"
cd crete-core
make EXTRA_CFLAGS="-DSNIC_ANOLIS_VERSION14"
make install
cd ..
echo "build crete pnic modules"
cd crete-pnic
make EXTRA_CFLAGS="-DSNIC_ANOLIS_VERSION14"
;;
openeuler_kernel)
echo "Build nic modules"
echo "build crete core modules"
cd crete-core
make clean
make EXTRA_CFLAGS="-DSNIC_OPENEULER_VERSION136"
make install
cd ..
echo "build crete pnic modules"
cd crete-pnic
make clean
make EXTRA_CFLAGS="-DSNIC_OPENEULER_VERSION136"
cd ../
echo "build crete vdpa modules"
cd crete-vnet
./build_euler.sh
;;
all)
echo "Build nic modules"
echo "build crete core modules"
echo "EXTRA_CFLAGS is $CFLAGS_KEY"
cd crete-core
make clean
make EXTRA_CFLAGS=$CFLAGS_KEY
cd ..
echo "build crete pnic modules"
cd crete-pnic
make clean
make EXTRA_CFLAGS=$CFLAGS_KEY
;;
clean)
echo "Clean build dir ......"
cd crete-core
make clean
cd ..
cd crete-pnic
make clean
;;
*)
usage
;;
esac
echo "Building kernel..."
echo "Building kernel..."

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: GPL-2.0
# EXTRA_CFLAGS += -DCONFIG_NOSIM_DEBUG
KBUILD :=/lib/modules/$(shell uname -r)/build
ifeq ($(KERNELRELEASE), )
DRIVER := crete_core
COMMON_MK ?= $(wildcard common.mk)
ifeq (${COMMON_MK},)
$(error Cannot find common.mk build rules)
else
include ${COMMON_MK}
endif
all:
+$(call kernelbuild,modules)
clean:
+$(call kernelbuild,clean)
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod .*.cmd .tmp_versions -rf
install:
install -D -m 644 Module.symvers /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
auxiliary_info:
@./scripts/check_aux_bus.sh --verbose --ksrc="${KSRC}" --build-kernel="${BUILD_KERNEL}"
ifeq (${NEED_AUX_BUS},1)
all: auxiliary_info
endif
else
ifeq (${NEED_AUX_BUS},2)
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
export KBUILD_EXTRA_SYMBOLS
endif
obj-m := crete_core.o
crete_core-y := crete.o \
crete_rdma_dev.o \
crete_rdma_adapt.o \
crete_aux_dev.o \
crete_cmd.o \
crete_cmd_if.o \
crete_txrx.o \
crete_event.o \
crete_sriov.o \
crete_eswitch.o \
crete_devlink.o \
crete_dcb_nl.o \
crete_sriov_sysfs.o \
crete_ptp.o \
crete_stub.o \
crete_ethtool.o \
crete_eswoffloads.o \
crete_fw_update.o \
crete_pldmfw_lib.o \
crete_rep.o \
crete_core_debugfs.o \
crete_lag.o \
crete_lag_debugfs.o \
crete_debugfs_statistics.o
endif

View File

@ -0,0 +1,28 @@
编译提示:
SIM环境编译时需关闭CONFIG_NOSIM_DEBUG
内核模拟环境调试需打开CONFIG_NOSIM_DEBUG
默认关闭:CONFIG_NOSIM_DEBUG
定义后端编号为idx的tx q的控制寄存器
0x1000 + (idx * 0x100) 最多8个
定义后端编号为idx的tx q的描述符长度寄存器
0x1004 + (idx * 0x100)
定义描述符地址lo寄存器
0x1008 + idx * 0x100
定义描述符地址hi寄存器
0x100c + idx * 0x100
定义doorbell寄存器
0x1010 + idx * 0x100
定义中断使能寄存器 0x3000 + (idx * 0x10)
增加netlink套接字用于后续用户态调试
测试用例详见ssh://git@bit.jaguarmicro.com:7999/~foryun.ma/shell_kernel_test.git 中,test_netlink函数

View File

@ -0,0 +1,433 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2023, Jaguar Micro. All rights reserved.
#
# common Makefile rules useful for out-of-tree Linux driver builds
#
# Usage: include filename.mk
#
# After including, you probably want to add a minimum_kver_check call
#
# Required Variables:
# DRIVER
# -- Set to the lowercase driver name
#####################
# Helpful functions #
#####################
readlink = $(shell readlink -f ${1})
# helper functions for converting kernel version to version codes
get_kver = $(or $(word ${2},$(subst ., ,${1})),0)
get_kvercode = $(shell [ "${1}" -ge 0 -a "${1}" -le 255 2>/dev/null ] && \
[ "${2}" -ge 0 -a "${2}" -le 255 2>/dev/null ] && \
[ "${3}" -ge 0 -a "${3}" -le 255 2>/dev/null ] && \
printf %d $$(( ( ${1} << 16 ) + ( ${2} << 8 ) + ( ${3} ) )) )
################
# depmod Macro #
################
cmd_depmod = /sbin/depmod $(if ${SYSTEM_MAP_FILE},-e -F ${SYSTEM_MAP_FILE}) \
$(if $(strip ${INSTALL_MOD_PATH}),-b ${INSTALL_MOD_PATH}) \
-a ${KVER}
################
# dracut Macro #
################
cmd_initrd := $(shell \
if which dracut > /dev/null 2>&1 ; then \
echo "dracut --force"; \
elif which update-initramfs > /dev/null 2>&1 ; then \
echo "update-initramfs -u"; \
fi )
#####################
# Environment tests #
#####################
DRIVER_UPPERCASE := $(shell echo ${DRIVER} | tr "[:lower:]" "[:upper:]")
ifeq (,${BUILD_KERNEL})
BUILD_KERNEL=$(shell uname -r)
endif
# Kernel Search Path
# All the places we look for kernel source
KSP := /lib/modules/${BUILD_KERNEL}/source \
/lib/modules/${BUILD_KERNEL}/build \
/usr/src/linux-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/-.*//') \
/usr/src/kernel-headers-${BUILD_KERNEL} \
/usr/src/kernel-source-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux \
/usr/src/kernels/${BUILD_KERNEL} \
/usr/src/kernels \
${KBUILD}
# prune the list down to only values that exist and have an include/linux
# sub-directory. We can't use include/config because some older kernels don't
# have this.
test_dir = $(shell [ -e ${dir}/include/linux ] && echo ${dir})
KSP := $(foreach dir, ${KSP}, ${test_dir})
# we will use this first valid entry in the search path
ifeq (,${KSRC})
KSRC := $(firstword ${KSP})
endif
ifeq (,${KSRC})
$(warning *** Kernel header files not in any of the expected locations.)
$(warning *** Install the appropriate kernel development package, e.g.)
$(error kernel-devel, for building kernel modules and try again)
else
ifeq (/lib/modules/${BUILD_KERNEL}/source, ${KSRC})
KOBJ := /lib/modules/${BUILD_KERNEL}/build
else
KOBJ := ${KSRC}
endif
endif
SCRIPT_PATH := ${KSRC}/scripts
# Version file Search Path
VSP := ${KOBJ}/include/generated/utsrelease.h \
${KOBJ}/include/linux/utsrelease.h \
${KOBJ}/include/linux/version.h \
${KOBJ}/include/generated/uapi/linux/version.h \
/boot/vmlinuz.version.h
# Config file Search Path
CSP := ${KOBJ}/include/generated/autoconf.h \
${KOBJ}/include/linux/autoconf.h \
/boot/vmlinuz.autoconf.h
# System.map Search Path (for depmod)
MSP := ${KSRC}/System.map \
/usr/lib/debug/boot/System.map-${BUILD_KERNEL} \
/boot/System.map-${BUILD_KERNEL}
# prune the lists down to only files that exist
test_file = $(shell [ -f ${1} ] && echo ${1})
VSP := $(foreach file, ${VSP}, $(call test_file,${file}))
CSP := $(foreach file, ${CSP}, $(call test_file,${file}))
MSP := $(foreach file, ${MSP}, $(call test_file,${file}))
# and use the first valid entry in the Search Paths
ifeq (,${VERSION_FILE})
VERSION_FILE := $(firstword ${VSP})
endif
ifeq (,${CONFIG_FILE})
CONFIG_FILE := $(firstword ${CSP})
endif
ifeq (,${SYSTEM_MAP_FILE})
SYSTEM_MAP_FILE := $(firstword ${MSP})
endif
ifeq (,$(wildcard ${VERSION_FILE}))
$(error Linux kernel source not configured - missing version header file)
endif
ifeq (,$(wildcard ${CONFIG_FILE}))
$(error Linux kernel source not configured - missing autoconf.h)
endif
ifeq (,$(wildcard ${SYSTEM_MAP_FILE}))
$(warning Missing System.map file - depmod will not check for missing symbols during module installation)
endif
ifneq ($(words $(subst :, ,$(CURDIR))), 1)
$(error Sources directory '$(CURDIR)' cannot contain spaces nor colons. Rename directory or move sources to another path)
endif
########################
# Extract config value #
########################
get_config_value = $(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
grep -m 1 ${1} | awk '{ print $$3 }')
#######################
# Linux Version Setup #
#######################
# The following command line parameter is intended for development of KCOMPAT
# against upstream kernels such as net-next which have broken or non-updated
# version codes in their Makefile. They are intended for debugging and
# development purpose only so that we can easily test new KCOMPAT early. If you
# don't know what this means, you do not need to set this flag. There is no
# arcane magic here.
# Convert LINUX_VERSION into LINUX_VERSION_CODE
ifneq (${LINUX_VERSION},)
LINUX_VERSION_CODE=$(call get_kvercode,$(call get_kver,${LINUX_VERSION},1),$(call get_kver,${LINUX_VERSION},2),$(call get_kver,${LINUX_VERSION},3))
endif
# Honor LINUX_VERSION_CODE
ifneq (${LINUX_VERSION_CODE},)
$(warning Forcing target kernel to build with LINUX_VERSION_CODE of ${LINUX_VERSION_CODE}$(if ${LINUX_VERSION}, from LINUX_VERSION=${LINUX_VERSION}). Do this at your own risk.)
KVER_CODE := ${LINUX_VERSION_CODE}
EXTRA_CFLAGS += -DLINUX_VERSION_CODE=${LINUX_VERSION_CODE}
endif
# Determine SLE_KERNEL_REVISION for SuSE SLE >= 11 (needed by kcompat)
# This assumes SuSE will continue setting CONFIG_LOCALVERSION to the string
# appended to the stable kernel version on which their kernel is based with
# additional versioning information (up to 3 numbers), a possible abbreviated
# git SHA1 commit id and a kernel type, e.g. CONFIG_LOCALVERSION=-1.2.3-default
# or CONFIG_LOCALVERSION=-999.gdeadbee-default
# SLE >= 15SP3 added additional information about version and service pack
# to their kernel version e.g CONFIG_LOCALVERSION=-150300.59.43.1-default
#
# SLE_LOCALVERSION_CODE is also exported to support legacy kcompat.h
# definitions.
ifeq (1,$(call get_config_value,CONFIG_SUSE_KERNEL))
ifneq (10,$(call get_config_value,CONFIG_SLE_VERSION))
CONFIG_LOCALVERSION := $(call get_config_value,CONFIG_LOCALVERSION)
LOCALVERSION := $(shell echo ${CONFIG_LOCALVERSION} | \
cut -d'-' -f2 | sed 's/\.g[[:xdigit:]]\{7\}//')
LOCALVER_A := $(shell echo ${LOCALVERSION} | cut -d'.' -f1)
ifeq ($(shell test ${LOCALVER_A} -gt 65535; echo $$?),0)
LOCAL_VER_MAJOR := $(shell echo ${LOCALVER_A:0:3})
LOCAL_VER_MINOR := $(shell echo ${LOCALVER_A:3:3})
LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
LOCALVER_D := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f4)
SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_B} \* 65536 + \
0${LOCALVER_C} \* 256 + 0${LOCALVER_D})
EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
EXTRA_CFLAGS += -DSLE_KERNEL_REVISION=${LOCALVER_B}
else
LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_A} \* 65536 + \
0${LOCALVER_B} \* 256 + 0${LOCALVER_C})
EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
EXTRA_CFLAGS += -DSLE_KERNEL_REVISION=${LOCALVER_A}
endif
endif
endif
# Check if it is Oracle Linux UEK kernel and take release patch number from it
ifneq (,$(findstring uek,${BUILD_KERNEL}))
EXTRAVERSION := $(shell echo ${BUILD_KERNEL} | cut -s -d '-' -f2-)
UEK_RELEASE_NUMBER := $(shell echo ${EXTRAVERSION} | cut -s -d '.' -f1)
UEK_MINOR_RELEASE_NUMBER := $(shell echo ${EXTRAVERSION} | cut -s -d '.' -f2)
EXTRA_CFLAGS += -DUEK_RELEASE_NUMBER=${UEK_RELEASE_NUMBER}
EXTRA_CFLAGS += -DUEK_MINOR_RELEASE_NUMBER=${UEK_MINOR_RELEASE_NUMBER}
endif
EXTRA_CFLAGS += ${CFLAGS_EXTRA}
# get the kernel version - we use this to find the correct install path
KVER := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VERSION_FILE} | grep UTS_RELEASE | \
awk '{ print $$3 }' | sed 's/\"//g')
# assume source symlink is the same as build, otherwise adjust KOBJ
ifneq (,$(wildcard /lib/modules/${KVER}/build))
ifneq (${KSRC},$(call readlink,/lib/modules/${KVER}/build))
KOBJ=/lib/modules/${KVER}/build
endif
endif
ifeq (${KVER_CODE},)
KVER_CODE := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VSP} 2> /dev/null |\
grep -m 1 LINUX_VERSION_CODE | awk '{ print $$3 }' | sed 's/\"//g')
endif
# minimum_kver_check
#
# helper function to provide uniform output for different drivers to abort the
# build based on kernel version check. Usage: "$(call minimum_kver_check,2,6,XX)".
define _minimum_kver_check
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,${1},${2},${3}) ]; echo "$$?"))
$$(warning *** Aborting the build.)
$$(error This driver is not supported on kernel versions older than ${1}.${2}.${3})
endif
endef
minimum_kver_check = $(eval $(call _minimum_kver_check,${1},${2},${3}))
#############################
# kcompat definitions setup #
#############################
# In most cases, kcompat flags can be checked within the driver source files
# using simple CPP checks. However, it may be necessary to check for a flag
# value within the Makefile for some specific edge cases. For example, if an
# entire feature ought to be excluded on some kernels due to missing
# functionality.
#
# To support this, kcompat_defs.h is compiled and converted into a word list
# that can be checked to determine whether a given kcompat feature flag will
# be defined for this kernel.
#
# KCOMPAT_DEFINITIONS holds the set of all macros which are defined. Note
# this does include a large number of standard/builtin definitions.
#
# Use is_kcompat_defined as a $(call) function to check whether a given flag
# is defined or undefined. For example:
#
# ifeq ($(call is_kcompat_defined,HAVE_FEATURE_FLAG),1)
#
# ifneq ($(call is_kcompat_defined,HAVE_FEATURE_FLAG),1)
#
# The is_kcompat_defined function returns 1 if the macro name is defined,
# and the empty string otherwise.
#
# There is no mechanism to extract the value of the kcompat definition.
# Supporting this would be non-trivial as Make does not have a map variable
# type.
#
# Note that only the new layout is supported. Legacy definitions in
# kcompat.h are not supported. If you need to check one of these, please
# refactor it into the new layout.
ifneq ($(wildcard ./kcompat_defs.h),)
KCOMPAT_DEFINITIONS := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM \
-I${KOBJ}/include \
-I${KOBJ}/include/generated/uapi \
kcompat_defs.h | awk '{ print $$2 }')
is_kcompat_defined = $(if $(filter ${1},${KCOMPAT_DEFINITIONS}),1,)
else
KCOMPAT_DEFINITIONS :=
is_kcompat_defined =
endif
################
# Manual Pages #
################
MANSECTION = 7
ifeq (,${MANDIR})
# find the best place to install the man page
MANPATH := $(shell (manpath 2>/dev/null || echo $MANPATH) | sed 's/:/ /g')
ifneq (,${MANPATH})
# test based on inclusion in MANPATH
test_dir = $(findstring ${dir}, ${MANPATH})
else
# no MANPATH, test based on directory existence
test_dir = $(shell [ -e ${dir} ] && echo ${dir})
endif
# our preferred install path
# should /usr/local/man be in here ?
MANDIR := /usr/share/man /usr/man
MANDIR := $(foreach dir, ${MANDIR}, ${test_dir})
MANDIR := $(firstword ${MANDIR})
endif
ifeq (,${MANDIR})
# fallback to /usr/man
MANDIR := /usr/man
endif
####################
# CCFLAGS variable #
####################
# set correct CCFLAGS variable for kernels older than 2.6.24
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,2,6,24) ]; echo $$?))
CCFLAGS_VAR := EXTRA_CFLAGS
else
CCFLAGS_VAR := ccflags-y
endif
#################
# KBUILD_OUTPUT #
#################
# Only set KBUILD_OUTPUT if the real paths of KOBJ and KSRC differ
ifneq ($(call readlink,${KSRC}),$(call readlink,${KOBJ}))
export KBUILD_OUTPUT ?= ${KOBJ}
endif
############################
# Module Install Directory #
############################
# Default to using updates/drivers/net/ethernet/jm/ path, since depmod since
# v3.1 defaults to checking updates folder first, and only checking kernels/
# and extra afterwards. We use updates instead of kernel/* due to desire to
# prevent over-writing built-in modules files.
export INSTALL_MOD_DIR ?= updates/drivers/net/ethernet/jm/${DRIVER}
#################
# Auxiliary Bus #
#################
# If the check_aux_bus script exists, then this driver depends on the
# auxiliary module. Run the script to determine if we need to include
# auxiliary files with this build.
CHECK_AUX_BUS ?= ./scripts/check_aux_bus.sh
ifneq ($(call test_file,${CHECK_AUX_BUS}),)
NEED_AUX_BUS := $(shell ${CHECK_AUX_BUS} --ksrc="${KSRC}" --build-kernel="${BUILD_KERNEL}" >/dev/null 2>&1; echo $$?)
endif # check_aux_bus exists
# The out-of-tree auxiliary module we ship should be moved into this
# directory as part of installation.
export INSTALL_AUX_DIR ?= updates/drivers/net/ethernet/jm/auxiliary
# If we're installing auxiliary bus out-of-tree, the following steps are
# necessary to ensure the relevant files get put in place.
AUX_BUS_HEADER ?= linux/auxiliary_bus.h
ifeq (${NEED_AUX_BUS},2)
define auxiliary_post_install
install -D -m 644 Module.symvers ${INSTALL_MOD_PATH}/lib/modules/${KVER}/extern-symvers/jm_auxiliary.symvers
install -d ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_AUX_DIR}
install -D -m 644 jm_auxiliary.ko ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_AUX_DIR}/
install -D -m 644 ${AUX_BUS_HEADER} ${INSTALL_MOD_PATH}/${KSRC}/include/linux/auxiliary_bus.h
endef
else
auxiliary_post_install =
endif
ifeq (${NEED_AUX_BUS},2)
define auxiliary_post_uninstall
rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/extern-symvers/jm_auxiliary.symvers
rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_AUX_DIR}/jm_auxiliary.ko
rm -f ${INSTALL_MOD_PATH}/${KSRC}/include/linux/auxiliary_bus.h
endef
else
auxiliary_post_uninstall =
endif
ifeq (${NEED_AUX_BUS},2)
EXTRA_CFLAGS += -DUSE_JM_AUX_BUS
endif
######################
# Kernel Build Macro #
######################
# kernel build function
# ${1} is the kernel build target
# ${2} may contain any extra rules to pass directly to the sub-make process
#
# This function is expected to be executed by
# @+$(call kernelbuild,<target>,<extra parameters>)
# from within a Makefile recipe.
#
# The following variables are expected to be defined for its use:
# CCFLAGS_VAR -- the CCFLAGS variable to set extra CFLAGS
# EXTRA_CFLAGS -- a set of extra CFLAGS to pass into the ccflags-y variable
# KSRC -- the location of the kernel source tree to build against
# DRIVER_UPPERCASE -- the uppercase name of the kernel module, set from DRIVER
# W -- if set, enables the W= kernel warnings options
# C -- if set, enables the C= kernel sparse build options
#
kernelbuild = ${MAKE} ${CCFLAGS_VAR}="${EXTRA_CFLAGS}" \
-C "${KSRC}" \
CONFIG_${DRIVER_UPPERCASE}=m \
M="${CURDIR}" \
$(if ${W},W="${W}") \
$(if ${C},C="${C}") \
$(if ${NEED_AUX_BUS},NEED_AUX_BUS="${NEED_AUX_BUS}") \
${2} ${1}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,736 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_H_
#define _CRETE_H_
#include <linux/pci.h>
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/bitops.h>
#include <linux/if_vlan.h>
#include <linux/version.h>
#include <net/dst_metadata.h>
#ifndef USE_JM_AUX_BUS
#include <linux/auxiliary_bus.h>
#else
#include "linux/auxiliary_bus.h"
#endif
#include "kcompat_std_defs.h"
#include "rdma.h"
#include "crete_txrx.h"
#include "crete_sriov.h"
#include "crete_eswitch.h"
#include "crete_dcb_nl.h"
#include "crete_lag.h"
#include "crete_debugfs_statistics.h"
/*micro filed*/
#define MAX_MSIX_ENTRIES 10
#define MAX_Q_VECTORS 8
#define CRETE_MAX_TX_QUEUES 8
#define CRETE_MAX_RX_QUEUES 8
#define CRETE_DEFAULT_TXD 256
#define CRETE_DEFAULT_TX_WORK 128
#define CRETE_MIN_TXD 80
#define CRETE_MAX_TXD 4096
#define CRETE_DEFAULT_RXD 256
#define CRETE_MIN_RXD 80
#define CRETE_MAX_RXD 4096
#define CRETE_DEFAULT_ITR 3 /* dynamic */
#define CRETE_MAX_ITR_USECS 10000
#define CRETE_MIN_ITR_USECS 10
#define CRETE_Q_VECTORS 1
#define CRETE_ETH_PKT_HDR_PAD (ETH_HLEN + ETH_FCS_LEN)
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
#define MAX_JUMBO_FRAME_SIZE 0x2600
#define MAX_STD_JUMBO_FRAME_SIZE 9216
/* Supported Rx Buffer Sizes */
#define CRETE_RXBUFFER_256 256
#define CRETE_RXBUFFER_1536 1536
#define CRETE_RXBUFFER_2048 2048
#define CRETE_TS_HDR_LEN 16
#define ALIGN_TO_DW(a) (((a) + 3ULL) & (~3))
#define CRETE_CMD_WQ_MAX_NAME 32
/* device desc offset */
#define CRETE_JDH_OFFSET (CRETE_LEGACY_RESV)
#define CRETE_JND_OFFSET (CRETE_JDH_OFFSET + sizeof(struct crete_desc_hdr))
#define CRETE_JRD_OFFSET (CRETE_JND_OFFSET + sizeof(struct crete_ndc_dpt))
#define CRETE_CAP_OFFSET 8
enum {
CRETE_FLAG_DISABLE_ALL_ADEV = 1 << 0,
CRETE_PAGE_MODE = 1 << 1,
CRETE_FLAG_HAS_MSIX = 1 << 13,
};
#define CRETE_LEGACY_RESV 0x0
#define CRETE_MAGIC_NUM 0xdeadbeef
#define CRETE_EVENT_VECTOR 0
#define CRETE_CMD_DATA_BLOCK_SIZE 512
enum crete_coredev_type {
CRETE_COREDEV_PF,
CRETE_COREDEV_VF,
CRETE_COREDEV_SF,
};
enum crete_device_type {
CRETE_DEVICE_CRETE,
CRETE_DEVICE_PNIC,
CRETE_DEVICE_RNIC,
CRETE_DEVICE_FAKE,
};
enum {
CRETE_PCI_DEV_IS_VF = 1 << 0,
};
#define CRETE_ADEV_NAME "crete_core"
/*enum filed*/
enum crete_state_t {
__CRETE_TESTING,
__CRETE_RESETING,
__CRETE_DOWN,
};
/* Device Capability type */
enum crete_cap_type {
CRETE_NET_CONF_CAP = 2,
CRETE_RDMA_CONF_CAP = 3,
CRETE_OFFLOAD_CONF_CAP = 4,
CRETE_RES_CONF_CAP = 5,
CRETE_DEVS_CONF_CAP = 6,
CRETE_SHARES_DB_CAP = 7,
CRETE_CAP_MAX,
};
struct crete_init_seg {
uint16_t fw_ver_minor;
uint16_t fw_ver_major;
uint16_t fw_revision;
uint16_t cmd_interface_rev;
uint8_t cp_status;
uint8_t cp_caps;
uint8_t dev_status;
uint8_t reset_dev;
uint32_t cmd_path_db;
uint32_t cmd_path_entry[16];
uint32_t resv1[8];
uint32_t event_buffer[8];
uint32_t event_buffer_addr_low;
uint32_t event_buffer_addr_hi;
uint8_t event_busy;
uint8_t event_buffer_size;
uint16_t event_vector;
uint32_t event_credit_doorbell;
uint16_t resv2;
uint16_t aq_queue_size;
uint32_t aq_queue_db;
uint32_t aq_base_addr_low;
uint32_t aq_base_addr_hi;
uint32_t shared_res_lock;
uint32_t shared_res_db;
uint32_t extra_admin_db;
uint32_t resv3[13];
uint32_t timestamp[2];
} __packed;
struct cmd_info {
uint32_t owner:1;
uint32_t out_inline:1;
uint32_t in_inline:1;
uint32_t event_notify:1;
uint32_t status:4;
uint32_t sig:8;
uint32_t cmd_encap_type:8;
uint32_t cid:8;
};
struct crete_cmd_entry {
uint32_t in_len;
uint32_t out_len;
uint64_t in_ptr;
uint64_t out_ptr;
uint8_t inline_data[36];
union {
struct cmd_info cmd_info;
uint32_t cmd_info_data;
};
} __packed;
struct crete_cmd_prot_block {
u8 sig;
u8 block_num;
u8 rsvd0;
u8 cid;
uint32_t cmd_data_len;//CRETE_CMD_DATA_BLOCK_SIZE
uint64_t next;
uint32_t next_len;
uint32_t cmd_data[];
} __packed;
struct crete_cmd_mailbox {
void *buf;
dma_addr_t dma;
struct crete_cmd_mailbox *next;
};
struct crete_cmd_msg {
struct list_head list;
u32 msg_mode;
u32 len;
struct crete_cmd_mailbox *next;
u8 inline_data[36]; //inline bd Optimize todo
}__aligned(8);
#define CRETE_MAX_COMMANDS 32
struct crete_cmd_work_ent {
unsigned long state;
struct crete_cmd_msg *inb;
struct crete_cmd_msg *outb;
void *out;
int out_size;
int idx;
struct completion handling;
struct completion done;
struct crete_cmd *cmd;
struct work_struct work;
struct crete_cmd_entry *lay;
int ret;
u8 status;//fw return cmd status
u16 cmd_id;
bool polling;
u64 ts1;
u64 ts2;
/* Track the max comp handlers */
refcount_t refcnt;
};
struct crete_cmd {
struct crete_nb nb;
u8 mode;
u8 poll_mode;
void *cmd_buf;
dma_addr_t cmd_dma;
u32 cmd_size;
u32 cmd_stride;
struct dma_pool *pool;
int max_cmds;
unsigned long bitmask;
char wq_name[CRETE_CMD_WQ_MAX_NAME];
struct workqueue_struct *wq;
struct semaphore sem;
spinlock_t alloc_lock;
struct crete_cmd_work_ent *ent_arr[CRETE_MAX_COMMANDS];
};
/* for test qp create */
struct crete_qbase_info {
void *va;
dma_addr_t pa;
};
struct crete_queue_info {
uint8_t rx_qid;
uint16_t q_size;
uint16_t vec[2];
struct crete_qbase_info sq[2];
struct crete_qbase_info cq[2];
};
/*
*Device Capability Descriptor
*Device Capability Descriptor Header
*/
struct crete_desc_hdr {
uint32_t magic;
uint32_t cap_cnt:8;
uint32_t len:12;
uint32_t offset:12;
};
// net device configuration descriptor,cap_type = 2
struct crete_ndc_dpt {
uint32_t type:8;
uint32_t resv:24;
uint32_t len:12;
uint32_t offset:20;
};
// Rdma Device Configuration Descriptor,cap_type = 3
struct crete_rdma_cfg_desc {
uint32_t cap_type:8;
uint32_t resv:24;
uint32_t len:12;
uint32_t offset:20;
};
// Offload Configuration Descriptor,cap_type = 4
struct crete_offload_cfg_desc {
uint32_t cap_type:8;
uint32_t resv:24;
uint32_t len:12;
uint32_t offset:20;
};
// resource configuration descriptor,cap_type = 5
struct crete_rc_dpt {
uint32_t type:8;
uint32_t ru_size:12;
uint32_t ru_max:12;
uint32_t len:12;
uint32_t offset:20;
};
//Device-specific Configuration Descriptor,cap_type = 6
struct crete_devs_dpt {
uint32_t cap_type:8;
uint32_t resv:24;
uint32_t len:12;
uint32_t offset:20;
};
//Shared Data Descriptor,cap_type = 7
struct crete_shared_dpt {
uint32_t cap_type:8;
uint32_t len:24;
uint32_t offset;
};
/* hw */
struct crete_hw {
struct crete_init_seg __iomem *io_addr;
struct crete_desc_hdr jdh;
struct crete_ndc_dpt jnd;
struct crete_rdma_cfg_desc rdma_desc;
struct crete_offload_cfg_desc offload_desc;
struct crete_rc_dpt jrd;
struct crete_devs_dpt dev_spec_desc;
struct crete_shared_dpt share_data_desc;
};
struct crete_aux_dev {
struct crete_core_dev *core_dev;
struct auxiliary_device adev;
int idx;
};
#define CRETE_MAX_UC_ADDRS 4
#define CRETE_MAX_MC_ADDRS 16
#define L2_SET_RX_MASK_REQ_MASK_MCAST 0x1UL
#define L2_SET_RX_MASK_REQ_MASK_ALL_MCAST 0x2UL
#define L2_SET_RX_MASK_REQ_MASK_BCAST 0x4UL
#define L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS 0x8UL
struct crete_priv {
struct crete_core_dev *coredev;
struct crete_esw_rep *rep;
struct net_device *netdev;
struct workqueue_struct *wq;
struct work_struct set_rx_mode_work;
struct crete_dcbx dcbx;
struct crete_dcbx_dp dcbx_dp;
/* vport rx mode */
u32 rx_mask;
__le64 fw_l2_filter_id[CRETE_MAX_UC_ADDRS];
/* index 0 always dev_addr */
u16 uc_filter_count;
u8 *uc_list;
u8 *mc_list;
int mc_list_size;
int mc_list_count;
int vlan_range_num;
};
struct crete_debugfs_entries {
struct dentry *dbg_root;
struct dentry *lag_debugfs;
struct dentry *statistics_debugfs;
};
struct crete_irq_info {
char name[IFNAMSIZ + 2];
irq_handler_t handler;
unsigned int vector;
u8 requested:1;
u8 have_cpumask:1;
};
struct crete_pf_info {
u16 fw_fid;
u16 port_id;
u8 mac_addr[ETH_ALEN];
u32 first_vf_id;
u16 active_vfs;
u16 registered_vfs;
u16 max_vfs;
void *hwrm_cmd_req_addr[4];
dma_addr_t hwrm_cmd_req_dma_addr[4];
struct crete_vf_info *vf;
struct kobject *config;
struct kobject *groups_config;
struct crete_sriov_vf_sysfs *vf_sysfs;
};
struct rdma_dev_adapt {
unsigned int flags;
unsigned int priv_flags;
unsigned int bar_offset;
unsigned int bar_len;
phys_addr_t uar_base;
unsigned int uar_size;
void __iomem *reg_addr; /*bar addr*/
__le32 *cmd_db_reg; /* cmd db addr*/
__le32 __iomem *eq_db_reg;
struct mutex intf_state_mutex;
unsigned int vector_base;
unsigned int vector_num;
};
struct crete_qp_context {
__le16 rx_qid; /* must be even */
__le16 event_credit;
__le16 rx_sq_vq_size; /* vnet rx vq size */
__le16 rx_cq_size; /* unless for vnet */
__le16 tx_sq_vq_size; /* tx vq size for vnet */
__le16 tx_cq_size; /* useless for vnet */
__le16 rx_queue_vec; /* rx queue interrupt vector */
__le16 tx_queue_vec; /* tx queue interrupt vector */
__le64 rx_sq_desc_base; /* rx queue desc base address for vnet */
__le64 rx_cq_used_base; /* rx cq address ,rx used ring address for vnet */
__le64 tx_sq_desc_base; /* tx sq address, tx queue desc address for vnet */
__le64 tx_cq_used_base; /* tx cq address, tx queue used ring address for vnet */
};
struct crete_queue_context {
__le16 qid; /* must be even */
__le16 queue_size; /* vnet io vq size */
__le16 cq_size; /* vnet cq size */
__le16 queue_vec; /*queue interrupt vector */
__le16 resv; /*reserved */
__le64 queue_desc_base; /* rx queue desc base address for vnet */
__le64 queue_used_base; /* rx cq address ,rx used ring address for vnet */
};
struct crete_core_qpcap {
u16 max_queue_size;
u8 max_qp_num;
u8 ctrl_queue_size;
};
struct crete_core_cap {
struct crete_core_qpcap qpcap;
__le64 hw_features;
__le64 driver_features;
// pf core cap need more
};
struct crete_qp_cap {
u8 ctrl_queue_size;
u8 max_qp_num;
__le16 max_queue_size;
} __packed;
struct crete_txq_stats {
struct u64_stats_sync syncp;
u64 packets;
u64 bytes;
u64 kicks;
};
struct crete_rxq_stats {
struct u64_stats_sync syncp;
u64 packets;
u64 bytes;
u64 drops;
u64 kicks;
};
#define CRETE_TXQ_STATS(m) offsetof(struct crete_txq_stats, m)
#define CRETE_RXQ_STATS(m) offsetof(struct crete_rxq_stats, m)
struct crete_core_dev {
#define CRETE_MAX_MSIX_NUM 4096U
spinlock_t lock;
struct device *device;
void __iomem *db_base;
struct pci_dev *pdev;
struct crete_core_cap cap;
struct crete_txring_info *txring;
u16 *txring_mapping;
// u16 txring_size;
struct crete_rxring_info *rxring;
u16 *rxring_mapping;
// u16 rxring_size;
u16 ring_size;
// ring parameters
u32 rx_buf_size;
u32 rx_buf_use_size; /* useable size */
u16 rx_offset;
u16 rx_dma_offset;
struct crete_db *db;
//struct crete_core_cap *cap;
struct crete_napi *jnapi;
struct crete_rxcp_ring_info *rxcpring;
struct crete_txcp_ring_info *txcpring;
u16 max_qp_num;
unsigned long state;
struct net_device *netdev;
u64 netdev_features;
u64 offload_features;
unsigned int flags;
u32 rss_queues;
u8 __iomem *io_addr;
phys_addr_t bar_addr; //for further consider
struct crete_hw hw;
struct crete_queue_info q_info; // for create qp test
struct crete_aux_dev **adev;
int adev_idx;
struct crete_irq_info *irq_info;
struct crete_cmd cmd;
struct crete_event_irq *event_irq;
u16 irq_num;
unsigned long irqbit[BITS_TO_LONGS(CRETE_MAX_MSIX_NUM)];
struct msix_entry *msix_ent;
enum crete_coredev_type coredev_type;
enum crete_device_type device_type;
struct crete_pf_info pf;
struct crete_vf_info vf;
bool sriov_cfg;
struct jm_rdma_core rdma_coredev;
struct rdma_dev_adapt rdma_adp;
struct crete_eswitch *eswitch;
struct crete_lag_cap lag_cap;
struct crete_debugfs_entries dbg;
struct crete_lag *lag_dev;
struct crete_debugfs_statistics *debugfs_statis;
u16 sfi_id;
u16 lag_enable;
};
enum crete_feature_type {
CRETE_FEATURE_NETDEV,
CRETE_FEATURE_OFFLOAD
};
static inline unsigned int crete_rd32(struct crete_core_dev *p, u32 reg)
{
u8 __iomem *ioaddr = READ_ONCE(p->io_addr);
u32 value = 0;
value = readl(&ioaddr[reg]);
return value;
}
static inline void crete_ioread32(void __iomem *addr, void *buffer,
unsigned int count)
{
int i = 0;
u32 *buf = buffer;
u8 __iomem *address = addr;
if (count) {
for (i = 0; i < count; i++)
readsl(address + i * 4, buf++, 1);
}
}
static inline void crete_iowrite32(void __iomem *addr, void *buffer,
unsigned int count)
{
int i = 0;
u32 *buf = buffer;
u8 __iomem *address = addr;
if (count) {
for (i = 0; i < count; i++)
writesl(address + i * 4, buf++, 1);
}
}
static inline struct device *crete_hw_to_dev(struct crete_hw *hw)
{
struct crete_core_dev *core_dev = container_of(hw, struct crete_core_dev, hw);
return &core_dev->pdev->dev;
}
int crete_adev_idx_alloc(void);
void crete_adev_idx_free(int idx);
static inline bool crete_sriov_is_enabled(struct crete_core_dev *dev)
{
return pci_num_vf(dev->pdev) ? true : false;
}
static inline bool crete_core_is_pf(const struct crete_core_dev *dev)
{
return dev->coredev_type == CRETE_COREDEV_PF;
}
static inline bool crete_core_is_vf(const struct crete_core_dev *dev)
{
return dev->coredev_type == CRETE_COREDEV_VF;
}
static inline bool crete_have_rdma_cap(const struct crete_core_dev *dev)
{
return dev->hw.rdma_desc.cap_type == CRETE_RDMA_CONF_CAP;
}
static inline bool crete_have_net_cap(const struct crete_core_dev *dev)
{
return dev->hw.jnd.type == CRETE_NET_CONF_CAP;
}
static inline u16 fw_ver_maj(struct crete_core_dev *dev)
{
struct crete_hw *hw = &dev->hw;
return readw(&hw->io_addr->fw_ver_major);
}
static inline u16 fw_ver_min(struct crete_core_dev *dev)
{
struct crete_hw *hw = &dev->hw;
return readw(&hw->io_addr->fw_ver_minor);
}
static inline u16 fw_ver_sub(struct crete_core_dev *dev)
{
struct crete_hw *hw = &dev->hw;
return readw(&hw->io_addr->cmd_interface_rev);
}
static inline u16 fw_ver_rev(struct crete_core_dev *dev)
{
struct crete_hw *hw = &dev->hw;
return readw(&hw->io_addr->fw_revision);
}
int crete_req_msixirq(struct crete_core_dev *core_dev);
void crete_free_msixirq(struct crete_core_dev *core_dev, int irq);
static inline bool __crete_test_bit(const u64 features, unsigned int fbit)
{
/* Did you forget to fix assumptions on max features? */
if (__builtin_constant_p(fbit))
BUILD_BUG_ON(fbit >= 64);
else
WARN_ON_ONCE(fbit >= 64);
return features & BIT_ULL(fbit);
}
static inline bool crete_has_feature(const struct crete_core_dev *cdev,
enum crete_feature_type feature_type, unsigned int fbit)
{
if (feature_type == CRETE_FEATURE_NETDEV)
return __crete_test_bit(cdev->netdev_features, fbit);
else
return __crete_test_bit(cdev->offload_features, fbit);
}
/* NEED_ETH_HW_ADDR_SET
*
* eth_hw_addr_set was added by upstream commit
* 48eab831ae8b ("net: create netdev->dev_addr assignment helpers")
*
* Using eth_hw_addr_set became required in 5.17, when the dev_addr field in
* the netdev struct was constified. See 48eab831ae8b ("net: create
* netdev->dev_addr assignment helpers")
*/
#ifdef NEED_ETH_HW_ADDR_SET
static inline void eth_hw_addr_set(struct net_device *dev, const u8 *addr)
{
ether_addr_copy(dev->dev_addr, addr);
}
#endif /* NEED_ETH_HW_ADDR_SET */
int crete_cmd_init(struct crete_core_dev *cdev);
int crete_event_init(struct crete_hw *hw);
void crete_cmd_exit(struct crete_core_dev *cdev);
void crete_event_exit(struct crete_hw *hw);
int crete_adev_init(struct crete_core_dev *core_dev);
void crete_adev_cleanup(struct crete_core_dev *core_dev);
int crete_rescan_drivers_locked(struct crete_core_dev *core_dev);
int crete_rescan_drivers(struct crete_core_dev *dev);
void crete_dev_list_lock(void);
void crete_dev_list_unlock(void);
int crete_dev_list_trylock(void);
void crete_sriov_disable(struct pci_dev *pdev);
int crete_register_device(struct crete_core_dev *core_dev);
void crete_unregister_device(struct crete_core_dev *core_dev);
void crete_detach_device(struct crete_core_dev *core_dev);
int crete_attach_device(struct crete_core_dev *core_dev);
int crete_change_mac_addr(struct net_device *netdev, void *p);
void crete_set_rx_mode(struct net_device *dev);
void crete_init_msix(struct crete_core_dev *core_dev);
void crete_exit_irq(struct crete_core_dev *core_dev);
extern struct dentry *crete_debugfs_root;
void crete_register_debugfs(void);
void crete_unregister_debugfs(void);
struct dentry *crete_debugfs_get_dev_root(struct crete_core_dev *dev);
extern const struct net_device_ops crete_netdev_ops;
extern const struct ethtool_ops crete_ethtool_ops;
#endif

View File

@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
#include "crete_rdma_dev.h"
#include "crete_devlink.h"
static DEFINE_MUTEX(crete_intf_mutex);
static DEFINE_IDA(crete_adev_ida);
enum {
CRETE_INTERFACE_PROTOCOL_ETH,
CRETE_INTERFACE_PROTOCOL_ETH_REP,
CRETE_INTERFACE_PROTOCOL_IB,
CRETE_INTERFACE_PROTOCOL_IB_REP,
CRETE_INTERFACE_PROTOCOL_VNET,
CRETE_INTERFACE_PROTOCOL_VNIC,
CRETE_INTERFACE_PROTOCOL_MAX
};
static const struct crete_adev_device {
const char *suffix;
bool (*is_supported)(struct crete_core_dev *core_dev);
bool (*is_enabled)(struct crete_core_dev *core_dev);
} crete_adev_devices[] = {
[CRETE_INTERFACE_PROTOCOL_ETH] = { .suffix = "eth",
.is_supported = &crete_eth_supported,
.is_enabled = &crete_eth_enabled },
[CRETE_INTERFACE_PROTOCOL_ETH_REP] = { .suffix = "eth-rep",
.is_supported = &crete_eth_rep_supported,
.is_enabled = &crete_eth_rep_enabled },
/*
* [CRETE_INTERFACE_PROTOCOL_IB] = { .suffix = "rdma",
* .is_supported = &crete_rdma_supported,
* .is_enabled = &crete_rdma_enabled },
* [CRETE_INTERFACE_PROTOCOL_IB_REP] = { .suffix = "rdma-rep",
* .is_supported = &crete_rdma_rep_supported,
* .is_enabled = &crete_rdma_rep_enabled },
*/
[CRETE_INTERFACE_PROTOCOL_VNET] = { .suffix = "vnet",
.is_supported = &crete_vnet_supported,
.is_enabled = &crete_vnet_enabled },
[CRETE_INTERFACE_PROTOCOL_VNIC] = { .suffix = "nic",
.is_supported = &crete_nic_supported,
.is_enabled = &crete_nic_enabled },
};
int crete_adev_idx_alloc(void)
{
return ida_alloc(&crete_adev_ida, GFP_KERNEL);
}
void crete_adev_idx_free(int idx)
{
ida_free(&crete_adev_ida, idx);
}
int crete_adev_init(struct crete_core_dev *core_dev)
{
struct crete_aux_dev **adev;
adev = kcalloc(ARRAY_SIZE(crete_adev_devices),
sizeof(struct crete_aux_dev *), GFP_KERNEL | GFP_ATOMIC);
if (!adev)
return -ENOMEM;
core_dev->adev = adev;
return 0;
}
void crete_adev_cleanup(struct crete_core_dev *core_dev)
{
struct crete_aux_dev **adev = core_dev->adev;
kfree(adev);
}
static void crete_adev_release(struct device *dev)
{
struct crete_aux_dev *crete_adev =
container_of(dev, struct crete_aux_dev, adev.dev);
int idx = crete_adev->idx;
struct crete_core_dev *core_dev = crete_adev->core_dev;
kfree(crete_adev);
core_dev->adev[idx] = NULL;
}
static struct crete_aux_dev *add_adev(struct crete_core_dev *core_dev,
int idx)
{
const char *suffix = crete_adev_devices[idx].suffix;
struct auxiliary_device *adev;
struct crete_aux_dev *madev;
int ret;
madev = kzalloc(sizeof(*madev), GFP_KERNEL);
if (!madev)
return ERR_PTR(-ENOMEM);
adev = &madev->adev;
adev->id = core_dev->adev_idx;
adev->name = suffix;
adev->dev.parent = &core_dev->pdev->dev;
adev->dev.release = crete_adev_release;
madev->core_dev = core_dev;
madev->idx = idx;
ret = auxiliary_device_init(adev);
if (ret) {
kfree(madev);
return ERR_PTR(ret);
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ERR_PTR(ret);
}
return madev;
}
static void del_adev(struct auxiliary_device *adev)
{
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
int crete_attach_device(struct crete_core_dev *core_dev)
{
struct crete_aux_dev **crete_adev = core_dev->adev;
struct auxiliary_device *adev;
struct auxiliary_driver *adrv;
int ret = 0, i;
mutex_lock(&crete_intf_mutex);
for (i = 0; i < ARRAY_SIZE(crete_adev_devices); i++) {
if (!crete_adev[i]) {
bool is_supported = false;
if (crete_adev_devices[i].is_enabled) {
bool enabled;
enabled = crete_adev_devices[i].is_enabled(core_dev);
if (!enabled)
continue;
}
if (crete_adev_devices[i].is_supported)
is_supported = crete_adev_devices[i].is_supported(core_dev);
if (!is_supported)
continue;
crete_adev[i] = add_adev(core_dev, i);
if (IS_ERR(crete_adev[i])) {
ret = PTR_ERR(crete_adev[i]);
crete_adev[i] = NULL;
}
} else {
adev = &crete_adev[i]->adev;
if (!adev->dev.driver)
continue;
adrv = to_auxiliary_drv(adev->dev.driver);
if (adrv->resume)
ret = adrv->resume(adev);
}
if (ret) {
WARN_ONCE(1, "Device[%d] (%s) failed to load\n",
i, crete_adev_devices[i].suffix);
break;
}
}
mutex_unlock(&crete_intf_mutex);
return ret;
}
void crete_detach_device(struct crete_core_dev *core_dev)
{
struct crete_aux_dev **crete_adev = core_dev->adev;
struct auxiliary_device *adev;
struct auxiliary_driver *adrv;
pm_message_t pm = {};
int i;
if (!crete_adev)
pr_err("crete adev null\n");
mutex_lock(&crete_intf_mutex);
for (i = ARRAY_SIZE(crete_adev_devices) - 1; i >= 0; i--) {
if (!crete_adev[i])
continue;
if (crete_adev_devices[i].is_enabled) {
bool enabled;
enabled = crete_adev_devices[i].is_enabled(core_dev);
if (!enabled)
goto skip_suspend;
}
adev = &crete_adev[i]->adev;
/* Auxiliary driver was unbind manually through sysfs */
if (!adev->dev.driver)
goto skip_suspend;
adrv = to_auxiliary_drv(adev->dev.driver);
if (adrv->suspend) {
adrv->suspend(adev, pm);
continue;
}
skip_suspend:
del_adev(&crete_adev[i]->adev);
crete_adev[i] = NULL;
}
mutex_unlock(&crete_intf_mutex);
}
int crete_register_device(struct crete_core_dev *core_dev)
{
int ret;
mutex_lock(&crete_intf_mutex);
core_dev->flags &= ~CRETE_FLAG_DISABLE_ALL_ADEV;
ret = crete_rescan_drivers_locked(core_dev);
if (crete_have_rdma_cap(core_dev))
ret |= jm_rescan_drivers_locked(&core_dev->rdma_coredev);
mutex_unlock(&crete_intf_mutex);
if (ret)
crete_unregister_device(core_dev);
return ret;
}
void crete_unregister_device(struct crete_core_dev *core_dev)
{
mutex_lock(&crete_intf_mutex);
core_dev->flags |= CRETE_FLAG_DISABLE_ALL_ADEV;
if (crete_have_rdma_cap(core_dev))
jm_rescan_drivers_locked(&core_dev->rdma_coredev);
crete_rescan_drivers_locked(core_dev);
mutex_unlock(&crete_intf_mutex);
}
static int add_drivers(struct crete_core_dev *core_dev)
{
int i, ret = 0;
struct crete_aux_dev **crete_adev = core_dev->adev;
for (i = 0; i < ARRAY_SIZE(crete_adev_devices); i++) {
bool is_supported = false;
if (crete_adev[i])
continue;
if (crete_adev_devices[i].is_supported)
is_supported = crete_adev_devices[i].is_supported(core_dev);
if (!is_supported)
continue;
crete_adev[i] = add_adev(core_dev, i);
if (IS_ERR(crete_adev[i])) {
WARN_ONCE(1, "Device[%d] (%s) failed to load\n",
i, crete_adev_devices[i].suffix);
/* We continue to rescan drivers and leave to the caller
* to make decision if to release everything or continue.
*/
ret = PTR_ERR(crete_adev[i]);
crete_adev[i] = NULL;
}
}
return ret;
}
static void delete_drivers(struct crete_core_dev *core_dev)
{
struct crete_aux_dev **crete_adev = core_dev->adev;
bool delete_all;
int i;
delete_all = core_dev->flags & CRETE_FLAG_DISABLE_ALL_ADEV;
for (i = ARRAY_SIZE(crete_adev_devices) - 1; i >= 0; i--) {
bool is_supported = false;
if (!crete_adev[i])
continue;
if (crete_adev_devices[i].is_enabled) {
bool enabled;
enabled = crete_adev_devices[i].is_enabled(core_dev);
if (!enabled)
goto del_adev;
}
if (crete_adev_devices[i].is_supported && !delete_all)
is_supported = crete_adev_devices[i].is_supported(core_dev);
if (is_supported)
continue;
del_adev:
del_adev(&crete_adev[i]->adev);
crete_adev[i] = NULL;
}
}
int crete_rescan_drivers_locked(struct crete_core_dev *core_dev)
{
int err = 0;
delete_drivers(core_dev);
if (core_dev->flags & CRETE_FLAG_DISABLE_ALL_ADEV)
return 0;
err = add_drivers(core_dev);
return err;
}
void crete_dev_list_lock(void)
{
mutex_lock(&crete_intf_mutex);
}
void crete_dev_list_unlock(void)
{
mutex_unlock(&crete_intf_mutex);
}
int crete_dev_list_trylock(void)
{
return mutex_trylock(&crete_intf_mutex);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,367 @@
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_CMD_H
#define _CRETE_CMD_H
#include "crete.h"
#include <linux/types.h>
#include <uapi/linux/stddef.h>
extern uint crete_cmd_debug_sw;
#define CRETE_CMD_INLINE_LEN 36
#define CRETE_CMD_TRY_NUM 60
#define CRETE_TO_CMD_MS 60000
#define OWNER_MASK 0x1
#define CRETE_GET_CMD_BD_LEN(len) \
(((len) > CRETE_CMD_DATA_BLOCK_SIZE) ? \
DIV_ROUND_UP(CRETE_CMD_DATA_BLOCK_SIZE + sizeof(struct crete_cmd_prot_block), 4) : \
DIV_ROUND_UP((len) + sizeof(struct crete_cmd_prot_block), 4))
#define CRETE_COMMAND_STR_CASE(__cmd) case CRETE_CMD_ ## __cmd: return #__cmd
#define crete_cmd_dbg(__dev, format, ...) \
dev_dbg((__dev)->device, "%s:%d:(pid %d): " format, \
__func__, __LINE__, current->pid, \
##__VA_ARGS__)
#define crete_cmd_dbg_mask(__dev, mask, format, ...) \
do { \
if ((mask) & crete_cmd_debug_sw) \
crete_cmd_dbg(__dev, format, ##__VA_ARGS__); \
} while (0)
/* helper macros */
#define __crete_nullp(typ) ((struct crete_cmd_##typ##_bits *)0)
#define __crete_bit_sz(typ, fld) sizeof(__crete_nullp(typ)->fld)
#define __crete_bit_off(typ, fld) (offsetof(struct crete_cmd_##typ##_bits, fld))
#define __crete_16_off(typ, fld) (__crete_bit_off(typ, fld) / 16)
#define __crete_dw_off(typ, fld) (__crete_bit_off(typ, fld) / 32)
#define __crete_64_off(typ, fld) (__crete_bit_off(typ, fld) / 64)
#define __crete_16_bit_off(typ, fld) (__crete_bit_off(typ, fld) & 0xf)
#define __crete_dw_bit_off(typ, fld) (__crete_bit_off(typ, fld) & 0x1f)
#define __crete_mask(typ, fld) ((u32)((1ull << __crete_bit_sz(typ, fld)) - 1))
#define __crete_dw_mask(typ, fld) (__crete_mask(typ, fld) << __crete_dw_bit_off(typ, fld))
#define __crete_mask16(typ, fld) ((u16)((1ull << __crete_bit_sz(typ, fld)) - 1))
#define __crete_16_mask(typ, fld) (__crete_mask16(typ, fld) << __crete_16_bit_off(typ, fld))
#define __crete_st_sz_bits(typ) sizeof(struct crete_cmd_##typ##_bits)
#define CRETE_FLD_SZ_BYTES(typ, fld) (__crete_bit_sz(typ, fld) / 8)
#define CRETE_ST_SZ_BYTES(typ) (sizeof(struct crete_cmd_##typ##_bits) / 8)
#define CRETE_ST_SZ_DW(typ) (sizeof(struct crete_cmd_##typ##_bits) / 32)
#define CRETE_ST_SZ_QW(typ) (sizeof(struct crete_cmd_##typ##_bits) / 64)
#define CRETE_UN_SZ_BYTES(typ) (sizeof(union crete_cmd_##typ##_bits) / 8)
#define CRETE_UN_SZ_DW(typ) (sizeof(union crete_cmd_##typ##_bits) / 32)
#define CRETE_BYTE_OFF(typ, fld) (__crete_bit_off(typ, fld) / 8)
#define CRETE_ADDR_OF(typ, p, fld) ((void *)((uint8_t *)(p) + CRETE_BYTE_OFF(typ, fld)))
/* insert a value to a struct */
#define CRETE_SET(typ, p, fld, v) do { \
u32 _v = v; \
BUILD_BUG_ON(__crete_st_sz_bits(typ) % 32); \
*((__le32 *)(p) + __crete_dw_off(typ, fld)) = \
cpu_to_le32((le32_to_cpu(*((__le32 *)(p) + __crete_dw_off(typ, fld))) & \
(~__crete_dw_mask(typ, fld))) | (((_v) & __crete_mask(typ, fld)) \
<< __crete_dw_bit_off(typ, fld))); \
} while (0)
#define CRETE_ARRAY_SET(typ, p, fld, idx, v) do { \
BUILD_BUG_ON(__crete_bit_off(typ, fld) % 32); \
CRETE_SET(typ, p, fld[idx], v); \
} while (0)
#define CRETE_SET_TO_ONES(typ, p, fld) do { \
BUILD_BUG_ON(__crete_st_sz_bits(typ) % 32); \
*((__le32 *)(p) + __crete_dw_off(typ, fld)) = \
cpu_to_le32((le32_to_cpu(*((__le32 *)(p) + __crete_dw_off(typ, fld))) & \
(~__crete_dw_mask(typ, fld))) | ((__crete_mask(typ, fld)) \
<< __crete_dw_bit_off(typ, fld))); \
} while (0)
#define CRETE_GET(typ, p, fld) ((le32_to_cpu(*((__le32 *)(p) +\
__crete_dw_off(typ, fld))) >> __crete_dw_bit_off(typ, fld)) & \
__crete_mask(typ, fld))
#define CRETE_GET_PR(typ, p, fld) ({ \
u32 ___t = CRETE_GET(typ, p, fld); \
pr_debug(#fld " = 0x%x\n", ___t); \
___t; \
})
#define __CRETE_SET64(typ, p, fld, v) do { \
BUILD_BUG_ON(__crete_bit_sz(typ, fld) != 64); \
*((__le64 *)(p) + __crete_64_off(typ, fld)) = cpu_to_le64(v); \
} while (0)
#define CRETE_SET64(typ, p, fld, v) do { \
BUILD_BUG_ON(__crete_bit_off(typ, fld) % 64); \
__CRETE_SET64(typ, p, fld, v); \
} while (0)
#define CRETE_ARRAY_SET64(typ, p, fld, idx, v) do { \
BUILD_BUG_ON(__crete_bit_off(typ, fld) % 64); \
__CRETE_SET64(typ, p, fld[idx], v); \
} while (0)
#define CRETE_GET64(typ, p, fld) le64_to_cpu(*((__le64 *)(p) + __crete_64_off(typ, fld)))
#define CRETE_GET64_PR(typ, p, fld) ({ \
u64 ___t = CRETE_GET64(typ, p, fld); \
pr_debug(#fld " = 0x%llx\n", ___t); \
___t; \
})
#define CRETE_GET16(typ, p, fld) ((le16_to_cpu(*((__le16 *)(p) +\
__crete_16_off(typ, fld))) >> __crete_16_bit_off(typ, fld)) & \
__crete_mask16(typ, fld))
#define CRETE_SET16(typ, p, fld, v) do { \
u16 _v = v; \
BUILD_BUG_ON(__crete_st_sz_bits(typ) % 16); \
*((__le16 *)(p) + __crete_16_off(typ, fld)) = \
cpu_to_le16((le16_to_cpu(*((__le16 *)(p) + __crete_16_off(typ, fld))) & \
(~__crete_16_mask(typ, fld))) | (((_v) & __crete_mask16(typ, fld)) \
<< __crete_16_bit_off(typ, fld))); \
} while (0)
enum {
CMD_MODE_POLLING,
CMD_MODE_EVENTS
};
enum {
CMD_OWNER_SW = 0x0,
CMD_OWNER_HW = 0x1,
};
/* cmd delivery status */
enum crete_cmd_status {
CRETE_CMD_DELIVERY_STAT_OK = 0x0,
CRETE_CMD_DELIVERY_STAT_SIGNAT_ERR = 0x1,
CRETE_CMD_DELIVERY_STAT_CID_ERR = 0x2,
CRETE_CMD_DELIVERY_STAT_DATA_FORMAT_ERR = 0x3,
CRETE_CMD_DELIVERY_STAT_OUT_INSUFFICIENT_ERR = 0x4,
CRETE_CMD_DELIVERY_STAT_OWNER_ERR = 0x5,
};
/* return cmd status */
enum return_cmd_status {
SUCCESS,
INTERNAL_ERR,
BAD_ID,
BAD_OP,
BAD_PARAM,
BAD_STATE,
BAD_RESOURCE,
};
enum {
CRETE_CMD_ENT_STATE_PENDING_COMP,
};
enum {
CRETE_TRIGGERED_CMD_COMP = (u64)1 << 32,
};
/* cmd id */
enum crete_gener_cmd_id {
CRETE_CMD_GET_STATUS = 0x100,
CRETE_CMD_SET_STATUS,
CRETE_CMD_GET_FEAT,
CRETE_CMD_SET_FEAT,
CRETE_CMD_GET_DEV_TYPE,
CRETE_CMD_SET_DEV_TYPE,
CRETE_CMD_RESET_DEV,
CRETE_CMD_STOP_DEV,
CRETE_CMD_RESTORE_DEV,
CRETE_CMD_GET_DEV_ATTR,
CRETE_CMD_SET_QP_NUM = 0x10a,
CRETE_CMD_GET_SFI = 0x110,
CRETE_CMD_GEN_MAX,
};
/* qp group */
enum crete_qp_cmd_id {
CRETE_CMD_GET_QP_CAP = 0x300,
CRETE_CMD_CREATE_QP,
CRETE_CMD_DESTORY_QP,
CRETE_CMD_CREATE_QUEUE,
CRETE_CMD_DESTROY_QUEUE = 0x304,
CRETE_CMD_ENABLE_QUEUE = 0x305,
CRETE_CMD_DISABLE_QUEUE = 0x306,
CRETE_CMD_ENABLE_RXEN,
CRETE_CMD_DISABLE_RXEN,
CRETE_CMD_RESET_QUEUE = 0x309,
CRETE_CMD_GET_Q_STATE,
CRETE_CMD_QP_MAX,
};
enum crete_vport_cmd_id {
CRETE_CMD_SET_VPORT_RX_MODE = 0x500,
CRETE_CMD_SET_ESWITCH_MODE = 0x501,
CRETE_CMD_VPORT_ATTR_GET = 0x502,
CRETE_CMD_SET_VPORT_LINK_STATE = 0x505,
CRETE_CMD_SET_MTU = 0x506,
CRETE_CMD_SET_TRUST = 0x508,
CRETE_CMD_GET_VPORT_PKT_STAT = 0x509,
CRETE_CMD_GET_VPORT_LINK_STATE,
CRETE_CMD_GET_VORT_RX_MODE,
CRETE_CMD_SET_TCP_LRO,
CRETE_CMD_GET_TCP_LRO,
CRETE_CMD_SET_RX_RSS,
CRETE_CMD_GET_RX_RSS,
CRETE_CMD_SET_RX_TIMESTAMP,
CRETE_CMD_GET_RX_TIMESTAMP,
CRETE_CMD_GET_TRUST,
CRETE_CMD_SET_UC_MAC,
CRETE_CMD_SET_VF_SHAPER = 0x551,
CRETE_CMD_VPORT_MAX,
};
/*
enum crete_vport_cmd_id {
CRETE_CMD_SET_VPORT_RX_MODE = 0x500,
CRETE_CMD_GET_VORT_RX_MODE,
CRETE_CMD_VPORT_ATTR_GET,
// CRETE_CMD_SET_VPORT_LINK_STATE,
CRETE_CMD_GET_VPORT_LINK_STATE,
CRETE_CMD_SET_TCP_LRO,
CRETE_CMD_GET_TCP_LRO,
CRETE_CMD_SET_RX_RSS,
CRETE_CMD_GET_RX_RSS,
CRETE_CMD_SET_RX_TIMESTAMP,
CRETE_CMD_GET_RX_TIMESTAMP,
CRETE_CMD_SET_TRUST,
CRETE_CMD_GET_TRUST,
CRETE_CMD_SET_UC_MAC = 0x50c,
CRETE_CMD_SET_VF_SHAPER = 0x50d,
CRETE_CMD_SET_VPORT_LINK_STATE,
CRETE_CMD_VPORT_MAX,
};
*/
/* port group */
enum crete_port_cmd_id {
CRETE_CMD_SET_PORT_TRUST_STATUS = 0x801,
CRETE_CMD_SET_PCP_MAP_TC,
CRETE_CMD_SET_DSCP_MAP_TC,
CRETE_CMD_SET_FC_ENABLE,
CRETE_CMD_SET_FC_TIMEOUT,
CRETE_CMD_SET_PFC_ENABLE,
CRETE_CMD_SET_ETS,
CRETE_CMD_GET_PORT_NUM = 0x808,
CRETE_CMD_GET_PORT_LINK_STATUS,
CRETE_CMD_GET_REPORT_PORT_LINK_STATUS,
CRETE_CMD_GET_PORT_SPEED_DUPLEX_MODE,
CRETE_CMD_SET_PORT_SPEED_DUPLEX_MODE,
CRETE_CMD_GET_PORT_FEC_MODE,
CRETE_CMD_SET_PORT_FEC_MODE,
CRETE_CMD_PORT_MAX,
};
/* netdev group */
enum crete_netdev_cmd_id {
CRETE_CMD_SET_SOP_PADDING = 0x400,
CRETE_CMD_GET_SOP_PADDING,
CRETE_CMD_SET_AUTO_SUPPRESS,
CRETE_CMD_GET_AUTO_SUPPRESS,
CRETE_CMD_SET_MODERATION_TEMP,
CRETE_CMD_GET_MODERATION_TEMP,
CRETE_CMD_SET_INT_MODERATION,
CRETE_CMD_GET_INT_MODERATION,
CRETE_CMD_SET_TX_INORDER,
CRETE_CMD_GET_TX_INORDER,
CRETE_CMD_SET_CQE_AGGREGATION_TEMP,
CRETE_CMD_GET_CQE_AGGREGATION_TEMP,
CRETE_CMD_SET_CQE_AGGREGATION,
CRETE_CMD_GET_CQE_AGGREGATION,
CRETE_CMD_SET_RX_MERGE,
CRETE_CMD_GET_RX_MERGE,
CRETE_CMD_NEDEV_MAX,
};
enum crete_lag_cmd_id {
CRETE_CMD_GET_LAG_CAP = 0x0503,
CRETE_CMD_LAG_CONFIG = 0x0504,
CRETE_CMD_ENABLE_LAG = 0x050c,
};
/* migration cmd*/
enum crete_lm_cmd_id {
CRETE_CMD_SET_VQ_MIG_STATE = 0x30c,
CRETE_CMD_GET_VQ_MIG_STATE = 0x30d,
CRETE_CMD_GET_VQ_MIG_STATE_BATCH = 0x30e,
CRETE_CMD_SET_MIG_LOG_STATE = 0x112,
CRETE_CMD_SET_MIG_LOG_BASE = 0x113,
};
/* firmware */
enum crete_firmware_cmd_id {
CRETE_CMD_FWU_LOCK = 0x201,
CRETE_CMD_FWU_UNLOCK,
CRETE_CMD_FWU_PKEY,
CRETE_CMD_FWU_VER,
CRETE_CMD_FWU_XFER,
CRETE_CMD_FWU_END,
};
/*set mtu*/
enum crete_set_mtu_op {
CRETE_SET_MTU_MACPORT = 1,
CRETE_SET_MTU_VPORT = 2,
};
#define MAC_MTU(v) ((v) + ETH_HLEN)
/*get vport pkt statistics*/
enum crete_get_vport_statistics_op {
CRETE_GET_PKT_STATIS_VPORT = 0,
CRETE_GET_PKT_STATIS_MAC = 1,
CRETE_GET_PKT_STATIS_LAG = 2,
};
enum crete_tmplate_cmd_id {
CRETE_CMD_GET_VF_MAC = 0x8101,
};
int crete_cmd_exec_polling(struct crete_core_dev *dev, void *in, int in_size,
void *out, int out_size);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/debugfs.h>
#include "crete.h"
struct dentry *crete_debugfs_root;
EXPORT_SYMBOL(crete_debugfs_root);
void crete_register_debugfs(void)
{
crete_debugfs_root = debugfs_create_dir("crete", NULL);
}
void crete_unregister_debugfs(void)
{
debugfs_remove(crete_debugfs_root);
}
struct dentry *crete_debugfs_get_dev_root(struct crete_core_dev *dev)
{
return dev->dbg.dbg_root;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_DCBX_H__
#define __CRETE_DCBX_H__
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/atomic.h>
#include <linux/xarray.h>
#include <net/devlink.h>
#define CRETE_SUPPORTED_DSCP 64
#define CRETE_SUPPORTED_PCP 8
#define CRETE_CMD_DSCP_BIT_WIDTH 0x8
#define CRETE_CMD_DSCP_TC_MASK 0xF
#define CRETE_CMD_DSCP_EN_SHIFT 0x7
#define CRETE_CMD_QDSCP_NUM 16
#define CRETE_CMD_QSCP_NUM_PERQ 4
#define CRETE_DEFAULT_CABLE_LEN 7 /* 7 meters */
#define CRETE_1GB (1000000)
#define CRETE_100MB (100000)
enum crete_dcbx_oper_mode {
CRETE_DCBX_PARAM_VER_OPER_HOST = 0x0,
CRETE_DCBX_PARAM_VER_OPER_AUTO = 0x3,
};
enum {
INIT,
DELETE,
};
struct crete_cee_config {
/* bw pct for priority group */
u8 pg_bw_pct[CEE_DCBX_MAX_PGS];
u8 prio_to_pg_map[CEE_DCBX_MAX_PRIO];
bool pfc_setting[CEE_DCBX_MAX_PRIO];
bool pfc_enable;
};
struct crete_dcbx_dp {
u8 dscp2prio[CRETE_SUPPORTED_DSCP];
u8 trust_state;
};
struct crete_dcbx {
enum crete_dcbx_oper_mode mode;
struct crete_cee_config cee_cfg; /* pending configuration */
u8 dscp_app_cnt;
/* The only setting that cannot be read from FW */
u8 tc_tsa[IEEE_8021QAZ_MAX_TCS];
u8 cap;
/* Buffer configuration */
bool manual_buffer;
u32 cable_len;
u32 xoff;
u16 port_buff_cell_sz;
};
enum crete_port_trust_state {
CRETE_PORT_TRUST_PCP = 1,
CRETE_PORT_TRUST_DSCP = 2,
};
enum {
CRETE_DISABLE_MAXRATE = 0,
CRETE_KBPS_UNIT = 1,
CRETE_MBPS_UNIT = 2,
CRETE_GBPS_UNIT = 3,
CRETE_PPS_UNIT = 4,
CRETE_KPPS_UNIT = 5,
CRETE_MPPS_UNIT = 6,
};
struct tc_configuration {
u8 weight;
u8 unit;
u8 pg_id;
u32 maxrate;
};
struct dscp_configuration {
u8 tc : 4;
u8 en : 1;
};
struct pcp_configuration {
u8 tc : 3;
u8 en : 1;
};
struct crete_priv;
void crete_dcbnl_build_netdev(struct net_device *netdev);
void crete_dcbnl_initialize(struct crete_priv *priv);
void crete_dcbnl_init_app(struct crete_priv *priv);
#endif

View File

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
#include "crete_cmd_if.h"
static int statistics_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *core_dev = file->private;
struct crete_debugfs_statistics *debugfs_statis = core_dev->debugfs_statis;
struct crete_port_statistics port_statistics;
int ret = 0;
mutex_lock(&debugfs_statis->statis_mutex);
ret = crete_get_port_statistics(core_dev, &port_statistics);
if(ret){
mutex_unlock(&debugfs_statis->statis_mutex);
return ret;
}
debugfs_statis->rx_bytes += port_statistics.rx_bytes;
debugfs_statis->rx_pkts += port_statistics.rx_pkts;
debugfs_statis->tx_bytes += port_statistics.tx_bytes;
debugfs_statis->tx_pkts += port_statistics.tx_pkts;
seq_printf(file, "rx bytes : 0x%llx\n", debugfs_statis->rx_bytes);
seq_printf(file, "rx pkts : 0x%llx\n", debugfs_statis->rx_pkts);
seq_printf(file, "tx bytes : 0x%llx\n", debugfs_statis->tx_bytes);
seq_printf(file, "tx pkts : 0x%llx\n", debugfs_statis->tx_pkts);
mutex_unlock(&debugfs_statis->statis_mutex);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(statistics);
int crete_register_debugfs_statistics(struct crete_core_dev *dev)
{
struct crete_debugfs_statistics *debugfs_statis = NULL;
struct dentry *debugfs = NULL;
debugfs_statis = kzalloc(sizeof(*debugfs_statis), GFP_KERNEL);
if(!debugfs_statis){
dev_err(dev->device, "failed to alloc debugfs statistics\n");
return -1;
}
mutex_init(&debugfs_statis->statis_mutex);
dev->debugfs_statis = debugfs_statis;
debugfs = debugfs_create_file("statistics", 0444, crete_debugfs_get_dev_root(dev), dev, &statistics_fops);
if(!debugfs){
dev_err(dev->device, "failed to create debugfs file statistics\n");
return -1;
}
dev->dbg.statistics_debugfs = debugfs;
return 0;
}
int crete_unregister_debugfs_statistics(struct crete_core_dev *dev)
{
if(dev->dbg.statistics_debugfs){
debugfs_remove_recursive(dev->dbg.statistics_debugfs);
}
if(dev->debugfs_statis){
kfree(dev->debugfs_statis);
dev->debugfs_statis = NULL;
}
return 0;
}

View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/mutex.h>
struct crete_debugfs_statistics {
struct mutex statis_mutex;
uint64_t tx_pkts;
uint64_t tx_bytes;
uint64_t rx_pkts;
uint64_t rx_bytes;
};
int crete_register_debugfs_statistics(struct crete_core_dev *dev);
int crete_unregister_debugfs_statistics(struct crete_core_dev *dev);

View File

@ -0,0 +1,542 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <net/devlink.h>
#include "crete.h"
#include "crete_eswitch.h"
#include "crete_fw_update.h"
struct crete_eswitch *crete_devlink_eswitch_get(struct devlink *devlink)
{
struct crete_core_dev *dev = devlink_priv(devlink);
return dev->eswitch;
}
static int esw_mode_from_devlink(u16 mode, u16 *crete_mode)
{
switch (mode) {
case DEVLINK_ESWITCH_MODE_LEGACY:
*crete_mode = CRETE_ESWITCH_LEGACY;
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
*crete_mode = CRETE_ESWITCH_OFFLOADS;
break;
default:
return -EINVAL;
}
return 0;
}
static int esw_mode_to_devlink(u16 crete_mode, u16 *mode)
{
switch (crete_mode) {
case CRETE_ESWITCH_LEGACY:
*mode = DEVLINK_ESWITCH_MODE_LEGACY;
break;
case CRETE_ESWITCH_OFFLOADS:
*mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
break;
default:
return -EINVAL;
}
return 0;
}
int crete_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack)
{
u16 cur_crete_mode, crete_mode = 0;
struct crete_eswitch *esw;
int err = 0;
esw = crete_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return PTR_ERR(esw);
if (esw_mode_from_devlink(mode, &crete_mode))
return -EINVAL;
err = crete_esw_try_lock(esw);
if (err < 0) {
NL_SET_ERR_MSG_MOD(extack, "Can't change mode, E-Switch is busy");
goto eswitch_busy;
}
cur_crete_mode = err;
err = 0;
if (cur_crete_mode == crete_mode)
goto unlock;
/* cmd queue notify firmware */
crete_eswitch_disable_locked(esw);
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
err = esw_offloads_start(esw, extack);
crete_rescan_drivers_locked(esw->dev);
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
crete_rescan_drivers_locked(esw->dev);
err = esw_offloads_stop(esw, extack);
//crete_rescan_drivers_locked(esw->dev);
} else {
err = -EINVAL;
}
unlock:
crete_esw_unlock(esw);
eswitch_busy:
return err;
}
int crete_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{
struct crete_eswitch *esw;
int err;
esw = crete_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return PTR_ERR(esw);
down_read(&esw->mode_lock);
err = esw_mode_to_devlink(esw->mode, mode);
up_read(&esw->mode_lock);
return err;
}
static int crete_devlink_flash_update(struct devlink *devlink,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct crete_core_dev *cdev = devlink_priv(devlink);
#ifndef CONFIG_DEVLINK_CARRYOUT_OPTIMIZE
const struct firmware *fw;
int err;
err = request_firmware_direct(&fw, params->file_name, cdev->device);
if (err)
return err;
err = crete_firmware_flash(cdev, fw, extack, CRETE_FWU_DEVLINK);
release_firmware(fw);
#else
return crete_firmware_flash(cdev, params->fw, extack, CRETE_FWU_DEVLINK);
#endif
return 0;
}
static u8 crete_fw_ver_major(u32 version)
{
return (version >> 24) & 0xff;
}
static u8 crete_fw_ver_minor(u32 version)
{
return (version >> 16) & 0xff;
}
static u16 crete_fw_ver_subminor(u32 version)
{
return version & 0xffff;
}
#define DEVLINK_FW_STRING_LEN 32
int crete_fw_version_query(struct crete_core_dev *dev,
u32 *running_ver, u32 *pending_ver)
{
dev_warn(&dev->pdev->dev, "%s devlink info get fw version stub\n", __func__);
*running_ver = 0x20231025;
*pending_ver = 0x20231024;
return 0;
}
static int
crete_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
struct crete_core_dev *dev = devlink_priv(devlink);
char version_str[DEVLINK_FW_STRING_LEN];
u32 running_fw, stored_fw;
int err;
char *psid_stub = "crete_stub_psid";
err = devlink_info_version_fixed_put(req, "fw.psid", psid_stub);
if (err)
return err;
err = crete_fw_version_query(dev, &running_fw, &stored_fw);
if (err)
return err;
snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
crete_fw_ver_major(running_fw), crete_fw_ver_minor(running_fw),
crete_fw_ver_subminor(running_fw));
err = devlink_info_version_running_put(req, "fw.version", version_str);
if (err)
return err;
err = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
version_str);
if (err)
return err;
/* no pending version, return running (stored) version */
if (stored_fw == 0)
stored_fw = running_fw;
snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
crete_fw_ver_major(stored_fw), crete_fw_ver_minor(stored_fw),
crete_fw_ver_subminor(stored_fw));
err = devlink_info_version_stored_put(req, "fw.version", version_str);
if (err)
return err;
return devlink_info_version_stored_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
version_str);
}
static struct devlink_ops crete_pf_dl_ops = {
.eswitch_mode_set = crete_devlink_eswitch_mode_set,
.eswitch_mode_get = crete_devlink_eswitch_mode_get,
.info_get = crete_devlink_info_get,
.flash_update = crete_devlink_flash_update,
};
static struct devlink_ops crete_dft_dl_ops;
struct devlink *crete_devlink_alloc(struct device *dev, bool is_pf)
{
struct devlink_ops *dl_ops;
if (is_pf)
dl_ops = &crete_pf_dl_ops;
else
dl_ops = &crete_dft_dl_ops;
#ifndef NEED_DEVLINK_ALLOC_SETS_DEV
return devlink_alloc(dl_ops, sizeof(struct crete_core_dev),
dev);
#else
return devlink_alloc(dl_ops, sizeof(struct crete_core_dev));
#endif
}
void crete_devlink_free(struct devlink *devlink)
{
devlink_free(devlink);
}
bool crete_eth_supported(struct crete_core_dev *core_dev)
{
if (core_dev->device_type != CRETE_DEVICE_CRETE)
return false;
if (!crete_have_net_cap(core_dev))
return false;
return true;
}
bool crete_eth_enabled(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_eth_rep_supported(struct crete_core_dev *core_dev)
{
if(core_dev->device_type == CRETE_DEVICE_PNIC)
return false;
return true;
}
bool crete_eth_rep_enabled(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_rdma_supported(struct crete_core_dev *core_dev)
{
if(core_dev->device_type == CRETE_DEVICE_PNIC)
return false;
return true;
}
bool crete_rdma_enabled(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_rdma_rep_supported(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_rdma_rep_enabled(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_vnet_supported(struct crete_core_dev *core_dev)
{
if (core_dev->coredev_type == CRETE_COREDEV_PF)
return false;
if (core_dev->device_type == CRETE_DEVICE_PNIC)
return true;
if (core_dev->device_type != CRETE_DEVICE_CRETE)
return false;
if (!crete_have_net_cap(core_dev))
return false;
return true;
}
bool crete_vnet_enabled(struct crete_core_dev *core_dev)
{
return true;
}
bool crete_nic_supported(struct crete_core_dev *core_dev)
{
if (core_dev->device_type != CRETE_DEVICE_PNIC ||
!crete_core_is_pf(core_dev))
return false;
if (!crete_have_net_cap(core_dev))
return false;
return true;
}
bool crete_nic_enabled(struct crete_core_dev *core_dev)
{
return true;
}
#ifndef CONFIG_WITHOUT_DEVLINK_PARAM_ETH
static const struct devlink_param enable_eth_param =
DEVLINK_PARAM_GENERIC(ENABLE_ETH, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL, NULL);
static int crete_devlink_eth_param_register(struct devlink *devlink)
{
struct crete_core_dev *dev = devlink_priv(devlink);
union devlink_param_value value;
int err;
if (!crete_eth_supported(dev))
return 0;
err = devlink_param_register(devlink, &enable_eth_param);
if (err)
return err;
value.vbool = true;
devlink_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
value);
devlink_param_publish(devlink, &enable_eth_param);
return 0;
}
static void crete_devlink_eth_param_unregister(struct devlink *devlink)
{
struct crete_core_dev *dev = devlink_priv(devlink);
if (!crete_eth_supported(dev))
return;
devlink_param_unpublish(devlink, &enable_eth_param);
devlink_param_unregister(devlink, &enable_eth_param);
}
static int crete_devlink_enable_rdma_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
struct netlink_ext_ack *extack)
{
struct crete_core_dev *dev = devlink_priv(devlink);
bool new_state = val.vbool;
if (new_state && !crete_rdma_supported(dev))
return -EOPNOTSUPP;
return 0;
}
static const struct devlink_param enable_rdma_param =
DEVLINK_PARAM_GENERIC(ENABLE_RDMA, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL, crete_devlink_enable_rdma_validate);
static int crete_devlink_rdma_param_register(struct devlink *devlink)
{
union devlink_param_value value;
int err;
if (!IS_ENABLED(CONFIG_crete_INFINIBAND))
return 0;
err = devlink_param_register(devlink, &enable_rdma_param);
if (err)
return err;
value.vbool = true;
devlink_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
value);
devlink_param_publish(devlink, &enable_rdma_param);
return 0;
}
static void crete_devlink_rdma_param_unregister(struct devlink *devlink)
{
if (!IS_ENABLED(CONFIG_crete_INFINIBAND))
return;
devlink_param_unpublish(devlink, &enable_rdma_param);
devlink_param_unregister(devlink, &enable_rdma_param);
}
static const struct devlink_param enable_vnet_param =
DEVLINK_PARAM_GENERIC(ENABLE_VNET, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL, NULL);
static int crete_devlink_vnet_param_register(struct devlink *devlink)
{
struct crete_core_dev *dev = devlink_priv(devlink);
union devlink_param_value value;
int err;
if (!crete_vnet_supported(dev))
return 0;
err = devlink_param_register(devlink, &enable_vnet_param);
if (err)
return err;
value.vbool = true;
devlink_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
value);
devlink_param_publish(devlink, &enable_rdma_param);
return 0;
}
static void crete_devlink_vnet_param_unregister(struct devlink *devlink)
{
struct crete_core_dev *dev = devlink_priv(devlink);
if (!crete_vnet_supported(dev))
return;
devlink_param_unpublish(devlink, &enable_vnet_param);
devlink_param_unregister(devlink, &enable_vnet_param);
}
#endif
static int crete_devlink_auxdev_params_register(struct devlink *devlink)
{
#ifndef CONFIG_WITHOUT_DEVLINK_PARAM_ETH
int err;
err = crete_devlink_eth_param_register(devlink);
if (err)
return err;
err = crete_devlink_rdma_param_register(devlink);
if (err)
goto rdma_err;
err = crete_devlink_vnet_param_register(devlink);
if (err)
goto vnet_err;
return 0;
vnet_err:
crete_devlink_rdma_param_unregister(devlink);
rdma_err:
crete_devlink_eth_param_unregister(devlink);
return err;
#else
return 0;
#endif
}
static void crete_devlink_auxdev_params_unregister(struct devlink *devlink)
{
#ifndef CONFIG_WITHOUT_DEVLINK_PARAM_ETH
crete_devlink_vnet_param_unregister(devlink);
crete_devlink_rdma_param_unregister(devlink);
crete_devlink_eth_param_unregister(devlink);
#endif
}
int crete_devlink_register(struct devlink *devlink)
{
int err;
struct crete_core_dev *core_dev = devlink_priv(devlink);
struct pci_dev *pdev = core_dev->pdev;
dev_info(&pdev->dev, "devlink register");
#ifndef HAVE_DEVLINK_REGISTER_SETS_DEV
devlink_register(devlink);
err = 0;
#else
err = devlink_register(devlink, &pdev->dev);
#endif
if (err)
return err;
err = crete_devlink_auxdev_params_register(devlink);
if (err)
goto auxdev_reg_err;
return 0;
auxdev_reg_err:
devlink_unregister(devlink);
return err;
}
void crete_devlink_unregister(struct devlink *devlink)
{
crete_devlink_auxdev_params_unregister(devlink);
devlink_unregister(devlink);
}

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_DEVLINK_H__
#define __CRETE_DEVLINK_H__
#include <net/devlink.h>
struct devlink *crete_devlink_alloc(struct device *dev, bool is_pf);
void crete_devlink_free(struct devlink *devlink);
int crete_devlink_register(struct devlink *devlink);
void crete_devlink_unregister(struct devlink *devlink);
bool crete_eth_supported(struct crete_core_dev *core_dev);
bool crete_eth_enabled(struct crete_core_dev *core_dev);
bool crete_eth_rep_supported(struct crete_core_dev *core_dev);
bool crete_eth_rep_enabled(struct crete_core_dev *core_dev);
bool crete_rdma_supported(struct crete_core_dev *core_dev);
bool crete_rdma_enabled(struct crete_core_dev *core_dev);
bool crete_rdma_rep_supported(struct crete_core_dev *core_dev);
bool crete_rdma_rep_enabled(struct crete_core_dev *core_dev);
bool crete_vnet_supported(struct crete_core_dev *core_dev);
bool crete_vnet_enabled(struct crete_core_dev *core_dev);
bool crete_nic_supported(struct crete_core_dev *core_dev);
bool crete_nic_enabled(struct crete_core_dev *core_dev);
#endif /* __CRETE_DEVLINK_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,295 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_ESWITCH_H
#define __CRETE_ESWITCH_H
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/atomic.h>
#include <linux/xarray.h>
#include <net/devlink.h>
#include "crete_event.h"
/* The vport iterator is valid only after vport are initialized in mlx5_eswitch_init.
* Borrowed the idea from xa_for_each_marked() but with support for desired last element.
*/
#define crete_esw_for_each_vport(esw, index, vport) \
xa_for_each(&((esw)->vports), index, vport)
#define crete_esw_for_each_rep(esw, i, rep) \
xa_for_each(&((esw)->eswoffloads.vport_reps), i, rep)
#define crete_esw_for_each_entry_marked(xa, index, entry, last, filter) \
for (index = 0, entry = xa_find(xa, &index, last, filter); \
entry; entry = xa_find_after(xa, &index, last, filter))
#define crete_esw_for_each_vport_marked(esw, index, vport, last, filter) \
crete_esw_for_each_entry_marked(&((esw)->vports), index, vport, last, filter)
#define crete_esw_for_each_vf_vport(esw, index, vport, last) \
crete_esw_for_each_vport_marked(esw, index, vport, last, CRETE_ESW_VPT_VF)
#define crete_esw_for_each_host_func_vport(esw, index, vport, last) \
crete_esw_for_each_vport_marked(esw, index, vport, last, CRETE_ESW_VPT_HOST_FN)
/* Each mark identifies eswitch vport type.
* CRETE_ESW_VPT_HOST_FN is used to identify both PF and VF ports using
* a single mark.
* MLX5_ESW_VPT_VF identifies a SRIOV VF vport.
* MLX5_ESW_VPT_SF identifies SF vport.
*/
#define CRETE_ESW_VPT_HOST_FN XA_MARK_0
#define CRETE_ESW_VPT_VF XA_MARK_1
#define CRETE_ESW_VPT_SF XA_MARK_2
/* stub start*/
#define CRETE_MAX_UC_PER_VPORT(dev) (8)
#define CRETE_MAX_MC_PER_VPORT(dev) (8)
#define CRETE_EVENT_TYPE_NIC_VPORT_CHANGE 0xd
#define CRETE_EVENT_TYPE_ESW_FUNCTIONS_CHANGED 0xe
#define CRETE_MAX_CFA_CODE (65535)
#define CRETE_VF_IDX_INVALID 0xffff
/* stub end*/
#define CRETE_ESWITCH_IGNORE_NUM_VFS (-1)
struct crete_esw_fun {
struct crete_nb nb;
u16 num_vfs;
};
/* Vport number for each function must keep unchanged */
enum {
CRETE_VPORT_PF = 0x0,
CRETE_VPORT_FIRST_VF = 0x1,
CRETE_VPORT_UPLINK = 0xffff
};
#define VPORT(vfid) (vfid + CRETE_VPORT_FIRST_VF)
enum {
CRETE_VPORT_STATE_OP_MOD_VNIC_VPORT = 0x0,
CRETE_VPORT_STATE_OP_MOD_ESW_VPORT = 0x1,
CRETE_VPORT_STATE_OP_MOD_UPLINK = 0x2,
};
struct crete_vport_info {
u8 mac[ETH_ALEN];
u16 vlan;
int link_state;
u8 qos;
__be16 vlan_proto;
u8 spoofchk:1;
u8 trusted:1;
/* the admin approved vlan list */
DECLARE_BITMAP(vlan_trunk_8021q_bitmap, VLAN_N_VID);
u32 group;
};
/* Vport context events */
enum crete_esw_vport_event {
CRETE_VPORT_UC_ADDR_CHANGE = BIT(0),
CRETE_VPORT_MC_ADDR_CHANGE = BIT(1),
CRETE_VPORT_PROMISC_CHANGE = BIT(3),
};
enum {
CRETE_VPORT_ADMIN_STATE_DOWN = 0x0,
CRETE_VPORT_ADMIN_STATE_UP = 0x1,
CRETE_VPORT_ADMIN_STATE_AUTO = 0x2,
};
enum {
CRETE_ESWITCH_LEGACY,
CRETE_ESWITCH_OFFLOADS
};
enum {
REP_UNREGISTERED,
REP_REGISTERED,
REP_LOADED,
};
#define CRETE_LEGACY_SRIOV_VPORT_EVENTS (CRETE_VPORT_UC_ADDR_CHANGE | \
CRETE_VPORT_MC_ADDR_CHANGE | \
CRETE_VPORT_PROMISC_CHANGE)
struct crete_vport {
struct crete_core_dev *dev;
struct crete_vport_info info;
struct work_struct vport_change_handler;
struct {
bool enabled;
u32 min_rate;
u32 max_rate;
struct crete_esw_rate_group *group;
} qos;
u16 vport;
bool enabled;
enum crete_esw_vport_event enabled_events;
int index;
struct devlink_port *dl_port;
};
enum {
CRETE_ESW_FDB_CREATED = BIT(0),
};
struct crete_esw_rep;
struct crete_esw_offload {
struct xarray vport_reps;
u16 *cfa_code_map;
};
struct crete_vf_rep_stats {
u64 packets;
u64 bytes;
u64 dropped;
};
struct crete_esw_rep {
struct crete_core_dev *cdev;
struct net_device *dev;
struct metadata_dst *dst;
u16 vport_idx;
u16 tx_cfa_action;
u16 rx_cfa_code;
u16 sfi_code;
struct crete_vf_rep_stats rx_stats;
struct crete_vf_rep_stats tx_stats;
struct crete_eswitch *esw;
atomic_t state;
};
struct crete_eswitch {
struct crete_core_dev *dev;
struct xarray vports;
int total_vports; /* nums(PF) + nums(VF) + nums(uplink) */
int enabled_vports;
int mode; /* legacy or offload */
u16 manager_vport; /* vport0(PF) */
u16 first_host_vport; /* first vf */
/* Synchronize between vport change events
* and async SRIOV admin state changes
*/
struct mutex state_lock;
/* Protects eswitch mode change that occurs via one or more
* user commands, i.e. sriov state change, devlink commands.
*/
struct rw_semaphore mode_lock;
atomic64_t user_count;
struct workqueue_struct *work_queue; /* vport change handle */
struct crete_nb nb;
struct crete_esw_fun esw_funcs;
struct crete_esw_offload eswoffloads;
};
/**
* crete_esw_event_info - Indicates eswitch mode changed/changing.
*
* @new_mode: New mode of eswitch.
*/
struct crete_esw_event_info {
u16 new_mode;
};
/* Init API */
int crete_eswitch_init(struct crete_core_dev *dev);
void crete_eswitch_cleanup(struct crete_eswitch *esw);
/* SRIOV API */
int crete_eswitch_enable(struct crete_eswitch *esw, int num_vfs);
void crete_eswitch_disable_sriov(struct crete_eswitch *esw, bool clear_vf);
void crete_eswitch_disable(struct crete_eswitch *esw);
void crete_eswitch_disable_locked(struct crete_eswitch *esw);
/* eswitch vport API */
int crete_eswitch_set_vport_mac(struct crete_eswitch *esw,
u16 vport, const u8 *mac);
int crete_eswitch_set_vport_state(struct crete_eswitch *esw,
u16 vport, int link_state);
int crete_eswitch_set_vport_vlan(struct crete_eswitch *esw,
int vport, u16 vlan, u8 qos,
__be16 vlan_proto);
int crete_eswitch_set_vport_spoofchk(struct crete_eswitch *esw, u16 vport,
bool spoofchk);
int crete_eswitch_set_vport_trust(struct crete_eswitch *esw, u16 vport_num,
bool setting);
int crete_eswitch_set_vport_rate(struct crete_eswitch *esw, u16 vport,
u32 max_rate, u32 min_rate);
/* eswitch rw lock API */
bool crete_esw_hold(struct crete_core_dev *dev);
void crete_esw_release(struct crete_core_dev *dev);
void crete_esw_get(struct crete_core_dev *dev);
void crete_esw_put(struct crete_core_dev *dev);
int crete_esw_try_lock(struct crete_eswitch *esw);
void crete_esw_unlock(struct crete_eswitch *esw);
/* devlink API */
int esw_offloads_start(struct crete_eswitch *esw,
struct netlink_ext_ack *extack);
int esw_offloads_stop(struct crete_eswitch *esw,
struct netlink_ext_ack *extack);
struct crete_vport *crete_eswitch_get_vport(struct crete_eswitch *esw,
u16 vport_num);
int crete_eswitch_add_vport_trunk_range(struct crete_eswitch *esw,
int vport, u16 start_vlan,
u16 end_vlan);
int crete_eswitch_del_vport_trunk_range(struct crete_eswitch *esw,
int vport, u16 start_vlan,
u16 end_vlan);
int crete_esw_qos_set_sysfs_group_max_rate(struct crete_eswitch *esw,
struct crete_esw_rate_group *group,
u32 max_rate);
int crete_esw_qos_set_sysfs_group_min_rate(struct crete_eswitch *esw,
struct crete_esw_rate_group *group,
u32 min_rate);
int crete_esw_qos_vport_update_sysfs_group(struct crete_eswitch *esw,
int vport_num, u32 group_id);
#endif /* __CRETE_ESWITCH_H */

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include <net/devlink.h>
#include <linux/xarray.h>
#include "crete.h"
#include "crete_eswitch.h"
#include "crete_rep.h"
int crete_offloads_rep_cleanup(struct crete_eswitch *esw)
{
struct crete_esw_rep *rep;
unsigned long i;
crete_esw_for_each_rep(esw, i, rep) {
xa_erase(&esw->eswoffloads.vport_reps, rep->vport_idx);
kfree(rep);
}
xa_destroy(&esw->eswoffloads.vport_reps);
kfree(esw->eswoffloads.cfa_code_map);
esw->eswoffloads.cfa_code_map = NULL;
return 0;
}
/*
* crete offloads representors initial
* init the offloads reps xarray
* alloc the reps struct and cfa code map
*/
int crete_offloads_rep_init(struct crete_eswitch *esw)
{
struct crete_vport *vport;
struct crete_esw_rep *rep;
unsigned long i;
int err;
xa_init(&esw->eswoffloads.vport_reps);
crete_esw_for_each_vport(esw, i, vport) {
rep = kzalloc(sizeof(*rep), GFP_KERNEL);
if (!rep) {
err = -ENOMEM;
goto err;
}
rep->vport_idx = vport->index;
atomic_set(&rep->state, REP_UNREGISTERED);
err =
xa_insert(&esw->eswoffloads.vport_reps, vport->index, rep,
GFP_KERNEL);
if (err) {
kfree(rep);
goto err;
}
}
esw->eswoffloads.cfa_code_map = kcalloc(CRETE_MAX_CFA_CODE,
sizeof(*esw->eswoffloads.cfa_code_map), GFP_KERNEL);
if (!esw->eswoffloads.cfa_code_map) {
err = -ENOMEM;
goto err;
}
for (i = 0; i < CRETE_MAX_CFA_CODE; i++)
esw->eswoffloads.cfa_code_map[i] = CRETE_VF_IDX_INVALID;
return 0;
err:
crete_offloads_rep_cleanup(esw);
return err;
}
void crete_unload_reps_all_vport(struct crete_eswitch *esw)
{
struct crete_esw_rep *rep;
unsigned long i;
crete_esw_for_each_rep(esw, i, rep) {
if (atomic_read(&rep->state) != REP_LOADED)
continue;
crete_alloc_vf_rep_unload(esw->dev, rep);
atomic_set(&rep->state, REP_REGISTERED);
}
}
int crete_load_reps_all_vport(struct crete_eswitch *esw)
{
struct crete_esw_rep *rep;
unsigned long i;
int err;
crete_esw_for_each_rep(esw, i, rep) {
/* not exceed the max enable vf numbers */
if (i >= esw->esw_funcs.num_vfs)
break;
/* check the rep is registered */
if (atomic_read(&rep->state) != REP_REGISTERED)
continue;
if (crete_alloc_vf_rep_load(esw->dev, rep)) {
err = -ENOMEM;
goto err;
}
atomic_set(&rep->state, REP_LOADED);
}
return 0;
err:
crete_unload_reps_all_vport(esw);
return err;
}
static void crete_eswitch_register_vport_reps(struct crete_eswitch *esw)
{
struct crete_esw_rep *rep;
unsigned long i;
crete_esw_for_each_rep(esw, i, rep) {
rep->esw = esw;
atomic_set(&rep->state, REP_REGISTERED);
}
}
static void crete_eswitch_unregister_vport_reps(struct crete_eswitch *esw)
{
struct crete_esw_rep *rep;
unsigned long i;
if (esw->mode == CRETE_ESWITCH_OFFLOADS)
crete_unload_reps_all_vport(esw);
crete_esw_for_each_rep(esw, i, rep)
atomic_set(&rep->state, REP_UNREGISTERED);
}
static int crete_rep_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct crete_aux_dev *aux_dev =
container_of(adev, struct crete_aux_dev, adev);
struct crete_core_dev *cdev = aux_dev->core_dev;
struct crete_eswitch *esw = cdev->eswitch;
/* rep init */
crete_eswitch_register_vport_reps(esw);
return 0;
}
/*
* about the anolis 5.10.134-14 kernel version
* auxliary define with return int value
*/
#ifdef SNIC_ANOLIS_VERSION14
static int crete_rep_remove(struct auxiliary_device *adev)
{
struct crete_aux_dev *aux_dev =
container_of(adev, struct crete_aux_dev, adev);
crete_eswitch_unregister_vport_reps(aux_dev->core_dev->eswitch);
return 0;
}
#else
static void crete_rep_remove(struct auxiliary_device *adev)
{
struct crete_aux_dev *aux_dev =
container_of(adev, struct crete_aux_dev, adev);
crete_eswitch_unregister_vport_reps(aux_dev->core_dev->eswitch);
}
#endif
static const struct auxiliary_device_id crete_rep_id_table[] = {
{.name = CRETE_ADEV_NAME ".eth-rep", },
{ }
};
struct auxiliary_driver crete_rep_driver = {
.name = CRETE_ADEV_NAME ".eth-rep",
.probe = crete_rep_probe,
.remove = crete_rep_remove,
.id_table = crete_rep_id_table,
};

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __ESWOFFLOADS_
#define __ESWOFFLOADS_
int crete_offloads_rep_cleanup(struct crete_eswitch *esw);
int crete_offloads_rep_init(struct crete_eswitch *esw);
int crete_load_reps_all_vport(struct crete_eswitch *esw);
void crete_unload_reps_all_vport(struct crete_eswitch *esw);
#endif

View File

@ -0,0 +1,308 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/ethtool_netlink.h>
#include <linux/firmware.h>
#include "crete.h"
#include "crete_cmd_if.h"
#include "crete_regs.h"
#include "crete_fw_update.h"
struct crete_stats_desc {
char desc[ETH_GSTRING_LEN];
size_t offset;
};
struct crete_stats_desc crete_txq_stats_desc[] = {
{"packets", CRETE_TXQ_STATS(packets)},
{"bytes", CRETE_TXQ_STATS(bytes)},
{"kicks", CRETE_TXQ_STATS(kicks)},
};
struct crete_stats_desc crete_rxq_stats_desc[] = {
{"packets", CRETE_RXQ_STATS(packets)},
{"bytes", CRETE_RXQ_STATS(bytes)},
{"drops", CRETE_RXQ_STATS(drops)},
{"kicks", CRETE_RXQ_STATS(kicks)},
};
#define CRETE_TXQ_STATS_LEN ARRAY_SIZE(crete_txq_stats_desc)
#define CRETE_RXQ_STATS_LEN ARRAY_SIZE(crete_rxq_stats_desc)
void crete_ethtool_get_drvinfo(struct crete_priv *priv,
struct ethtool_drvinfo *drvinfo)
{
struct crete_core_dev *coredev = priv->coredev;
int count;
strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%d.%d.%d.%d", fw_ver_maj(coredev),
fw_ver_min(coredev), fw_ver_sub(coredev), fw_ver_rev(coredev));
strscpy(drvinfo->bus_info, dev_name(&coredev->pdev->dev),
sizeof(drvinfo->bus_info));
}
static void crete_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo)
{
struct crete_priv *priv = netdev_priv(dev);
crete_ethtool_get_drvinfo(priv, drvinfo);
}
static void get_speed_duplex(struct net_device *netdev,
struct ethtool_link_ksettings *link_ksettings)
{
u32 speed = SPEED_UNKNOWN;
u8 duplex = DUPLEX_UNKNOWN;
if (!netif_carrier_ok(netdev))
goto out;
/* get speed TODO */
duplex = DUPLEX_FULL;
out:
link_ksettings->base.speed = speed;
link_ksettings->base.duplex = duplex;
}
int crete_ethtool_get_link_ksettings(struct crete_priv *priv,
struct ethtool_link_ksettings *link_ksettings)
{
ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
get_speed_duplex(priv->netdev, link_ksettings);
return 0;
}
static int crete_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *link_ksettings)
{
struct crete_priv *priv = netdev_priv(netdev);
return crete_ethtool_get_link_ksettings(priv, link_ksettings);
}
int crete_ethtool_set_link_ksettings(struct crete_priv *priv,
const struct ethtool_link_ksettings *link_ksettings)
{
struct crete_core_dev *cdev = priv->coredev;
u32 speed;
speed = link_ksettings->base.speed;
crete_info(&cdev->pdev->dev, "set link speed:%u\n", speed);
return 0;
}
static int crete_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *link_ksettings)
{
struct crete_priv *priv = netdev_priv(netdev);
return crete_ethtool_set_link_ksettings(priv, link_ksettings);
}
int crete_ethtool_set_pauseparam(struct crete_priv *priv,
struct ethtool_pauseparam *pauseparam)
{
struct crete_core_dev *cdev = priv->coredev;
int err;
// if (pauseparam->autoneg)
// return -EINVAL;
err = crete_set_fc_enable(cdev, 1,
pauseparam->rx_pause ? 1 : 0,
pauseparam->tx_pause ? 1 : 0);
if (err) {
netdev_err(priv->netdev, "%s: crete_set_fc_enable failed:0x%x\n",
__func__, err);
}
return err;
}
int crete_query_port_pause(struct crete_core_dev *dev,
u32 *rx_pause, u32 *tx_pause)
{
*rx_pause = 0;
*tx_pause = 0;
return 0;
}
void crete_ethtool_get_pauseparam(struct crete_priv *priv,
struct ethtool_pauseparam *pauseparam)
{
struct crete_core_dev *cdev = priv->coredev;
int err;
err = crete_query_port_pause(cdev, &pauseparam->rx_pause,
&pauseparam->tx_pause);
if (err) {
netdev_err(priv->netdev, "%s: crete_query_port_pause failed:0x%x\n",
__func__, err);
}
}
static int crete_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pauseparam)
{
struct crete_priv *priv = netdev_priv(netdev);
return crete_ethtool_set_pauseparam(priv, pauseparam);
}
void crete_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pauseparam)
{
struct crete_priv *priv = netdev_priv(netdev);
crete_ethtool_get_pauseparam(priv, pauseparam);
}
int crete_ethtool_flash_device(struct crete_priv *priv,
struct ethtool_flash *flash)
{
struct crete_core_dev *cdev = priv->coredev;
struct net_device *dev = priv->netdev;
const struct firmware *fw;
int err;
if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
return -EOPNOTSUPP;
err = request_firmware_direct(&fw, flash->data, &dev->dev);
if (err)
return err;
dev_hold(dev);
rtnl_unlock();
err = crete_firmware_flash(cdev, fw, NULL, CRETE_FWU_ETHTOOL);
release_firmware(fw);
rtnl_lock();
dev_put(dev);
return err;
}
static int crete_flash_device(struct net_device *dev,
struct ethtool_flash *flash)
{
struct crete_priv *priv = netdev_priv(dev);
return crete_ethtool_flash_device(priv, flash);
}
static void crete_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
struct crete_priv *priv = netdev_priv(dev);
struct crete_core_dev *cdev = priv->coredev;
char *p = (char *)data;
unsigned int i, j;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < cdev->ring_size; i++) {
for (j = 0; j < CRETE_RXQ_STATS_LEN; j++) {
snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_%s",
i, crete_rxq_stats_desc[j].desc);
p += ETH_GSTRING_LEN;
}
}
for (i = 0; i < cdev->ring_size; i++) {
for (j = 0; j < CRETE_TXQ_STATS_LEN; j++) {
snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_%s",
i, crete_txq_stats_desc[j].desc);
p += ETH_GSTRING_LEN;
}
}
break;
}
}
static void crete_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct crete_priv *priv = netdev_priv(dev);
struct crete_core_dev *cdev = priv->coredev;
unsigned int idx = 0, start, i, j;
const u8 *stats_base;
size_t offset;
for (i = 0; i < cdev->ring_size; i++) {
stats_base = (u8 *)cdev->rxring[i].rxq_stats;
do {
start = u64_stats_fetch_begin_irq(&cdev->rxring[i].rxq_stats->syncp);
for (j = 0; j < CRETE_RXQ_STATS_LEN; j++) {
offset = crete_rxq_stats_desc[j].offset;
data[idx + j] = *(u64 *) (stats_base + offset);
}
} while (u64_stats_fetch_retry_irq(&cdev->rxring[i].rxq_stats->syncp, start));
idx += CRETE_RXQ_STATS_LEN;
}
for (i = 0; i < cdev->ring_size; i++) {
stats_base = (u8 *)&cdev->txring[i].txq_stats;
do {
start = u64_stats_fetch_begin_irq(&cdev->txring[i].txq_stats->syncp);
for (j = 0; j < CRETE_TXQ_STATS_LEN; j++) {
offset = crete_txq_stats_desc[j].offset;
data[idx + j] = *(u64 *) (stats_base + offset);
}
} while (u64_stats_fetch_retry_irq(&cdev->txring[i].txq_stats->syncp, start));
idx += CRETE_TXQ_STATS_LEN;
}
}
const struct ethtool_ops crete_ethtool_ops = {
.get_drvinfo = crete_get_drvinfo,
.get_link_ksettings = crete_get_link_ksettings,
.set_link_ksettings = crete_set_link_ksettings,
//.get_pauseparam = crete_get_pauseparam,
.set_pauseparam = crete_set_pauseparam,
.flash_device = crete_flash_device,
.get_strings = crete_get_strings,
.get_ethtool_stats = crete_get_ethtool_stats,
};

View File

@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __CRETE_ETHTOOL_COMMON_H__
#define __CRETE_ETHTOOL_COMMON_H__
#include "crete.h"
#include <linux/ethtool.h>
#define AUTO_NEG_OP_BIT BIT(2)
#define DUPLEX_MODE_OP_BIT BIT(1)
#define LINK_SPEED_OP_BIT BIT(0)
enum crete_link_mode {
CRETE_10GBASE = 1,
CRETE_25GBASE,
CRETE_40GBASE,
CRETE_50GBASE,
CRETE_100GBASE,
CRETE_200GBASE,
CRETE_400GBASE,
CRETE_LINK_MODES_NUMBER,
};
enum crete_link_mode_bit {
CRETE_10GBASE_BIT,
CRETE_25GBASE_BIT,
CRETE_40GBASE_BIT,
CRETE_50GBASE_BIT,
CRETE_100GBASE_BIT,
CRETE_200GBASE_BIT,
CRETE_400GBASE_BIT,
CRETE_LINK_MODES_CAP_BIT,
};
enum crete_duplex {
CRETE_HALF_DUPLEX,
CRETE_FULL_DUPLEX,
CRETE_DUPLEX_MAX,
};
enum crete_fec_mode {
CRETE_FEC_OFF = 0,
CRETE_FEC_AUTO,
CRETE_FEC_RS,
CRETE_FEC_BASER,
CRETE_FEC_LLRS,
};
static const u32 crete_link_speed[CRETE_LINK_MODES_NUMBER] = {
0,
[CRETE_10GBASE] = SPEED_10000,
[CRETE_25GBASE] = SPEED_25000,
[CRETE_40GBASE] = SPEED_40000,
[CRETE_50GBASE] = SPEED_50000,
[CRETE_100GBASE] = SPEED_100000,
[CRETE_200GBASE] = SPEED_200000,
[CRETE_400GBASE] = SPEED_400000,
};
static const u32 crete_fec_2_ethtool[] = {
[CRETE_FEC_OFF] = ETHTOOL_FEC_OFF,
[CRETE_FEC_AUTO] = ETHTOOL_FEC_AUTO,
[CRETE_FEC_RS] = ETHTOOL_FEC_RS,
[CRETE_FEC_BASER] = ETHTOOL_FEC_BASER,
[CRETE_FEC_LLRS] = ETHTOOL_FEC_LLRS,
};
static const u32 crete_fec_2_ethtool_bit[] = {
[CRETE_FEC_OFF] = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
[CRETE_FEC_RS] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[CRETE_FEC_BASER] = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
[CRETE_FEC_LLRS] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
};
static const u8 crete_link_duplex[CRETE_DUPLEX_MAX] = {
[CRETE_HALF_DUPLEX] = DUPLEX_HALF,
[CRETE_FULL_DUPLEX] = DUPLEX_FULL,
};
struct crete_speed_duplex {
uint16_t speed;
uint16_t duplex;
uint32_t duplex_cap;
uint32_t speed_cap;
};
#endif

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
#include "crete_cmd.h"
#include "crete_regs.h"
#define EVNET_IN_MASK 0x02
#define EVNET_BUSY_MASK 0x01
#define EVNET_NO_BUSY_MASK 0xFE
static irqreturn_t irq_int_handler(int irq, void *dev)
{
struct crete_core_dev *cdev = (struct crete_core_dev *)dev;
struct crete_event_irq *event_irq = cdev->event_irq;
struct crete_event_entry cee;
struct crete_event_buffer_head event_buffer_head;
struct crete_hw *hw = &cdev->hw;
uint32_t total_len_dw;
uint32_t index = 1;
uint8_t val = 0;
bool device_owner = false;
bool buf_inline = false;
val = readb(&hw->io_addr->event_busy);
if (val & EVNET_BUSY_MASK) {
device_owner = true;
buf_inline = !!(val & EVNET_IN_MASK);
} else {
dev_err(cdev->device, "device is not set owner!\n");
return IRQ_HANDLED;
}
if(!buf_inline) {
dev_err(cdev->device, "current not support not inline!\n");
writeb(val & EVNET_NO_BUSY_MASK, &hw->io_addr->event_busy);
return IRQ_HANDLED;
}
crete_ioread32(&hw->io_addr->event_buffer[0],
&event_buffer_head, 1);
total_len_dw = event_buffer_head.event_entry_length;
memset(&cee, 0, sizeof(struct crete_event_entry));
while (index <= total_len_dw) {
crete_ioread32(&hw->io_addr->event_buffer[index], &cee, 1);
if (cee.event_length)
crete_ioread32(&hw->io_addr->event_buffer[index+1],
cee.event_data, cee.event_length);
atomic_notifier_call_chain(&event_irq->nh[cee.event_type], cee.event_type, &cee);
pr_info("crete event handle event type:%u\n", cee.event_type);
index += (cee.event_length + 1);
}
writeb(val & EVNET_NO_BUSY_MASK, &hw->io_addr->event_busy);
return IRQ_HANDLED;
}
int crete_event_alloc_buf(struct crete_core_dev *cdev,
struct crete_event_irq *event_irq)
{
struct crete_hw *hw = &cdev->hw;
size_t size = CRETE_EVENT_ALLOC_BUFFER_SIZE * sizeof(uint32_t);
event_irq->event_buf_size = size;
crete_info(cdev->device, "event_irq->event_buf_size:%ld", size);
event_irq->event_buf = dma_alloc_coherent(cdev->device, CRETE_EVENT_ALLOC_BUFFER_SIZE*4,
&event_irq->event_dma, GFP_KERNEL | __GFP_ZERO);
if (!event_irq->event_buf)
return -ENOMEM;
crete_info(cdev->device, "event buffer dma addr:0x%llx\n", event_irq->event_dma);
iseg_wd8(hw, struct crete_init_seg,
event_buffer_size, (u8)(event_irq->event_buf_size));
iseg_wd32(hw, struct crete_init_seg, event_buffer_addr_low,
(u32)(event_irq->event_dma & 0xffffffff));
iseg_wd32(hw, struct crete_init_seg,
event_buffer_addr_hi, (u32)(event_irq->event_dma >> 32));
/* Make sure firmware sees the complete address before we proceed */
wmb();
return 0;
}
static int crete_event_start(struct crete_hw *hw)
{
int i, err, irqno;
struct crete_event_irq *event_irq;
struct crete_core_dev *cdev = container_of(hw,
struct crete_core_dev, hw);
struct device *dev = crete_hw_to_dev(hw);
struct crete_irq_info *irq_info = NULL;
struct msix_entry *msix_ent = NULL;
irqno = crete_req_msixirq(cdev);
irq_info = &cdev->irq_info[irqno];
msix_ent = &cdev->msix_ent[irqno];
if (!(cdev->flags & CRETE_FLAG_HAS_MSIX))
return 0;
event_irq = kzalloc(sizeof(*event_irq), GFP_KERNEL);
if (!event_irq)
return -ENOMEM;
#ifndef CONFIG_NOSIM_DEBUG
writew(irqno, &hw->io_addr->event_vector);
#endif
for (i = 0; i < CRETE_EVENT_TYPE_MAX; i++)
ATOMIC_INIT_NOTIFIER_HEAD(&event_irq->nh[i]);
snprintf(event_irq->name, sizeof(event_irq->name), "event@pci:%s", pci_name(cdev->pdev));
crete_info(dev, "event_irq_name[%s]", event_irq->name);
event_irq->vector = irq_info->vector;
event_irq->entry = irqno;
cdev->event_irq = event_irq;
err = request_irq(event_irq->vector, irq_int_handler, 0, event_irq->name, cdev);
if (err) {
crete_err(dev, "Failed to request irq. err = %d\n", err);
goto err_req_irq;
}
irq_info->requested = 1;
irq_info->handler = irq_int_handler;
crete_info(dev, "crete_event init success event_irq_name[%s], vector[%d], irq[%d]",
event_irq->name, irqno, event_irq->vector);
return 0;
err_req_irq:
crete_free_msixirq(cdev, irqno);
kfree(event_irq);
return err;
}
int crete_event_notifier_register(struct crete_core_dev *dev, struct crete_nb *nb)
{
struct crete_event_irq *irq_nb = dev->event_irq;
return atomic_notifier_chain_register(&irq_nb->nh[nb->event_type], &nb->nb);
}
EXPORT_SYMBOL(crete_event_notifier_register);
int crete_event_notifier_unregister(struct crete_core_dev *dev, struct crete_nb *nb)
{
struct crete_event_irq *irq_nb = dev->event_irq;
return atomic_notifier_chain_unregister(&irq_nb->nh[nb->event_type], &nb->nb);
}
EXPORT_SYMBOL(crete_event_notifier_unregister);
int crete_event_init(struct crete_hw *hw)
{
int err = 0;
uint8_t val;
struct device *dev = crete_hw_to_dev(hw);
val = readb(&hw->io_addr->cp_caps);
if (val & CRETE_CP_EP) {
err = crete_event_start(hw);
if (err < 0) {
crete_info(dev, "crete_event_start failed!\n");
return err;
}
val = readb(&hw->io_addr->cp_status);
val |= CRETE_CP_EP;
writeb(val, &hw->io_addr->cp_status);
} else {
crete_info(dev, "not support event path!\n");
}
return err;
}
void crete_event_exit(struct crete_hw *hw)
{
struct crete_irq_info *irq_info;
struct crete_core_dev *cdev = container_of(hw,
struct crete_core_dev, hw);
struct device *dev = crete_hw_to_dev(hw);
if (!cdev->event_irq) {
crete_info(dev, "crete event already exit\n");
return;
}
irq_info = &cdev->irq_info[cdev->event_irq->entry];
if (irq_info->requested) {
crete_free_msixirq(cdev, cdev->event_irq->vector);
free_irq(irq_info->vector, cdev);
kfree(cdev->event_irq);
cdev->event_irq = NULL;
}
crete_info(dev, "crete event exit\n");
}
EXPORT_SYMBOL(crete_event_exit);

View File

@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_EVENT_H
#define _CRETE_EVENT_H
#include "crete.h"
#include <linux/types.h>
#include <uapi/linux/stddef.h>
#define CRETE_MAX_IRQ_NAME 32
#define CRETE_EVENT_ALLOC_BUFFER_SIZE 8
#define CRETE_EVENT_SUPPORTED(hw) (readb(&(hw)->io_addr->cp_caps) & CRETE_CP_EP)
// enum crete_event_offset {
// CRETE_EVENT_TYPE_CMDPATH = 0,
// CRETE_EVENT_TYPE_ADMIN = 1,
// };
enum crete_event_type {
/* Completion group */
CRETE_EVENT_TYPE_CP = 0,
/* status Change group */
/* Error Report group */
/* Data transfer group */
CRETE_EVENT_PTP_TIMESTAMP = 1,
CRETE_EVENT_PORT_LINK_CHANGE = 0x201,
CRETE_EVENT_TYPE_MAX,
};
enum crete_vnet_evnet_subtype {
CRETE_EVENT_VNET_LINK_CHANGE = 0,
CRETE_EVENT_VNET_RESET,
};
enum crete_portchange_event_subtype {
CRETE_EVENT_PORT_LINK_DOWN = 0,
CRETE_EVENT_PORT_LINK_UP = 1,
CRETE_EVENT_PORT_LINK_ERR
};
enum crete_cp_event_subtype {
CRETE_EVENT_STYPE_CMDPATH = 0,
CRETE_EVENT_STYPE_ADMIN = 1,
};
struct crete_event_irq {
struct atomic_notifier_head nh[CRETE_EVENT_TYPE_MAX];
cpumask_var_t mask;
char name[CRETE_MAX_IRQ_NAME];
u32 vector;
u16 entry;
void *event_buf;
dma_addr_t event_dma;
u8 event_buf_size;
};
struct crete_event_cmd {
uint16_t entry_id;
uint16_t rsvd;
};
struct crete_event_buffer_head {
u8 resv0;
u8 event_seq;
uint8_t event_sig;
uint8_t event_entry_length;
};
struct crete_event_entry {
uint8_t event_length;
uint8_t event_sub_type;
uint16_t event_type;
uint32_t event_data[]; //mlx5_eqe
};
struct crete_nb {
struct notifier_block nb;
u16 event_type;
};
#define CRETE_NB_INIT(name, handler, event) do { \
(name)->nb.notifier_call = handler; \
(name)->event_type = CRETE_EVENT_TYPE_##event; \
} while (0)
#define crete_nb_cof(ptr, type, member) \
(container_of(container_of(ptr, struct crete_nb, nb), type, member))
extern int crete_event_notifier_register(struct crete_core_dev *dev, struct crete_nb *nb);
extern int crete_event_notifier_unregister(struct crete_core_dev *dev, struct crete_nb *nb);
#endif

View File

@ -0,0 +1,515 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
#include "crete_cmd.h"
#include "crete_regs.h"
#include <asm/unaligned.h>
#include <linux/uuid.h>
#include "crete_fw_update.h"
#include "crete_pldmfw_lib.h"
#include "crete_cmd_if.h"
static const struct pldmfw_ops crete_fwu_ops = {
.match_record = NULL,
.send_package_data = NULL,
.send_component_table = NULL,
.flash_component = NULL,
.finalize_update = NULL,
};
static void crete_fwu_status_notify(struct crete_fwu_priv *fwu_priv,
const char *msg, const char *comp_name,
u32 done_bytes, u32 total_bytes)
{
devlink_flash_update_status_notify(fwu_priv->devlink, msg, comp_name,
done_bytes, total_bytes);
}
static int crete_acquire_flashlock(struct crete_fwu_priv *fwu_priv)
{
u32 in[CRETE_ST_SZ_DW(fwu_lock_in)] = {0};
u32 out[CRETE_ST_SZ_DW(fwu_lock_out)] = {0};
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
CRETE_SET(fwu_lock_in, in, cmd_id, CRETE_CMD_FWU_LOCK);
CRETE_SET(fwu_lock_in, in, seq_id, seq_id);
CRETE_SET(fwu_lock_in, in, cmd, CRETE_FWU_LOCKED);
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, sizeof(in), out, sizeof(out));
if (ret < 0)
return ret;
st = CRETE_GET(fwu_lock_out, out, status);
ret = CRETE_GET16(fwu_lock_out, out, status_inner);
cretefw_info(fwu_priv, "st[%d] fwlock inner status[%d]\n", st, ret);
return ret;
}
static int crete_release_flashlock(struct crete_fwu_priv *fwu_priv)
{
u32 in[CRETE_ST_SZ_DW(fwu_unlock_in)] = {0};
u32 out[CRETE_ST_SZ_DW(fwu_unlock_out)] = {0};
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
CRETE_SET(fwu_unlock_in, in, cmd_id, CRETE_CMD_FWU_UNLOCK);
CRETE_SET(fwu_unlock_in, in, seq_id, seq_id);
CRETE_SET(fwu_unlock_in, in, cmd, CRETE_FWU_UNLOCK);
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, sizeof(in), out, sizeof(out));
if (ret < 0)
return ret;
st = CRETE_GET(fwu_unlock_out, out, status);
ret = CRETE_GET16(fwu_unlock_out, out, status_inner);
cretefw_info(fwu_priv, "st[%d] fwu unlock inner status[%d]\n", st, ret);
return ret;
}
static int crete_fwu_pkey(struct crete_fwu_priv *fwu_priv, struct crete_pldmfw_priv *data)
{
u32 in[CRETE_ST_SZ_DW(fwu_pkey_in)] = {0};
u32 out[CRETE_ST_SZ_DW(fwu_pkey_out)] = {0};
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
CRETE_SET(fwu_pkey_in, in, cmd_id, CRETE_CMD_FWU_PKEY);
CRETE_SET(fwu_pkey_in, in, seq_id, seq_id);
CRETE_SET(fwu_pkey_in, in, cmd, CRETE_FWU_PKEY);
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, sizeof(in), out, sizeof(out));
if (ret < 0)
return ret;
st = CRETE_GET(fwu_pkey_out, out, status);
ret = CRETE_GET16(fwu_pkey_out, out, status_inner);
cretefw_info(fwu_priv, "st[%d] fwu pkey inner status[%d]\n", st, ret);
return ret;
}
static int crete_fwu_ver(struct crete_fwu_priv *fwu_priv, struct crete_pldmfw_priv *data)
{
u32 *in, *out;
int outlen = CRETE_ST_SZ_BYTES(fwu_ver_out);
int inlen = CRETE_ST_SZ_BYTES(fwu_ver_in);
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
int component_count = data->component_count;
struct pldmfw_component *component;
int i = 0;
inlen += component_count * CRETE_FLD_SZ_BYTES(fwu_ver_in, comp_list[0]);
outlen += component_count * CRETE_FLD_SZ_BYTES(fwu_ver_out, version_list[0]);
in = kvzalloc(inlen, GFP_KERNEL);
out = kvzalloc(outlen, GFP_KERNEL);
if (!out || !in) {
ret = -ENOMEM;
goto err_out;
}
CRETE_SET(fwu_ver_in, in, cmd_id, CRETE_CMD_FWU_VER);
CRETE_SET(fwu_ver_in, in, cmd, CRETE_FWU_VER);
CRETE_SET(fwu_ver_in, in, seq_id, seq_id);
list_for_each_entry(component, &data->components, entry) {
if (i >= component_count)
break;
CRETE_ARRAY_SET(fwu_ver_in, in, comp_list, i, component->identifier);
i++;
}
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, inlen, out, outlen);
if (ret < 0)
goto err_out;
st = CRETE_GET(fwu_ver_out, out, status);
ret = CRETE_GET(fwu_ver_out, out, status_inner);
cretefw_info(fwu_priv, "st[%d] fwu_ver inner status[%d]\n", st, ret);
/*TODO*/
/*
* version_out = CRETE_ADDR_OF(fwu_ver_out, out, version_list);
* for (i = 0; i < component_count; i++, version_out += CRETE_ST_SZ_BYTES(version_list)) {
* version = CRETE_GET_PR(version_list, version_out, qid);
* version_efuse = CRETE_GET_PR(version_list, version_out, result);
* crete_fw_checkversion(version, version_efuse, flag);
* }
*/
err_out:
kvfree(in);
kvfree(out);
return ret;
}
static void
crete_check_fwu_ack(struct crete_fwu_priv *fwu_priv, const char *comp_name, u16 status_code,
struct netlink_ext_ack *extack)
{
#define CRETEFW_ACK_PRFX "check fwu_ack: "
#define CRETEFW_CHECK_ACK(msg, err) \
CRETEFW_ERR_MSG(fwu_priv, extack, CRETEFW_ACK_PRFX msg, err)
cretefw_info(fwu_priv, "%s: firmware response code 0x%x\n", comp_name, status_code);
switch (status_code) {
case CRETE_FWU_SUCCESS:
/* firmware indicated this update is good to proceed */
return;
case CRETE_FWU_ERR_SEQ_ID:
CRETEFW_CHECK_ACK("flash components err seq_id", status_code);
break;
case CRETE_FWU_CRC_ERR:
CRETEFW_CHECK_ACK("flash components crc err", status_code);
break;
case CRETE_FWU_BUSY:
CRETEFW_CHECK_ACK("flash device is busy", status_code);
break;
case CRETE_FWU_LOCK_FAIL:
CRETEFW_CHECK_ACK("flash lock failed", status_code);
break;
case CRETE_FWU_PKEY_ERR:
CRETEFW_CHECK_ACK("flash components pkey err", status_code);
break;
case CRETE_FWU_INVALID_ID:
CRETEFW_CHECK_ACK("flash components invalid img id", status_code);
break;
case CRETE_FWU_FLASH_ERR:
CRETEFW_CHECK_ACK("flash components write err", status_code);
break;
case CRETE_FWU_EFUSE_ERR:
CRETEFW_CHECK_ACK("flash components write efuse err", status_code);
break;
case CRETE_FWU_SYNC_ERR:
CRETEFW_CHECK_ACK("flash components sync err", status_code);
break;
case CRETE_FWU_TRANS_ERR:
CRETEFW_CHECK_ACK("flash components trans err", status_code);
break;
case CRETE_FWU_TIMEOUT:
CRETEFW_CHECK_ACK("flash components wait timeout", status_code);
break;
case CRETE_FWU_STATUS_ERR:
CRETEFW_CHECK_ACK("flash components status mismatch", status_code);
break;
case CRETE_FWU_OTHER_ERR:
CRETEFW_CHECK_ACK("flash components unexpected err", status_code);
break;
default:
CRETEFW_CHECK_ACK("Unrecognized command status code", status_code);
break;
}
}
static int crete_fwu_end(struct crete_fwu_priv *fwu_priv, struct crete_pldmfw_priv *data)
{
u32 in[CRETE_ST_SZ_DW(fwu_end_in)] = {0};
u32 out[CRETE_ST_SZ_DW(fwu_end_out)] = {0};
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
CRETE_SET(fwu_end_in, in, cmd_id, CRETE_CMD_FWU_END);
CRETE_SET(fwu_end_in, in, cmd, CRETE_FWU_IMG_END);
CRETE_SET(fwu_end_in, in, seq_id, seq_id);
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, sizeof(in), out, sizeof(out));
if (ret < 0)
return ret;
st = CRETE_GET(fwu_end_out, out, status);
ret = CRETE_GET(fwu_end_out, out, status_inner);
cretefw_info(fwu_priv, "st[%d] fwu end inner end [%d]\n", st, ret);
return ret;
}
static int crete_flash_component_block(u32 offset_uint, u16 block_size, u8 *block,
bool last_cmd, u16 identifier, struct crete_fwu_priv *fwu_priv, u16 *st_code)
{
u32 out[CRETE_ST_SZ_DW(fwu_xfer_out)] = {0};
u32 *in, *block_ptr;
int inlen = CRETE_ST_SZ_BYTES(fwu_xfer_in);
u32 calculated_crc = 0;
u16 seq_id = fwu_priv->seq_id;
int ret = 0;
u8 st = 0;
int attempts = 0;
inlen += block_size;
in = kvzalloc(inlen, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto flash_out;
}
identifier = last_cmd ? (identifier | BIT(15)) : (identifier & ~BIT(15));
CRETE_SET(fwu_xfer_in, in, cmd_id, CRETE_CMD_FWU_XFER);
CRETE_SET(fwu_xfer_in, in, seq_id, seq_id);
CRETE_SET(fwu_xfer_in, in, cmd, CRETE_FWU_IMG_XFER);
CRETE_SET(fwu_xfer_in, in, flag, identifier);
CRETE_SET(fwu_xfer_in, in, len, block_size);
CRETE_SET(fwu_xfer_in, in, offset, offset_uint);
block_ptr = CRETE_ADDR_OF(fwu_xfer_in, in, data);
memcpy(block_ptr, block, block_size);
calculated_crc = crc32_le(~0, block, block_size) ^ ~0;
CRETE_SET(fwu_xfer_in, in, crc, calculated_crc);
do {
ret = crete_cmd_exec_polling(fwu_priv->cdev, in, inlen, out, sizeof(out));
if (ret && ret != -EREMOTEIO) {
cretefw_err(fwu_priv, "fwu_xfer cmd carryout failed ret[%d]\n", ret);
goto flash_out;
}
st = CRETE_GET(fwu_xfer_out, out, status);
*st_code = CRETE_GET(fwu_xfer_out, out, status_inner);
cretefw_info(fwu_priv, "attempts[%d] st[%d] fwu_xfer status[%d]\n",
attempts, st, *st_code);
if (!st && *st_code == CRETE_FWU_SUCCESS)
goto flash_out;
if (*st_code != CRETE_FWU_CRC_ERR)
goto flash_out;
attempts++;
} while (attempts < CRETE_MAX_ATTEMPTS_XFER);
flash_out:
kvfree(in);
return ret ? ret : *st_code;
}
static int crete_flash_component(struct crete_fwu_priv *fwu_priv,
struct pldmfw_component *component)
{
u32 offset = 0;
u32 offset_uint = 0;
bool last_cmd;
u16 status_code;
int err;
struct netlink_ext_ack *extack = fwu_priv->extack;
u8 *block;
const u8 *image = component->component_data;
u32 length = component->component_size;
const char *comp_name = component->version_string;
if (comp_name == NULL)
return -EINVAL;
cretefw_info(fwu_priv, "Beginning write of flash component '%s' size '%d'\n",
comp_name, length);
crete_fwu_status_notify(fwu_priv, "Flashing component", comp_name, 0, length);
block = kzalloc(CRETE_MAX_FWU_BUF_LEN, GFP_KERNEL);
if (!block)
return -ENOMEM;
do {
u32 block_size;
block_size = min_t(u32, CRETE_MAX_FWU_BUF_LEN, length - offset);
last_cmd = !(offset + block_size < length);
memcpy(block, image + offset, block_size);
status_code = CRETE_FWU_OTHER_ERR;
err = crete_flash_component_block(offset_uint, block_size, block,
last_cmd, component->identifier, fwu_priv, &status_code);
if (err)
break;
offset += block_size;
fwu_priv->seq_id++;
CRETE_FWU_INCREMENT_OFFSET(offset_uint);
crete_fwu_status_notify(fwu_priv, "Flashing component", comp_name, offset, length);
} while (!last_cmd);
crete_check_fwu_ack(fwu_priv, comp_name, status_code, extack);
if (err)
crete_fwu_status_notify(fwu_priv, "Flashing failed",
comp_name, length, length);
else
crete_fwu_status_notify(fwu_priv, "Flashing done",
comp_name, length, length);
kfree(block);
return err;
}
static int crete_flash_components(struct crete_fwu_priv *fwu_priv, struct crete_pldmfw_priv *data)
{
struct pldmfw_record *record;
struct pldmfw_component *component;
unsigned long *bitmap = NULL;
int err = 0;
list_for_each_entry(record, &data->records, entry) {
bitmap = record->component_bitmap;
list_for_each_entry(component, &data->components, entry) {
u8 index = component->index, transfer_flag = 0;
if (!test_bit(index, bitmap))
continue;
cretefw_info(fwu_priv, "identifier: %d\n", component->identifier);
cretefw_info(fwu_priv, "version_string: %s\n", component->version_string);
cretefw_info(fwu_priv, "classification: %d\n", component->classification);
if(component->version_string == NULL)
continue;
/* determine whether this is the start, middle, end, or both
* the start and end of the component tables
*/
if (index == find_first_bit(bitmap, data->component_bitmap_len))
transfer_flag |= PLDM_TRANSFER_FLAG_START;
if (index == find_last_bit(bitmap, data->component_bitmap_len))
transfer_flag |= PLDM_TRANSFER_FLAG_END;
if (!transfer_flag)
transfer_flag = PLDM_TRANSFER_FLAG_MIDDLE;
err = crete_flash_component(fwu_priv, component);
if (err)
return err;
}
}
return err;
}
static int crete_flash_image(struct crete_fwu_priv *fwu_priv, const struct firmware *fw)
{
struct crete_pldmfw_priv *data;
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
INIT_LIST_HEAD(&data->records);
INIT_LIST_HEAD(&data->components);
data->fw = fw;
data->context = &fwu_priv->context;
err = crete_pldm_parse_image(data);
if (err)
goto out_release_data;
cretefw_info(fwu_priv, "total_header_size : %d\n", data->total_header_size);
cretefw_info(fwu_priv, "record_count : %d\n", data->record_count);
cretefw_info(fwu_priv, "component_bitmap_len : %d\n", data->component_bitmap_len);
cretefw_info(fwu_priv, "component_count : %d\n", data->component_count);
err = crete_fwu_pkey(fwu_priv, data);
if (err)
goto out_release_data;
err = crete_fwu_ver(fwu_priv, data);
if (err)
goto out_release_data;
err = crete_flash_components(fwu_priv, data);
if (err)
goto out_release_data;
err = crete_fwu_end(fwu_priv, data);
out_release_data:
crete_pldmfw_free_priv(data);
kfree(data);
return err;
}
int crete_firmware_flash(struct crete_core_dev *cdev,
const struct firmware *firmware,
struct netlink_ext_ack *extack, enum crete_fwu_type type)
{
struct crete_fwu_priv fwu_priv;
int err;
if (!crete_core_is_pf(cdev))
return 0;
memset(&fwu_priv, 0, sizeof(fwu_priv));
fwu_priv.context.ops = &crete_fwu_ops;
fwu_priv.context.dev = cdev->device;
fwu_priv.devlink = priv_to_devlink(cdev);
fwu_priv.extack = extack;
fwu_priv.seq_id = 0;
fwu_priv.cdev = cdev;
cretefw_info(&fwu_priv, "Initialize firmware flash process\n");
#ifndef CONFIG_DEVLINK_CARRYOUT_OPTIMIZE
if (type == CRETE_FWU_DEVLINK)
devlink_flash_update_begin_notify(fwu_priv.devlink);
#endif
crete_fwu_status_notify(&fwu_priv, "Preparing to flash", NULL, 0, 0);
err = crete_acquire_flashlock(&fwu_priv);
if (err) {
CRETEFW_ERR_MSG(&fwu_priv, extack, "Failed to acquire device flash lock", err);
goto flash_out;
}
err = crete_flash_image(&fwu_priv, firmware);
if (err)
CRETEFW_ERR_MSG(&fwu_priv, extack, "Failed to flash PLDM image", err);
err = crete_release_flashlock(&fwu_priv);
if (err)
CRETEFW_ERR_MSG(&fwu_priv, extack, "Failed to release device flash lock", err);
flash_out:
#ifndef CONFIG_DEVLINK_CARRYOUT_OPTIMIZE
if (type == CRETE_FWU_DEVLINK)
devlink_flash_update_end_notify(fwu_priv.devlink);
#endif
return err;
}
EXPORT_SYMBOL(crete_firmware_flash);

View File

@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_FW_UPDATE_H
#define _CRETE_FW_UPDATE_H
#include <linux/crc32.h>
#include <linux/pldmfw.h>
#include <linux/firmware.h>
#define CRETE_MAX_FWU_BUF_LEN 512
#define CRETE_MAX_FWU_BUF_LEN_UINT 256
#define CRETE_FWU_OFFSET_INCREMENT (CRETE_MAX_FWU_BUF_LEN / CRETE_MAX_FWU_BUF_LEN_UINT)
#define CRETE_FWU_INCREMENT_OFFSET(offset) ((offset) += CRETE_FWU_OFFSET_INCREMENT)
#define CRETE_MAX_ATTEMPTS_XFER 3
#define CRETE_FWU_PKEY_FLAG BIT(1)
#define CRETE_FWU_ACTIVE_FLAG BIT(2)
#define CRETE_FWU_FORCE_FLAG BIT(3)
#define CRETE_FWU_EFUSE_FLAH BIT(4)
enum crete_fwu_cmd {
CRETE_FWU_LOCKED = 1,
CRETE_FWU_PKEY,
CRETE_FWU_VER,
CRETE_FWU_IMG_XFER,
CRETE_FWU_IMG_END,
CRETE_FWU_ACT,
CRETE_FWU_SYNC,
CRETE_FWU_EFUSE,
CRETE_FWU_UNLOCK,
CRETE_FWU_QUERY,
CRETE_FWU_LOG,
CRETE_FWU_IMG_INFO,
CRETE_FWU_IMG_READ,
CRETE_FWU_ACK_HALF = 0xfe,
CRETE_FWU_ACK = 0xff,
};
enum crete_fwu_ack {
CRETE_FWU_SUCCESS = 0,
CRETE_FWU_ERR_SEQ_ID,
CRETE_FWU_CRC_ERR,
CRETE_FWU_BUSY,
CRETE_FWU_LOCK_FAIL,
CRETE_FWU_PKEY_ERR,
CRETE_FWU_INVALID_ID,
CRETE_FWU_FLASH_ERR,
CRETE_FWU_EFUSE_ERR,
CRETE_FWU_SYNC_ERR,
CRETE_FWU_TRANS_ERR,
CRETE_FWU_TIMEOUT,
CRETE_FWU_STATUS_ERR,
CRETE_FWU_OTHER_ERR,
};
enum crete_fwu_type {
CRETE_FWU_ETHTOOL = 0,
CRETE_FWU_DEVLINK = 1,
};
struct crete_fwu_priv {
struct pldmfw context;
struct devlink *devlink;
struct crete_core_dev *cdev;
struct netlink_ext_ack *extack;
u16 seq_id;
};
static inline
struct device *cretefw_dev_dev(struct crete_fwu_priv *fwu_priv)
{
return fwu_priv->cdev->device;
}
#define CRETEFW_PRFX "cretefw: "
#define cretefw_info(fwu_priv, fmt, ...) \
dev_info(cretefw_dev_dev(fwu_priv), CRETEFW_PRFX fmt, ## __VA_ARGS__)
#define cretefw_err(fwu_priv, fmt, ...) \
dev_err(cretefw_dev_dev(fwu_priv), CRETEFW_PRFX fmt, ## __VA_ARGS__)
#define cretefw_dbg(fwu_priv, fmt, ...) \
dev_dbg(cretefw_dev_dev(fwu_priv), CRETEFW_PRFX fmt, ## __VA_ARGS__)
#define CRETEFW_ERR_PRFX "Firmware flash failed: "
#define CRETEFW_ERR_MSG(fwu_priv, extack, msg, err) do { \
cretefw_err(fwu_priv, "%s, err (%d)\n", CRETEFW_ERR_PRFX msg, err); \
NL_SET_ERR_MSG_MOD(extack, CRETEFW_ERR_PRFX msg); \
} while (0)
int crete_firmware_flash(struct crete_core_dev *cdev,
const struct firmware *firmware,
struct netlink_ext_ack *extack, enum crete_fwu_type type);
#endif

View File

@ -0,0 +1,840 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/netdevice.h>
#include <net/bonding.h>
#include "crete.h"
#include "crete_cmd.h"
#include "crete_cmd_if.h"
static inline bool crete_lag_is_supported(struct crete_core_dev *dev)
{
if (!dev->lag_cap.lag_master) {
if (dev->lag_cap.num_ports == CRETE_MIN_LAG_PORTS ||
dev->lag_cap.num_ports <= CRETE_MAX_LAG_PORTS)
dev->lag_enable = CRETE_LAG_DISABLE;
return false;
} else {
if (dev->lag_cap.num_ports != CRETE_MIN_LAG_PORTS &&
dev->lag_cap.num_ports != CRETE_MAX_LAG_PORTS) {
dev->lag_enable = CRETE_LAG_DISABLE;
return false;
}
}
return true;
}
static inline void crete_ldev_get(struct crete_lag *ldev)
{
kref_get(&ldev->ref);
}
static void crete_ldev_free(struct kref *ref)
{
struct crete_lag *ldev = container_of(ref, struct crete_lag, ref);
if (ldev->nb.notifier_call)
unregister_netdevice_notifier_net(&init_net, &ldev->nb);
destroy_workqueue(ldev->wq);
mutex_destroy(&ldev->lock);
kfree(ldev);
}
static void crete_ldev_put(struct crete_lag *ldev)
{
kref_put(&ldev->ref, crete_ldev_free);
}
static void *pci_get_other_drvdata(struct device *this, struct device *other)
{
if (this->driver != other->driver)
return NULL;
return pci_get_drvdata(to_pci_dev(other));
}
static int _next_phys_dev(struct crete_core_dev *tmp_dev,
const struct crete_core_dev *curr_dev)
{
if (tmp_dev == curr_dev)
return 0;
return 1;
}
static bool crete_check_in_one_lag(struct crete_core_dev *t, struct crete_core_dev *tmp)
{
if (t->lag_cap.lag_id != tmp->lag_cap.lag_id ||
t->lag_cap.mode_support != tmp->lag_cap.mode_support ||
t->lag_cap.hash_type != tmp->lag_cap.hash_type ||
t->lag_cap.num_ports != tmp->lag_cap.num_ports)
return false;
return true;
}
/*
* should be implemented in the public interface
*/
static int next_phys_lag_dev(struct device *dev, const void *data)
{
struct crete_core_dev *tmp_dev, *this = (struct crete_core_dev *)data;
tmp_dev = pci_get_other_drvdata(this->device, dev);
if (!tmp_dev)
goto done;
if (!crete_core_is_pf(tmp_dev))
goto done;
if (!crete_lag_is_supported(tmp_dev))
goto done;
if (!crete_check_in_one_lag(this, tmp_dev))
goto done;
return _next_phys_dev(tmp_dev, data);
done:
return 0;
}
/*
* should be implemented in the public interface
*/
static struct crete_core_dev *crete_get_next_dev(struct crete_core_dev *dev,
int (*match)(struct device *dev, const void *data))
{
struct device *next;
if (!crete_core_is_pf(dev))
return NULL;
next = bus_find_device(&pci_bus_type, NULL, dev, match);
if (!next)
return NULL;
put_device(next);
return pci_get_drvdata(to_pci_dev(next));
}
/*
* should be implemented in the public interface
*/
struct crete_core_dev *crete_get_next_phy_dev_lag(struct crete_core_dev *dev)
{
return crete_get_next_dev(dev, &next_phys_lag_dev);
}
static void crete_queue_bond_work(struct crete_lag *ldev, unsigned long delay)
{
queue_delayed_work(ldev->wq, &ldev->bond_work, delay);
}
struct crete_cmd_lag_context_bits test;
static int crete_cmd_create_lag(struct crete_lag *ldev)
{
int in_len = CRETE_ST_SZ_BYTES(create_lag_in);
int out_len = CRETE_ST_SZ_BYTES(create_lag_out);
void *in, *out, *lagc;
int lagc_size = CRETE_ST_SZ_BYTES(lag_context);
struct crete_core_dev *dev = ldev->pf[CRETE_LAG_P1].dev;
int status;
int ret = 0;
int i = 0;
in_len += lagc_size;
in = kvzalloc(in_len, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto done;
}
out = kvzalloc(out_len, GFP_KERNEL);
if (!out) {
ret = -ENOMEM;
kvfree(in);
goto done;
}
CRETE_SET(create_lag_in, in, cmd_id, CRETE_CMD_LAG_CONFIG);
CRETE_SET(create_lag_in, in, opcode, CRETE_CREATE_LAG);
lagc = CRETE_ADDR_OF(create_lag_in, in, lag_context);
CRETE_SET(lag_context, lagc, lag_id, dev->lag_cap.lag_id);
CRETE_SET(lag_context, lagc, lag_mode, ldev->info.upper_lag_mode);
CRETE_SET(lag_context, lagc, hash_type, ldev->info.hash_type);
CRETE_SET(lag_context, lagc, lu_te_num, ldev->ports);
for (i = 0; i < ldev->ports; i++)
CRETE_ARRAY_SET(lag_context, lagc, lu_te_mem, i, ldev->pf[i].dev->sfi_id);
ret = crete_cmd_exec_polling(dev, in, in_len, out, sizeof(out));
if (ret) {
crete_info(dev->device, "create lag cmd err[%d]", ret);
goto out;
}
status = CRETE_GET(create_lag_out, out, status);
crete_info(dev->device, "create lag status:%d", status);
out:
kfree(in);
kfree(out);
done:
return ret;
}
static void crete_activate_lag(struct crete_lag *ldev)
{
crete_cmd_create_lag(ldev);
ldev->mode = CRETE_LAG_ACTIVE;
}
static int crete_cmd_modify_lag(struct crete_lag *ldev)
{
int in_len = CRETE_ST_SZ_BYTES(modify_lag_in);
int out_len = CRETE_ST_SZ_BYTES(modify_lag_out);
void *in, *out, *lagc;
int lagc_size = CRETE_ST_SZ_BYTES(lag_context);
struct crete_core_dev *dev = ldev->pf[CRETE_LAG_P1].dev;
int status;
int ret = 0;
int i = 0;
in_len += lagc_size;
in = kvzalloc(in_len, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto done;
}
out = kvzalloc(out_len, GFP_KERNEL);
if (!out) {
ret = -ENOMEM;
kvfree(in);
goto done;
}
CRETE_SET(modify_lag_in, in, cmd_id, CRETE_CMD_LAG_CONFIG);
CRETE_SET(modify_lag_in, in, opcode, CRETE_MODIFY_LAG);
lagc = CRETE_ADDR_OF(modify_lag_in, in, lag_context);
CRETE_SET(lag_context, lagc, lag_id, dev->lag_cap.lag_id);
CRETE_SET(lag_context, lagc, lag_mode, ldev->info.upper_lag_mode);
CRETE_SET(lag_context, lagc, hash_type, dev->lag_cap.hash_type);
for (i = 0; i < ldev->ports; i++) {
if (ldev->info.netdev_state[i].link_up &
ldev->info.netdev_state[i].tx_enabled) {
CRETE_ARRAY_SET(lag_context, lagc, lu_te_mem, ldev->info.netdev_idx,
ldev->pf[i].dev->sfi_id);
ldev->info.netdev_idx++;
pr_debug("func:%s--line:%d sfi_id:0x%x\n", __func__, __LINE__, ldev->pf[i].dev->sfi_id);
}
}
ldev->info.active_port = ldev->info.netdev_idx;
ldev->info.netdev_idx = 0;
CRETE_SET(lag_context, lagc, lu_te_num, ldev->info.active_port);
ret = crete_cmd_exec_polling(dev, in, in_len, out, sizeof(out));
if (ret) {
crete_info(dev->device, "modify lag cmd err[%d]", ret);
goto out;
}
status = CRETE_GET(modify_lag_out, out, status);
crete_info(dev->device, "modify lag status:%d", status);
out:
kfree(in);
kfree(out);
done:
return ret;
}
static void crete_modify_lag(struct crete_lag *ldev)
{
crete_cmd_modify_lag(ldev);
}
static int crete_cmd_destroy_lag(struct crete_lag *ldev, struct crete_core_dev *spec_dev)
{
int in_len = CRETE_ST_SZ_BYTES(destroy_lag_in);
int out_len = CRETE_ST_SZ_BYTES(destroy_lag_out);
void *in, *out, *lagc;
int lagc_size = CRETE_ST_SZ_BYTES(lag_context);
struct crete_core_dev *dev =
spec_dev == NULL ? ldev->pf[CRETE_LAG_P1].dev : spec_dev;
int status;
int ret = 0;
in_len += lagc_size;
in = kvzalloc(in_len, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto done;
}
out = kvzalloc(out_len, GFP_KERNEL);
if (!out) {
ret = -ENOMEM;
kvfree(in);
goto done;
}
CRETE_SET(destroy_lag_in, in, cmd_id, CRETE_CMD_LAG_CONFIG);
CRETE_SET(destroy_lag_in, in, opcode, CRETE_DESTROY_LAG);
lagc = CRETE_ADDR_OF(destroy_lag_in, in, lag_context);
CRETE_SET(lag_context, lagc, lag_id, dev->lag_cap.lag_id);
ret = crete_cmd_exec_polling(dev, in, in_len, out, sizeof(out));
if (ret) {
crete_info(dev->device, "destroy lag cmd err[%d]", ret);
goto out;
}
status = CRETE_GET(destroy_lag_out, out, status);
crete_info(dev->device, "destroy lag status:%d", status);
out:
kfree(in);
kfree(out);
done:
return ret;
}
int crete_cmd_lag_enable(struct crete_core_dev *dev, u16 lag_enable)
{
int in_len = CRETE_ST_SZ_BYTES(lag_enable_in);
int out_len = CRETE_ST_SZ_BYTES(lag_enable_out);
void *in, *out;
int status;
int ret = 0;
in = kvzalloc(in_len, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto done;
}
out = kvzalloc(out_len, GFP_KERNEL);
if (!out) {
ret = -ENOMEM;
kvfree(in);
goto done;
}
CRETE_SET(lag_enable_in, in, cmd_id, CRETE_CMD_ENABLE_LAG);
CRETE_SET(lag_enable_in, in, opcode, 0);
CRETE_SET(lag_enable_in, in, vport_id, dev->sfi_id);
CRETE_SET(lag_enable_in, in, lag_enable, lag_enable);
ret = crete_cmd_exec_polling(dev, in, in_len, out, sizeof(out));
if (ret) {
crete_info(dev->device, "enable lag cmd err[%d]", ret);
goto out;
}
status = CRETE_GET(lag_enable_out, out, status);
crete_info(dev->device, "enable lag status:%d", status);
out:
kfree(in);
kfree(out);
done:
return ret;
}
static void crete_disable_lag(struct crete_lag *ldev, struct crete_core_dev *dev)
{
crete_cmd_destroy_lag(ldev, dev);
ldev->mode = CRETE_LAG_INACTIVE;
}
static void crete_do_bond(struct crete_lag *ldev)
{
bool do_bond;
struct crete_lag_info lag_info = {};
if (!crete_lag_is_ready(ldev)) {
do_bond = false;
} else {
lag_info = ldev->info;
do_bond = lag_info.is_bonded;
}
if (do_bond && !__crete_lag_is_active(ldev)) {
crete_activate_lag(ldev);
crete_modify_lag(ldev);
} else if (do_bond && __crete_lag_is_active(ldev))
crete_modify_lag(ldev);
else if (!do_bond && __crete_lag_is_active(ldev))
crete_disable_lag(ldev, NULL);
}
static void crete_do_bond_work(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct crete_lag *ldev = container_of(delayed_work, struct crete_lag,
bond_work);
int status;
status = crete_dev_list_trylock();
if (!status) {
crete_queue_bond_work(ldev, 100);
return;
}
mutex_lock(&ldev->lock);
crete_do_bond(ldev);
mutex_unlock(&ldev->lock);
crete_dev_list_unlock();
}
static int crete_lag_dev_get_netdev_idx(struct crete_lag *ldev,
struct net_device *ndev)
{
int i;
for (i = 0; i < ldev->ports; i++) {
/* add pointer protect*/
if (ldev->pf[i].dev)
if (ldev->pf[i].dev->netdev == ndev)
return i;
}
return -ENOENT;
}
static int crete_handle_changeupper_event(struct crete_lag *ldev,
struct crete_lag_info *lag_info,
struct netdev_notifier_changeupper_info *info)
{
struct net_device *upper = info->upper_dev, *ndev_tmp;
struct netdev_lag_upper_info *lag_upper_info = NULL;
struct bonding *bond = netdev_priv(upper);
bool is_bonded, is_in_lag, mode_supported;
bool has_inactive = 0;
struct slave *slave;
u8 bond_status = 0;
int num_slaves = 0;
int changed = 0;
int idx;
if (!netif_is_lag_master(upper))
return 0;
if (info->linking)
lag_upper_info = info->upper_info;
rcu_read_lock();
for_each_netdev_in_bond_rcu(upper, ndev_tmp) {
idx = crete_lag_dev_get_netdev_idx(ldev, ndev_tmp);
if (idx >= 0) {
slave = bond_slave_get_rcu(ndev_tmp);
if (slave)
has_inactive |= bond_is_slave_inactive(slave);
bond_status |= (1 << idx);
}
num_slaves++;
}
rcu_read_unlock();
if (!(bond_status & GENMASK(ldev->ports - 1, 0)))
return 0;
if (lag_upper_info) {
lag_info->tx_type = lag_upper_info->tx_type;
lag_info->hash_type = lag_upper_info->hash_type;
}
if (bond)
lag_info->upper_lag_mode = BOND_MODE(bond);
lag_info->has_inactive = has_inactive;
is_in_lag = num_slaves == ldev->ports &&
bond_status == GENMASK(ldev->ports - 1, 0);
/* Lag mode must be activebackup or hash. */
mode_supported = ((1 << lag_info->upper_lag_mode) & ldev->mode_supported);
is_bonded = is_in_lag && mode_supported;
if (lag_info->is_bonded != is_bonded) {
lag_info->is_bonded = is_bonded;
changed = 1;
}
if (!is_in_lag)
return changed;
if (!crete_lag_is_ready(ldev))
NL_SET_ERR_MSG_MOD(info->info.extack,
"Can't activate LAG offload");
else if (!mode_supported)
NL_SET_ERR_MSG_MOD(info->info.extack,
"Can't activate LAG offload, TX type isn't supported");
return changed;
}
static int crete_handle_changelowerstate_event(struct crete_lag *ldev,
struct crete_lag_info *lag_info,
struct net_device *ndev,
struct netdev_notifier_changelowerstate_info *info)
{
struct netdev_lag_lower_state_info *lag_lower_info;
int idx;
if (!netif_is_lag_port(ndev))
return 0;
idx = crete_lag_dev_get_netdev_idx(ldev, ndev);
if (idx < 0)
return 0;
lag_lower_info = info->lower_state_info;
if (!lag_lower_info)
return 0;
lag_info->netdev_state[idx] = *lag_lower_info;
return 1;
}
static int crete_handle_changeinfodata_event(struct crete_lag *ldev,
struct crete_lag_info *lag_info,
struct net_device *ndev)
{
struct net_device *ndev_tmp;
struct slave *slave;
bool has_inactive = 0;
int idx;
if (!netif_is_lag_master(ndev))
return 0;
rcu_read_lock();
for_each_netdev_in_bond_rcu(ndev, ndev_tmp) {
idx = crete_lag_dev_get_netdev_idx(ldev, ndev_tmp);
if (idx < 0)
continue;
slave = bond_slave_get_rcu(ndev_tmp);
if (slave)
has_inactive |= bond_is_slave_inactive(slave);
}
rcu_read_unlock();
if (lag_info->has_inactive == has_inactive)
return 0;
lag_info->has_inactive = has_inactive;
return 1;
}
static int crete_lag_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
struct crete_lag_info info;
struct crete_lag *ldev;
int changed = 0, change_lower = 0;
if (event != NETDEV_CHANGEUPPER &&
event != NETDEV_CHANGELOWERSTATE &&
event != NETDEV_CHANGEINFODATA)
return NOTIFY_DONE;
ldev = container_of(this, struct crete_lag, nb);
info = ldev->info;
switch (event) {
case NETDEV_CHANGEUPPER:
changed = crete_handle_changeupper_event(ldev, &info, ptr);
break;
case NETDEV_CHANGELOWERSTATE:
change_lower = crete_handle_changelowerstate_event(ldev, &info,
ndev, ptr);
break;
case NETDEV_CHANGEINFODATA:
changed = crete_handle_changeinfodata_event(ldev, &info, ndev);
break;
default:
break;
}
ldev->info = info;
if (changed || change_lower) {
pr_debug("func:%s--line:%d, changed:%d change_lower:%d\n",
__func__, __LINE__, changed, change_lower);
if (change_lower) {
crete_queue_bond_work(ldev, 100);
}
else
crete_queue_bond_work(ldev, 0);
}
return NOTIFY_DONE;
}
static struct crete_lag *crete_lag_dev_alloc(struct crete_core_dev *dev)
{
struct crete_lag *ldev;
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev)
return NULL;
ldev->wq = create_singlethread_workqueue("crete_lag");
if (!ldev->wq) {
kfree(ldev);
return NULL;
}
kref_init(&ldev->ref);
mutex_init(&ldev->lock);
INIT_DELAYED_WORK(&ldev->bond_work, crete_do_bond_work);
ldev->nb.notifier_call = crete_lag_netdev_event;
if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
ldev->nb.notifier_call = NULL;
dev_err(dev->device, "failed to register LAG dev notifier\n");
}
ldev->mode = CRETE_LAG_INACTIVE;
ldev->ports = dev->lag_cap.num_ports;
ldev->mode_supported = dev->lag_cap.mode_support;
ldev->hash_supported = dev->lag_cap.hash_type;
ldev->lag_id = dev->lag_cap.lag_id;
return ldev;
}
static inline int crete_get_dev_index(struct crete_core_dev *dev)
{
int idx = dev->lag_cap.pf_id;;
if (idx >= 0 && idx < CRETE_MAX_LAG_PORTS)
return idx;
else
return -1;
}
static void crete_ldev_add(struct crete_lag *ldev, struct crete_core_dev *dev)
{
int fn = crete_get_dev_index(dev);
if (fn >= ldev->ports || fn < 0) {
dev_dbg(dev->device, "can't support lag, port id:%d\n", fn);
return;
}
ldev->pf[fn].dev = dev;
dev->lag_dev = ldev;
ldev->port_flags |= 1 << fn;
if (ldev->port_flags == GENMASK(ldev->ports - 1, 0)) {
crete_disable_lag(ldev, NULL);
set_bit(CRETE_LAG_READY, &ldev->state_flags);
}
}
static int __crete_lag_dev_add(struct crete_core_dev *dev)
{
struct crete_lag *ldev = NULL;
struct crete_core_dev *tmp_dev;
tmp_dev = crete_get_next_phy_dev_lag(dev);
if (tmp_dev) {
dev_info(dev->device, "found peer core dev:%s\n", dev_name(tmp_dev->device));
ldev = tmp_dev->lag_dev;
}
if (!ldev) {
ldev = crete_lag_dev_alloc(dev);
if (!ldev) {
dev_err(dev->device, "failed to alloc lag dev\n");
return 0;
}
crete_ldev_add(ldev, dev);
return 0;
}
mutex_lock(&ldev->lock);
crete_ldev_get(ldev);
crete_ldev_add(ldev, dev);
mutex_unlock(&ldev->lock);
return 0;
}
static int crete_get_lag_cap(struct crete_core_dev *dev)
{
int ret;
int in_len = CRETE_ST_SZ_BYTES(get_lag_cap_in);
int out_len = CRETE_ST_SZ_BYTES(get_lag_cap_out);
void *in, *out;
u8 status;
in = kvzalloc(in_len, GFP_KERNEL);
if (!in) {
ret = -ENOMEM;
goto done;
}
out = kvzalloc(out_len, GFP_KERNEL);
if (!out) {
ret = -ENOMEM;
kvfree(in);
goto done;
}
CRETE_SET(get_lag_cap_in, in, cmd_id, CRETE_CMD_GET_LAG_CAP);
CRETE_SET(get_lag_cap_in, in, opcode, 0);
CRETE_SET(get_lag_cap_in, in, vport_id, dev->sfi_id);
ret = crete_cmd_exec_polling(dev, in, in_len, out, out_len);
if (ret < 0)
goto err_out;
status = CRETE_GET(get_lag_cap_out, out, status);
if (status != SUCCESS) {
u32 err_type = CRETE_GET(get_lag_cap_out, out, err_type);
crete_err(dev->device,
"crete get lag cap failed, status:0x%x err type:0x%x\n",
status, err_type);
ret = -EINVAL;
goto err_out;
}
dev->lag_cap.lag_master = CRETE_GET(get_lag_cap_out, out, lag_master);
dev->lag_cap.lag_id = CRETE_GET(get_lag_cap_out, out, lag_id);
dev->lag_cap.mode_support = CRETE_GET(get_lag_cap_out, out, mode_support);
dev->lag_cap.hash_type = CRETE_GET(get_lag_cap_out, out, hash_type);
dev->lag_cap.num_ports = CRETE_GET(get_lag_cap_out, out, num_ports);
dev->lag_cap.pf_id = CRETE_GET(get_lag_cap_out, out, pf_id);
err_out:
kvfree(in);
kvfree(out);
done:
return ret;
}
int crete_lag_add(struct crete_core_dev *dev)
{
int ret = 0;
dev->lag_enable = CRETE_LAG_UNSUPPORT;
ret = crete_get_lag_cap(dev);
if (ret < 0)
goto done;
crete_add_lag_enable_debugfs(dev);
if (!crete_lag_is_supported(dev))
goto done;
dev->lag_enable = CRETE_LAG_ENABLE;
recheck:
crete_dev_list_lock();
ret = __crete_lag_dev_add(dev);
crete_dev_list_unlock();
if (ret) {
msleep(50);
goto recheck;
}
if (dev->lag_dev)
crete_ldev_add_debugfs(dev);
done:
return ret;
}
static void crete_ldev_remove(struct crete_lag *ldev, struct crete_core_dev *dev)
{
int i;
for (i = 0; i < ldev->ports; i++)
if (ldev->pf[i].dev == dev)
break;
if (i == ldev->ports) {
if (__crete_lag_is_active(ldev))
crete_disable_lag(ldev, dev);
return;
}
ldev->pf[i].dev = NULL;
dev->lag_dev = NULL;
}
void crete_lag_remove(struct crete_core_dev *dev)
{
struct crete_lag *ldev;
ldev = dev->lag_dev;
if (!ldev)
return;
crete_ldev_remove_debugfs(dev->dbg.lag_debugfs);
mutex_lock(&ldev->lock);
crete_ldev_remove(ldev, dev);
mutex_unlock(&ldev->lock);
crete_ldev_put(ldev);
}

View File

@ -0,0 +1,126 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __CRETE_LAG_H__
#define __CRETE_LAG_H__
#include <linux/debugfs.h>
#include "crete.h"
#define CRETE_MAX_LAG_PORTS 4
#define CRETE_MIN_LAG_PORTS 2
#ifndef DEFINE_SHOW_STORE_ATTRIBUTE
#define DEFINE_SHOW_STORE_ATTRIBUTE(__name) \
static int __name ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, __name ## _show, inode->i_private); \
} \
\
static const struct file_operations __name ## _fops = { \
.owner = THIS_MODULE, \
.open = __name ## _open, \
.read = seq_read, \
.write = __name ## _write, \
.llseek = seq_lseek, \
.release = single_release, \
}
#endif
struct crete_lag_cap {
u8 lag_master;
u8 lag_id;
u8 mode_support;
u8 hash_type;
u8 num_ports;
u8 pf_id;
u8 resv[2];
};
enum {
CRETE_LAG_P1,
CRETE_LAG_P2,
CRETE_LAG_P3,
CRETE_LAG_P4,
};
enum crete_lag_mode {
CRETE_LAG_INACTIVE,
CRETE_LAG_ACTIVE,
};
enum crete_lag_state {
CRETE_LAG_READY,
};
enum crete_lag_pri {
CRETE_LAG_DISABLE,
CRETE_LAG_ENABLE,
CRETE_LAG_UNSUPPORT,
CRETE_LAG_PRI_MAX,
};
/* Used for collection of netdev event info. */
struct crete_lag_info {
enum netdev_lag_tx_type tx_type;
struct netdev_lag_lower_state_info netdev_state[CRETE_MAX_LAG_PORTS];
unsigned int is_bonded:1;
unsigned int has_inactive:1;
enum netdev_lag_hash hash_type;
u8 upper_lag_mode;
u8 active_port;
u8 netdev_idx;
};
struct crete_lag_func {
struct crete_core_dev *dev;
//struct net_device *netdev;
bool has_drop;
};
struct crete_lag {
enum crete_lag_mode mode;
unsigned long state_flags;
u8 port_flags;
u8 ports;
u8 mode_supported;
u8 hash_supported;
u8 lag_id;
struct kref ref;
struct crete_lag_func pf[CRETE_MAX_LAG_PORTS];
struct crete_lag_info info;
struct workqueue_struct *wq;
struct delayed_work bond_work;
struct notifier_block nb;
struct mutex lock;
};
static inline bool crete_is_supported_lag(struct crete_core_dev *dev)
{
return true;
}
static inline bool crete_lag_is_ready(struct crete_lag *ldev)
{
return test_bit(CRETE_LAG_READY, &ldev->state_flags);
}
static inline bool __crete_lag_is_active(struct crete_lag *ldev)
{
return (ldev->mode == CRETE_LAG_ACTIVE);
}
void crete_ldev_add_debugfs(struct crete_core_dev *dev);
void crete_add_lag_enable_debugfs(struct crete_core_dev *dev);
void crete_ldev_remove_debugfs(struct dentry *dbg);
int crete_lag_add(struct crete_core_dev *dev);
void crete_lag_remove(struct crete_core_dev *dev);
int crete_cmd_lag_enable(struct crete_core_dev *dev, u16 lag_enable);
#if 0
void crete_lag_add_netdev(struct crete_core_dev *dev,
struct net_device *netdev);
void crete_lag_remove_netdev(struct crete_core_dev *dev,
struct net_device *netdev);
#endif
#endif

View File

@ -0,0 +1,196 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
static int state_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev;
bool active;
ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
active = __crete_lag_is_active(ldev);
mutex_unlock(&ldev->lock);
seq_printf(file, "%s\n", active ? "active" : "disabled");
return 0;
}
static int members_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev;
int i;
ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
for (i = 0; i < ldev->ports; i++) {
if (!ldev->pf[i].dev)
continue;
seq_printf(file, "%s\n", dev_name(ldev->pf[i].dev->device));
}
mutex_unlock(&ldev->lock);
return 0;
}
static int mode_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
seq_printf(file, "0x%x\n", ldev->mode_supported);
mutex_unlock(&ldev->lock);
return 0;
}
static int hash_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
seq_printf(file, "0x%x\n", ldev->hash_supported);
mutex_unlock(&ldev->lock);
return 0;
}
static int lag_id_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
seq_printf(file, "0x%x\n", ldev->lag_id);
mutex_unlock(&ldev->lock);
return 0;
}
static int max_port_show(struct seq_file *file, void *priv)
{
struct crete_core_dev *dev = file->private;
struct crete_lag *ldev = dev->lag_dev;
mutex_lock(&ldev->lock);
seq_printf(file, "0x%x\n", ldev->ports);
mutex_unlock(&ldev->lock);
return 0;
}
static ssize_t lag_enable_write(struct file *file,
const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct crete_core_dev *dev = m->private;
u16 lag_enable;
int ret;
if (dev->lag_enable == CRETE_LAG_UNSUPPORT)
return -EINVAL;
ret = kstrtou16_from_user(ubuf, len, 10, &lag_enable);
if (ret < 0)
return ret;
if (lag_enable != CRETE_LAG_DISABLE &&
lag_enable != CRETE_LAG_ENABLE)
return -EINVAL;
if (lag_enable == dev->lag_enable)
return len;
ret = crete_cmd_lag_enable(dev, lag_enable);
if (ret)
return ret;
dev->lag_enable = lag_enable;
*offp += len;
return len;
}
static int lag_enable_show(struct seq_file *m, void *data)
{
struct crete_core_dev *dev = m->private;
if (dev->lag_enable == CRETE_LAG_ENABLE)
seq_puts(m, "lag is enabled\n");
else if (dev->lag_enable == CRETE_LAG_DISABLE)
seq_puts(m, "lag is disabled\n");
else
seq_puts(m, "lag is unsupported\n");
return 0;
}
DEFINE_SHOW_ATTRIBUTE(state);
DEFINE_SHOW_ATTRIBUTE(members);
DEFINE_SHOW_ATTRIBUTE(mode);
DEFINE_SHOW_ATTRIBUTE(hash);
DEFINE_SHOW_ATTRIBUTE(lag_id);
DEFINE_SHOW_ATTRIBUTE(max_port);
DEFINE_SHOW_STORE_ATTRIBUTE(lag_enable);
void crete_add_lag_enable_debugfs(struct crete_core_dev *dev)
{
debugfs_create_file("lag_enable", 0644, crete_debugfs_get_dev_root(dev),
dev, &lag_enable_fops);
}
void crete_ldev_add_debugfs(struct crete_core_dev *dev)
{
struct dentry *dbg;
dbg = debugfs_create_dir("lag", crete_debugfs_get_dev_root(dev));
dev->dbg.lag_debugfs = dbg;
debugfs_create_file("state", 0444, dbg, dev, &state_fops);
debugfs_create_file("members", 0444, dbg, dev, &members_fops);
debugfs_create_file("mode_supported", 0444, dbg, dev, &mode_fops);
debugfs_create_file("hash_supported", 0444, dbg, dev, &hash_fops);
debugfs_create_file("lag_id", 0444, dbg, dev, &lag_id_fops);
debugfs_create_file("max_port", 0444, dbg, dev, &max_port_fops);
}
void crete_ldev_remove_debugfs(struct dentry *dbg)
{
debugfs_remove_recursive(dbg);
}

View File

@ -0,0 +1,589 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2018-2019, Intel Corporation. */
#include <asm/unaligned.h>
#include <linux/crc32.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pldmfw.h>
#include <linux/slab.h>
#include <linux/uuid.h>
#include "crete_pldmfw_lib.h"
#include "crete_regs.h"
/**
* crete_pldm_check_fw_space - Verify that the firmware image has space left
* @data: pointer to private data
* @offset: offset to start from
* @length: length to check for
*
* Verify that the firmware data can hold a chunk of bytes with the specified
* offset and length.
*
* Returns: zero on success, or -EFAULT if the image does not have enough
* space left to fit the expected length.
*/
static int
crete_pldm_check_fw_space(struct crete_pldmfw_priv *data, size_t offset, size_t length)
{
size_t expected_size = offset + length;
struct device *dev = data->context->dev;
if (data->fw->size < expected_size) {
dev_err(dev, "Firmware file size smaller than expected. Got %zu bytes, needed %zu bytes\n",
data->fw->size, expected_size);
return -EFAULT;
}
return 0;
}
/**
* crete_pldm_move_fw_offset - Move the current firmware offset forward
* @data: pointer to private data
* @bytes_to_move: number of bytes to move the offset forward by
*
* Check that there is enough space past the current offset, and then move the
* offset forward by this amount.
*
* Returns: zero on success, or -EFAULT if the image is too small to fit the
* expected length.
*/
static int
crete_pldm_move_fw_offset(struct crete_pldmfw_priv *data, size_t bytes_to_move)
{
int err;
err = crete_pldm_check_fw_space(data, data->offset, bytes_to_move);
if (err)
return err;
data->offset += bytes_to_move;
return 0;
}
/**
* crete_pldm_parse_header - Validate and extract details about the PLDM header
* @data: pointer to private data
*
* Performs initial basic verification of the PLDM image, up to the first
* firmware record.
*
* This includes the following checks and extractions
*
* * Verify that the UUID at the start of the header matches the expected
* value as defined in the DSP0267 PLDM specification
* * Check that the revision is 0x01
* * Extract the total header_size and verify that the image is large enough
* to contain at least the length of this header
* * Extract the size of the component bitmap length
* * Extract a pointer to the start of the record area
*
* Returns: zero on success, or a negative error code on failure.
*/
static int crete_pldm_parse_header(struct crete_pldmfw_priv *data)
{
const struct __pldmfw_record_area *record_area;
struct device *dev = data->context->dev;
const struct __pldm_header *header;
size_t header_size;
int err;
err = crete_pldm_move_fw_offset(data, sizeof(*header));
if (err)
return err;
header = (const struct __pldm_header *)data->fw->data;
data->header = header;
if (!uuid_equal(&header->id, &pldm_firmware_header_id)) {
dev_err(dev, "Invalid package header identifier. Expected UUID %pUB, but got %pUB\n",
&pldm_firmware_header_id, &header->id);
return -EINVAL;
}
if (header->revision != PACKAGE_HEADER_FORMAT_REVISION) {
dev_err(dev, "Invalid package header revision. Expected revision %u but got %u\n",
PACKAGE_HEADER_FORMAT_REVISION, header->revision);
return -EOPNOTSUPP;
}
data->total_header_size = get_unaligned_le16(&header->size);
header_size = data->total_header_size - sizeof(*header);
err = crete_pldm_check_fw_space(data, data->offset, header_size);
if (err)
return err;
data->component_bitmap_len =
get_unaligned_le16(&header->component_bitmap_len);
if (data->component_bitmap_len % 8 != 0) {
dev_err(dev, "Invalid component bitmap length. The length is %u, which is not a multiple of 8\n",
data->component_bitmap_len);
return -EINVAL;
}
data->bitmap_size = data->component_bitmap_len / 8;
err = crete_pldm_move_fw_offset(data, header->version_len);
if (err)
return err;
/* extract a pointer to the record area, which just follows the main
* PLDM header data.
*/
record_area = (const struct __pldmfw_record_area *)(data->fw->data +
data->offset);
err = crete_pldm_move_fw_offset(data, sizeof(*record_area));
if (err)
return err;
data->record_count = record_area->record_count;
data->record_start = record_area->records;
dev_info(dev, "data->offset [0x%lx] record_count [%d] record_start [%p]\n", data->offset,
record_area->record_count, record_area->records);
return 0;
}
/**
* crete_pldm_check_desc_tlv_len - Check that the length matches expectation
* @data: pointer to image details
* @type: the descriptor type
* @size: the length from the descriptor header
*
* If the descriptor type is one of the documented descriptor types according
* to the standard, verify that the provided length matches.
*
* If the type is not recognized or is VENDOR_DEFINED, return zero.
*
* Returns: zero on success, or -EINVAL if the specified size of a standard
* TLV does not match the expected value defined for that TLV.
*/
static int
crete_pldm_check_desc_tlv_len(struct crete_pldmfw_priv *data, u16 type, u16 size)
{
struct device *dev = data->context->dev;
u16 expected_size;
switch (type) {
case PLDM_DESC_ID_PCI_VENDOR_ID:
case PLDM_DESC_ID_PCI_DEVICE_ID:
case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
case PLDM_DESC_ID_PCI_SUBDEV_ID:
expected_size = 2;
break;
case PLDM_DESC_ID_PCI_REVISION_ID:
expected_size = 1;
break;
case PLDM_DESC_ID_PNP_VENDOR_ID:
expected_size = 3;
break;
case PLDM_DESC_ID_IANA_ENTERPRISE_ID:
case PLDM_DESC_ID_ACPI_VENDOR_ID:
case PLDM_DESC_ID_PNP_PRODUCT_ID:
case PLDM_DESC_ID_ACPI_PRODUCT_ID:
expected_size = 4;
break;
case PLDM_DESC_ID_UUID:
expected_size = 16;
break;
case PLDM_DESC_ID_VENDOR_DEFINED:
return 0;
default:
/* Do not report an error on an unexpected TLV */
dev_err(dev, "Found unrecognized TLV type 0x%04x\n", type);
return 0;
}
if (size != expected_size) {
dev_err(dev, "Found TLV type 0x%04x with unexpected length. Got %u bytes, but expected %u bytes\n",
type, size, expected_size);
return -EINVAL;
}
return 0;
}
/**
* pldm_parse_desc_tlvs - Check and skip past a number of TLVs
* @data: pointer to private data
* @record: pointer to the record this TLV belongs too
* @desc_count: descriptor count
*
* From the current offset, read and extract the descriptor TLVs, updating the
* current offset each time.
*
* Returns: zero on success, or a negative error code on failure.
*/
static int
crete_pldm_parse_desc_tlvs(struct crete_pldmfw_priv *data,
struct pldmfw_record *record, u8 desc_count)
{
const struct __pldmfw_desc_tlv *__desc;
const u8 *desc_start;
u8 i;
desc_start = data->fw->data + data->offset;
pldm_for_each_desc_tlv(i, __desc, desc_start, desc_count) {
struct pldmfw_desc_tlv *desc;
int err;
u16 type, size;
err = crete_pldm_move_fw_offset(data, sizeof(*__desc));
if (err)
return err;
type = get_unaligned_le16(&__desc->type);
/* According to DSP0267, this only includes the data field */
size = get_unaligned_le16(&__desc->size);
err = crete_pldm_check_desc_tlv_len(data, type, size);
if (err)
return err;
/* check that we have space and move the offset forward */
err = crete_pldm_move_fw_offset(data, size);
if (err)
return err;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = type;
desc->size = size;
desc->data = __desc->data;
list_add_tail(&desc->entry, &record->descs);
}
return 0;
}
/**
* crete_pldm_parse_one_record - Verify size of one PLDM record
* @data: pointer to image details
* @__record: pointer to the record to check
*
* This function checks that the record size does not exceed either the size
* of the firmware file or the total length specified in the header section.
*
* It also verifies that the recorded length of the start of the record
* matches the size calculated by adding the static structure length, the
* component bitmap length, the version string length, the length of all
* descriptor TLVs, and the length of the package data.
*
* Returns: zero on success, or a negative error code on failure.
*/
static int
crete_pldm_parse_one_record(struct crete_pldmfw_priv *data,
const struct __pldmfw_record_info *__record)
{
struct pldmfw_record *record;
size_t measured_length;
int err;
const u8 *bitmap_ptr;
u16 record_len;
int i;
/* Make a copy and insert it into the record list */
record = kzalloc(sizeof(*record), GFP_KERNEL);
if (!record)
return -ENOMEM;
INIT_LIST_HEAD(&record->descs);
list_add_tail(&record->entry, &data->records);
/* Then check that we have space and move the offset */
err = crete_pldm_move_fw_offset(data, sizeof(*__record));
if (err)
return err;
record_len = get_unaligned_le16(&__record->record_len);
record->package_data_len = get_unaligned_le16(&__record->package_data_len);
record->device_update_flags = get_unaligned_le32(&__record->device_update_flags);
record->version_len = __record->version_len;
record->version_type = __record->version_type;
bitmap_ptr = data->fw->data + data->offset;
/* check that we have space for the component bitmap length */
err = crete_pldm_move_fw_offset(data, data->bitmap_size);
if (err)
return err;
record->component_bitmap_len = data->component_bitmap_len;
record->component_bitmap = bitmap_zalloc(record->component_bitmap_len,
GFP_KERNEL);
if (!record->component_bitmap)
return -ENOMEM;
for (i = 0; i < data->bitmap_size; i++)
bitmap_set_value8(record->component_bitmap, bitmap_ptr[i], i * 8);
record->version_string = data->fw->data + data->offset;
err = crete_pldm_move_fw_offset(data, record->version_len);
if (err)
return err;
/* Scan through the descriptor TLVs and find the end */
err = crete_pldm_parse_desc_tlvs(data, record, __record->descriptor_count);
if (err)
return err;
record->package_data = data->fw->data + data->offset;
err = crete_pldm_move_fw_offset(data, record->package_data_len);
if (err)
return err;
measured_length = data->offset - ((const u8 *)__record - data->fw->data);
if (measured_length != record_len) {
dev_err(data->context->dev, "Unexpected record length. Measured record length is %zu bytes, expected length is %u bytes\n",
measured_length, record_len);
return -EFAULT;
}
return 0;
}
/**
* crete_pldm_parse_records - Locate the start of the component area
* @data: pointer to private data
*
* Extract the record count, and loop through each record, searching for the
* component area.
*
* Returns: zero on success, or a negative error code on failure.
*/
static int crete_pldm_parse_records(struct crete_pldmfw_priv *data)
{
const struct __pldmfw_component_area *component_area;
const struct __pldmfw_record_info *record;
int err;
u8 i;
pldm_for_each_record(i, record, data->record_start, data->record_count) {
err = crete_pldm_parse_one_record(data, record);
if (err)
return err;
}
/* Extract a pointer to the component area, which just follows the
* PLDM device record data.
*/
component_area = (const struct __pldmfw_component_area *)(data->fw->data + data->offset);
err = crete_pldm_move_fw_offset(data, sizeof(*component_area));
if (err)
return err;
data->component_count =
get_unaligned_le16(&component_area->component_image_count);
data->component_start = component_area->components;
return 0;
}
/**
* crete_pldm_parse_components - Locate the CRC header checksum
* @data: pointer to private data
*
* Extract the component count, and find the pointer to the component area.
* Scan through each component searching for the end, which should point to
* the package header checksum.
*
* Extract the package header CRC and save it for verification.
*
* Returns: zero on success, or a negative error code on failure.
*/
static int crete_pldm_parse_components(struct crete_pldmfw_priv *data)
{
const struct __pldmfw_component_info *__component;
struct device *dev = data->context->dev;
const u8 *header_crc_ptr;
int err;
u8 i;
pldm_for_each_component(i, __component, data->component_start, data->component_count) {
struct pldmfw_component *component;
u32 offset, size;
err = crete_pldm_move_fw_offset(data,
sizeof(*__component) + COMPONENT_OPAQUE_DATA_LENGTH);
if (err)
return err;
err = crete_pldm_move_fw_offset(data, __component->version_len);
if (err)
return err;
offset = get_unaligned_le32(&__component->location_offset);
size = get_unaligned_le32(&__component->size);
err = crete_pldm_check_fw_space(data, offset, size);
if (err)
return err;
component = kzalloc(sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
component->index = i;
component->classification = get_unaligned_le16(&__component->classification);
component->identifier = get_unaligned_le16(&__component->identifier);
component->comparison_stamp = get_unaligned_le32(&__component->comparison_stamp);
component->options = get_unaligned_le16(&__component->options);
component->activation_method = get_unaligned_le16(&__component->activation_method);
component->version_type = __component->version_type;
component->version_len = __component->version_len;
component->version_string = __component->version_string;
component->component_data = data->fw->data + offset;
component->component_size = size;
list_add_tail(&component->entry, &data->components);
}
header_crc_ptr = data->fw->data + data->offset;
// dev_err(dev, "printk CRC:\n");
// hexdump((char *)header_crc_ptr, sizeof(data->header_crc));
err = crete_pldm_move_fw_offset(data, sizeof(data->header_crc));
if (err)
return err;
/* Make sure that we reached the expected offset */
if (data->offset != data->total_header_size) {
dev_err(dev, "Invalid firmware header size. Expected %u but got %zu\n",
data->total_header_size, data->offset);
return -EFAULT;
}
data->header_crc = get_unaligned_le32(header_crc_ptr);
return 0;
}
/**
* crete_pldm_verify_header_crc - Verify that the CRC in the header matches
* @data: pointer to private data
*
* Calculates the 32-bit CRC using the standard IEEE 802.3 CRC polynomial and
* compares it to the value stored in the header.
*
* Returns: zero on success if the CRC matches, or -EBADMSG on an invalid CRC.
*/
static int crete_pldm_verify_header_crc(struct crete_pldmfw_priv *data)
{
struct device *dev = data->context->dev;
u32 calculated_crc;
size_t length;
/* Calculate the 32-bit CRC of the header contents up to but
* not including the checksum. Note that the Linux crc32_le function
* does not perform an expected final XOR.
*/
length = data->offset - sizeof(data->header_crc);
calculated_crc = crc32_le(~0, data->fw->data, length) ^ ~0;
if (calculated_crc != data->header_crc) {
dev_err(dev, "Invalid CRC in firmware header. Got 0x%08x but expected 0x%08x\n",
calculated_crc, data->header_crc);
return -EBADMSG;
}
return 0;
}
/**
* crete_pldmfw_free_priv - Free memory allocated while parsing the PLDM image
* @data: pointer to the PLDM data structure
*
* Loops through and clears all allocated memory associated with each
* allocated descriptor, record, and component.
*/
void crete_pldmfw_free_priv(struct crete_pldmfw_priv *data)
{
struct pldmfw_component *component, *c_safe;
struct pldmfw_record *record, *r_safe;
struct pldmfw_desc_tlv *desc, *d_safe;
list_for_each_entry_safe(component, c_safe, &data->components, entry) {
list_del(&component->entry);
kfree(component);
}
list_for_each_entry_safe(record, r_safe, &data->records, entry) {
list_for_each_entry_safe(desc, d_safe, &record->descs, entry) {
list_del(&desc->entry);
kfree(desc);
}
if (record->component_bitmap) {
bitmap_free(record->component_bitmap);
record->component_bitmap = NULL;
}
list_del(&record->entry);
kfree(record);
}
}
EXPORT_SYMBOL(crete_pldmfw_free_priv);
/**
* crete_pldm_parse_image - parse and extract details from PLDM image
* @data: pointer to private data
*
* Verify that the firmware file contains valid data for a PLDM firmware
* file. Extract useful pointers and data from the firmware file and store
* them in the data structure.
*
* The PLDM firmware file format is defined in DMTF DSP0267 1.0.0. Care
* should be taken to use get_unaligned_le* when accessing data from the
* pointers in data.
*
* Returns: zero on success, or a negative error code on failure.
*/
int crete_pldm_parse_image(struct crete_pldmfw_priv *data)
{
int err;
struct device *dev = data->context->dev;
if (WARN_ON(!(data->context->dev && data->fw->data && data->fw->size)))
return -EINVAL;
err = crete_pldm_parse_header(data);
if (err) {
dev_err(dev, "crete_pldm parse_header failed err %d\n", err);
return err;
}
err = crete_pldm_parse_records(data);
if (err) {
dev_err(dev, "crete_pldm parse_records failed err %d\n", err);
return err;
}
err = crete_pldm_parse_components(data);
if (err) {
dev_err(dev, "crete_pldm parse_components failed err %d\n", err);
return err;
}
return crete_pldm_verify_header_crc(data);
}
EXPORT_SYMBOL(crete_pldm_parse_image);
MODULE_AUTHOR("Jacob Keller <jacob.e.keller@intel.com>");
MODULE_DESCRIPTION("PLDM firmware flash update library");

View File

@ -0,0 +1,278 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018-2019, Intel Corporation. */
#ifndef _CRETE_PLDMFW_LIB_H_
#define _CRETE_PLDMFW_LIB_H_
/* The following data structures define the layout of a firmware binary
* following the "PLDM For Firmware Update Specification", DMTF standard
* #DSP0267.
*
* pldmfw.c uses these structures to implement a simple engine that will parse
* a fw binary file in this format and perform a firmware update for a given
* device.
*
* Due to the variable sized data layout, alignment of fields within these
* structures is not guaranteed when reading. For this reason, all multi-byte
* field accesses should be done using the unaligned access macros.
* Additionally, the standard specifies that multi-byte fields are in
* LittleEndian format.
*
* The structure definitions are not made public, in order to keep direct
* accesses within code that is prepared to deal with the limitation of
* unaligned access.
*/
/* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
static const uuid_t pldm_firmware_header_id =
UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
/* Revision number of the PLDM header format this code supports */
// SIM_DEBUG
#define PACKAGE_HEADER_FORMAT_REVISION 0x03
#define COMPONENT_OPAQUE_DATA_LENGTH 4
/* timestamp104 structure defined in PLDM Base specification */
#define PLDM_TIMESTAMP_SIZE 13
struct __pldm_timestamp {
u8 b[PLDM_TIMESTAMP_SIZE];
} __packed __aligned(1);
/* Package Header Information */
struct __pldm_header {
uuid_t id; /* PackageHeaderIdentifier */
u8 revision; /* PackageHeaderFormatRevision */
__le16 size; /* PackageHeaderSize */
struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
__le16 component_bitmap_len; /* ComponentBitmapBitLength */
u8 version_type; /* PackageVersionStringType */
u8 version_len; /* PackageVersionStringLength */
/*
* DSP0267 also includes the following variable length fields at the
* end of this structure:
*
* PackageVersionString, length is version_len.
*
* The total size of this section is
* sizeof(pldm_header) + version_len;
*/
u8 version_string[]; /* PackageVersionString */
} __packed __aligned(1);
/* Firmware Device ID Record */
struct __pldmfw_record_info {
__le16 record_len; /* RecordLength */
u8 descriptor_count; /* DescriptorCount */
__le32 device_update_flags; /* DeviceUpdateOptionFlags */
u8 version_type; /* ComponentImageSetVersionType */
u8 version_len; /* ComponentImageSetVersionLength */
__le16 package_data_len; /* FirmwareDevicePackageDataLength */
/*
* DSP0267 also includes the following variable length fields at the
* end of this structure:
*
* ApplicableComponents, length is component_bitmap_len from header
* ComponentImageSetVersionString, length is version_len
* RecordDescriptors, a series of TLVs with 16bit type and length
* FirmwareDevicePackageData, length is package_data_len
*
* The total size of each record is
* sizeof(pldmfw_record_info) +
* component_bitmap_len (converted to bytes!) +
* version_len +
* <length of RecordDescriptors> +
* package_data_len
*/
u8 variable_record_data[];
} __packed __aligned(1);
/* Firmware Descriptor Definition */
struct __pldmfw_desc_tlv {
__le16 type; /* DescriptorType */
__le16 size; /* DescriptorSize */
u8 data[]; /* DescriptorData */
} __aligned(1);
/* Firmware Device Identification Area */
struct __pldmfw_record_area {
u8 record_count; /* DeviceIDRecordCount */
/* This is not a struct type because the size of each record varies */
u8 records[];
} __aligned(1);
/* Individual Component Image Information */
struct __pldmfw_component_info {
__le16 classification; /* ComponentClassfication */
__le16 identifier; /* ComponentIdentifier */
__le32 comparison_stamp; /* ComponentComparisonStamp */
__le16 options; /* componentOptions */
__le16 activation_method; /* RequestedComponentActivationMethod */
__le32 location_offset; /* ComponentLocationOffset */
__le32 size; /* ComponentSize */
u8 version_type; /* ComponentVersionStringType */
u8 version_len; /* ComponentVersionStringLength */
/*
* DSP0267 also includes the following variable length fields at the
* end of this structure:
*
* ComponentVersionString, length is version_len
*
* The total size of this section is
* sizeof(pldmfw_component_info) + version_len;
*/
u8 version_string[];
} __packed __aligned(1);
/* Component Image Information Area */
struct __pldmfw_component_area {
__le16 component_image_count;
/* This is not a struct type because the component size varies */
u8 components[];
} __aligned(1);
/**
* pldm_first_desc_tlv
* @start: byte offset of the start of the descriptor TLVs
*
* Converts the starting offset of the descriptor TLVs into a pointer to the
* first descriptor.
*/
#define pldm_first_desc_tlv(start) \
((const struct __pldmfw_desc_tlv *)(start))
/**
* pldm_next_desc_tlv
* @desc: pointer to a descriptor TLV
*
* Finds the pointer to the next descriptor following a given descriptor
*/
#define pldm_next_desc_tlv(desc) \
((const struct __pldmfw_desc_tlv *)((desc)->data + \
get_unaligned_le16(&(desc)->size)))
/**
* pldm_for_each_desc_tlv
* @i: variable to store descriptor index
* @desc: variable to store descriptor pointer
* @start: byte offset of the start of the descriptors
* @count: the number of descriptors
*
* for loop macro to iterate over all of the descriptors of a given PLDM
* record.
*/
#define pldm_for_each_desc_tlv(i, desc, start, count) \
for ((i) = 0, (desc) = pldm_first_desc_tlv(start); \
(i) < (count); \
(i)++, (desc) = pldm_next_desc_tlv(desc))
/**
* pldm_first_record
* @start: byte offset of the start of the PLDM records
*
* Converts a starting offset of the PLDM records into a pointer to the first
* record.
*/
#define pldm_first_record(start) \
((const struct __pldmfw_record_info *)(start))
/**
* pldm_next_record
* @record: pointer to a PLDM record
*
* Finds a pointer to the next record following a given record
*/
#define pldm_next_record(record) \
((const struct __pldmfw_record_info *) \
((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
/**
* pldm_for_each_record
* @i: variable to store record index
* @record: variable to store record pointer
* @start: byte offset of the start of the records
* @count: the number of records
*
* for loop macro to iterate over all of the records of a PLDM file.
*/
#define pldm_for_each_record(i, record, start, count) \
for ((i) = 0, (record) = pldm_first_record(start); \
(i) < (count); \
(i)++, (record) = pldm_next_record(record))
/**
* pldm_first_component
* @start: byte offset of the start of the PLDM components
*
* Convert a starting offset of the PLDM components into a pointer to the
* first component
*/
#define pldm_first_component(start) \
((const struct __pldmfw_component_info *)(start))
/**
* pldm_next_component
* @component: pointer to a PLDM component
*
* Finds a pointer to the next component following a given component
*/
#define pldm_next_component(component) \
((const struct __pldmfw_component_info *)((component)->version_string + \
(component)->version_len + COMPONENT_OPAQUE_DATA_LENGTH))
/**
* pldm_for_each_component
* @i: variable to store component index
* @component: variable to store component pointer
* @start: byte offset to the start of the first component
* @count: the number of components
*
* for loop macro to iterate over all of the components of a PLDM file.
*/
#define pldm_for_each_component(i, component, start, count) \
for ((i) = 0, (component) = pldm_first_component(start); \
(i) < (count); \
(i)++, (component) = pldm_next_component(component))
struct crete_pldmfw_priv {
struct pldmfw *context;
const struct firmware *fw;
/* current offset of firmware image */
size_t offset;
struct list_head records;
struct list_head components;
/* PLDM Firmware Package Header */
const struct __pldm_header *header;
u16 total_header_size;
/* length of the component bitmap */
u16 component_bitmap_len;
u16 bitmap_size;
/* Start of the component image information */
u16 component_count;
const u8 *component_start;
/* Start pf the firmware device id records */
const u8 *record_start;
u8 record_count;
/* The CRC at the end of the package header */
u32 header_crc;
struct pldmfw_record *matching_record;
};
int crete_pldm_parse_image(struct crete_pldmfw_priv *data);
void crete_pldmfw_free_priv(struct crete_pldmfw_priv *data);
#endif

View File

@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/clocksource.h>
#include <linux/highmem.h>
#include <linux/ptp_clock_kernel.h>
#include "crete.h"
#include "crete_ptp.h"
static int crete_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
pr_warn("ptp %s stub\n", __func__);
return 0;
}
static int crete_ptp_adjphase(struct ptp_clock_info *ptp, s32 delta)
{
pr_warn("ptp %s stub\n", __func__);
return 0;
}
static int crete_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
pr_warn("ptp %s stub\n", __func__);
return 0;
}
static int crete_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
pr_warn("ptp %s stub\n", __func__);
return 0;
}
static int crete_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts)
{
pr_warn("ptp %s stub\n", __func__);
return 0;
}
static const struct ptp_clock_info crete_ptp_clock_info = {
.owner = THIS_MODULE,
.name = "crete_ptp",
.max_adj = 50000000,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
.n_pins = 0,
.pps = 0,
.adjfine = crete_ptp_adjfine,
.adjphase = crete_ptp_adjphase,
.adjtime = crete_ptp_adjtime,
.gettimex64 = crete_ptp_gettimex,
.settime64 = crete_ptp_settime,
.enable = NULL,
.verify = NULL,
};
void crete_init_clock(struct crete_core_dev *mdev)
{
pr_warn("ptp %s stub\n", __func__);
}
void crete_cleanup_clock(struct crete_core_dev *mdev)
{
pr_warn("ptp %s stub\n", __func__);
}

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_PTP_H
#define __CRETE_PTP_H
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/atomic.h>
#include <linux/xarray.h>
#include <net/devlink.h>
#include <linux/net_tstamp.h>
#include "crete_eswitch.h"
struct crete_clock {
struct crete_nb pps_nb;
seqlock_t lock;
struct hwtstamp_config hwtstamp_config;
struct ptp_clock *ptp;
struct ptp_clock_info ptp_info;
};
void crete_init_clock(struct crete_core_dev *mdev);
void crete_cleanup_clock(struct crete_core_dev *mdev);
#endif /* __CRETE_PTP_H */

View File

@ -0,0 +1,241 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete_rdma_adapt.h"
#include "crete_rdma_dev.h"
#define RDMA_ERR(pdev, fmt, ...) dev_err(&pdev->dev, fmt, ##__VA_ARGS__)
#define jm_core_dbg(pdev, format, ...) \
dev_dbg(&pdev->dev, "%s:%d:(pid %d): " format, __func__, \
__LINE__, current->pid, ##__VA_ARGS__)
#define TO_EQ_DB_VAL(ci, alt, v0, v1) \
((((ci) & 0xffffff) << 2) | (((alt) ? (v0) : (v1)) & 0x3))
static bool crete_rdma_is_error(struct jm_rdma_core *dev)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
if (!dev) {
pr_err("rdma get irq err: dev is null\n");
return -EINVAL;
}
return pci_channel_offline(core_dev->pdev);
}
static void crete_rdma_trigger_doorbell(struct jm_rdma_core *dev, u32 event)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
if (!dev) {
pr_err("rdma get irq err: dev is null\n");
return;
}
jm_core_dbg(core_dev->pdev, "rdma db base addr:0x%p val:0x%x\r\n",
core_dev->rdma_adp.cmd_db_reg, event);
iowrite32(event, core_dev->rdma_adp.cmd_db_reg);
}
static int crete_rdma_get_irqn(struct jm_rdma_core *dev, int index)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
int irq;
if (!dev) {
pr_err("rdma get irq err: dev is null\n");
goto ret;
}
if (index >= core_dev->rdma_adp.vector_num + core_dev->rdma_adp.vector_base) {
pr_err("@@@@###index =%d >= num=%d vector_base=%d@@@@\n",
index, core_dev->rdma_adp.vector_num, core_dev->rdma_adp.vector_base);
goto ret;
}
irq = core_dev->irq_info[index].vector;
jm_core_dbg(core_dev->pdev, "vector base = %d index = %d irqn =%d\n",
core_dev->rdma_adp.vector_base, index, irq);
return irq;
ret:
return -EINVAL;
}
struct device *crete_rdma_get_device(struct jm_rdma_core *dev)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
struct pci_dev *pdev = core_dev->pdev;
return &pdev->dev;
}
void crete_rdma_get_dev_info(struct jm_rdma_core *dev, u8 *feature,
u8 *rev_id, u16 *dev_id, u16 *vendor)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
struct pci_dev *pdev = core_dev->pdev;
*rev_id = pdev->revision;
*dev_id = pdev->device;
*vendor = pdev->vendor;
if (!pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64))
*feature = *feature | JM_DEVICE_FEATURE_ATOMIC_HCA;
}
void crete_rdma_get_bar(struct jm_rdma_core *dev, void **base, void **eq_reg)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
*base = core_dev->rdma_adp.reg_addr;
*eq_reg = core_dev->rdma_adp.eq_db_reg;
}
void crete_rdma_get_uar(struct jm_rdma_core *dev, phys_addr_t *base, int *len)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
*base = core_dev->rdma_adp.uar_base;
*len = core_dev->rdma_adp.uar_size;
}
void crete_rdma_get_vector(struct jm_rdma_core *dev, int *num, int *base)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
*num = core_dev->rdma_adp.vector_num;
*base = core_dev->rdma_adp.vector_base;
}
static struct jm_rdma_ops jm_pci_core_ops = {
.get_device = crete_rdma_get_device,
.get_dev_info = crete_rdma_get_dev_info,
.cmdq_notify = crete_rdma_trigger_doorbell,
.get_irqn = crete_rdma_get_irqn,
.store_bond_info = NULL,
.get_bar = crete_rdma_get_bar,
.get_uar = crete_rdma_get_uar,
.get_vector = crete_rdma_get_vector,
.is_error = crete_rdma_is_error,
.timer_db = NULL,
.reload = NULL,
};
int crete_rdma_init_core_dev(struct crete_core_dev *core_dev, struct pci_dev *pdev)
{
struct jm_rdma_core *dev;
int ret = 0;
dev = &core_dev->rdma_coredev;
dev->ops = &jm_pci_core_ops;
mutex_init(&core_dev->rdma_adp.intf_state_mutex);
ret = jm_adev_idx_alloc();
if (ret < 0) {
RDMA_ERR(pdev, "failed to initialize adev index\n");
goto err_core_free;
}
dev->adev_idx = ret;
ret = jm_adev_init(dev);
if (ret < 0) {
RDMA_ERR(pdev, "failed to initialize adev table\n");
goto err_idx_free;
}
return 0;
err_idx_free:
jm_adev_idx_free(dev->adev_idx);
err_core_free:
mutex_destroy(&core_dev->rdma_adp.intf_state_mutex);
return ret;
}
static void crete_rdma_remove_core_dev(struct crete_core_dev *core_dev)
{
struct jm_rdma_core *dev;
dev = &core_dev->rdma_coredev;
jm_adev_cleanup(dev);
jm_adev_idx_free(dev->adev_idx);
mutex_destroy(&core_dev->rdma_adp.intf_state_mutex);
}
int crete_rdma_coredev_init(struct crete_core_dev *core_dev)
{
int err;
if (!crete_have_rdma_cap(core_dev)) {
jm_core_dbg(core_dev->pdev, "not found rdma cap.\n");
return 0;
}
core_dev->rdma_adp.flags |= CORSICA_RDMA_MASK;
err = crete_rdma_init_core_dev(core_dev, core_dev->pdev);
if (err)
goto err_rdma_init_core_dev;
core_dev->rdma_adp.reg_addr =
core_dev->io_addr + core_dev->hw.rdma_desc.offset * CRETE_RDMA_OFFSET_UNIT;
core_dev->rdma_adp.bar_offset = core_dev->hw.rdma_desc.offset * CRETE_RDMA_OFFSET_UNIT;
core_dev->rdma_adp.bar_len = core_dev->hw.rdma_desc.len * CRETE_RDMA_OFFSET_UNIT;
core_dev->rdma_adp.cmd_db_reg = core_dev->rdma_adp.reg_addr + JM_DEV_CMD_DB_OFFSET;
core_dev->rdma_adp.eq_db_reg = core_dev->rdma_adp.reg_addr + JM_DEV_EQ_DB_OFFSET;
core_dev->rdma_adp.uar_base =
core_dev->bar_addr + core_dev->rdma_adp.bar_offset + JM_DEV_INIT_SEG_SIZE;
core_dev->rdma_adp.uar_size = JM_DEV_UAR_SEG_SIZE;
jm_core_dbg(core_dev->pdev,
"reg_addr =0x%p uar_base =0x%llx uar_size =0x%x bar=%d init_base=0x%llx offset=0x%x\n",
core_dev->rdma_adp.reg_addr, core_dev->rdma_adp.uar_base,
core_dev->rdma_adp.uar_size, JM_DEV_BAR_IDX, core_dev->bar_addr,
core_dev->rdma_adp.bar_offset);
return 0;
err_rdma_init_core_dev:
crete_rdma_remove_core_dev(core_dev);
return err;
}
void crete_rdma_coredev_uninit(struct crete_core_dev *core_dev)
{
if (!crete_have_rdma_cap(core_dev))
return;
crete_rdma_remove_core_dev(core_dev);
memset(&core_dev->rdma_coredev, 0, sizeof(core_dev->rdma_coredev));
}

View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_RDMA_CORE_ADAPT_H
#define __CRETE_RDMA_CORE_ADAPT_H
#include "crete.h"
#define JM_AUX_VECTOR_NUM 3
enum {
JM_EQ_DB_FLAG_ARM = BIT(0),
JM_EQ_DB_FLAG_COMP = BIT(1),
};
enum {
JM_PRIV_FLAGS_DISABLE_IB_ADEV = 1 << 0,
JM_PRIV_FLAGS_DISABLE_ALL_ADEV = 1 << 1,
JM_PRIV_FLAGS_DETACH = 1 << 2,
};
enum {
JM_DEV_BAR_IDX = 0,
JM_DEV_INIT_SEG_SIZE = 64 * 1024,
JM_DEV_CMD_DB_OFFSET = 0xEFC0,
JM_DEV_EQ_DB_OFFSET = 0xF000,
JM_DEV_UAR_SEG_SIZE = 64 * 1024,
};
#define CRETE_RDMA_OFFSET_UNIT 0x1000
int crete_rdma_coredev_init(struct crete_core_dev *core_dev);
void crete_rdma_coredev_uninit(struct crete_core_dev *core_dev);
#endif

View File

@ -0,0 +1,254 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2022, Jaguarmicro Technologies, Inc. All rights reserved.
*/
#include <linux/idr.h>
#include <linux/slab.h>
#include "crete_rdma_dev.h"
#include "rdma.h"
#include "crete_rdma_adapt.h"
/* intf dev list mutex */
static DEFINE_MUTEX(jm_intf_mutex);
static DEFINE_IDA(jm_adev_ida);
bool is_ib_supported(struct jm_rdma_core *dev)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
if (core_dev->rdma_adp.priv_flags & JM_PRIV_FLAGS_DISABLE_IB_ADEV)
return false;
if (!(core_dev->rdma_adp.flags & CORSICA_RDMA_MASK))
return false;
return true;
}
enum {
JM_INTERFACE_PROTOCOL_IB,
};
static const struct jm_adev_device {
const char *suffix;
bool (*is_supported)(struct jm_rdma_core *dev);
} jm_adev_devices[] = {
[JM_INTERFACE_PROTOCOL_IB] = { .suffix = "rdma",
.is_supported = &is_ib_supported },
};
int jm_adev_idx_alloc(void)
{
return ida_alloc(&jm_adev_ida, GFP_KERNEL);
}
void jm_adev_idx_free(int idx)
{
ida_free(&jm_adev_ida, idx);
}
int jm_adev_init(struct jm_rdma_core *dev)
{
struct jm_rdma_adev **adev;
adev = kcalloc(ARRAY_SIZE(jm_adev_devices),
sizeof(struct jm_rdma_adev *), GFP_KERNEL);
if (!adev)
return -ENOMEM;
dev->adev = adev;
return 0;
}
void jm_adev_cleanup(struct jm_rdma_core *dev)
{
kfree(dev->adev);
}
static void adev_release(struct device *dev)
{
struct jm_rdma_adev *adev = container_of(dev, struct jm_rdma_adev, adev.dev);
struct jm_rdma_core *core = adev->rdma_core;
int idx = adev->idx;
kfree(adev);
core->adev[idx] = NULL;
}
static struct jm_rdma_adev *add_adev(struct jm_rdma_core *dev, int idx)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
const char *suffix = jm_adev_devices[idx].suffix;
struct auxiliary_device *adev;
struct jm_rdma_adev *jadev;
int ret;
jadev = kzalloc(sizeof(*jadev), GFP_KERNEL);
if (!jadev)
return ERR_PTR(-ENOMEM);
adev = &jadev->adev;
adev->id = dev->adev_idx;
adev->name = suffix;
adev->dev.parent = &core_dev->pdev->dev;
adev->dev.release = adev_release;
jadev->rdma_core = dev;
jadev->idx = idx;
ret = auxiliary_device_init(adev);
if (ret) {
kfree(jadev);
return ERR_PTR(ret);
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ERR_PTR(ret);
}
return jadev;
}
static void del_adev(struct auxiliary_device *adev)
{
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
int jm_attach_device(struct jm_rdma_core *dev)
{
struct auxiliary_device *adev;
struct auxiliary_driver *adrv;
struct jm_rdma_adev **jadev = dev->adev;
int ret = 0, i;
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
mutex_lock(&jm_intf_mutex);
core_dev->rdma_adp.priv_flags &= ~JM_PRIV_FLAGS_DETACH;
for (i = 0; i < ARRAY_SIZE(jm_adev_devices); i++) {
if (!jadev[i]) {
bool is_supported = false;
if (jm_adev_devices[i].is_supported)
is_supported = jm_adev_devices[i].is_supported(dev);
if (!is_supported)
continue;
jadev[i] = add_adev(dev, i);
if (IS_ERR(jadev[i])) {
ret = PTR_ERR(jadev[i]);
jadev[i] = NULL;
}
} else {
adev = &(jadev[i]->adev);
if (!adev->dev.driver)
continue;
adrv = to_auxiliary_drv(adev->dev.driver);
if (adrv->resume)
ret = adrv->resume(adev);
}
if (ret) {
pr_warn("Device[%d] (%s) failed to load\n",
i, jm_adev_devices[i].suffix);
break;
}
}
mutex_unlock(&jm_intf_mutex);
return ret;
}
void jm_detach_device(struct jm_rdma_core *dev)
{
struct auxiliary_device *adev;
struct auxiliary_driver *adrv;
struct jm_rdma_adev **jadev = dev->adev;
pm_message_t pm = {};
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
int i;
if (!jadev) {
pr_err("jnet adev null\n");
return;
}
mutex_lock(&jm_intf_mutex);
for (i = ARRAY_SIZE(jm_adev_devices) - 1; i >= 0; i--) {
if (!jadev[i])
continue;
adev = &jadev[i]->adev;
if (!adev->dev.driver) {
pr_err("adev->dev.driver is null\n");
goto skip_suspend;
}
adrv = to_auxiliary_drv(adev->dev.driver);
if (adrv->suspend) {
adrv->suspend(adev, pm);
continue;
}
skip_suspend:
del_adev(&jadev[i]->adev);
jadev[i] = NULL;
}
core_dev->rdma_adp.priv_flags |= JM_PRIV_FLAGS_DETACH;
mutex_unlock(&jm_intf_mutex);
}
static int add_drivers(struct jm_rdma_core *dev)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(jm_adev_devices); i++) {
bool is_supported = false;
if (dev->adev[i])
continue;
if (jm_adev_devices[i].is_supported)
is_supported = jm_adev_devices[i].is_supported(dev);
if (!is_supported)
continue;
dev->adev[i] = add_adev(dev, i);
if (IS_ERR(dev->adev[i])) {
pr_warn("Device[%d] (%s) failed to load\n", i,
jm_adev_devices[i].suffix);
ret = PTR_ERR(dev->adev[i]);
dev->adev[i] = NULL;
}
}
return ret;
}
static void delete_drivers(struct jm_rdma_core *dev)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
bool delete_all;
int i;
delete_all = core_dev->rdma_adp.priv_flags & JM_PRIV_FLAGS_DISABLE_ALL_ADEV;
for (i = ARRAY_SIZE(jm_adev_devices) - 1; i >= 0; i--) {
bool is_supported = false;
if (!dev->adev[i])
continue;
if (jm_adev_devices[i].is_supported && !delete_all)
is_supported = jm_adev_devices[i].is_supported(dev);
if (is_supported)
continue;
del_adev(&dev->adev[i]->adev);
dev->adev[i] = NULL;
}
}
int jm_rescan_drivers_locked(struct jm_rdma_core *dev)
{
struct crete_core_dev *core_dev = container_of(dev, struct crete_core_dev, rdma_coredev);
lockdep_assert_held(&jm_intf_mutex);
if (core_dev->rdma_adp.priv_flags & JM_PRIV_FLAGS_DETACH)
return 0;
delete_drivers(dev);
if (core_dev->rdma_adp.priv_flags & JM_PRIV_FLAGS_DISABLE_ALL_ADEV)
return 0;
return add_drivers(dev);
}

View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0-only*/
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_RDMA_DEV_H
#define __CRETE_RDMA_DEV_H
#include "rdma.h"
enum {
CORSICA_RDMA_MASK = 1 << 4,
};
int jm_adev_idx_alloc(void);
void jm_adev_idx_free(int idx);
int jm_adev_init(struct jm_rdma_core *dev);
bool is_ib_supported(struct jm_rdma_core *dev);
void jm_adev_cleanup(struct jm_rdma_core *dev);
int jm_attach_device(struct jm_rdma_core *dev);
void jm_detach_device(struct jm_rdma_core *dev);
int jm_rescan_drivers_locked(struct jm_rdma_core *dev);
#endif

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_REGS_H
#define _CRETE_REGS_H
#include "crete.h"
#include <uapi/linux/stddef.h>
/* Additional Transmit Descriptor Control definitions */
#define CRETE_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
#define CRETE_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
#define CRETE_TCTL_EN 0x00000002
#define CRETE_RCTL_EN 0x00000002
#define CRETE_TCTL 0x100
#define CRETE_RCTL 0x400
#define CRETE_TXDCTL(n) (0x1000 + ((n) * 0x100))
#define CRETE_RXDCTL(n) (0x2000 + ((n) * 0x100))
#define CRETE_TDLEN(n) (0x1004 + ((n) * 0x100))
#define CRETE_RDLEN(n) (0x2004 + ((n) * 0x100))
#define CRETE_TD_LO(n) (0x1008 + ((n) * 0x100))
#define CRETE_TD_HI(n) (0x100c + ((n) * 0x100))
#define CRETE_RD_LO(n) (0x2008 + ((n) * 0x100))
#define CRETE_RD_HI(n) (0x200c + ((n) * 0x100))
#define CRETE_TDH(n) (0x1010 + ((n) * 0x100))
#define CRETE_RDH(n) (0x2010 + (n) * 0x100)
#define CRETE_TDT(n) (0x1014 + ((n) * 0x100))
#define CRETE_RDT(n) (0x2014 + ((n) * 0x100))
#define CRETE_INTR(n) (0x3000 + ((n) * 0x10))
/* reg bits */
#define CRETE_HW_RESET_OK 0
#define CRETE_HW_RESET 1
#define CRETE_HW_RESET_TIMEOUT 10
/* dev status */
#define CRETE_DEV_ACK BIT(0)
#define CRETE_DEV_DRV BIT(1)
#define CRETE_DEV_CAP BIT(2)
#define CRETE_DEV_CP BIT(3)
#define CRETE_DEV_FAIL BIT(7)
#define CRETE_DEV_OK 0
#define POLL_RETRY_LIMIT 5
/* cp caps */
#define CRETE_CP_CMDPATH BIT(0)
#define CRETE_CP_ADQ BIT(1)
#define CRETE_CP_EP BIT(2)
#define CRETE_CP_CQ_EP BIT(3)
/*reg ops*/
//#define wr32(p, reg, val) crete_wr32(p, reg, val)
#ifdef __compiler_offsetof
#define reg_off(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)
#else
#define reg_off(TYPE, MEMBER) ((size_t) &(((TYPE *)0)->MEMBER))
#endif
#define rd32(p, reg) crete_rd32(p, reg)
#define wr32(reg, val) \
do { \
u8 __iomem *hw_addr = READ_ONCE(adapter->io_addr); \
writel((val), &hw_addr[(reg)]); \
} while (0)
#define iseg_rd32(hw,type, mem) \
do { \
u8 __iomem *hw_addr = (u8 __iomem *)READ_ONCE(hw->io_addr); \
return readl(hw_addr + reg_off(type, mem)); \
} while (0)
/* maybe too complex */
#define iseg_wd32(hw, type, mem, val) \
do { \
u8 __iomem *hw_addr = (u8 __iomem *)READ_ONCE((hw)->io_addr); \
writel((val), hw_addr + reg_off(type, mem)); \
} while (0)
#define iseg_rd8(hw,type, mem) \
do { \
u8 __iomem *hw_addr = (u8 __iomem *)READ_ONCE(hw->io_addr); \
return readb(hw_addr + reg_off(type, mem)); \
} while (0)
#define iseg_wd8(hw, type, mem, val) \
do { \
u8 __iomem *hw_addr = (u8 __iomem *)READ_ONCE(hw->io_addr); \
writeb((val), hw_addr + reg_off(type, mem)); \
} while (0)
#define POLL_CTRL_PATH_STATUS(hw, bit, cdev, err) \
do { \
int retry = POLL_RETRY_LIMIT; \
while (!(val = readb(&(hw)->io_addr->cp_status) & (bit)) && retry) { \
(retry)--; \
mdelay(10); \
crete_err((cdev)->device, "device crtl path not ready\n"); \
} \
if (retry == 0) { \
(err) = -EBUSY; \
} \
} while (0)
static inline void hexdump(const unsigned char *buf, unsigned short len)
{
print_hex_dump(KERN_ERR," data: ", DUMP_PREFIX_NONE, 16, 1, buf, len, true);
}
#endif

View File

@ -0,0 +1,263 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/ethtool.h>
#include <linux/jhash.h>
#include <net/pkt_cls.h>
#include "crete.h"
u16 crete_xmit_get_sfiinfo(struct sk_buff *skb)
{
struct metadata_dst *dst = skb_metadata_dst(skb);
if (!dst || dst->type != METADATA_HW_PORT_MUX)
return CRETE_MAX_CFA_CODE;
return dst->u.port_info.port_id;
}
struct net_device *crete_get_vf_rep(struct crete_core_dev *cdev, u16 cfa_code)
{
u16 vf_idx;
u16 *cfa_code_map = cdev->eswitch->eswoffloads.cfa_code_map;
struct crete_esw_rep *rep;
if (cfa_code && cfa_code_map) {
vf_idx = cfa_code_map[cfa_code];
if (vf_idx != CRETE_MAX_CFA_CODE) {
rep =
xa_load(&cdev->eswitch->eswoffloads.vport_reps,
vf_idx);
if (rep)
return rep->dev;
}
}
return NULL;
}
void crete_vf_rep_rx(struct crete_core_dev *cdev, struct sk_buff *skb)
{
struct crete_priv *priv = netdev_priv(skb->dev);
struct crete_esw_rep *vf_rep = priv->rep;
vf_rep->rx_stats.bytes += skb->len;
vf_rep->rx_stats.packets++;
netif_receive_skb(skb);
}
static const struct ethtool_ops crete_vf_rep_ethtool_ops = {
.get_drvinfo = NULL
};
static int crete_vf_rep_setup_tc(struct net_device *dev,
enum tc_setup_type type, void *type_data)
{
return 0;
}
static void
crete_vf_rep_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
struct crete_priv *priv = netdev_priv(dev);
struct crete_esw_rep *vf_rep = priv->rep;
stats->rx_packets = vf_rep->rx_stats.packets;
stats->rx_bytes = vf_rep->rx_stats.bytes;
stats->tx_packets = vf_rep->tx_stats.packets;
stats->tx_bytes = vf_rep->tx_stats.bytes;
}
static int crete_vf_rep_open(struct net_device *dev)
{
struct crete_priv *priv = netdev_priv(dev);
struct crete_core_dev *cdev = priv->coredev;
/*
* with pf netdevice running
* enable the rep netdevice
*/
if (netif_running(cdev->netdev)) {
netif_carrier_on(dev);
netif_tx_start_all_queues(dev);
}
return 0;
}
static int crete_vf_rep_close(struct net_device *dev)
{
netif_carrier_off(dev);
netif_tx_disable(dev);
return 0;
}
static netdev_tx_t crete_vf_rep_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct crete_priv *priv = netdev_priv(dev);
struct crete_esw_rep *vf_rep = priv->rep;
int err, len = skb->len;
/*
* drop the skb _skb_refdst
*/
skb_dst_drop(skb);
dst_hold((struct dst_entry *)vf_rep->dst);
/*
* redirection the skb dst with the rep dst info
*/
skb_dst_set(skb, (struct dst_entry *)vf_rep->dst);
/* skb reuse the pf netdevice */
skb->dev = vf_rep->dst->u.port_info.lower_dev;
err = dev_queue_xmit(skb);
if (!err) {
vf_rep->tx_stats.bytes += len;
vf_rep->tx_stats.packets++;
}
return err;
}
static const struct net_device_ops crete_vf_rep_netdev_ops = {
.ndo_open = crete_vf_rep_open,
.ndo_stop = crete_vf_rep_close,
.ndo_start_xmit = crete_vf_rep_xmit,
.ndo_get_stats64 = crete_vf_rep_get_stats64,
.ndo_setup_tc = crete_vf_rep_setup_tc,
};
int crete_alloc_vf_rep_load(struct crete_core_dev *cdev,
struct crete_esw_rep *rep)
{
struct crete_eswitch *esw = rep->esw;
u16 *cfa_code_map = esw->eswoffloads.cfa_code_map;
struct net_device *dev;
struct net_device *pf_dev = cdev->netdev;
struct crete_priv *priv;
u16 sfi_code = 0;
int err;
dev = alloc_etherdev(sizeof(*priv));
if (!dev)
return -ENOMEM;
priv = netdev_priv(dev);
priv->coredev = cdev;
priv->netdev = dev;
priv->rep = rep;
/* alloc sfi code from FW */
//crete_request_sfiinfo(cdev);
rep->sfi_code = sfi_code;
/* cfa code hash map */
// cfa_code_map[rep->vport_idx] = sfi_code;
cfa_code_map[sfi_code] = rep->vport_idx;
/*
* alloc hw port mux metadata used for rep
* tx and rx function
*/
rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL);
if (!rep->dst) {
err = -ENOMEM;
goto err1;
}
rep->dst->u.port_info.port_id = rep->sfi_code;
rep->dst->u.port_info.lower_dev = cdev->netdev;
dev->netdev_ops = &crete_vf_rep_netdev_ops;
dev->ethtool_ops = &crete_vf_rep_ethtool_ops;
dev->hw_features = pf_dev->hw_features;
dev->gso_partial_features = pf_dev->gso_partial_features;
dev->vlan_features = pf_dev->vlan_features;
dev->hw_enc_features = pf_dev->hw_enc_features;
dev->features |= pf_dev->features;
/*
* rep net device use the random mac address
* vf rep random mac address
*/
eth_hw_addr_random(dev);
/*
* ********* please notice here **********
* vf rep mtu need to ref the vf function
*/
dev->min_mtu = ETH_MIN_MTU;
dev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
err = register_netdev(dev);
if (err)
goto err2;
rep->dev = dev;
err2:
dst_release((struct dst_entry *)rep->dst);
rep->dst = NULL;
err1:
free_netdev(dev);
return err;
}
void crete_alloc_vf_rep_unload(struct crete_core_dev *cdev,
struct crete_esw_rep *rep)
{
struct net_device *dev = rep->dev;
struct crete_eswitch *esw = cdev->eswitch;
u16 *cfa_code_map = esw->eswoffloads.cfa_code_map;
if (netif_running(dev))
crete_vf_rep_close(dev);
cfa_code_map[rep->vport_idx] = CRETE_MAX_CFA_CODE;
synchronize_net();
dst_release((struct dst_entry *)rep->dst);
rep->dst = NULL;
rep->sfi_code = CRETE_MAX_CFA_CODE;
unregister_netdev(dev);
free_netdev(dev);
rep->dev = NULL;
}

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_REP
#define __CRETE_REP
u16 crete_xmit_get_sfiinfo(struct sk_buff *skb);
struct net_device *crete_get_vf_rep(struct crete_core_dev *cdev, u16 cfa_code);
void crete_vf_rep_rx(struct crete_core_dev *cdev, struct sk_buff *skb);
int crete_alloc_vf_rep_load(struct crete_core_dev *cdev,
struct crete_esw_rep *rep);
void crete_alloc_vf_rep_unload(struct crete_core_dev *cdev,
struct crete_esw_rep *rep);
#endif

View File

@ -0,0 +1,611 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include "crete.h"
#include "crete_sriov.h"
#include "crete_eswitch.h"
#include "crete_sriov_sysfs.h"
static int crete_set_vf_attr(struct crete_core_dev *core_dev, int num_vfs)
{
int i;
struct crete_vf_info *vf;
for (i = 0; i < num_vfs; i++) {
vf = &core_dev->pf.vf[i];
memset(vf, 0, sizeof(*vf));
}
return 0;
}
static int crete_alloc_vf_resources(struct crete_core_dev *core_dev, int num_vfs)
{
core_dev->pf.vf = kcalloc(num_vfs, sizeof(struct crete_vf_info), GFP_KERNEL);
if (!core_dev->pf.vf)
return -ENOMEM;
crete_set_vf_attr(core_dev, num_vfs);
return 0;
}
static void crete_free_vf_resources(struct crete_core_dev *core_dev)
{
core_dev->pf.active_vfs = 0;
kfree(core_dev->pf.vf);
core_dev->pf.vf = NULL;
}
static u16 crete_get_max_vfs(struct crete_core_dev *core_dev)
{
return pci_sriov_get_totalvfs(core_dev->pdev);
}
int crete_get_func_caps(struct crete_core_dev *core_dev)
{
struct crete_pf_info *pf = &core_dev->pf;
struct crete_vf_info *vf = &core_dev->vf;
if (crete_core_is_pf(core_dev)) {
pf->fw_fid = 0;
pf->port_id = 0;
pf->first_vf_id = 0;
pf->max_vfs = crete_get_max_vfs(core_dev);
/* pf mac */
} else if (crete_core_is_vf(core_dev)) {
vf->fw_fid = 0;
/* vf mac */
}
return 0;
}
EXPORT_SYMBOL(crete_get_func_caps);
int crete_sriov_init(struct crete_core_dev *core_dev)
{
struct pci_dev *pdev = core_dev->pdev;
int err;
if (!crete_core_is_pf(core_dev))
return 0;
core_dev->pf.max_vfs = crete_get_max_vfs(core_dev);
core_dev->pf.active_vfs = pci_num_vf(pdev);
err = crete_sriov_sysfs_init(core_dev);
if (err) {
pr_err("failed to init SRIOV sysfs (%d)\n", err);
return err;
}
return 0;
}
void crete_sriov_cleanup(struct crete_core_dev *dev)
{
if (!crete_core_is_pf(dev))
return;
crete_sriov_sysfs_cleanup(dev);
}
static int crete_device_enable_sriov(struct crete_core_dev *core_dev, int num_vfs)
{
struct crete_pf_info *pf = &core_dev->pf;
int vf_id;
int rc;
rc = crete_eswitch_enable(core_dev->eswitch, num_vfs);
if (rc) {
pr_err("failed to enable eswitch SRIOV (%d)\n", rc);
return rc;
}
rc = crete_alloc_vf_resources(core_dev, num_vfs);
if (rc)
goto err_crete_alloc_vf_resources;
for (vf_id = 0; vf_id < num_vfs; vf_id++) {
pf->vf[vf_id].enabled = 1;
pr_info("successfully enabled VF%d\n", vf_id);
}
rc = crete_create_vfs_sysfs(core_dev, num_vfs);
if (rc) {
pr_err("failed to create SRIOV sysfs (%d)\n", rc);
goto err_crete_crete_vfs_sysfs;
}
core_dev->sriov_cfg = 1;
return 0;
err_crete_crete_vfs_sysfs:
for (vf_id = num_vfs - 1; vf_id >= 0; vf_id--) {
if (!pf->vf[vf_id].enabled)
continue;
pf->vf[vf_id].enabled = 0;
}
crete_free_vf_resources(core_dev);
err_crete_alloc_vf_resources:
core_dev->sriov_cfg = 0;
crete_eswitch_disable_sriov(core_dev->eswitch, true);
return rc;
}
void
crete_device_disable_sriov(struct crete_core_dev *core_dev, int num_vfs, bool clear_vf)
{
struct crete_pf_info *pf = &core_dev->pf;
int vf_id;
crete_destroy_vfs_sysfs(core_dev, num_vfs);
for (vf_id = num_vfs - 1; vf_id >= 0; vf_id--) {
if (!pf->vf[vf_id].enabled)
continue;
pf->vf[vf_id].enabled = 0;
pr_info("successfully disabled VF%d\n", vf_id);
}
crete_free_vf_resources(core_dev);
core_dev->sriov_cfg = 0;
crete_eswitch_disable_sriov(core_dev->eswitch, clear_vf);
}
static int crete_sriov_enable(struct pci_dev *pdev, int num_vfs)
{
struct crete_core_dev *core_dev = pci_get_drvdata(pdev);
int err;
err = crete_device_enable_sriov(core_dev, num_vfs);
if (err) {
dev_err(&pdev->dev, "crete_device_enable_sriov failed : %d\n", err);
return err;
}
err = pci_enable_sriov(pdev, num_vfs);
if (err) {
dev_err(&pdev->dev, "pci_enable_sriov failed : %d\n", err);
crete_device_disable_sriov(core_dev, num_vfs, true);
}
return err;
}
void crete_sriov_disable(struct pci_dev *pdev)
{
struct crete_core_dev *core_dev = pci_get_drvdata(pdev);
int num_vfs = pci_num_vf(core_dev->pdev);
pci_disable_sriov(pdev);
crete_device_disable_sriov(core_dev, num_vfs, true);
}
int crete_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
struct crete_core_dev *core_dev = pci_get_drvdata(pdev);
int err = 0;
if (num_vfs)
err = crete_sriov_enable(pdev, num_vfs);
else
crete_sriov_disable(pdev);
if (!err)
core_dev->pf.active_vfs = num_vfs;
return err ? err : num_vfs;
}
static int crete_vf_ndo_prep(struct net_device *netdev, int vf_id)
{
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
if (!pf.active_vfs) {
dev_err(&pdev->dev, "vf ndo called though sriov is disabled\n");
return -EINVAL;
}
if (vf_id >= pf.active_vfs) {
dev_err(&pdev->dev, "Invalid VF id %d\n", vf_id);
return -EINVAL;
}
return 0;
}
bool crete_is_trusted_vf(struct net_device *netdev, struct crete_vf_info *vf)
{
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
if (crete_core_is_pf(core_dev))
return !!(vf->flags & CRETE_VF_TRUST);
dev_err(&pdev->dev, "VF trust %s\n",
!!(vf->func_qcfg_flags & FUNC_QCFG_RESP_FLAGS_TRUSTED_VF) ? "ON":"OFF");
//bnxt_hwrm_func_qcfg_flags(bp, vf);
return !!(vf->func_qcfg_flags & FUNC_QCFG_RESP_FLAGS_TRUSTED_VF);
}
int crete_get_vf_config(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
dev_err(&pdev->dev, "get VF:%d config", vf_id);
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
ivi->vf = vf_id;
vf = &pf.vf[vf_id];
if (is_valid_ether_addr(vf->mac_addr))
memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN);
else
memcpy(&ivi->mac, vf->vf_mac_addr, ETH_ALEN);
ivi->max_tx_rate = vf->max_tx_rate;
ivi->min_tx_rate = vf->min_tx_rate;
ivi->vlan = vf->vlan;
if (vf->flags & CRETE_VF_QOS)
ivi->qos = vf->vlan >> VLAN_PRIO_SHIFT;
else
ivi->qos = 0;
ivi->spoofchk = !!(vf->flags & CRETE_VF_SPOOFCHK);
ivi->trusted = crete_is_trusted_vf(netdev, vf);
if (!(vf->flags & CRETE_VF_LINK_FORCED))
ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
else if (vf->flags & CRETE_VF_LINK_UP)
ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
else
ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
return 0;
}
/*
*Setting the MAC Address for a VF
*To change the MAC address for the specified VF:
*# ip link set <ethX> vf 0 mac <address>
*For example:
*# ip link set <ethX> vf 0 mac 00:01:02:03:04:05
*This setting lasts until the PF is reloaded.
*NOTE: For untrusted VFs, assigning a MAC address for a VF from the host will
*disable any subsequent requests to change the MAC address from within the VM.
*This is a security feature. The VM is not aware of this restriction, so if this
*is attempted in the VM, it will trigger MDD events. Trusted VFs are allowed to
*change the MAC address from within the VM.
*/
int crete_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
dev_err(&pdev->dev, "Set VF MAC VF id %d mac:%2x-%2x-%2x-%2x-%2x-%2x\n",
vf_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memcpy(vf->mac_addr, mac, ETH_ALEN);
return crete_eswitch_set_vport_mac(core_dev->eswitch, VPORT(vf_id), vf->mac_addr);
}
/*
* Configuring VLAN Tagging on SR-IOV Enabled Adapter Ports
*To configure VLAN tagging for the ports on an SR-IOV enabled adapter, use the
*following command. The VLAN configuration should be done before the VM is booted.
*The VF is not aware of the VLAN tag being
*inserted on transmit and removed on received frames (sometimes called "port
*VLAN" mode).
*# ip link set dev <ethX> vf <id> vlan <vlan id>
* For example, the following will configure PF eth0 and the first VF on VLAN 10:
*# ip link set dev eth0 vf 0 vlan 10
*add a VLAN interface on the VF interface. For example:
*# ip link add link eth2 name eth2.100 type vlan id 100
* Note that the order in which you set the VF to promiscuous mode and add the
*VLAN interface does not matter (you can do either first). The result in this
*example is that the VF will get all traffic that is tagged with VLAN 100.
*/
int crete_set_vf_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, __be16 vlan_proto)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
u16 vlan_tag;
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
/* TODO: needed to implement proper handling of user priority,
* currently fail the command if there is valid priority
*/
if (vlan_id > 4095 || qos)
return -EINVAL;
vlan_tag = vlan_id;
if (vlan_tag == vf->vlan)
return 0;
dev_err(&pdev->dev, "Set VF VLAN VF id %d VLAN:%d QOS:%d vlan_proto:%d\n",
vf_id, vlan_id, qos, vlan_proto);
//TBD, add adminQ cmd
rc = crete_eswitch_set_vport_vlan(core_dev->eswitch,
VPORT(vf_id), vlan_id, qos, htons(ETH_P_8021Q));
if (rc) {
dev_err(&pdev->dev, "Set VF VLAN VF id %d VLAN:%d QOS:%d vlan_proto:%d failed, err:%d\n",
vf_id, vlan_id, qos, vlan_proto, rc);
return rc;
}
vf->vlan = vlan_tag;
return 0;
}
/*
*Virtual Function (VF) Tx Rate Limit
*Use the ip command to configure the maximum or minimum Tx rate limit for a VF
*from the PF interface.
*For example, to set a maximum Tx rate limit of 8000Mbps for VF 0:
*# ip link set eth0 vf 0 max_tx_rate 8000
*For example, to set a minimum Tx rate limit of 1000Mbps for VF 0:
*# ip link set eth0 vf 0 min_tx_rate 1000
*1.If DCB or ADQ are enabled on a PF, you cannot set a minimum Tx rate on the
*VFs associated with that PF.
*2.If both DCB and ADQ are disabled on a PF, then you can set a minimum Tx rate
*on the VFs associated with that PF.
*3.If you set a minimum Tx rate limit on a PF for SR-IOV VFs and then apply a
*DCB or ADQ configuration, the PF cannot guarantee the minimum Tx rate limits
*for those VFs.
*If you set a minimum Tx rate on VFs across multiple ports that have an
*aggregate bandwidth over 100Gbps, the PFs cannot guarantee the minimum Tx rate
*set for the VFs.
*/
int crete_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, int max_tx_rate)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
u32 pf_link_speed = 400000; /* TBD get from hw */
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
if (max_tx_rate > pf_link_speed) {
dev_err(&pdev->dev, "max tx rate %d exceed PF link speed for VF %d\n",
max_tx_rate, vf_id);
return -EINVAL;
}
if (min_tx_rate > pf_link_speed) {
dev_err(&pdev->dev, "min tx rate %d is invalid for VF %d\n",
min_tx_rate, vf_id);
return -EINVAL;
}
if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate)
return 0;
rc = crete_eswitch_set_vport_rate(core_dev->eswitch,
VPORT(vf_id), max_tx_rate, min_tx_rate);
if (rc) {
dev_err(&pdev->dev, "Set vf_bw failed %d, vf:%d max_rate min_rate:%d rc:%d\n",
vf_id, max_tx_rate, min_tx_rate, rc);
return rc;
}
vf->min_tx_rate = min_tx_rate;
vf->max_tx_rate = max_tx_rate;
dev_err(&pdev->dev, "Set VF %d vf_bw min_tx_rate:%d max_tx_rate:%d\n", vf_id,
min_tx_rate, max_tx_rate);
return 0;
}
int crete_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
vf->flags &= ~(CRETE_VF_LINK_UP | CRETE_VF_LINK_FORCED);
switch (link) {
case IFLA_VF_LINK_STATE_AUTO:
vf->flags |= CRETE_VF_LINK_UP;
dev_err(&pdev->dev, "Set VF %d link_state Auto\n", vf_id);
break;
case IFLA_VF_LINK_STATE_DISABLE:
vf->flags |= CRETE_VF_LINK_FORCED;
dev_err(&pdev->dev, "Set VF %d link_state Disable\n", vf_id);
break;
case IFLA_VF_LINK_STATE_ENABLE:
vf->flags |= CRETE_VF_LINK_UP | CRETE_VF_LINK_FORCED;
dev_err(&pdev->dev, "Set VF %d link_state Enable\n", vf_id);
break;
default:
dev_err(&pdev->dev, "Invalid link option\n");
rc = -EINVAL;
break;
}
if (vf->flags & (CRETE_VF_LINK_UP | CRETE_VF_LINK_FORCED)) {
rc = crete_eswitch_set_vport_state(core_dev->eswitch, VPORT(vf_id), link);
if (rc)
dev_err(&pdev->dev, "Set link state failed %d, link:%d rc:%d\n",
vf_id, link, rc);
}
return rc;
}
/*
*MAC and VLAN Anti-Spoofing Feature for VFs
*When a malicious driver on a Virtual Function (VF) interface attempts to send a
*spoofed packet, it is dropped by the hardware and not transmitted.
*NOTE: This feature can be disabled for a specific VF:
*# ip link set <ethX> vf <vf id> spoofchk {off|on}
*/
int crete_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool setting)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
bool old_setting = false;
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
if (vf->flags & CRETE_VF_SPOOFCHK)
old_setting = true;
if (old_setting == setting)
return 0;
rc = crete_eswitch_set_vport_spoofchk(core_dev->eswitch, VPORT(vf_id), setting);
if (rc)
dev_err(&pdev->dev, "Set VF %d spoofchk %s rc:%d\n",
vf_id, setting ? "ON":"OFF", rc);
dev_err(&pdev->dev, "Set VF %d spoofchk %s\n", vf_id, setting ? "ON":"OFF");
if (setting)
vf->flags |= CRETE_VF_SPOOFCHK;
else
vf->flags &= ~CRETE_VF_SPOOFCHK;
return 0;
}
/*
*Trusted VFs and VF Promiscuous Mode
*This feature allows you to designate a particular VF as trusted and allows that
*trusted VF to request selective promiscuous mode on the Physical Function (PF).
*To set a VF as trusted or untrusted, enter the following command in the
*Hypervisor:
*# ip link set dev <ethX> vf 1 trust [on|off]
*NOTE: It's important to set the VF to trusted before setting promiscuous mode.
*If the VM is not trusted, the PF will ignore promiscuous mode requests from the
*VF. If the VM becomes trusted after the VF driver is loaded, you must make a
*new request to set the VF to promiscuous.
*Once the VF is designated as trusted, use the following commands in the VM to
*set the VF to promiscuous mode. For promiscuous all:
*# ip link set <ethX> promisc on
* Where <ethX> is a VF interface in the VM
*For promiscuous Multicast:
*# ip link set <ethX> allmulticast on
* Where <ethX> is a VF interface in the VM
*/
int crete_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
{
int rc;
struct crete_vf_info *vf;
struct crete_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
struct crete_pf_info pf = core_dev->pf;
rc = crete_vf_ndo_prep(netdev, vf_id);
if (rc)
return rc;
vf = &pf.vf[vf_id];
dev_err(&pdev->dev, "Set VF %d trust %s\n", vf_id, trusted ? "ON":"OFF");
rc = crete_eswitch_set_vport_trust(core_dev->eswitch, VPORT(vf_id), trusted);
if (rc) {
dev_err(&pdev->dev, "Set VF %d trust %s rc:%d\n", vf_id, trusted ? "ON":"OFF", rc);
return rc;
}
if (trusted)
vf->flags |= CRETE_VF_TRUST;
else
vf->flags &= ~CRETE_VF_TRUST;
return 0;
}
int crete_approve_mac(struct crete_core_dev *core_dev, const u8 *mac)
{
int rc = 0;
struct pci_dev *pdev = core_dev->pdev;
if (crete_core_is_pf(core_dev))
return 0;
if (is_valid_ether_addr(core_dev->vf.mac_addr))
rc = -EADDRNOTAVAIL;
/* admin Q to PF approve VF MAC */
dev_err(&pdev->dev, "VF MAC address %pM approved by the PF\n", mac);
return 0;
}

View File

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_SRIOV_H
#define __CRETE_SRIOV_H
struct crete_vf_context {
int enabled;
u64 port_guid;
u64 node_guid;
/* Valid bits are used to validate administrative guid only.
* Enabled after ndo_set_vf_guid
*/
u8 port_guid_valid:1;
u8 node_guid_valid:1;
};
#define CRETE_VF_QOS 0x1
#define CRETE_VF_SPOOFCHK 0x2
#define CRETE_VF_LINK_FORCED 0x4
#define CRETE_VF_LINK_UP 0x8
#define CRETE_VF_TRUST 0x10
/*stub micro define */
#define FUNC_QCFG_RESP_FLAGS_TRUSTED_VF 0x40UL
struct crete_vf_info {
u16 fw_fid;
u8 mac_addr[ETH_ALEN]; /* PF assigned MAC Address */
u8 vf_mac_addr[ETH_ALEN]; /* VF assigned MAC address, only stored by PF. */
u16 vlan;
u16 func_qcfg_flags;
u32 flags;
u32 min_tx_rate;
u32 max_tx_rate;
u32 enabled;
void *hwrm_cmd_req_addr;
dma_addr_t hwrm_cmd_req_dma_addr;
};
int crete_get_func_caps(struct crete_core_dev *core_dev);
int crete_sriov_init(struct crete_core_dev *core_dev);
void crete_sriov_cleanup(struct crete_core_dev *dev);
int crete_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
int crete_get_vf_config(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi);
int crete_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
int crete_set_vf_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, __be16 vlan_proto);
int crete_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, int max_tx_rate);
int crete_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
int crete_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool setting);
int crete_set_vf_trust(struct net_device *netdev, int vf_id, bool trust);
int crete_approve_mac(struct crete_core_dev *core_dev, const u8 *mac);
bool crete_is_trusted_vf(struct net_device *netdev, struct crete_vf_info *vf);
void crete_device_disable_sriov(struct crete_core_dev *core_dev, int num_vfs, bool clear_vf);
#endif /* __CRETE_SRIOV_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_SRIOV_SYSFS_H
#define __CRETE_SRIOV_SYSFS_H
enum {
CRETE_RATE_LIMIT_RX,
CRETE_RATE_LIMIT_TX,
};
enum crete_flow_meter_mode {
CRETE_RATE_LIMIT_BPS,
CRETE_RATE_LIMIT_PPS,
};
enum {
CRETE_RATE_LIMIT_DATA_RATE,
CRETE_RATE_LIMIT_DATA_BURST,
CRETE_RATE_LIMIT_DATA_PACKETS_DROPPED,
CRETE_RATE_LIMIT_DATA_BYTES_DROPPED,
};
#define CRETE_ESW_QOS_SYSFS_GROUP_MAX_ID 255
#define CRETE_ESW_QOS_NON_SYSFS_GROUP (CRETE_ESW_QOS_SYSFS_GROUP_MAX_ID + 1)
struct crete_sriov_vf_meter_type {
int rx_tx;
int xps;
};
struct crete_sriov_vf_sysfs {
struct crete_core_dev *dev;
struct kobject kobj;
struct kobject page_kobj;
int vf;
union {
struct crete_sriov_vf_meters *meters;
struct crete_sriov_vf_meter_type meter_type;
};
};
struct crete_sriov_vf_meters {
struct kobject *kobj;
struct kobject *rx_kobj;
struct kobject *tx_kobj;
struct crete_sriov_vf_sysfs meters[4];
};
struct mlxdevm_rate_group {
struct list_head list;
char *name;
u64 tx_max;
u64 tx_share;
};
struct crete_esw_rate_group {
struct crete_core_dev *dev;
struct mlxdevm_rate_group devm;
u32 tsar_ix;
u32 max_rate;
u32 min_rate;
u32 bw_share;
struct list_head list;
/* sysfs group related fields */
struct kobject kobj;
u32 group_id;
u32 num_vports;
};
enum port_state_policy {
CRETE_POLICY_DOWN = 0,
CRETE_POLICY_UP = 1,
CRETE_POLICY_FOLLOW = 2,
CRETE_POLICY_INVALID = 0xffffffff
};
int crete_create_vfs_sysfs(struct crete_core_dev *dev, int num_vfs);
void crete_destroy_vfs_sysfs(struct crete_core_dev *dev, int num_vfs);
int crete_create_vf_group_sysfs(struct crete_core_dev *dev,
u32 group_id, struct kobject *group_kobj);
void crete_destroy_vf_group_sysfs(struct crete_core_dev *dev,
struct kobject *group_kobj);
int crete_sriov_sysfs_init(struct crete_core_dev *dev);
void crete_sriov_sysfs_cleanup(struct crete_core_dev *dev);
#endif /* __CRETE_SRIOV_SYSFS_H */

View File

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "crete.h"
#include "crete_stub.h"

View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CRETE_STUB_H
#define __CRETE_STUB_H
#include <linux/netdevice.h>
#include "crete.h"
/*tmp micro*/
#define PCI_VENDOR_ID_CRETE 0x1f53
#define PF_DEVICE_ID 0x1B20
#define VF_DEVICE_ID 0x1B21
#define PF_DEVICE_ID_SIM 0x9527
#define VF_DEVICE_ID_SIM 0x9523
#define PF_DEVICE_ID_NIC 0x3B20
#define VF_DEVICE_ID_NIC 0x3B21
#define PF_DEVICE_ID_CMCC 0x2C20
#define VF_DEVICE_ID_CMCC 0x2C22
#define PF_DEVICE_ID_FAKE 0x1C00
#endif /* __CRETE_STUB_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,636 @@
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/******************************************************************************
* crete_ring.c
*
* Jmnd crete driver
*
* Authors: Jmnd
*
*/
#ifndef __CRETE_IOQUEUE_H
#define __CRETE_IOQUEUE_H
#define CRETE_RING_DEFAULT_DEEP 1024UL
#define CRETE_ENTRY_DFAULT_SIZE 16UL
#define CRETE_PKTTYPE0_LENGTH 1UL
#define CRETE_PKTTYPE1_LENGTH 2UL
#define CRETE_PKTTYPE2_LENGTH 3UL
#define CRETE_PKTTYPE3_LENGTH 4UL
enum {
BD_SIZE16 = 0,
BD_SIZE32,
BD_SIZE48,
BD_SIZE64
};
enum {
TUNNEL_NONE = 0x0,
TUNNEL_ONE = 0x2,
TUNNEL_TWO = 0x3,
TUNNEL_ERR = 0x1
};
#define CRETE_PKT_LENGTH(bd_size) \
(bd_size == BD_SIZE16 ? CRETE_PKTTYPE0_LENGTH : \
(bd_size == BD_SIZE32 ? CRETE_PKTTYPE1_LENGTH : \
(bd_size == BD_SIZE48 ? CRETE_PKTTYPE2_LENGTH : \
(bd_size == BD_SIZE64 ? CRETE_PKTTYPE3_LENGTH : 0))))
#define CRETE_RX_OFFSET (NET_SKB_PAD + NET_IP_ALIGN)
#define CRETE_RX_DMA_OFFSET NET_SKB_PAD
#define CRETE_TX_DIR 0
#define CRETE_RX_DIR 1
#define CRETE_TX_DIR_BITS (1 << 4)
#define CRETE_RX_DIR_BITS (1 << 3)
/* The feature bitmap for Crete netdev */
#define CRETE_NET_F_SOP_PADDING 0
#define CRETE_NET_F_EOP_PADDING 1
#define CRETE_NET_F_AUTO_INTR_SUP 2
#define CRETE_NET_F_INTR_MOD 3
#define CRETE_NET_F_TX_INORDER 5
#define CRETE_NET_F_CQE_AGG 7
#define CRETE_NET_F_RX_MERGE 8
/* The feature bitmap for Crete offload */
#define CRETE_NET_F_RX_VLAN_FILTER 0
#define CRETE_NET_F_RX_VLAN_STRIP 1
#define CRETE_NET_F_RX_IPV4_CSUM 2
#define CRETE_NET_F_RX_UDP_CSUM 3
#define CRETE_NET_F_RX_TCP_CSUM 4
#define CRETE_NET_F_RX_SCTP_CSUM 5
#define CRETE_NET_F_RX_TCP_LRO 6
#define CRETE_NET_F_RX_RSS_HASH 7
#define CRETE_NET_F_RX_TIMESTAMP 8
#define CRETE_NET_F_RX_METADATA 9
#define CRETE_NET_F_TX_IPV4_CSUM 32
#define CRETE_NET_F_TX_TCP_CSUM 33
#define CRETE_NET_F_TX_UDP_CSUM 34
#define CRETE_NET_F_TX_SCTP_CSUM 35
#define CRETE_NET_F_TX_OUTER_IPV4_CSUM 36
#define CRETE_NET_F_TX_OUTER_UDP_CSUM 37
#define CRETE_NET_F_TX_TCP_TSO 38
#define CRETE_NET_F_TX_IP_TNL_TSO 39
#define CRETE_NET_F_TX_UDP_TNL_TSO 40
#define CRETE_NET_F_TX_VLAN_INSERT 41
#define CRETE_NET_F_TX_QINQ_INSERT 42
#define CRETE_NET_F_TX_SEND_ON_TIMESTAMP 43
#define CRETE_NET_F_TX_METADATA 44
#define CRETE_NET_F_VPORT_RX_FLOW_TABLE 59
#define CRETE_NET_F_FDB_TABLE 60
#define CRETE_NET_F_FLOW_REDIR_TABLE 61
#define CRETE_NET_F_L2_SWITCH_TABLE 62
#define CRETE_NET_F_VSWITCH_OFFLOAD 63
enum CRETE_DB_TYPE {
DB_RXRQ = 0,
DB_TXSQ,
DB_RXCQ_ARM,
DB_TXCQ_ARM
};
#define CRETE_RING_MEM_SIZE 4
#define CRETE_TX_FREE_SIZE_THD 16
#define CRETE_TX_CPR_SIZE_PTH 8
#define CRETE_SETBDSIZE(x, size) (x->bd_size = size)
#define CRETE_NEXTID(x, val, mask) \
((x + val) & mask)
#define CRETE_DESC_VALID(txcmp, txcpr) \
(txcmp->wrap_counter == (1 ^ txcpr->wrap_counter))
#define CRETE_DESC_BUFID(txcmp) \
(txcmp->buf_id)
#define CRETE_DESC_TYPE(txcmp) \
(txcmp->bd_type)
#define CRETE_DESC_SIZE(txcmp) \
(txcmp->bd_size)
#define CRETE_DESC_BDLEN(txbd) \
(CRETE_PKT_LENGTH(CRETE_DESC_SIZE(txbd)))
#define CRETE_RX_PKT_LEN(bd) \
(le16_to_cpu(bd->pkt_len))
#define CRETE_WRITE_64BITADDR(s, le64_val) \
do { \
s->addr_lo = le64_val & 0xFFFFFFFF; \
s->addr_hi = (le64_val >> 32UL) & 0xFFFFFFFF; \
}while(0)
#define crete_err(__dev, format, ...) \
dev_err(__dev, "%s:%d:(pid %d): " format, \
__func__, __LINE__, current->pid, \
##__VA_ARGS__)
#define crete_info(__dev, format, ...) \
dev_info(__dev, "%s:%d:(pid %d): " format, \
__func__, __LINE__, current->pid, \
##__VA_ARGS__)
#define crete_warn(__dev, format, ...) \
dev_warn(__dev, "%s:%d:(pid %d): " format, \
__func__, __LINE__, current->pid, \
##__VA_ARGS__)
/****begin define the io queue struct ****/
/**
* struct crete_rx_bd - crete rx rqe define
* @pkttype: pkttype 0 0:16bytes 1:2*16bytes 2:3*16bytes 3:4*16bytes
* @buf_id: the packet buffer id ,do not need to convert order sequence.
* @resv: resver bytes
* @buf_len: buffer length
* @addr_lo: address lower32
* @addr_hi: address high32
*/
struct crete_rx_bd {
u16 bd_size:3;
u16 rsv0:13;
u16 buf_id;
__le16 buf_len;
__le16 resv;
__le32 addr_lo;
__le32 addr_hi;
} __packed;
/**
* struct crete_rxcq_32bd - crete rx rqe define
* @pkttype: pkttype 0 0:16bytes 1:2*16bytes 2:3*16bytes 3:4*16bytes
* @vlan_strip: the packet buffer id
* @rss_validate: resver bytes
* @outer_vlan_tpid: buffer length
* @addr_lo: address lower32
* @addr_hi: address high32
* Little Endian Only
*/
struct crete_rxcq_32bd_low {
/* dw0 */
u16 bd_size:3;
u16 bd_type:2;
u16 rsv0:2;
u16 wrap_counter:1;
u16 pkt_err_type:3;
u16 l4_cksum_ok:1;
u16 l3_cksum_ok:1;
u16 l2_type:2;
u16 ptp_pkt:1;
u16 buf_id;
/* dw1 */
u32 pkt_len:17;
u32 l4_hdr_type:3;
u32 l3_hdr_type:3;
u32 outer_l3_type:1;
u32 ip_frag:1;
u32 tunnel_mode:2;
u32 l2_valid:1;
u32 outer_ip_ext_opts:1;
u32 tunnel_ip_ext_opts:1;
u32 tunnel_l3_type:1;
u32 ip_ext_opts:1;
/* dw2 */
u16 src_port_id:12;
u16 rsv1:4;
u16 pkt_type:4;
u16 rsv2:2;
u16 rss_level:2;
u16 rss_type:8;
/* dw3 */
__le32 rss_hash;
/* dw4 */
__le32 timestamp;
/* dw5 */
__le16 vlan_tci;
u16 strip_vlan_tpid:3;
u16 vlan_strip:1;
u16 rsv3:4;
u16 rx_drop_counter:8;
/* dw6 */
__le32 metadata0;
/* dw7 */
__le32 metadata1;
} __packed;
/**
* struct crete_rxcq_32bd_hi - crete rx rqe define
* @rsv0:
* @wrap_counter:
* @rsv1: resver bytes
* @flow_tag0: buffer length
* @timestamps: address lower32
* @addr_hi: address high32
*/
struct crete_rxcq_32bd_hi {
/* dw 0 */
u16 rsv0:7;
u16 wrap_counter:1;
u16 lro_seg_num:8;
__le16 lro_checksum;
/* dw 1 */
u16 rsv1:4;
u16 lro_tcp_psh:1;
u16 lro_abrt:3;
u16 lro_min_ttl:8;
__le16 lro_tcp_win;
/* dw 2 */
__le32 lro_ack_seq_num;
/* dw 3 */
u32 timestamp_type:2;
u32 rsv2:30;
/* dw 4 */
__le32 timestamp_low;
/* dw 5 */
__le32 timestamp_high;
/* dw 6 */
__le32 metadata2;
/* dw 7 */
__le32 metadata3;
} __packed;
/**
* struct crete_rxcq_64bd - rx 64bytes bd
* @bd_l: low 32 bytes bd
* @bd_h: high 32 bytes bd
*/
struct crete_rxcq_64bd {
struct crete_rxcq_32bd_low bd_l;
struct crete_rxcq_32bd_hi bd_h;
} __packed;
/**
* struct crete_txbd - 16bytes no offloads
* @pkt_type:
* @no_complete:
*/
struct crete_txbd {
/* dw 0 */
u16 bd_size:3;
u16 rsv:2;
u16 eop:1;
u16 debug_trace:1;
u16 rsv0:1;
u16 bd_num:6;
u16 outmost_l3_cksum:1;
u16 outmost_l4_cksum:1;
u16 buf_id;
/* dw 1 */
u16 dst_port:12;
u16 rsv1:3;
u16 dst_port_valid:1;
__le16 buf_len;
/* dw 2 */
__le32 addr_lo;
/* dw 3 */
__le32 addr_hi;
} __packed;
struct crete_txbd_l1 {
/* dw 0 */
__le16 vlan_cli;
u16 vlan_insert:1;
u16 vlan_tpid:3;
u16 out3rd_l3_cksum:1;
u16 out3rd_l4_cksum:1;
u16 out2nd_l3_cksum:1;
u16 out2nd_l4_cksum:1;
u16 mac_timestamp_en:1;
u16 udp_tunnel_sport:1;
u16 rsv0:6;
/* dw 1 */
u8 outer_l4_offset;
u8 outer_l3_offset;
u8 l4_offset;
u8 l3_offset;
/* dw 2 */
u16 rsv1:15;
u16 tso_en:1;
u16 l4_tunnel_type:2;
u16 mss:14;
/* dw 3 */
__le32 metadata;
} __packed;
struct crete_32txbd {
struct crete_txbd bd_l0;
struct crete_txbd_l1 bd_l1;
} __packed;
struct crete_txbd_l2 {
/* dw 0 */
u16 rsv0:15;
u16 meter_valid:1;
__le16 meter_len;
/* dw 1 */
__le16 meterid0;
__le16 meterid1;
/* dw 2 */
__le16 meterid2;
__le16 meterid3;
/* dw 3 */
__le16 meterid4;
__le16 meterid5;
} __packed;
struct crete_48txbd {
struct crete_txbd bd_l0;
struct crete_txbd_l1 bd_l1;
struct crete_txbd_l2 bd_l2;
} __packed;
/**
* struct tx_cq_bd
* @pkt_type:
* @rsv0:
* @timestamp_high_flag:
*/
struct tx_cq_bd {
/* dw 0 */
u16 bd_size:3;
u16 bd_type:2;
u16 rsv0:2;
u16 wrap_counter:1;
u16 rsv1:8;
__le16 buf_id;
/* dw 1 */
__le32 errors;
/* dw 2 */
__le32 rsv2;
/* dw 3 */
__le32 timestamps;
} __packed;
union crete_db_info {
__le32 val;
struct {
__le16 index;
u16 vqn:11;
u16 debug_trace:1;
u16 type:4;
} db_info;
} __packed;
/**
* struct crete_db - crete rx db define
* @val: doorbell register value, notice le mode
* @type: sq / rq / eq
* @vqn: qp index
* @index: sq/rq entry bd index
*/
struct crete_db {
void __iomem *db_addr;
spinlock_t lock;
union {
__le32 val;
struct {
u32 type:5;
u32 resv:3;
u32 vqn:8;
__le16 index:16;
} db_info;
};
};
/****end define the io queue struct ****/
/**
* struct crete_rx_buf
* @page page
* @data:point to the rxbuf cpu address
* @mapping:device dma handle address
* kref: used for the
*/
struct crete_rx_buf {
refcount_t kref;
struct page *page;
void *data;
u8 *data_ptr;
dma_addr_t mapping;
// struct kref kref;
};
/**
* struct crete_tx_buf
* @skb: skb buffer address
* @mapping:device dma handle address
* @kref: ref counter
* @rx_prod: cons the rx production index
*/
struct crete_tx_buf {
// struct kref kref;
refcount_t kref;
struct sk_buff *skb;
dma_addr_t mapping;
void (*release)(struct kref *kref);
u16 rx_prod;
u16 nr_frags;
u16 nr_bdnum;
};
/**
* struct crete_rxring_mem
* all the qp memory info need the struct
* fly with bp memory
* @rx_bd: rx sq virtual memory address
* @rx_bd_map: rx bd dma handle
*/
struct crete_ring_mem {
void *ring_base[CRETE_RING_MEM_SIZE];
dma_addr_t rx_bd_map[CRETE_RING_MEM_SIZE];
};
struct crete_rxcp_ring_info {
void *rxcq_base;
void *priv; // used for crete_napi
dma_addr_t rxcq_mapping;
size_t bd_len;
u16 cp_prod;
u16 cp_cons;
u32 ring_size;
u32 ring_mask;
u8 wrap_counter:1;
};
struct crete_txcp_ring_info {
void *txcq_base;
void *priv; // used for crete_napi
dma_addr_t txcq_mapping;
size_t bd_len;
u16 cp_prod;
u16 cp_cons;
u32 ring_size;
u32 ring_mask;
atomic_t ring_avail;
u8 wrap_counter:1;
};
/**
* struct crete_rxring
* @rx_bd:rx ring descripion
* @db:ring doorbell
* @rx_buf: rxring buffer
*/
struct crete_rxring_info {
struct crete_rx_bd *rx_bd;
dma_addr_t rx_bd_mapping;
size_t bd_len;
struct crete_rx_buf *rx_buf;
struct crete_rxcp_ring_info *cpring;
void *priv; // used for crete_napi
refcount_t jref;
struct crete_db db;
struct crete_rxq_stats *rxq_stats;
u16 rx_dbprod;
u16 rx_prod;
u16 rx_cons;
u16 rx_ring_size;
u16 rx_ring_mask;
u8 queue_id;
u8 id;
u16 vec;
};
struct crete_txring_info {
struct crete_txbd *tx_bd;
dma_addr_t tx_bd_mapping;
size_t bd_len;
struct crete_db *db;
struct crete_tx_buf *tx_buf;
struct crete_txcp_ring_info *cpring;
void *priv; // used for crete_napi
//struct crete_db db;
struct crete_txq_stats *txq_stats;
u16 tx_prod;
u16 tx_dbprod;
u16 tx_cons;
u16 tx_ring_size;
u16 tx_ring_mask;
refcount_t jref;
u8 id;
u16 vec;
atomic_t ring_avail;
u8 kick_pending:1;
};
struct crete_napi {
struct napi_struct napi;
struct crete_core_dev *cdev;
union {
struct crete_rxring_info *rxring;
struct crete_txring_info *txring;
};
union {
struct crete_rxcp_ring_info *rxcpring;
struct crete_txcp_ring_info *txcpring;
};
};
static inline u32 crete_tx_avail(struct crete_txring_info *txr)
{
barrier();
// return txr->tx_ring_size - ((txr->tx_prod - txr->tx_cons) & txr->tx_ring_mask);
return atomic_read(&txr->ring_avail);
}
static inline u32 crete_tx_length(struct crete_txring_info *txr)
{
barrier();
return (txr->tx_ring_size - atomic_read(&txr->ring_avail));
}
extern struct crete_core_dev *g_cdev;
//extern int crete_cdev_cap_init(struct crete_core_dev *cdev);
extern netdev_tx_t crete_start_xmit(struct sk_buff *skb,
struct net_device *dev);
extern int crete_poll_tx(struct napi_struct *napi, int budget);
extern int crete_poll_rx(struct napi_struct *napi, int budget);
extern int crete_features_negotiate(struct crete_core_dev *cdev);
extern int crete_close(struct net_device *dev);
extern int crete_open(struct net_device *dev);
/*
* static inline void crete_txbuf_release(struct kref *kref, struct device *dev)
* {
* struct crete_tx_buf *txbuf;
* struct
* txbuf = container_of(kref, struct crete_tx_buf, kref);
* if (!txbuf)
* return;
* dma_unmap_single(&pdev->dev, dma_unmap_addr(tx_buf, mapping),
* skb_headlen(skb), DMA_TO_DEVICE);
* dev_kfree_skb_any(skb);
* }
*/
#endif /* __CRETE_IOQUEUE_H */

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2023, Jaguar Micro. All rights reserved */
#ifndef _KCOMPAT_STD_DEFS_H_
#define _KCOMPAT_STD_DEFS_H_
/* This file contains the definitions for what kernel features need backports
* for a given kernel. It targets only the standard stable kernel releases.
* It must check only LINUX_VERSION_CODE and assume the kernel is a standard
* release, and not a custom distribution.
*
* It must define HAVE_<FLAG> and NEED_<FLAG> for features. It must not
* implement any backports, instead leaving the implementation to the
* kcompat_impl.h header.
*
* If a feature can be easily implemented as a replacement macro or fully
* backported, use a NEED_<FLAG> to indicate that the feature needs
* a backport. (If NEED_<FLAG> is undefined, then no backport for that feature
* is needed).
*
* If a feature cannot be easily implemented in kcompat directly, but
* requires drivers to make specific changes such as stripping out an entire
* feature or modifying a function pointer prototype, use a HAVE_<FLAG>.
*/
#ifndef LINUX_VERSION_CODE
#error "LINUX_VERSION_CODE is undefined"
#endif
#ifndef KERNEL_VERSION
#error "KERNEL_VERSION is undefined"
#endif
/*****************************************************************************/
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 18, 0))
#define CONFIG_DEVLINK_WITHOUT_FLASH
#define CONFIG_WITHOUT_DEVLINK_PARAM_ETH
// #define NEED_ETH_HW_ADDR_SET
#endif /* 4,18,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
#define NEED_ETH_HW_ADDR_SET
#endif /* 5.10.0 */
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 134))
#define NEED_ETH_HW_ADDR_SET
#define CONFIG_WITHOUT_DEVLINK_PARAM_ETH
#define HAVE_DEVLINK_REGISTER_SETS_DEV
#define NEED_DEVLINK_ALLOC_SETS_DEV
#endif /* 5.10.134 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0))
#define CONFIG_DEVLINK_CARRYOUT_OPTIMIZE
#endif /* 5.11.0 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
#define CONFIG_ETHTOOL_EXTEND_RINGPARAM
#endif /* 5.17.0 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
#define NETIF_NAPI_ADD_NEWAPI
#endif /* 5.19.0 */
/*****************************************************************************/
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0))
#else /* >=6.1.0 */
#define CONFIG_WITHOUT_DEVLINK_PARAM_ETH
#endif /* 6.1.0 */
/*
* about the anolis 5.10.134-14 kernel version
* auxliary define with return int value
*/
#ifdef SNIC_ANOLIS_VERSION14
// #define NEED_ETH_HW_ADDR_SET
#define CONFIG_WITHOUT_DEVLINK_PARAM_ETH
#define HAVE_DEVLINK_REGISTER_SETS_DEV
#define NEED_DEVLINK_ALLOC_SETS_DEV
#endif
#ifdef BCLINUX2110U4
#undef NEED_ETH_HW_ADDR_SET
#define CONFIG_ETHTOOL_EXTEND_RINGPARAM
#endif
#ifdef SNIC_OPENEULER_VERSION136
#define CONFIG_ETHTOOL_EXTEND_RINGPARAM
#endif
#endif /* _KCOMPAT_STD_DEFS_H_ */

View File

@ -0,0 +1,108 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/*
* Copyright (c) 2023, Jaguarmicro Technologies, Inc. All rights reserved.
*/
#ifndef JM_RDMA_H
#define JM_RDMA_H
#include <linux/io.h>
#ifndef USE_JM_AUX_BUS
#include <linux/auxiliary_bus.h>
#else
#include "linux/auxiliary_bus.h"
#endif
#include <linux/netdevice.h>
struct jm_rdma_core;
struct jm_rdma_adev;
/*
* struct device *(*get_device)(struct jm_rdma_core *rdma);
* Get struct device related with this auxiliary_device.
* For example:
* return &pci_dev.dev;
*
* void (*get_dev_info)(struct jm_rdma_core *rdma, u8 *feature,
* u8 *rev_id, u16 *dev_id);
* Get device's information.
* For example:
* *rev_id = pci_dev.revision;
* *dev_id = pci_dev.device;
* *vendor = pci_dev.vendor;
*
* void (*cmdq_notify)(struct jm_rdma_core *rdma, u32 event);
* Notify new command to the related command queue.
* For example:
* iowrite32(event, cmd_db_reg); //cmd_db_reg = reg_addr + 0xEFC0
*
* int (*get_irqn)(struct jm_rdma_core *rdma, int index);
* Get the irq number with the index.
* For example:
* return pci_irq_vector(ae_dev->pdev, index);
*
* int (*store_bond_info)(struct jm_rdma_core *rdma,
* struct net_device *master, bool flag);
* Currently an empty function(return 0) is ok.
*
* void (*get_bar)(struct jm_rdma_core *rdma, void **base, void **eq_reg);
* Get BAR mapping bar address and eq address.
* For example:
* *base = reg_addr; // reg_addr = ioremap(base_base, 64 * 1024)
* *eq_reg = eq_db_reg; // eq_db_reg = reg_addr + 0xF000
*
* void (*get_uar)(struct jm_rdma_core *rdma, phys_addr_t *base, u32 *len);
* Get UAR base and length.
* For example:
* *base = uar_base; //bar_base + 64 * 1024
* *len = uar_size; // 64 * 1024
*
* void (*get_vector)(struct jm_rdma_core *rdma, int num, int base);
* Get the base and number of rdma's interrupt vector.
* For example:
* *base = vector_base;
* *num = vector_num;
*
* void (*timer_db)(struct jm_rdma_core *rdma, u32 qpn, int flags);
* Trigger a time DB.
* Currently an empty function is ok.
*
* void (*reload)(struct jm_rdma_core *rdma);
* Reload rdma core driver.
* Currently an empty function is ok.
*
*/
struct jm_rdma_ops {
struct device *(*get_device)(struct jm_rdma_core *rdma);
void (*get_dev_info)(struct jm_rdma_core *rdma, u8 *feature, u8 *rev_id,
u16 *dev_id, u16 *vendor);
void (*cmdq_notify)(struct jm_rdma_core *rdma, u32 event);
int (*get_irqn)(struct jm_rdma_core *rdma, int index);
int (*store_bond_info)(struct jm_rdma_core *rdma,
struct net_device *master, bool flag);
void (*get_bar)(struct jm_rdma_core *rdma, void **base, void **eq_reg);
void (*get_uar)(struct jm_rdma_core *rdma, phys_addr_t *base, int *len);
void (*get_vector)(struct jm_rdma_core *rdma, int *num, int *base);
bool (*is_error)(struct jm_rdma_core *rdma);
void (*timer_db)(struct jm_rdma_core *rdma, u32 qpn, int flags);
void (*reload)(struct jm_rdma_core *rdma);
};
struct jm_rdma_core {
struct jm_rdma_ops *ops;
struct jm_rdma_adev **adev;
int adev_idx;
};
struct jm_rdma_adev {
struct auxiliary_device adev;
struct jm_rdma_core *rdma_core;
int idx;
};
enum {
JM_DEVICE_FEATURE_CMDQ_IS_PA = 1 << 0,
JM_DEVICE_FEATURE_ATOMIC_HCA = 1 << 1,
};
#endif

View File

@ -0,0 +1,239 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023, Jaguar Micro. All rights reserved
#
# Helper script to detect if auxiliary bus support. This script
#
# returns 0 when:
# - CONFIG_AUXILIARY_BUS=y
# - auxiliary_bus.h was found
#
# Returning 0 means the driver build/install doesn't need OOT
# auxiliary bus
#
# returns 1 when:
# - CONFIG_AUXILIARY_BUS=n (or any value that's not "=y")
# - kernel configuration was incorrect
# - kernel configuration file was not found
#
# Returning 1 means something bad/unexpected happened and the
# driver build/install should treat this as a failure
#
# returns 2 when:
# - When OOT auxiliary is needed regardless if a previous OOT
# auxiliary was already. This is done because the driver
# always needs to build against auxiliary.o to avoid
# warnings/errors since auxiliary.o is built-in to the
# driver's makefile
#
# Returning 2 means the driver build/install needs OOT auxiliary
# bus
#
# returns 3 when:
# - A file and/or directory does not exist
#
# Returning 3 means something bad/unexpected happened and the
# driver build/install should treat this as a failure
#
# Note: when ksrc and build-kernel are both specified on the
# command line and build-kernel is not in the same location
# as ksrc, then ksrc takes precedence. For example:
# ./check_aux_bus --ksrc=/lib/modules/5.8.0/source --build-kernel=5.10.0
#
# In this case the kernel config file won't be searched for and
# the script will only check to see if the in-tree/OOT auxiliary_bus.h
# file exists at ksrc.
msg()
{
if [ $verbose == 1 ]; then
echo -e $1
fi
}
exit_builtin_auxiliary_enabled() { exit 0; }
exit_kconfig_invalid() { exit 1; }
exit_need_oot_auxiliary() { exit 2; }
exit_not_found_failure() { exit 3; }
find_aux_bus_inc()
{
aux_bus_inc=$(find -L ${ksrc} -name "auxiliary_bus.h")
msg "auxiliary_bus.h location: ${aux_bus_inc}"
}
LINUX_INC_DIR="include/linux"
set_build_kernel()
{
build_kernel=$(uname -r)
}
find_kernel_source()
{
# All the default places to look for kernel source
test_dirs=(/lib/modules/${build_kernel}/source \
/lib/modules/${build_kernel}/build \
/usr/src/linux-${build_kernel} \
/usr/src/linux-$(echo ${build_kernel} | sed 's/-.*//') \
/usr/src/kernel-headers-${build_kernel} \
/usr/src/kernel-source-${build_kernel} \
/usr/src/linux-$(echo ${build_kernel} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux \
/usr/src/kernels/${build_kernel} \
/usr/src/kernels)
# Save the first valid kernel source path
for dir in "${test_dirs[@]}"; do
if [ -d ${dir}/${LINUX_INC_DIR} ]; then
ksrc=${dir}
break
fi
done
if [ -z ${ksrc} ]; then
echo "*** Kernel header files not in any of the expected locations."
echo "*** Install the appropriate kernel development package, e.g."
echo "kernel-devel, for building kernel modules and try again"
exit_not_found_failure
fi
}
find_config_file()
{
# only search for kernel .config file if build_kernel is pointing
# in the same tree as ksrc (see not about ksrc and build_kernel
# both set in the scripts header comment)
if [[ "$ksrc" != *"/lib/modules/${build_kernel}"* ]]; then
msg "ksrc=$ksrc not the same as location generated from"
msg "build_kernel=\"/lib/modules/${build_kernel}\", "
msg "not searching for kernel .config file"
else
kbuild_dir="/lib/modules/${build_kernel}/build"
file_locations=(${kbuild_dir}/include/generated/autoconf.h \
${kbuild_dir}/include/linux/autoconf.h \
/boot/bmlinux.autoconf.h)
for file in "${file_locations[@]}"; do
if [ -f ${file} ]; then
kconfig=${file}
break
fi
done
if [ -z ${kconfig} ]; then
msg "Kernel config file not found at any of the expected locations."
fi
fi
}
get_config_auxiliary_bus()
{
# CONFIG_AUXILIARY_BUS=0 corresponds to CONFIG_AUXILIARY_BUS=n
# CONFIG_AUXILIARY_BUS=1 corresponds to CONFIG_AUXILIARY_BUS=y
# CONFIG_AUXILIARY_BUS= corresponds to CONFIG_AUXILIARY_BUS not available in the kernel
CONFIG_AUXILIARY_BUS=$(grep CONFIG_AUXILIARY_BUS ${kconfig} | awk -F" " '{print $3}')
msg "CONFIG_AUXILIARY_BUS=${CONFIG_AUXILIARY_BUS}"
}
ksrc=""
build_kernel=""
verbose=0
usage()
{
script=$(basename $0)
echo -e "usage:"
echo -e "\t$script [options]"
echo -e "\n\toptions:"
echo -e "\t -v, --verbose"
echo -e "\t -h, --help"
echo -e "\n\turn script against specified kernel source"
echo -e "\t -k, --ksrc \"/lib/modules/5.12.0/source\""
echo -e "\n\turn script with kernel version (kernel version used to"
echo -e "find kernel source programatically)"
echo -e "\t -b, --build-kernel \"5.8.0\""
}
options=$(getopt -o "k:b:vh" --long ksrc:,build-kernel:,verbose,help -- "$@")
eval set -- "$options"
while :; do
case $1 in
-k|--ksrc) ksrc=$2; shift;;
-b|--build-kernel) build_kernel=$2; shift;;
-v|--verbose) verbose=1 ;;
-h|--help) usage && exit 0;;
--) shift; break;;
esac
shift
done
if [ $verbose == 1 ]; then
set -x
fi
# both build_kernel and ksrc are unset so programatically determine build_kernel
if [ -z $build_kernel ] && [ -z $ksrc ]; then
set_build_kernel
fi
# only programatically search for kernel source if ksrc not set on command line
if [ -z $ksrc ]; then
find_kernel_source
fi
find_config_file
if [ ! -z $kconfig ]; then
# if we found the kernel .config file then exit the script based on various
# conditions that depend on the CONFIG_AUXILIARY_BUS string being found
get_config_auxiliary_bus
if [ -z "$CONFIG_AUXILIARY_BUS" ]; then
msg "CONFIG_AUXILIARY_BUS not found in ${kconfig}."
# CONFIG_AUXILIARY_BUS string was not found, so OOT auxiliary is needed
exit_need_oot_auxiliary
elif [ "$CONFIG_AUXILIARY_BUS" = "1" ]; then
msg "CONFIG_AUXILIARY_BUS=y in ${kconfig}."
# CONFIG_AUXILIARY_BUS=y, so OOT auxiliary is not needed
exit_builtin_auxiliary_enabled
else
msg ""
msg "kernel $build_kernel supports auxiliary bus, but CONFIG_AUXILIARY_BUS"
msg "is not set in ${kconfig}. Rebuild your kernel with"
msg "CONFIG_AUXILIARY_BUS=y"
msg ""
# CONFIG_AUXILIARY_BUS is not "=y", but the string was found, so report
# the failure so it can be used to fail build/install
exit_kconfig_invalid
fi
else
if [ ! -d ${ksrc}/${LINUX_INC_DIR} ] && [ ! -d ${ksrc}/source/${LINUX_INC_DIR} ]; then
echo "${ksrc}/${LINUX_INC_DIR} and ${ksrc}/source/${LINUX_INC_DIR}"
echo "do not exist"
exit_not_found_failure
fi
# We didn't find a kernel .config file, so check to see if auxiliary_bus.h
# is found in the kernel source include directory
find_aux_bus_inc
if [ -f "$aux_bus_inc" ]; then
# AUXILIARY_MODULE_PREFIX is defined only in out-of-tree auxiliary bus
if [ $(grep -c AUXILIARY_MODULE_PREFIX $aux_bus_inc) -eq 0 ]; then
msg "in-tree auxiliary_bus.h found at ${ksrc}/${LINUX_INC_DIR}"
# If auxiliary_bus.h is included at ${ksrc} and it isn't our OOT version,
#then don't build OOT auxiliary as part of the driver makefile
exit_builtin_auxiliary_enabled
else
msg "OOT auxiliary_bus.h found at ${ksrc}/${LINUX_INC_DIR}"
# If auxiliary bus is included at ${ksrc} and it is our OOT version, then
# build OOT auxiliary as part of the driver makefile
exit_need_oot_auxiliary
fi
else
msg "auxiliary_bus.h not found at ${ksrc}/${LINUX_INC_DIR}"
exit_need_oot_auxiliary
fi
fi

View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0
# ccflags-y += -DCONFIG_NOSIM_DEBUG
obj-m := crete_pnic.o
crete_pnic-objs := crete_nic_main.o \
crete_nic_io.o \
crete_nic.o \
crete_nic_ethtool.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/
#################
# Auxiliary Bus #
# #################
AUX_BUS_SYM := /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
ifeq ($(wildcard $(AUX_BUS_SYM)),)
$(info ${AUX_BUS_SYM} File does not exist)
else
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
endif
KBUILD_EXTRA_SYMBOLS += $(PWD)/../crete-core/Module.symvers
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
@\rm *.o *.ko *.mod.c modules.order .*.mod Module.symvers crete_core.mod *.mod .*.cmd .tmp_versions .crete* -rf

View File

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* JaguarMicro virtual dev driver for virtio dataplane offloading
*
* Copyright (C) 2022 JaguarMicro Corporation.
*
* Author: Angus Chen <angus.chen@jaguarmicro.com>
*
*/
#include <linux/vdpa.h>
#include "../crete-core/crete_cmd_if.h"
#include "crete_nic.h"
void crete_vnic_priv_cleanup(struct crete_vnic_priv *priv)
{
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev;
struct crete_net_common_cfg *netcfg = &priv->net_cfg;
if (!priv->coredev)
return;
pdev = core_dev->pdev;
dev_err(&pdev->dev, "enter crete_priv_cleanup\n");
kfree(netcfg->mc_list);
netcfg->mc_list = NULL;
kfree(netcfg->uc_list);
netcfg->uc_list = NULL;
// memset(priv, 0, sizeof(*priv));
dev_err(&pdev->dev, "exit crete_priv_cleanup\n");
}
int crete_nic_set_device_type(struct crete_core_dev *core_dev, enum crete_dev_type op)
{
int ret;
struct pci_dev *pdev = core_dev->pdev;
u32 devtype = 0;
ret = crete_set_dev_type(core_dev, op);
if (ret) {
dev_err(&pdev->dev,
"Failed to set device type %x, set cmd error\n", op);
return -EINVAL;
}
ret = crete_get_dev_type(core_dev, &devtype);
if (ret) {
dev_err(&pdev->dev, "set dev type failed\n");
goto out;
}
if (devtype != op) {
dev_err(&pdev->dev,
" dev type not right check failed. dev type %x\n", op);
goto out;
}
return ret;
out:
return -EINVAL;
}
u64 crete_net_get_supported_features(struct crete_core_dev *core_dev,
enum crete_feature_opcode op)
{
struct pci_dev *pdev = core_dev->pdev;
u64 dev_features;
u64 ret;
ret = crete_cmd_get_features(core_dev, op, &dev_features);
if (ret) {
dev_err(&pdev->dev, "get device features is error\n");
ret = -EINVAL;
}
core_dev->cap.hw_features = dev_features;
dev_info(&pdev->dev, "device supported features[0x%llx]\n",
core_dev->cap.hw_features);
return ret;
}
u64 crete_net_get_max_supported_vqs(struct crete_core_dev *core_dev)
{
int ret;
u16 max_queue_size;
u8 max_qp_num;
u8 ctrl_queue_size;
struct pci_dev *pdev = core_dev->pdev;
ret =
crete_get_qp_cap(core_dev, &max_queue_size, &max_qp_num,
&ctrl_queue_size);
if (ret) {
dev_err(&pdev->dev, "%s is error\n", __func__);
return -EINVAL;
}
core_dev->cap.qpcap.ctrl_queue_size = ctrl_queue_size;
core_dev->cap.qpcap.max_qp_num = max_qp_num;
core_dev->cap.qpcap.max_queue_size = max_queue_size;
dev_info(&pdev->dev,
"crete vqs: ctl_qlen[0x%x] ioqlen[0x%x] maxvqs[%d]\n",
ctrl_queue_size, max_queue_size, max_qp_num);
return 0;
}
//todo: keyi cmd_if
int crete_trim_rings(struct crete_core_dev *cdev)
{
int cpunums = num_online_cpus();
int maxqpnums = cdev->cap.qpcap.max_qp_num;
if (maxqpnums > CRETE_VNIC_MAX_QUEUES) {
cdev->cap.qpcap.max_qp_num = CRETE_VNIC_MAX_QUEUES;
crete_err(cdev->device, "max qp greater than %d\n",
CRETE_VNIC_MAX_QUEUES);
}
cdev->ring_size = min(cpunums, maxqpnums);
if (!cdev->ring_size) {
crete_err(cdev->device, "ring size zero not right\n");
return -1;
}
return 0;
} //todo: keyi cmd_if
int crete_vnic_priv_init(struct crete_vnic_priv *priv,
struct net_device *netdev,
struct crete_core_dev *core_dev)
{
int mem_size = (CRETE_MAX_UC_ADDRS - 1) * ETH_ALEN;
struct crete_net_common_cfg *netcfg = &priv->net_cfg;
int rc = 0;
priv->coredev = core_dev;
priv->netdev = netdev;
netcfg->uc_list = kmalloc(mem_size, GFP_KERNEL);
if (!netcfg->uc_list) {
rc = -ENOMEM;
goto err_uc_list_alloc;
}
netcfg->mc_list_size = CRETE_MAX_MC_ADDRS * ETH_ALEN;
netcfg->mc_list = kmalloc(netcfg->mc_list_size, GFP_KERNEL);
if (!netcfg->mc_list) {
rc = -ENOMEM;
goto err_mc_list_alloc;
}
return 0;
err_mc_list_alloc:
kfree(netcfg->uc_list);
netcfg->uc_list = NULL;
err_uc_list_alloc:
return rc;
} //todo: keyi cmd_if
struct net_device *crete_vnic_create_netdev(struct crete_core_dev *coredev)
{
struct net_device *netdev;
unsigned int txqs, rxqs;
struct crete_vnic_priv *priv;
struct pci_dev *pdev = coredev->pdev;
int err;
txqs = coredev->ring_size;
rxqs = coredev->ring_size;
/* crete netdevice with max qp number */
netdev = alloc_etherdev_mqs(sizeof(struct crete_vnic_priv), txqs, rxqs);
if (!netdev) {
dev_err(&pdev->dev, "alloc_etherdev_mqs() failed\n");
return NULL;
}
priv = netdev_priv(netdev);
coredev->netdev = netdev;
err = crete_vnic_priv_init(priv, netdev, coredev);
if (err) {
dev_err(&pdev->dev, "crete_vnic_priv_init failed\n");
goto err_priv_init;
}
netif_tx_disable(netdev);
return netdev;
err_priv_init:
free_netdev(netdev);
return NULL;
} //todo: keyi cmd_if
void crete_build_common_netdev(struct net_device *netdev)
{
struct crete_vnic_priv *priv = netdev_priv(netdev);
struct crete_core_dev *core_dev = priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
netdev->watchdog_timeo = 5 * HZ;
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
SET_NETDEV_DEV(netdev, &pdev->dev);
strcpy(netdev->name, "eth%d");
}

View File

@ -0,0 +1,237 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* JaguarMicro virt device driver for virtio dataplane offloading
*
* Copyright (C) 2020 JaguarMicro Corporation.
*/
#ifndef _CRETE_NIC_H_
#define _CRETE_NIC_H_
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <uapi/linux/virtio_net.h>
#include <uapi/linux/virtio_config.h>
#include <uapi/linux/virtio_pci.h>
#include <linux/auxiliary_bus.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
#include "../crete-core/crete_cmd.h"
#include "../crete-core/crete_cmd_if.h"
/* Max 8 data queue pairs(16 queues) and one control vq for now. */
#define CRETE_VNIC_MAX_QUEUES 17
#define CRETE_VNIC_QUEUES_NOCTRL 16
#define CRETE_VNIC_QUEUE_ALIGNMENT PAGE_SIZE
/*attention pls ,it's the depth of queue*/
#define CRETE_VNIC_QUEUE_SIZE_MAX 512
#define CRETE_VNIC_QUEUE_SIZE_MIN 64
#define CRETE_VNIC_MSI_CONFIG_OFF 0
#define CRETE_VNIC_MSI_QUEUE_OFF 1
#define CRETE_VNIC_PCI_MAX_RESOURCE 6
#define VHOST_F_LOG_ALL 26
#define VHOST_ACCESS_WO 0x2
#define DEBUG
#define VIRTIO_NET_CONFIG_OFFSET_MAC offsetof(struct virtio_net_config, mac)
#define VIRTIO_NET_CONFIG_OFFSET_MTU offsetof(struct virtio_net_config, mtu)
/**********************************vnic add******************************************/
#define CRETE_VNIC_MQ_MAX 17
#define CRETE_VNIC_AUX_DEV_NAME "crete_core.nic"
#define CRETE_NIC_DRV_NAME "crete_pnic"
/* FIXME: MTU in config. */
#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
#define GOOD_COPY_LEN 128
#define VIRTNET_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD)
/* Amount of XDP headroom to prepend to packets for use by xdp_adjust_head */
#define VIRTIO_XDP_HEADROOM 256
/* RX packet size EWMA. The average packet size is used to determine the packet
* buffer size when refilling RX rings. As the entire RX ring may be refilled
* at once, the weight is chosen so that the EWMA will be insensitive to short-
* term, transient changes in packet size.
*/
DECLARE_EWMA(pkt_len, 0, 64)
#define GUEST_OFFLOAD_GRO_HW_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
(1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
(1ULL << VIRTIO_NET_F_GUEST_ECN) | \
(1ULL << VIRTIO_NET_F_GUEST_UFO))
struct crete_vnic_stat_desc {
char desc[ETH_GSTRING_LEN];
size_t offset;
};
struct crete_vnic_sq_stats {
struct u64_stats_sync syncp;
u64 packets;
u64 bytes;
u64 xdp_tx;
u64 xdp_tx_drops;
u64 kicks;
};
struct crete_vnic_rq_stats {
struct u64_stats_sync syncp;
u64 packets;
u64 bytes;
u64 drops;
u64 xdp_packets;
u64 xdp_tx;
u64 xdp_redirects;
u64 xdp_drops;
u64 kicks;
};
#define CRETE_VNIC_SQ_STAT(m) offsetof(struct crete_vnic_sq_stats, m)
#define CRETE_VNIC_RQ_STAT(m) offsetof(struct crete_vnic_rq_stats, m)
struct send_queue {
/* Virtqueue associated with this send _queue */
struct virtqueue *vq;
/* TX: fragments + linear part + virtio header */
struct scatterlist sg[MAX_SKB_FRAGS + 2];
/* Name of the send queue: output.$index */
char name[40];
struct crete_vnic_sq_stats stats;
struct napi_struct napi;
};
/* Internal representation of a receive virtqueue */
struct receive_queue {
/* Virtqueue associated with this receive_queue */
struct virtqueue *vq;
struct napi_struct napi;
struct bpf_prog __rcu *xdp_prog;
struct crete_vnic_rq_stats stats;
/* Chain pages by the private ptr. */
struct page *pages;
/* Average packet length for mergeable receive buffers. */
struct ewma_pkt_len mrg_avg_pkt_len;
/* Page frag for packet buffer allocation. */
struct page_frag alloc_frag;
/* RX: fragments + linear part + virtio header */
struct scatterlist sg[MAX_SKB_FRAGS + 2];
/* Min single buffer size for mergeable buffers case. */
unsigned int min_buf_len;
/* Name of this receive queue: input.$index */
char name[40];
};
struct crete_vnic_msix_info {
struct virtqueue *vq;
int qid;
/* MSI-X vector (or none) */
unsigned int msix_vector;
unsigned int irq;
bool ready;
char msix_name[256];
};
struct crete_net_common_cfg {
u32 rx_mask;
u16 uc_filter_count;
u8 *uc_list;
u8 *mc_list;
int mc_list_size;
int mc_list_count;
__u16 vportid;
__u8 mac[ETH_ALEN];
__u16 mtu;
__le32 speed;
/*
* 0x00 - half duplex
* 0x01 - full duplex
* Any other value stands for unknown.
*/
__u8 duplex;
/* maximum size of RSS key */
__u8 rss_max_key_size;
/* maximum number of indirection table entries */
__le16 rss_max_indirection_table_length;
/* bitmask of supported VIRTIO_NET_RSS_HASH_ types */
__le32 supported_hash_types;
__le16 vlanid;
};
struct crete_vnic_priv {
struct virtio_device vdev;
struct crete_core_dev *coredev;
struct net_device *netdev;
struct send_queue *sq;
struct receive_queue *rq;
unsigned int status;
u16 max_queue_pairs;
u16 curr_queue_pairs;
bool big_packets;
bool mergeable_rx_bufs;
bool any_header_sg;
u8 hdr_len;
struct delayed_work refill;
bool refill_enabled;
spinlock_t refill_lock;
bool affinity_hint_set;
struct hlist_node node;
struct hlist_node node_dead;
unsigned long guest_offloads;
unsigned long guest_offloads_capable;
spinlock_t lock;
struct crete_vnic_msix_info msix_info[CRETE_VNIC_MQ_MAX];
struct crete_net_common_cfg net_cfg;
struct crete_nb cnb;
struct work_struct set_rx_mode_work;
struct workqueue_struct *wq;
};
/*******************************************************************************/
enum crete_net_status {
CRETE_NET_DEV_STARTUP,
CRETE_NET_DEV_FEATURE_OK,
CRETE_NET_DEV_DEV_OK,
CRETE_NET_DEV_STOPPED
};
#define CRETE_RX_SEQ 0
#define CRETE_TX_SEQ 1
int crete_nic_set_hwstatus(struct crete_core_dev *core_dev, u8 status);
int crete_nic_set_device_type(struct crete_core_dev *core_dev,
enum crete_dev_type op);
int crete_trim_rings(struct crete_core_dev *core_dev);
struct net_device *crete_vnic_create_netdev(struct crete_core_dev *core_dev);
void crete_build_common_netdev(struct net_device *netdev);
void crete_vnic_destroy_netdev(struct net_device *netdev);
void crete_vnic_priv_cleanup(struct crete_vnic_priv *priv);
u64 crete_net_get_max_supported_vqs(struct crete_core_dev *core_dev);
u64 crete_net_get_supported_features(struct crete_core_dev *core_dev,
enum crete_feature_opcode op);
#endif /* _CRETE_NIC_H_ */

View File

@ -0,0 +1,516 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* A network driver using virtio.
*
* Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
*/
//#define DEBUG
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
#include "crete_nic.h"
#include "crete_nic_io.h"
#include <linux/firmware.h>
#include "../crete-core/crete_fw_update.h"
#define CRETE_VNIC_DRIVER_VERSION "crete-vnic-1.0"
/******************net tools****************************/
static void crete_vnic_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
struct crete_core_dev *core_dev = vnic_priv->coredev;
struct pci_dev *pdev = core_dev->pdev;
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
snprintf(info->fw_version, sizeof(info->fw_version),
"%d.%d.%d.%d", fw_ver_maj(core_dev),
fw_ver_min(core_dev), fw_ver_sub(core_dev), fw_ver_rev(core_dev));
strlcpy(info->version, CRETE_VNIC_DRIVER_VERSION,
sizeof(info->version));
strlcpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info));
}
static u32 crete_vnic_get_link(struct net_device *netdev)
{
//struct crete_vnic_priv *vnic_priv = netdev_priv(netdev);
//struct crete_core_dev *core_dev =vnic_priv->coredev;
/* If the link is not reported up to netdev, interrupts are disabled,
* and so the physical link state may have changed since we last
* looked. Set get_link_status to make sure that the true link
* state is interrogated, rather than pulling a cached and possibly
* stale link state from the driver.
*/
if (!netif_carrier_ok(netdev)) {
/*todo to vdev get link status */
return 0;
}
return 1;
}
/*
* about the anolis 5.10.134-14 kernel version
* auxliary define with return int value
*/
#if defined(SNIC_ANOLIS_VERSION14) || !defined(CONFIG_ETHTOOL_EXTEND_RINGPARAM)
static void crete_vnic_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
ring->rx_max_pending = virtqueue_get_vring_size(vnic_priv->rq[0].vq);
ring->tx_max_pending = virtqueue_get_vring_size(vnic_priv->sq[0].vq);
ring->rx_pending = ring->rx_max_pending;
ring->tx_pending = ring->tx_max_pending;
}
#else
static void crete_vnic_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam
*kernel_ring,
struct netlink_ext_ack *extack)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
ring->rx_max_pending = virtqueue_get_vring_size(vnic_priv->rq[0].vq);
ring->tx_max_pending = virtqueue_get_vring_size(vnic_priv->sq[0].vq);
ring->rx_pending = ring->rx_max_pending;
ring->tx_pending = ring->tx_max_pending;
}
#endif
static void crete_vnic_get_channels(struct net_device *dev,
struct ethtool_channels *channels)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
channels->combined_count = vnic_priv->curr_queue_pairs;
channels->max_combined = vnic_priv->max_queue_pairs;
channels->max_other = 0;
channels->rx_count = 0;
channels->tx_count = 0;
channels->other_count = 0;
}
/* TODO: Eliminate OOO packets during switching */
static int crete_vnic_set_channels(struct net_device *dev,
struct ethtool_channels *channels)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
u16 queue_pairs = channels->combined_count;
int err;
/* We don't support separate rx/tx channels.
* We don't allow setting 'other' channels.
*/
if (channels->rx_count || channels->tx_count || channels->other_count)
return -EINVAL;
if (queue_pairs > vnic_priv->max_queue_pairs || queue_pairs == 0)
return -EINVAL;
err = __crete_vnic_set_queues(dev, queue_pairs);
if (err)
goto err;
netif_set_real_num_tx_queues(dev, queue_pairs);
netif_set_real_num_rx_queues(dev, queue_pairs);
err:
return err;
}
int crete_vnic_ethtool_flash_device(struct crete_vnic_priv *vnic_priv,
struct ethtool_flash *flash)
{
struct crete_core_dev *cdev = vnic_priv->coredev;
struct net_device *dev = vnic_priv->netdev;
const struct firmware *fw;
int err;
if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
return -EOPNOTSUPP;
err = request_firmware_direct(&fw, flash->data, &dev->dev);
if (err)
return err;
dev_hold(dev);
rtnl_unlock();
err = crete_firmware_flash(cdev, fw, NULL, CRETE_FWU_ETHTOOL);
release_firmware(fw);
rtnl_lock();
dev_put(dev);
return err;
}
static int crete_vnic_flash_device(struct net_device *dev,
struct ethtool_flash *flash)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
return crete_vnic_ethtool_flash_device(vnic_priv, flash);
}
struct ptys2ethtool_config {
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertised);
};
static
struct ptys2ethtool_config ptys2ethtool_table[CRETE_LINK_MODES_CAP_BIT];
#define CRETE_BUILD_PTYS2ETHTOOL_CONFIG(reg_, table, ...) \
({ \
struct ptys2ethtool_config *cfg; \
const unsigned int modes[] = { __VA_ARGS__ }; \
unsigned int i, bit, idx; \
cfg = &table[reg_]; \
bitmap_zero(cfg->supported, \
__ETHTOOL_LINK_MODE_MASK_NBITS); \
bitmap_zero(cfg->advertised, \
__ETHTOOL_LINK_MODE_MASK_NBITS); \
for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \
bit = modes[i] % 64; \
idx = modes[i] / 64; \
__set_bit(bit, &cfg->supported[idx]); \
__set_bit(bit, &cfg->advertised[idx]); \
} \
})
void crete_build_ptys2ethtool_map(void)
{
memset(ptys2ethtool_table, 0, sizeof(ptys2ethtool_table));
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_10GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
ETHTOOL_LINK_MODE_10000baseER_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_25GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_40GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_50GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_100GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_200GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT);
CRETE_BUILD_PTYS2ETHTOOL_CONFIG(CRETE_400GBASE_BIT, ptys2ethtool_table,
ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT);
}
u16 crete_port_speed2linkmode(u32 speed)
{
int i;
for (i = 0; i < ARRAY_SIZE(crete_link_speed); ++i) {
if (crete_link_speed[i] == speed)
return i;
}
return 0;
}
int crete_ethtool_set_link_ksettings(struct crete_vnic_priv *vnic_priv,
const struct ethtool_link_ksettings *link_ksettings)
{
struct crete_core_dev *cdev = vnic_priv->coredev;
const struct ethtool_link_settings *base = &link_ksettings->base;
struct net_device *dev = vnic_priv->netdev;
struct crete_speed_duplex sd_current = {0};
u16 change_bit = 0;
u16 link_mode;
int ret;
if (base->autoneg == AUTONEG_ENABLE) {
netdev_err(dev, "Autonegotiation is not supported!\n");
return -EINVAL;
}
if (base->duplex != DUPLEX_FULL) {
netdev_err(dev, "Only full duplex mode is supported!\n");
return -EINVAL;
}
link_mode = crete_port_speed2linkmode(base->speed);
if (link_mode >= CRETE_LINK_MODES_NUMBER || link_mode < CRETE_10GBASE) {
netdev_err(dev, "speed parameter is illeagl.\n");
return -EINVAL;
}
ret = crete_get_port_speed_duplex(cdev, &sd_current);
if (ret) {
netdev_err(dev, "Failed to get current speed and duplex mode!\n");
return ret;
}
if (sd_current.speed == link_mode && sd_current.duplex == base->duplex) {
netdev_info(dev, "Speed and duplex mode are already set to the requested values.\n");
return 0;
}
change_bit |= (sd_current.speed != link_mode) ? LINK_SPEED_OP_BIT : 0;
change_bit |= (sd_current.duplex != base->duplex) ? DUPLEX_MODE_OP_BIT : 0;
if (!netif_running(dev)) {
netdev_err(dev, "Network interface is not running. Cannot change settings.\n");
return -EINVAL;
}
ret = crete_set_port_speed_duplex(cdev, link_mode, base->duplex, change_bit);
if (ret) {
netdev_err(dev, "Failed to set speed and duplex mode!\n");
return ret;
}
netdev_info(dev, "Speed set to %d Mbps, duplex mode set to full.\n", base->speed);
return 0;
}
static int crete_vnic_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *link_ksettings)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
return crete_ethtool_set_link_ksettings(vnic_priv, link_ksettings);
}
static void ptys2ethtool_adver_link(u32 eth_speed_cap,
u8 tx_pause, u8 rx_pause, struct ethtool_link_ksettings *link_ksettings)
{
unsigned long speed_cap = eth_speed_cap;
unsigned long *advertising_modes = link_ksettings->link_modes.advertising;
int speed;
for_each_set_bit(speed, &speed_cap, CRETE_LINK_MODES_CAP_BIT)
bitmap_or(advertising_modes, advertising_modes,
ptys2ethtool_table[speed].advertised,
__ETHTOOL_LINK_MODE_MASK_NBITS);
if (rx_pause)
ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Pause);
if (tx_pause ^ rx_pause)
ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Asym_Pause);
}
static void ptys2ethtool_supported_link(u32 eth_speed_cap,
struct ethtool_link_ksettings *link_ksettings)
{
unsigned long speed_cap = eth_speed_cap;
unsigned long *supported_modes = link_ksettings->link_modes.supported;
int speed;
for_each_set_bit(speed, &speed_cap, CRETE_LINK_MODES_CAP_BIT)
bitmap_or(supported_modes, supported_modes,
ptys2ethtool_table[speed].supported,
__ETHTOOL_LINK_MODE_MASK_NBITS);
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Pause);
}
static int get_fec_supported_advertised(struct crete_core_dev *cdev,
struct ethtool_link_ksettings *link_ksettings)
{
u16 active_fec;
u16 eth_fec_cap;
u8 fec;
int err;
unsigned long fec_cap;
err = crete_get_fec_mode(cdev, &active_fec, &eth_fec_cap);
if (err)
return err;
fec_cap = eth_fec_cap;
for_each_set_bit(fec, &fec_cap, ARRAY_SIZE(crete_fec_2_ethtool_bit))
__set_bit(crete_fec_2_ethtool_bit[fec], link_ksettings->link_modes.supported);
if (active_fec <= CRETE_FEC_LLRS)
__set_bit(crete_fec_2_ethtool_bit[active_fec],
link_ksettings->link_modes.advertising);
return 0;
}
static int crete_vnic_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *link_ksettings)
{
struct crete_speed_duplex sd = {0};
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
struct crete_core_dev *cdev = vnic_priv->coredev;
u8 rx_pause = 0;
u8 tx_pause = 0;
int ret = 0;
link_ksettings->base.speed = SPEED_UNKNOWN;
link_ksettings->base.duplex = DUPLEX_UNKNOWN;
ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
crete_get_pfc_enable(cdev, &rx_pause, &tx_pause);
ret = crete_get_port_speed_duplex(cdev, &sd);
if (ret) {
netdev_err(dev, "Failed to get speed and duplex mode!\n");
ret = 0;
}
if (sd.speed >= CRETE_10GBASE && sd.speed < CRETE_LINK_MODES_NUMBER)
link_ksettings->base.speed = crete_link_speed[sd.speed];
if (sd.duplex >= CRETE_HALF_DUPLEX && sd.duplex < CRETE_DUPLEX_MAX)
link_ksettings->base.duplex = crete_link_duplex[sd.duplex];
netdev_info(dev, "Speed Get speed[%d] speed_cap[0x%x].\n", sd.speed, sd.speed_cap);
ptys2ethtool_supported_link(sd.speed_cap, link_ksettings);
ptys2ethtool_adver_link(sd.speed_cap, tx_pause, rx_pause, link_ksettings);
link_ksettings->base.port = PORT_FIBRE;
ret = get_fec_supported_advertised(cdev, link_ksettings);
if (ret) {
netdev_err(dev, "%s: FEC caps query failed: %d\n",
__func__, ret);
ret = 0; /* don't fail caps query because of FEC error */
}
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, FIBRE);
ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, FIBRE);
return ret;
}
static int crete_vnic_set_fecparam(struct net_device *dev,
struct ethtool_fecparam *fecparam)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
struct crete_core_dev *cdev = vnic_priv->coredev;
unsigned long fec_bitmap;
u16 fec_policy = 0;
bitmap_from_arr32(&fec_bitmap, &fecparam->fec, sizeof(fecparam->fec) * BITS_PER_BYTE);
if (bitmap_weight(&fec_bitmap, ETHTOOL_FEC_LLRS_BIT + 1) > 1)
return -EOPNOTSUPP;
switch (fecparam->fec) {
case ETHTOOL_FEC_OFF:
fec_policy = CRETE_FEC_OFF;
break;
case ETHTOOL_FEC_RS:
fec_policy = CRETE_FEC_RS;
break;
case ETHTOOL_FEC_BASER:
fec_policy = CRETE_FEC_BASER;
break;
default:
netdev_err(dev, "Unsupported FEC mode: %d\n", fecparam->fec);
return -EINVAL;
}
return crete_set_fec_mode(cdev, fec_policy);
}
static u32 crete_fec_cap_to_ethtool_fec(u16 fec_cap)
{
u32 ethtool_fec = 0;
if (fec_cap & BIT(CRETE_FEC_OFF))
ethtool_fec |= ETHTOOL_FEC_OFF;
if (fec_cap & BIT(CRETE_FEC_AUTO))
ethtool_fec |= ETHTOOL_FEC_AUTO;
if (fec_cap & BIT(CRETE_FEC_RS))
ethtool_fec |= ETHTOOL_FEC_RS;
if (fec_cap & BIT(CRETE_FEC_BASER))
ethtool_fec |= ETHTOOL_FEC_BASER;
if (fec_cap & BIT(CRETE_FEC_LLRS))
ethtool_fec |= ETHTOOL_FEC_LLRS;
return ethtool_fec;
}
static int crete_vnic_get_fecparam(struct net_device *dev,
struct ethtool_fecparam *fecparam)
{
struct crete_vnic_priv *vnic_priv = netdev_priv(dev);
struct crete_core_dev *cdev = vnic_priv->coredev;
u16 fec_active;
u16 fec_cap;
int err;
err = crete_get_fec_mode(cdev, &fec_active, &fec_cap);
if (err)
return err;
fecparam->active_fec = crete_fec_2_ethtool[fec_active];
fecparam->fec = crete_fec_cap_to_ethtool_fec(fec_cap);
return 0;
}
static const struct ethtool_ops crete_vnic_ethtool_ops = {
.get_drvinfo = crete_vnic_get_drvinfo,
.get_link = crete_vnic_get_link,
.get_ringparam = crete_vnic_get_ringparam,
.get_strings = crete_vnic_get_strings,
.get_sset_count = crete_vnic_get_sset_count,
.get_ethtool_stats = crete_vnic_get_ethtool_stats,
.get_channels = crete_vnic_get_channels,
.set_channels = crete_vnic_set_channels,
.flash_device = crete_vnic_flash_device,
.get_link_ksettings = crete_vnic_get_link_ksettings,
.set_link_ksettings = crete_vnic_set_link_ksettings,
.get_fecparam = crete_vnic_get_fecparam,
.set_fecparam = crete_vnic_set_fecparam,
};
void crete_set_ethtool_ops(struct net_device *netdev)
{
netdev->ethtool_ops = &crete_vnic_ethtool_ops;
}

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_NIC_ETHTOOL_H_
#define _CRETE_NIC_ETHTOOL_H_
void crete_set_ethtool_ops(struct net_device *netdev);
void crete_build_ptys2ethtool_map(void);
#endif /* _CRETE_NIC_ETHTOOL_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CRETE_NIC_IO_H_
#define _CRETE_NIC_IO_H_
void crete_set_netdev_ops(struct net_device *netdev);
void crete_set_ethtool_ops(struct net_device *netdev);
void free_unused_bufs(struct crete_vnic_priv *vnic_priv);
void free_receive_bufs(struct crete_vnic_priv *vnic_priv);
void free_receive_page_frags(struct crete_vnic_priv *vnic_priv);
int crete_vnic_set_queues(struct net_device *netdev, u16 queue_pairs);
int __crete_vnic_set_queues(struct net_device *netdev, u16 queue_pairs);
void crete_vnic_recv_done(struct virtqueue *rvq);
void crete_vnic_xmit_done(struct virtqueue *vq);
int crete_vnic_poll_tx(struct napi_struct *napi, int budget);
int crete_vnic_poll(struct napi_struct *napi, int budget);
void crete_vnic_alloc_recv_buf(struct work_struct *work);
void crete_vnic_get_strings(struct net_device *dev, u32 stringset, u8 *data);
int crete_vnic_get_sset_count(struct net_device *dev, int sset);
void crete_vnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data);
#endif /* _CRETE_NIC_IO_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
# SPDX-License-Identifier: GPL-2.0-only
# When the make command line has the goal 'all' or no goal specified (i.e.
# when compiling the driver) a sub-make of the kernel's Makefile includes
# the kernel configuration (include/config/auto.conf), but if any other
# goal is specified (e.g. install) the kernel configuration does not get
# included. Set a variable and export it to track over sub-makes.
ifeq ($(MAKELEVEL),0)
ifeq ($(filter-out all, $(MAKECMDGOALS)),)
export KERNEL_CONFIG_INCLUDED=1
endif
endif
# Explicitly set shell to bash, to avoid issues on distros with a different
# default shell. Looking at you, Ubuntu.
SHELL=/bin/bash
COMMON_MK ?= $(wildcard $(src)/common.mk)
ifeq (${COMMON_MK},)
override src = .
COMMON_MK = $(wildcard $(src)/common.mk)
endif
ifeq (${COMMON_MK},)
$(error Cannot find common.mk build rules)
else
include ${COMMON_MK}
endif
# SIOV support is only supported if the kernel has features for controlling
# PASID support. Do not even try to build SIOV support if the kernel lacks
# the necessary infrastructure.
ifeq ($(call is_kcompat_defined,HAVE_PASID_SUPPORT),1)
ifeq ($(call is_kcompat_defined,HAVE_IOMMU_DEV_FEAT_AUX),1)
export ENABLE_SIOV_SUPPORT := 1
endif
endif
# LM support is only enabled if the kernel has features for LM v1 protocol.
# If the kernel lacks the necessary infrastructure, LM support will be disabled.
ifeq ($(call is_kcompat_defined,HAVE_LMV1_SUPPORT),1)
export ENABLE_LM_SUPPORT := 1
endif
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
#
ccflags-y += -I$(src)
subdir-ccflags-y += -I$(src)
obj-m += crete_vdpa.o
crete_vdpa-y := crete_vdpa_main.o \
crete_vdpa_dev.o \
else # ifneq($(KERNELRELEASE),)
# normal makefile
DRIVER := crete_vdpa
EXTRA_CFLAGS += -std=gnu11
# ice does not support building on kernels older than 3.10.0
$(call minimum_kver_check,3,10,0)
# Command to update initramfs or display a warning message
ifeq (${cmd_initrd},)
define cmd_initramfs
@echo "Unable to update initramfs. You may need to do this manually."
endef
else
define cmd_initramfs
@echo "Updating initramfs..."
$(call cmd_initrd)
endef
endif
all:
+$(call kernelbuild,modules)
#@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
ifneq ($(wildcard lttng),)
$(MAKE) -C lttng
endif
clean:
+$(call kernelbuild,clean)
@-rm -rf *.${MANSECTION}.gz *.ko
ifneq ($(wildcard lttng),)
$(MAKE) -C lttng clean
endif
# Install kernel module files. This target is called by the RPM specfile when
# generating binary RPMs, and is not expected to modify files outside of the
# build root. Thus, it must not update initramfs, or run depmod.
modules_install: all
+$(call kernelbuild,modules_install)
#$(MAKE) auxiliary_install
# Install kernel module files without auxiliary. This target is called by the
# RPM specfile when generating binary RPMs, and is not expected to modify
# files outside of the build root. Thus, it must not update initramfs, or run depmod.
modules_install_no_aux:
@+$(call kernelbuild,modules_install)
mandocs_install: all
install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
# After installing all the files, perform necessary work to ensure the system
# will use the new modules. This includes running depmod to update module
# dependencies and updating the initramfs image in case the module is loaded
# during early boot.
install: modules_install
$(call cmd_depmod)
$(call cmd_initramfs)
# Remove installed module files. This target is called by the RPM specfile when
# generating binary RPMs, and is not expected to modify files outside of the
# build root. Thus, it must not update the initramfs image or run depmod.
modules_uninstall:
rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko
#$(MAKE) auxiliary_uninstall
mandocs_uninstall:
rm -f ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz 2>/dev/null
# After uninstalling all the files, perform necessary work to restore the
# system back to using the default kernel modules. This includes running depmod
# to update module dependencies and updating the initramfs image.
uninstall: modules_uninstall
$(call cmd_depmod)
$(call cmd_initramfs)
#auxiliary_info:
# @../scripts/check_aux_bus --verbose --ksrc="${KSRC}" --build-kernel="${BUILD_KERNEL}"
#auxiliary_install:
# ${auxiliary_post_install}
#auxiliary_uninstall:
# ${auxiliary_post_uninstall}
#ifeq (${NEED_AUX_BUS},1)
#all: auxiliary_info
#endif
help:
@echo 'Building external (out-of-tree) modules:'
@echo ' all - default target, build the module(s) and manpage'
@echo ' clean - remove generated files'
@echo ' modules_install - install the module(s) only'
@echo ' install - install the module(s) and manpage, and update initramfs'
@echo ' modules_uninstall - uninstall the module(s) only'
@echo ' uninstall - uninstall the module(s) and manpage, and update initramfs'
@echo ''
@echo 'Command-line options:'
@echo ' KSRC=<path> - Path to kernel source (defaults to running kernel)'
@echo ' LINUX_VERSION=<x.y.z> - Debug tool to force kernel LINUX_VERSION_CODE for'
@echo ' external module(s). *** Use at your own risk! ***'
@echo ' INSTALL_MOD_PATH=<path> - Prefix added to default module(s) installation path'
@echo ' (/lib/modules/$$(KERNELRELEASE)/)'
@echo ' INSTALL_MOD_DIR=<path> - Install module(s) in subdirectory other than default'
@echo ' (.../updates/drivers/net/ethernet/jm/${DRIVER}/)'
@echo ''
.PHONY: all clean modules_install install modules_uninstall uninstall help
endif # ifneq($(KERNELRELEASE),)

View File

@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
#!/bin/bash
# common build rules useful for out-of-tree Linux driver builds
#
make clean
make EXTRA_CFLAGS="-DHAVE_VDPA_JMND_OPS"

View File

@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
#!/bin/bash
# common build rules useful for out-of-tree Linux driver builds
#
make clean
make EXTRA_CFLAGS="-DHAVE_VDPA_EULER_OPS"

View File

@ -0,0 +1,454 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# common Makefile rules useful for out-of-tree Linux driver builds
#
# Usage: include common.mk
#
# After including, you probably want to add a minimum_kver_check call
#
# Required Variables:
# DRIVER
# -- Set to the lowercase driver name
#####################
# Helpful functions #
#####################
SHELL := $(shell which bash)
src ?= $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
readlink = $(shell readlink -f ${1})
# helper functions for converting kernel version to version codes
get_kver = $(or $(word ${2},$(subst ., ,${1})),0)
get_kvercode = $(shell [ "${1}" -ge 0 -a "${1}" -le 255 2>/dev/null ] && \
[ "${2}" -ge 0 -a "${2}" -le 255 2>/dev/null ] && \
[ "${3}" -ge 0 -a "${3}" -le 255 2>/dev/null ] && \
printf %d $$(( ( ${1} << 16 ) + ( ${2} << 8 ) + ( ${3} ) )) )
################
# depmod Macro #
################
cmd_depmod = /sbin/depmod $(if ${SYSTEM_MAP_FILE},-e -F ${SYSTEM_MAP_FILE}) \
$(if $(strip ${INSTALL_MOD_PATH}),-b ${INSTALL_MOD_PATH}) \
-a ${KVER}
#####################
# Environment tests #
#####################
DRIVER_UPPERCASE := $(shell echo ${DRIVER} | tr "[:lower:]" "[:upper:]")
ifeq (,${BUILD_KERNEL})
BUILD_KERNEL=$(shell uname -r)
endif
# Kernel Search Path
# All the places we look for kernel source
KSP := /lib/modules/${BUILD_KERNEL}/source \
/lib/modules/${BUILD_KERNEL}/build \
/usr/src/linux-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/-.*//') \
/usr/src/kernel-headers-${BUILD_KERNEL} \
/usr/src/kernel-source-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux \
/usr/src/kernels/${BUILD_KERNEL} \
/usr/src/kernels
# prune the list down to only values that exist and have an include/linux
# sub-directory. We can't use include/config because some older kernels don't
# have this.
test_dir = $(shell [ -e ${dir}/include/linux ] && echo ${dir})
KSP := $(foreach dir, ${KSP}, ${test_dir})
# we will use this first valid entry in the search path
ifeq (,${KSRC})
KSRC := $(firstword ${KSP})
endif
ifeq (,${KSRC})
$(warning *** Kernel header files not in any of the expected locations.)
$(warning *** Install the appropriate kernel development package, e.g.)
$(error kernel-devel, for building kernel modules and try again)
else
ifeq (/lib/modules/${BUILD_KERNEL}/source, ${KSRC})
KOBJ := /lib/modules/${BUILD_KERNEL}/build
else
KOBJ := ${KSRC}
endif
endif
SCRIPT_PATH := ${KSRC}/scripts
info_signed_modules =
ifeq (,${SCRIPT_PATH})
info_signed_modules += echo "*** Could not find sign-file script. Cannot sign driver." ;
else
SIGN_FILE_EXISTS := $(or $(and $(wildcard $(SCRIPT_PATH)/sign-file),1),)
PRIV_KEY_EXISTS := $(or $(and $(wildcard jm-linux-key.key),1),)
PUB_KEY_EXISTS := $(or $(and $(wildcard jm-linux-key.crt),1),)
ifneq ($(and $(SIGN_FILE_EXISTS),$(PRIV_KEY_EXISTS),$(PUB_KEY_EXISTS)),)
info_signed_modules += \
echo "*** Is sign-file present: ${SIGN_FILE_EXISTS}" ; \
echo "*** Is private key present: ${PRIV_KEY_EXISTS}" ; \
echo "*** Is public key present: ${PUB_KEY_EXISTS}" ;
info_signed_modules += echo "*** All files are present, signing driver." ;
sign_driver = $(shell ${SCRIPT_PATH}/sign-file sha256 jm-linux-key.key \
intel-linux-key.crt ${DRIVER}.ko)
else
info_signed_modules += echo "*** Files are missing, cannot sign driver." ;
sign_driver =
endif
endif
# Version file Search Path
VSP := ${KOBJ}/include/generated/utsrelease.h \
${KOBJ}/include/linux/utsrelease.h \
${KOBJ}/include/linux/version.h \
${KOBJ}/include/generated/uapi/linux/version.h \
/boot/vmlinuz.version.h
# Config file Search Path
CSP := ${KOBJ}/include/generated/autoconf.h \
${KOBJ}/include/linux/autoconf.h \
/boot/vmlinuz.autoconf.h
# System.map Search Path (for depmod)
MSP := ${KSRC}/System.map \
/usr/lib/debug/boot/System.map-${BUILD_KERNEL} \
/boot/System.map-${BUILD_KERNEL}
# prune the lists down to only files that exist
test_file = $(shell [ -f ${1} ] && echo ${1})
VSP := $(foreach file, ${VSP}, $(call test_file,${file}))
CSP := $(foreach file, ${CSP}, $(call test_file,${file}))
MSP := $(foreach file, ${MSP}, $(call test_file,${file}))
# and use the first valid entry in the Search Paths
ifeq (,${VERSION_FILE})
VERSION_FILE := $(firstword ${VSP})
endif
ifeq (,${CONFIG_FILE})
CONFIG_FILE := $(firstword ${CSP})
endif
ifeq (,${SYSTEM_MAP_FILE})
SYSTEM_MAP_FILE := $(firstword ${MSP})
endif
ifeq (,$(wildcard ${VERSION_FILE}))
$(error Linux kernel source not configured - missing version header file)
endif
ifeq (,$(wildcard ${CONFIG_FILE}))
$(error Linux kernel source not configured - missing autoconf.h)
endif
ifeq (,$(wildcard ${SYSTEM_MAP_FILE}))
$(warning Missing System.map file - depmod will not check for missing symbols during module installation)
endif
ifneq ($(words $(subst :, ,$(CURDIR))), 1)
$(error Sources directory '$(CURDIR)' cannot contain spaces nor colons. Rename directory or move sources to another path)
endif
########################
# Extract config value #
########################
get_config_value = $(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
grep -m 1 ${1} | awk '{ print $$3 }')
################
# dracut Macro #
################
cmd_initrd := $(shell \
if [[ ${KOBJ} != /lib/modules/${BUILD_KERNEL}/* ]]; then \
echo ""; \
elif which dracut > /dev/null 2>&1 ; then \
echo "dracut --force --kver ${BUILD_KERNEL}"; \
elif which update-initramfs > /dev/null 2>&1 ; then \
echo "update-initramfs -u -k ${BUILD_KERNEL}"; \
fi )
########################
# Check module signing #
########################
CONFIG_MODULE_SIG_ALL := $(call get_config_value,CONFIG_MODULE_SIG_ALL)
CONFIG_MODULE_SIG_FORCE := $(call get_config_value,CONFIG_MODULE_SIG_FORCE)
CONFIG_MODULE_SIG_KEY := $(call get_config_value,CONFIG_MODULE_SIG_KEY)
SIG_KEY_SP := ${KOBJ}/${CONFIG_MODULE_SIG_KEY} \
${KOBJ}/certs/signing_key.pem
SIG_KEY_FILE := $(firstword $(foreach file, ${SIG_KEY_SP}, $(call test_file,${file})))
# print a warning if the kernel configuration attempts to sign modules but
# the signing key can't be found.
ifneq (${SIG_KEY_FILE},)
warn_signed_modules := : ;
else
warn_signed_modules :=
ifeq (${CONFIG_MODULE_SIG_ALL},1)
warn_signed_modules += \
echo "*** The target kernel has CONFIG_MODULE_SIG_ALL enabled, but" ; \
echo "*** the signing key cannot be found. Module signing has been" ; \
echo "*** disabled for this build." ;
endif # CONFIG_MODULE_SIG_ALL=y
ifeq (${CONFIG_MODULE_SIG_FORCE},1)
warn_signed_modules += \
echo "warning: The target kernel has CONFIG_MODULE_SIG_FORCE enabled," ; \
echo "warning: but the signing key cannot be found. The module must" ; \
echo "warning: be signed manually using 'scripts/sign-file'." ;
endif # CONFIG_MODULE_SIG_FORCE
DISABLE_MODULE_SIGNING := Yes
endif
#######################
# Linux Version Setup #
#######################
# The following command line parameter is intended for development of KCOMPAT
# against upstream kernels such as net-next which have broken or non-updated
# version codes in their Makefile. They are intended for debugging and
# development purpose only so that we can easily test new KCOMPAT early. If you
# don't know what this means, you do not need to set this flag. There is no
# arcane magic here.
# Convert LINUX_VERSION into LINUX_VERSION_CODE
ifneq (${LINUX_VERSION},)
LINUX_VERSION_CODE=$(call get_kvercode,$(call get_kver,${LINUX_VERSION},1),$(call get_kver,${LINUX_VERSION},2),$(call get_kver,${LINUX_VERSION},3))
endif
# Honor LINUX_VERSION_CODE
ifneq (${LINUX_VERSION_CODE},)
$(warning Forcing target kernel to build with LINUX_VERSION_CODE of ${LINUX_VERSION_CODE}$(if ${LINUX_VERSION}, from LINUX_VERSION=${LINUX_VERSION}). Do this at your own risk.)
KVER_CODE := ${LINUX_VERSION_CODE}
EXTRA_CFLAGS += -DLINUX_VERSION_CODE=${LINUX_VERSION_CODE}
endif
# Determine SLE_KERNEL_REVISION for SuSE SLE >= 11 (needed by kcompat)
# This assumes SuSE will continue setting CONFIG_LOCALVERSION to the string
# appended to the stable kernel version on which their kernel is based with
# additional versioning information (up to 3 numbers), a possible abbreviated
# git SHA1 commit id and a kernel type, e.g. CONFIG_LOCALVERSION=-1.2.3-default
# or CONFIG_LOCALVERSION=-999.gdeadbee-default
# SLE >= 15SP3 added additional information about version and service pack
# to their kernel version e.g CONFIG_LOCALVERSION=-150300.59.43.1-default
#
# SLE_LOCALVERSION_CODE is also exported to support legacy kcompat.h
# definitions.
ifeq (1,$(call get_config_value,CONFIG_SUSE_KERNEL))
ifneq (10,$(call get_config_value,CONFIG_SLE_VERSION))
CONFIG_LOCALVERSION := $(call get_config_value,CONFIG_LOCALVERSION)
LOCALVERSION := $(shell echo ${CONFIG_LOCALVERSION} | \
cut -d'-' -f2 | sed 's/\.g[[:xdigit:]]\{7\}//')
LOCALVER_A := $(shell echo ${LOCALVERSION} | cut -d'.' -f1)
ifeq ($(shell test ${LOCALVER_A} -gt 65535; echo $$?),0)
LOCAL_VER_MAJOR := $(shell echo ${LOCALVER_A:0:3})
LOCAL_VER_MINOR := $(shell echo ${LOCALVER_A:3:3})
LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
LOCALVER_D := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f4)
SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_B} \* 65536 + \
0${LOCALVER_C} \* 256 + 0${LOCALVER_D})
EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
EXTRA_CFLAGS += -DSLE_KERNEL_REVISION=${LOCALVER_B}
else
LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_A} \* 65536 + \
0${LOCALVER_B} \* 256 + 0${LOCALVER_C})
EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
EXTRA_CFLAGS += -DSLE_KERNEL_REVISION=${LOCALVER_A}
endif
endif
endif
EXTRA_CFLAGS += ${CFLAGS_EXTRA}
# get the kernel version - we use this to find the correct install path
KVER := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VERSION_FILE} | grep UTS_RELEASE | \
awk '{ print $$3 }' | sed 's/\"//g')
# assume source symlink is the same as build, otherwise adjust KOBJ
ifneq (,$(wildcard /lib/modules/${KVER}/build))
ifneq (${KSRC},$(call readlink,/lib/modules/${KVER}/build))
KOBJ=/lib/modules/${KVER}/build
endif
endif
ifeq (${KVER_CODE},)
KVER_CODE := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VSP} 2> /dev/null |\
grep -m 1 LINUX_VERSION_CODE | awk '{ print $$3 }' | sed 's/\"//g')
endif
# minimum_kver_check
#
# helper function to provide uniform output for different drivers to abort the
# build based on kernel version check. Usage: "$(call minimum_kver_check,2,6,XX)".
define _minimum_kver_check
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,${1},${2},${3}) ]; echo "$$?"))
$$(warning *** Aborting the build.)
$$(error This driver is not supported on kernel versions older than ${1}.${2}.${3})
endif
endef
minimum_kver_check = $(eval $(call _minimum_kver_check,${1},${2},${3}))
#############################
# kcompat definitions setup #
#############################
# In most cases, kcompat flags can be checked within the driver source files
# using simple CPP checks. However, it may be necessary to check for a flag
# value within the Makefile for some specific edge cases. For example, if an
# entire feature ought to be excluded on some kernels due to missing
# functionality.
#
# To support this, kcompat_defs.h is preprocessed and converted into a word list
# that can be checked to determine whether a given kcompat feature flag will
# be defined for this kernel.
#
# KCOMPAT_DEFINITIONS holds the set of all macros which are defined. Note
# this does include a large number of standard/builtin definitions.
#
# Use is_kcompat_defined as a $(call) function to check whether a given flag
# is defined or undefined. For example:
#
# ifeq ($(call is_kcompat_defined,HAVE_FEATURE_FLAG),1)
#
# ifneq ($(call is_kcompat_defined,HAVE_FEATURE_FLAG),1)
#
# The is_kcompat_defined function returns 1 if the macro name is defined,
# and the empty string otherwise.
#
# There is no mechanism to extract the value of the kcompat definition.
# Supporting this would be non-trivial as Make does not have a map variable
# type.
#
# Note that only the new layout is supported. Legacy definitions in
# kcompat.h are not supported. If you need to check one of these, please
# refactor it into the new layout.
# call script that populates defines automatically
#
# since is_kcompat_defined() is a macro, it's "computed" before any target
# recipe, kcompat_generated_defs.h is needed prior to that, so needs to be
# generated also via $(shell) call, which makes error handling ugly
$(if $(shell \
$(if $(findstring 1,${V}),,QUIET_COMPAT=1) \
KSRC=${KSRC} OUT=${src}/kcompat_generated_defs.h CONFFILE=${CONFIG_FILE} \
bash ${src}/kcompat-generator.sh && echo ok), , $(error kcompat-generator.sh failed))
KCOMPAT_DEFINITIONS := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM \
-I${KOBJ}/include \
-I${KOBJ}/include/generated/uapi \
${src}/kcompat_defs.h | awk '{ print $$2 }')
is_kcompat_defined = $(if $(filter ${1},${KCOMPAT_DEFINITIONS}),1,)
################
# Manual Pages #
################
MANSECTION = 7
ifeq (,${MANDIR})
# find the best place to install the man page
MANPATH := $(shell (manpath 2>/dev/null || echo $MANPATH) | sed 's/:/ /g')
ifneq (,${MANPATH})
# test based on inclusion in MANPATH
test_dir = $(findstring ${dir}, ${MANPATH})
else
# no MANPATH, test based on directory existence
test_dir = $(shell [ -e ${dir} ] && echo ${dir})
endif
# our preferred install path
# should /usr/local/man be in here ?
MANDIR := /usr/share/man /usr/man
MANDIR := $(foreach dir, ${MANDIR}, ${test_dir})
MANDIR := $(firstword ${MANDIR})
endif
ifeq (,${MANDIR})
# fallback to /usr/man
MANDIR := /usr/man
endif
####################
# CCFLAGS variable #
####################
# set correct CCFLAGS variable for kernels older than 2.6.24
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,2,6,24) ]; echo $$?))
CCFLAGS_VAR := EXTRA_CFLAGS
else
CCFLAGS_VAR := ccflags-y
endif
#################
# KBUILD_OUTPUT #
#################
# Only set KBUILD_OUTPUT if the real paths of KOBJ and KSRC differ
ifneq ($(call readlink,${KSRC}),$(call readlink,${KOBJ}))
export KBUILD_OUTPUT ?= ${KOBJ}
endif
############################
# Module Install Directory #
############################
# Default to using updates/drivers/net/ethernet/jm/ path, since depmod since
# v3.1 defaults to checking updates folder first, and only checking kernels/
# and extra afterwards. We use updates instead of kernel/* due to desire to
# prevent over-writing built-in modules files.
export INSTALL_MOD_DIR ?= updates/drivers/net/ethernet/jm/${DRIVER}
######################
# Kernel Build Macro #
######################
# kernel build function
# ${1} is the kernel build target
# ${2} may contain any extra rules to pass directly to the sub-make process
#
# This function is expected to be executed by
# @+$(call kernelbuild,<target>,<extra parameters>)
# from within a Makefile recipe.
#
# The following variables are expected to be defined for its use:
# GCC_I_SYS -- if set it will enable use of gcc-i-sys.sh wrapper to use -isystem
# CCFLAGS_VAR -- the CCFLAGS variable to set extra CFLAGS
# EXTRA_CFLAGS -- a set of extra CFLAGS to pass into the ccflags-y variable
# KSRC -- the location of the kernel source tree to build against
# DRIVER_UPPERCASE -- the uppercase name of the kernel module, set from DRIVER
# W -- if set, enables the W= kernel warnings options
# C -- if set, enables the C= kernel sparse build options
#
#
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/jm_auxiliary.symvers
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/crete.symvers
KBUILD_EXTRA_SYMBOLS += /lib/modules/$(shell uname -r)/extern-symvers/vdpa.symvers
#export KBUILD_EXTRA_SYMBOLS
kernelbuild = $(call warn_signed_modules) \
${MAKE} $(if ${GCC_I_SYS},CC="${GCC_I_SYS}") \
${CCFLAGS_VAR}="${EXTRA_CFLAGS}" \
-C "${KSRC}" \
CONFIG_${DRIVER_UPPERCASE}=m \
$(if ${DISABLE_MODULE_SIGNING},CONFIG_MODULE_SIG=n) \
$(if ${DISABLE_MODULE_SIGNING},CONFIG_MODULE_SIG_ALL=) \
M="${CURDIR}" \
$(if ${W},W="${W}") \
$(if ${C},C="${C}") \
${2} ${1}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* JaguarMicro virt device driver for virtio dataplane offloading
*
* Copyright (C) 2020 JaguarMicro Corporation.
*
* Author: Angus Chen <angus.chen@jaguarmicro.com>
*
*/
#ifndef _CRETE_VDPA_DEV_H_
#define _CRETE_VDPA_DEV_H_
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/vdpa.h>
#include <uapi/linux/virtio_net.h>
#include <uapi/linux/virtio_blk.h>
#include <uapi/linux/virtio_config.h>
#include <uapi/linux/virtio_pci.h>
#include <linux/auxiliary_bus.h>
#include "../crete-core/crete_cmd.h"
#include "kcompat_generated_defs.h"
/* Max 8 data queue pairs(16 queues) and one control vq for now. */
#define CORSICA_MAX_QUEUES 65
#define CORSICA_MAX_QUEUES_NOCTRL 64
#define CORSICA_QUEUE_ALIGNMENT PAGE_SIZE
/*attention pls ,it's the depth of queue*/
#define CORSICA_QUEUE_SIZE_MAX 1024
#define CORSICA_QUEUE_SIZE_MIN 64
#define CORSICA_MSI_CONFIG_OFF 0
#define CORSICA_MSI_QUEUE_OFF 1
#define CORSICA_PCI_MAX_RESOURCE 6
#define VHOST_F_LOG_ALL 26
#define VHOST_ACCESS_WO 0x2
#define DEBUG
#define CORSICA_ERR(pdev, fmt, ...) dev_err(&pdev->dev, fmt, ##__VA_ARGS__)
#define CORSICA_DBG(pdev, fmt, ...) dev_dbg(&pdev->dev, fmt, ##__VA_ARGS__)
#define CORSICA_INFO(pdev, fmt, ...) dev_info(&pdev->dev, fmt, ##__VA_ARGS__)
#define CORSICA_DEV_CONFIG_OFFSIZE 0x40
#define CORSICA_LOG_BASE_L 0x2
#define CORSICA_LOG_BASE_H 0x6
#define CORSICA_32_BIT_MASK 0xffffffff
#define CORSICA_LOG_BASE 0x100000000000
#define CORSICA_LM_DISABLE 0x0
#define CORSICA_LM_ENABLE 0x1
#define CORSICA_LM_STOP_DEV 0x2
#define CORSICA_LM_ENABLE_VF 0x4
#define CORSICA_LM_ENABLE_PF 0x8
#define CORSICA_DEV_STOPED 0x4
#define VIRTIO_NET_CONFIG_OFFSET_MAC offsetof(struct virtio_net_config, mac)
#define VIRTIO_NET_CONFIG_OFFSET_MTU offsetof(struct virtio_net_config, mtu)
#define VIRTIO_NET_CONFIG_OFFSET_STATUS offsetof(struct virtio_net_config, status)
#define CONFIG_ENABLE_TLP 0
#define CRETE_LOG_BASE_IOVA 0x100000000000
/*************************support bclinux********************************/
#ifndef HAVE_VDPA_MGMTDEV_OPS
struct vdpa_dev_set_config {
struct {
u8 mac[ETH_ALEN];
u16 mtu;
u16 max_vq_pairs;
} net;
u64 mask;
};
struct vdpa_mgmtdev_ops;
struct vdpa_mgmt_dev {
struct device *device;
const struct vdpa_mgmtdev_ops *ops;
struct virtio_device_id *id_table;
u64 config_attr_mask;
struct list_head list;
u64 supported_features;
u32 max_supported_vqs;
};
struct vdpa_mgmtdev_ops {
int (*dev_add)(struct vdpa_mgmt_dev *mdev, const char *name,
const struct vdpa_dev_set_config *config);
void (*dev_del)(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev);
};
#endif
enum crete_net_status {
CRETE_NET_DEV_STARTUP,
CRETE_NET_DEV_FEATURE_OK,
CRETE_NET_DEV_DEV_OK,
CRETE_NET_DEV_STOPPED
};
#define CRETE_RX_SEQ 0
#define CRETE_TX_SEQ 1
struct crete_mig_log {
u32 log_base_l;
u32 log_base_h;
/* TODO: need use array to store multiple iova */
u32 iova_addr_l;
u32 iova_addr_h;
u32 iova_size_l;
u32 iova_size_h;
struct list_head list;
unsigned int limit;
unsigned int nmaps;
} __packed;
struct virtio_vdpa_config {
union {
struct virtio_net_config v_net_config;
struct virtio_blk_config v_blk_config;
u8 config_offset[CORSICA_DEV_CONFIG_OFFSIZE];
};
};
struct crete_vdpa_config {
struct virtio_vdpa_config vdpa_config;
u16 lm_ctrl;
u16 reserved;
u32 log_base_l;
u32 log_base_h;
struct crete_mig_log mig_log;
u8 log_mask;
u8 reserved1;
} __packed;
struct crete_vring_lm_cfg {
u16 last_avail_idx;
u16 can_used; /* indircat the `last_avail_idx already been getted */
};
struct crete_lm_cfg {
struct crete_vdpa_config vdpa_lm_cfg;
struct crete_vring_lm_cfg vring_lm_cfg[CORSICA_MAX_QUEUES];
};
#define crete_private_to_vd(adapter) \
(&((struct crete_adapter *)adapter)->vd)
struct vring_info {
u64 desc;
u64 avail;
u64 used;
u16 size;
u16 last_avail_idx;
bool ready;
void __iomem *notify_addr;
phys_addr_t notify_pa;
u32 irq;
u32 irqvec;
struct vdpa_callback cb;
char msix_name[256];
};
struct crete_iotlb_map {
struct list_head link;
u64 start;
u64 last;
u64 size;
u64 addr;
u32 perm;
u32 flags_padding;
u64 __subtree_last;
void *opaque;
};
struct crete_vdpa {
struct crete_vnet_hw_cap *hcap; //vdpa device hw capability
/*********vdpa* soft capability*******/
u8 status;
u32 generation;
u16 qp_nums;
u16 num_queues;
u16 queue_size;
u64 driver_features;
u32 dev_type;
/************vdap queue***************************/
struct vring_info vring[CORSICA_MAX_QUEUES];
char config_msix_name[256];
struct vdpa_callback config_cb;
unsigned int config_irq;
u32 config_size;
u16 lm_ctrl;
u16 announce_count;
struct crete_mig_log mig_log;
bool have_hw_ctrl;
bool have_soft_ctrl;
bool have_ctrl_irq;
bool host_polling;
__le16 ctl_qlen;
u8 __iomem *lm_cfg;
struct crete_vring_lm_cfg vring_lm_cfg[CORSICA_MAX_QUEUES];
struct crete_nb cnb;
spinlock_t iommu_lock;
struct iommu_domain *domain;
struct vhost_iotlb resv_iotlb;
struct mm_struct *mm;
};
struct crete_adapter {
struct vdpa_device vdpa;
struct virtio_net_config config;
struct crete_core_dev *cdev;
struct crete_vdpa vd;
struct crete_vdpa_mgmtdev *priv;
};
struct crete_vnet_hw_cap {
__le64 hw_features;
__le16 max_vqpnum;
__le16 io_qlen;
__le16 ctl_qlen;
bool have_ctl;
__le16 vdpa_max_vqs;
};
struct crete_vdpa_mgmtdev {
struct vdpa_mgmt_dev mdev;
struct crete_adapter *adapter;
struct crete_core_dev *cdev;
struct crete_vnet_hw_cap hcap;
};
int crete_vdpa_set_hwstatus(struct crete_core_dev *core_dev, u8 status,
struct device *dev);
int crete_vdpa_get_mgmt_info(struct crete_vdpa_mgmtdev *cvm);
int crete_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
const struct vdpa_dev_set_config *config);
void crete_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev);
int crete_vdpa_set_device_type(struct crete_core_dev *core_dev);
#endif /* _CRETE_VDPA_DEV_H_ */

View File

@ -0,0 +1,171 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023, Jaguar Micro. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/pci.h>
#include <linux/vdpa.h>
#include "crete_vdpa_dev.h"
#define CRETE_VDPA_DRV_DESCRIPTION "JaguarMicro/CRETE VDPA VF Device Driver"
#define CRETE_VDPA_AUX_DEV_NAME "crete_core.vnet"
#define CRETE_VDPA_DRV_NAME "crete_vnet"
static int crete_vdpa_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct crete_aux_dev *cadev =
container_of(adev, struct crete_aux_dev, adev);
struct crete_core_dev *core_dev = cadev->core_dev;
struct pci_dev *pdev = core_dev->pdev;
struct device *dev = &pdev->dev;
struct crete_vdpa_mgmtdev *cvm;
int ret;
#if defined(HAVE_VDPA_MGMTDEV_OPS)
#else
struct vdpa_dev_set_config vdsc;
#endif
ret = crete_vdpa_set_device_type(core_dev);
if (ret) {
dev_err(dev,
"Failed to alloc memory for the vDPA management device\n");
return -EINVAL;
}
ret = crete_vdpa_set_hwstatus(core_dev, CRETE_NET_DEV_STARTUP, dev);
if (ret) {
dev_err(dev, "set net dev status failed\n");
return -EINVAL;
}
cvm = kzalloc(sizeof(struct crete_vdpa_mgmtdev), GFP_KERNEL);
if (!cvm)
return -ENOMEM;
cvm->cdev = core_dev;
ret = crete_vdpa_get_mgmt_info(cvm);
if (ret) {
dev_err(dev, "Failed to set vDPA management\n");
goto err;
}
dev_set_drvdata(&adev->dev, cvm);
#if defined(HAVE_VDPA_MGMTDEV_OPS)
ret = vdpa_mgmtdev_register(&cvm->mdev);
if (ret) {
dev_err(dev,
"Failed to initialize the management interfaces\n");
goto err;
}
#else
memset(&vdsc, 0, sizeof(struct vdpa_dev_set_config));
ret = crete_vdpa_dev_add(&cvm->mdev, "NULL", &vdsc);
if (ret) {
dev_err(dev,
"Failed to add vdpa device ret:%d\n",ret);
goto err_add;
}
#endif
//crete_vdpa_debugfs_add_dev(cvm);
//crete_vdpa_debugfs_add_hcap(cvm);
return 0;
err_add:
dev_set_drvdata(&adev->dev, NULL);
err:
kfree(cvm);
return ret;
}
static void crete_vdpa_remove(struct auxiliary_device *adev)
{
struct crete_vdpa_mgmtdev *crete_mgmt_dev;
struct device *dev = &adev->dev;
struct crete_adapter *adapter;
struct vdpa_device *vdpa_dev;
crete_mgmt_dev = dev_get_drvdata(&adev->dev);
dev_info(dev, "crete vdpa remove\n");
#if defined(HAVE_VDPA_MGMTDEV_OPS)
vdpa_mgmtdev_unregister(&crete_mgmt_dev->mdev);
#else
adapter = crete_mgmt_dev->adapter;
vdpa_dev = &adapter->vdpa;
crete_vdpa_dev_del(&crete_mgmt_dev->mdev, vdpa_dev);
crete_mgmt_dev->adapter = NULL;
// crete_vdpa_debugfs_del_vdpadev(crete_mgmt_dev);
kfree(crete_mgmt_dev);
dev_set_drvdata(&adev->dev, NULL);
#endif
}
static const struct auxiliary_device_id crete_vdpa_id_table[] = {
{.name = CRETE_VDPA_AUX_DEV_NAME,},
{},
};
static struct auxiliary_driver crete_vdpa_driver = {
.name = CRETE_VDPA_DRV_NAME,
.probe = crete_vdpa_probe,
.remove = crete_vdpa_remove,
.id_table = crete_vdpa_id_table,
};
static void __exit crete_vdpa_cleanup(void)
{
auxiliary_driver_unregister(&crete_vdpa_driver);
// crete_vnet_debugfs_destroy();
}
module_exit(crete_vdpa_cleanup);
static int __init crete_vdpa_init(void)
{
int err;
// crete_vnet_debugfs_create();
err = auxiliary_driver_register(&crete_vdpa_driver);
if (err) {
pr_err("%s: aux driver register failed: %pe\n",
CRETE_VDPA_DRV_NAME, ERR_PTR(err));
//crete_vnet_debugfs_destroy();
}
return err;
}
module_init(crete_vdpa_init);
MODULE_DESCRIPTION(CRETE_VDPA_DRV_DESCRIPTION);
MODULE_AUTHOR("jaguarmicro.com");
MODULE_LICENSE("GPL");
MODULE_VERSION("3.1.1");

View File

@ -0,0 +1,173 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
set -Eeuo pipefail
# This file generates HAVE_ and NEED_ defines for current kernel
# (or KSRC if provided).
#
# It does so by 'gen' function calls (see body of 'gen-devlink' for examples).
# 'gen' could look for various kinds of declarations in provided kernel headers,
# eg look for an enum in one of files specified and check if given enumeration
# (single value) is present. See 'Documentation' or comment above the 'gen' fun
# in the kcompat-lib.sh.
# Why using bash/awk instead of an old/legacy approach?
#
# The aim is to replicate all the defines provided by human developers
# in the past. Additional bonus is the fact, that we no longer need to care
# about backports done by OS vendors (RHEL, SLES, ORACLE, UBUNTU, more to come).
# We will even work (compile) with only part of backports provided.
#
# To enable smooth transition, especially in time of late fixes, "old" method
# of providing flags should still work as usual.
# End of intro.
# Find info about coding style/rules at the end of file.
# Most of the implementation is in kcompat-lib.sh, here are actual 'gen' calls.
export LC_ALL=C
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
ORIG_CWD="$(pwd)"
trap 'rc=$?; echo >&2 "$(realpath "$ORIG_CWD/${BASH_SOURCE[0]}"):$LINENO: failed with rc: $rc"' ERR
# shellcheck source=kcompat-lib.sh
source "$SCRIPT_DIR"/kcompat-lib.sh
# DO NOT break gen calls below (via \), to make our compat code more grep-able,
# keep them also grouped, first by feature (like DEVLINK), then by .h filename
# finally, keep them sorted within a group (sort by flag name)
# handy line of DOC copy-pasted form kcompat-lib.sh:
# gen DEFINE if (KIND [METHOD of]) NAME [(matches|lacks) PATTERN|absent] in <list-of-files>
function gen-vdpa() {
vh='include/linux/vdpa.h'
vm='include/linux/virtio_pci_modern.h'
if [ -f $vm ];then
gen HAVE_VIRTIO_PCI_MODERN if struct virtio_pci_modern_device in $vm
fi
#gen HAVE_VDPA_OPS_RESET_INFO if method reset of vdpa_config_ops matches lacks status in "$vh"
gen HAVE_VDPA_RESET_LACK_INFO if method reset of vdpa_config_ops lacks state in "$vh"
gen HAVE_VDPA_OPS_RESET if method reset of vdpa_config_ops in "$vh"
gen HAVE_VDPA_ALLOC_LACK_GROUP if fun __vdpa_alloc_device lacks ngroups in "$vh"
gen HAVE_VDPA_ALLOC_LACK_NAME if fun __vdpa_alloc_device lacks name in "$vh"
gen HAVE_VDPA_VQ_STATE_LACK_PACKED if struct vdpa_vq_state lacks packed in "$vh"
gen HAVE_VDPA_MGMTDEV_OPS if struct vdpa_mgmtdev_ops in "$vh"
gen HAVE_VDPA_DEV_SET_CONFIG if struct vdpa_dev_set_config in "$vh"
gen HAVE_VDPA_OPS_DEVICE_FEAT if method get_device_features of vdpa_config_ops in "$vh"
gen HAVE_VDPA_OPS_GET_CONFIG_SIZE if method get_config_size of vdpa_config_ops in "$vh"
gen HAVE_VDPA_OPS_LOG_BASE if method set_log_base of vdpa_config_ops in "$vh"
gen HAVE_VDPA_OPS_NUM_MIN if method get_vq_num_min of vdpa_config_ops in "$vh"
}
function gen-aux() {
ah='include/linux/auxiliary_bus.h'
mh='include/linux/mod_devicetable.h'
if config_has CONFIG_AUXILIARY_BUS; then
gen HAVE_AUXILIARY_DRIVER_INT_REMOVE if method remove of auxiliary_driver matches 'int' in "$ah"
fi
# generate HAVE_AUXILIARY_DEVICE_ID only for cases when it's disabled in .config
if ! config_has CONFIG_AUXILIARY_BUS; then
gen HAVE_AUXILIARY_DEVICE_ID if struct auxiliary_device_id in "$mh"
fi
}
function gen-pci() {
pcih='include/linux/pci.h'
gen HAVE_PCI_MSIX_ALLOC_IRQ_AT if fun pci_msix_alloc_irq_at in "$pcih"
gen HAVE_PCI_MSIX_CAN_ALLOC_DYN if fun pci_msix_can_alloc_dyn in "$pcih"
gen HAVE_PCI_MSIX_FREE_IRQ if fun pci_msix_free_irq in "$pcih"
gen HAVE_PER_VF_MSIX_SYSFS if method sriov_set_msix_vec_count of pci_driver in "$pcih"
gen HAVE_STRUCT_PCI_DEV_PTM_ENABLED if struct pci_dev matches ptm_enabled in "$pcih"
gen NEED_PCIE_FLR if fun pcie_flr absent in "$pcih"
gen NEED_PCIE_FLR_RETVAL if fun pcie_flr lacks 'int pcie_flr' in "$pcih"
gen NEED_PCIE_PTM_ENABLED if fun pcie_ptm_enabled absent in "$pcih"
gen NEED_PCI_ENABLE_PTM if fun pci_enable_ptm absent in "$pcih"
}
# all the generations, extracted from main() to keep normal code and various
# prep separated
function gen-all() {
# code above is covered by unit_tests/test_gold.sh
if [ -n "${JUST_UNIT_TESTING-}" ]; then
return
fi
gen-aux
gen-vdpa
gen-pci
}
function main() {
# check if caller (like our makefile) wants to redirect output to file
if [ -n "${OUT-}" ]; then
# in case OUT exists, we don't want to overwrite it, instead
# write to a temporary copy.
if [ -s "${OUT}" ]; then
TMP_OUT="$(mktemp "${OUT}.XXX")"
trap "rm -f '${TMP_OUT}'" EXIT
REAL_OUT="${OUT}"
OUT="${TMP_OUT}"
fi
exec > "$OUT"
# all stdout goes to OUT since now
echo "/* Autogenerated for KSRC=${KSRC-} via $(basename "$0") */"
fi
if [ -d "${KSRC-}" ]; then
cd "${KSRC}"
fi
# check if KSRC was ok/if we are in proper place to look for headers
if [ -z "$(filter-out-bad-files include/linux/kernel.h)" ]; then
echo >&2 "seems that there are no kernel includes placed in KSRC=${KSRC}
pwd=$(pwd); ls -l:"
ls -l >&2
exit 8
fi
# we need some flags from .config or (autoconf.h), required
if [ ! -f "${CONFFILE-}" ]; then
echo >&2 ".config should be passed as env CONFFILE
(and it's not set or not a file)"
exit 9
fi
echo "#ifndef _KCOMPAT_GENERATED_DEFS_H_"
echo "#define _KCOMPAT_GENERATED_DEFS_H_"
gen-all
echo "#endif /* _KCOMPAT_GENERATED_DEFS_H_ */"
if [ -n "${OUT-}" ]; then
cd "$ORIG_CWD"
# Compare and see if anything changed. This avoids updating
# mtime of the file.
if [ -n "${REAL_OUT-}" ]; then
if cmp --silent "${REAL_OUT}" "${TMP_OUT}"; then
# exit now, skipping print of the output since
# there were no changes. the trap should
# cleanup TMP_OUT
exit 0
fi
mv -f "${TMP_OUT}" "${REAL_OUT}"
OUT="${REAL_OUT}"
fi
# dump output, will be visible in CI
if [ -n "${JUST_UNIT_TESTING-}${QUIET_COMPAT-}" ]; then
return
fi
cat -n "$OUT" >&2
fi
}
main

View File

@ -0,0 +1,310 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# to be sourced
# General shell helpers
# exit with non-zero exit code; if there is only one param:
# exit with msg $1 and exit code from last command (or 99 if = 0)
# otherwise, exit with $1 and use remaining arguments as msg
function die() {
rc=$?
if [ $# -gt 1 ]; then
rc="$1"
shift
fi
[ "$rc" -ne 0 ] || rc=99
echo >&2 "$@"
exit $rc
}
# filter out paths that are not files
# input $@, output via echo;
# note: pass `-` for stdin
# note: outputs nothing if all input files are "bad" (eg. not existing), but it
# is left for caller to decide if this is an erorr condition;
# note: whitespaces are considered "bad" as part of filename, it's an error.
function filter-out-bad-files() {
if [[ $# = 1 && "$1" = '-' ]]; then
echo -
return 0
fi
if [ $# = 0 ]; then
die 10 "no files passed, use '-' when reading from pipe (|)"
fi
local any=0 diagmsgs=/dev/stderr re=$'[\t \n]'
[ -n "${QUIET_COMPAT-}" ] && diagmsgs=/dev/null
for x in "$@"; do
if [ -e "$x" ]; then
if [[ "$x" =~ $re ]]; then
die 11 "err: filename contains whitespaces: $x."
fi
echo "$x"
any=1
else
echo >&"$diagmsgs" filtering "$x" out
fi
done
if [ $any = 0 ]; then
echo >&"$diagmsgs" 'all files (for given query) filtered out'
fi
}
# Basics of regexp explained, as a reference for mostly-C programmers:
# (bash) "regexp-$VAR-regexp" - bash' VARs are placed into "QUOTED" strings
# /\);?$/ - match end of function declaration, $ is end of string
# ^[ \t]* - (heuristic), anything but comment, eg to exclude function docs
# /STH/, /END/ - (awk), print all lines sice STH matched, up to END, inclusive
# "Whitespace only"
WB='[ \t\n]'
# Helpers below print the thing that is looked for, for further grep'ping/etc.
# That simplifies process of excluding comments or spares us state machine impl.
#
# We take advantage of current/common linux codebase formatting here.
#
# Functions in this section require input file/s passed as args
# (usually one, but more could be supplied in case of renames in kernel),
# '-' could be used as an (only) file argument to read from stdin/pipe.
# wrapper over find-something-decl() functions below, to avoid repetition
# pass $what as $1, $end as $2, and $files to look in as rest of args
function find-decl() {
test $# -ge 3 # ensure that there are at least 3 params
local what end files
what="$1"
end="$2"
shift 2
files="$(filter-out-bad-files "$@")" || die
if [ -z "$files" ]; then
return 0
fi
# shellcheck disable=SC2086
awk "
/^$WB*\*/ {next}
$what, $end
" $files
}
# yield $1 function declaration (signature), don't pass return type in $1
# looks only in files specified ($2, $3...)
function find-fun-decl() {
test $# -ge 2
local what end
what="/$WB*([(]\*)?$1$WB*($|[()])/"
end='/\);?$/'
shift
find-decl "$what" "$end" "$@"
}
# yield $1 enum declaration (type/body)
function find-enum-decl() {
test $# -ge 2
local what end
what="/^$WB*enum$WB+$1"' \{$/'
end='/\};$/'
shift
find-decl "$what" "$end" "$@"
}
# yield $1 struct declaration (type/body)
function find-struct-decl() {
test $# -ge 2
local what end
what="/^$WB*struct$WB+$1"' \{$/'
end='/^\};$/' # that's (^) different from enum-decl
shift
find-decl "$what" "$end" "$@"
}
# yield first line of $1 macro definition
function find-macro-decl() {
test $# -ge 2
local what end
# only unindented defines, only whole-word match
what="/^#define$WB+$1"'([ \t\(]|$)/'
end=1 # only first line; use find-macro-implementation-decl for full body
shift
find-decl "$what" "$end" "$@"
}
# yield full macro implementation
function find-macro-implementation-decl() {
test $# -ge 2
local what end
# only unindented defines, only whole-word match
what="/^#define$WB+$1"'([ \t\(]|$)/'
# full implementation, until a line not ending in a backslash.
# Does not handle macros with comments embedded within the definition.
end='/[^\\]$/'
shift
find-decl "$what" "$end" "$@"
}
# yield first line of $1 typedef definition (simple typedefs only)
# this probably won't handle typedef struct { \n int foo;\n};
function find-typedef-decl() {
test $# -ge 2
local what end
what="/^typedef .* $1"';$/'
end=1
shift
find-decl "$what" "$end" "$@"
}
# gen() - DSL-like function to wrap around all the other
#
# syntax:
# gen DEFINE if (KIND [METHOD of]) NAME [(matches|lacks) PATTERN|absent] in <list-of-files>
# where:
# DEFINE is HAVE_ or NEED_ #define to print;
# `if` is there to just read it easier and made syntax easier to check;
#
# NAME is the name for what we are looking for;
#
# KIND specifies what kind of declaration/definition we are looking for,
# could be: fun, enum, struct, method, macro, typedef,
# 'implementation of macro'
# for KIND=method, we are looking for function ptr named METHOD in struct
# named NAME (two optional args are then necessary (METHOD & of));
#
# for KIND='implementation of macro' we are looking for the full
# implementation of the macro, not just its first line. This is usually
# combined with "matches" or "lacks".
#
# next [optional] args could be used:
# matches PATTERN - use to grep for the PATTERN within definition
# (eg, for ext_ack param)
# lacks - use to add #define only if there is no match of the PATTERN,
# *but* the NAME is *found*
# absent - the NAME that we grep for must be not found
# (ie: function not exisiting)
#
# without this optional params, behavior is the same as with
# `matches .` - use to grep just for existence of NAME;
#
# `in` is there to ease syntax, similar to `if` before.
#
# <list-of-files> is just space-separate list of files to look in,
# single (-) for stdin.
#
# PATTERN is an awk pattern, will be wrapped by two slashes (/)
function gen() {
test $# -ge 6 || die 20 "too few arguments, $# given, at least 6 needed"
local define if_kw kind name in_kw # mandatory
local of_kw method_name operator pattern # optional
local src_line="${BASH_SOURCE[0]}:${BASH_LINENO[0]}"
define="$1"
if_kw="$2"
kind="$3"
local orig_args_cnt=$#
shift 3
[ "$if_kw" != if ] && die 21 "$src_line: 'if' keyword expected, '$if_kw' given"
case "$kind" in
fun|enum|struct|macro|typedef)
name="$1"
shift
;;
method)
test $# -ge 5 || die 22 "$src_line: too few arguments, $orig_args_cnt given, at least 8 needed"
method_name="$1"
of_kw="$2"
name="$3"
shift 3
[ "$of_kw" != of ] && die 23 "$src_line: 'of' keyword expected, '$of_kw' given"
;;
implementation)
test $# -ge 5 || die 28 "$src_line: too few arguments, $orig_args_cnt given, at least 8 needed"
of_kw="$1"
kind="$2"
name="$3"
shift 3
[ "$of_kw" != of ] && die 29 "$src_line: 'of' keyword expected, '$of_kw' given"
[ "$kind" != macro ] && die 30 "$src_line: implementation only supports 'macro', '$kind' given"
kind=macro-implementation
;;
*) die 24 "$src_line: unknown KIND ($kind) to look for" ;;
esac
operator="$1"
case "$operator" in
absent)
pattern='.'
in_kw="$2"
shift 2
;;
matches|lacks)
pattern="$2"
in_kw="$3"
shift 3
;;
in)
operator=matches
pattern='.'
in_kw=in
shift
;;
*) die 25 "$src_line: unknown OPERATOR ($operator) to look for" ;;
esac
[ "$in_kw" != in ] && die 26 "$src_line: 'in' keyword expected, '$in_kw' given"
test $# -ge 1 || die 27 "$src_line: too few arguments, at least one filename expected"
local first_decl=
if [ "$kind" = method ]; then
first_decl="$(find-struct-decl "$name" "$@")" || exit 40
# prepare params for next lookup phase
set -- - # overwrite $@ to be single dash (-)
name="$method_name"
kind=fun
elif [[ $# = 1 && "$1" = '-' ]]; then
# avoid losing stdin provided to gen() due to redirection (<<<)
first_decl="$(cat -)"
fi
# lookup the NAME
local body
body="$(find-$kind-decl "$name" "$@" <<< "$first_decl")" || exit 41
awk -v define="$define" -v pattern="$pattern" -v "$operator"=1 '
BEGIN {
# prepend "identifier boundary" to pattern, also append
# it, but only for patterns not ending with such already
#
# eg: "foo" -> "\bfoo\b"
# "struct foo *" -> "\bstruct foo *"
# Note that mawk does not support "\b", so we have our
# own approximation, NI
NI = "[^A-Za-z0-9_]" # "Not an Indentifier"
if (!match(pattern, NI "$"))
pattern = pattern "(" NI "|$)"
pattern = "(^|" NI ")" pattern
}
/./ { not_empty = 1 }
$0 ~ pattern { found = 1 }
END {
if (lacks && !found && not_empty || matches && found || absent && !found)
print "#define", define
}
' <<< "$body"
}
# tell if given flag is enabled in .config
# return 0 if given flag is enabled, 1 otherwise
# inputs:
# $1 - flag to check (whole word, without _MODULE suffix)
# env flag $CONFFILE
#
# there are two "config" formats supported, to ease up integrators lifes
# .config (without leading #~ prefix):
#~ # CONFIG_ACPI_EC_DEBUGFS is not set
#~ CONFIG_ACPI_AC=y
#~ CONFIG_ACPI_VIDEO=m
# and autoconf.h, which would be:
#~ #define CONFIG_ACPI_AC 1
#~ #define CONFIG_ACPI_VIDEO_MODULE 1
function config_has() {
grep -qE "^(#define )?$1((_MODULE)? 1|=m|=y)$" "$CONFFILE"
}

View File

@ -0,0 +1,34 @@
#ifndef _KCOMPAT_DEFS_H_
#define _KCOMPAT_DEFS_H_
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#else
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
#endif /* LINUX_VERSION_CODE */
#ifndef UTS_RELEASE
#include <generated/utsrelease.h>
#endif
/*
* Include the definitions file for HAVE/NEED flags for the standard upstream
* kernels.
*
* Then, based on the distribution we detect, load the distribution specific
* definitions file that customizes the definitions for the target
* distribution.
*/
#include "kcompat_std_defs.h"
#ifdef RHEL_RELEASE_CODE
#include "kcompat_rhel_defs.h"
#endif
#include "kcompat_generated_defs.h"
#endif /* _KCOMPAT_DEFS_H_ */

View File

@ -0,0 +1,14 @@
/* Autogenerated for KSRC=/lib/modules/5.10.0-136.12.oe2203sp1/source via kcompat-generator.sh */
#ifndef _KCOMPAT_GENERATED_DEFS_H_
#define _KCOMPAT_GENERATED_DEFS_H_
#define HAVE_AUXILIARY_DEVICE_ID
#define HAVE_VIRTIO_PCI_MODERN
#define HAVE_VDPA_OPS_RESET
#define HAVE_VDPA_MGMTDEV_OPS
#define HAVE_VDPA_DEV_SET_CONFIG
#define HAVE_VDPA_OPS_DEVICE_FEAT
#define HAVE_VDPA_OPS_GET_CONFIG_SIZE
#define HAVE_VDPA_OPS_LOG_BASE
#define HAVE_STRUCT_PCI_DEV_PTM_ENABLED
#define NEED_PCIE_PTM_ENABLED
#endif /* _KCOMPAT_GENERATED_DEFS_H_ */

View File

@ -0,0 +1,164 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _KCOMPAT_RHEL_DEFS_H_
#define _KCOMPAT_RHEL_DEFS_H_
/* This is the RedHat Enterprise Linux distribution specific definitions file.
* It defines what features need backports for a given version of the RHEL
* kernel.
*
* It checks the RHEL_RELEASE_CODE and RHEL_RELEASE_VERSION macros to decide
* what support the target kernel has.
*
* It assumes that kcompat_std_defs.h has already been processed, and will
* #define or #undef any flags that have changed based on backports done by
* RHEL.
*/
#if !RHEL_RELEASE_CODE
#error "RHEL_RELEASE_CODE is 0 or undefined"
#endif
#ifndef RHEL_RELEASE_VERSION
#error "RHEL_RELEASE_VERSION is undefined"
#endif
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,3))
#define NEED_NETDEV_TXQ_BQL_PREFETCH
#else /* >= 7.3 */
#endif /* 7.3 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,4))
#define NEED_BUILD_BUG_ON
#else /* >= 7.4 */
#define HAVE_RHEL7_EXTENDED_OFFLOAD_STATS
#define HAVE_INCLUDE_BITFIELD
#endif /* 7.4 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5))
#else /* >= 7.5 */
#define HAVE_TCF_EXTS_TO_LIST
#define HAVE_FLOW_DISSECTOR_KEY_IP
#endif /* 7.5 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,6))
#undef HAVE_XDP_BUFF_RXQ
#undef HAVE_XDP_RXQ_INFO_REG_3_PARAMS
#else /* >= 7.6 */
#undef NEED_JIFFIES_64_TIME_IS_MACROS
#undef NEED_TC_CLS_CAN_OFFLOAD_AND_CHAIN0
#undef NEED_TC_SETUP_QDISC_MQPRIO
#endif /* 7.6 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,7))
#else /* >= 7.7 */
#define HAVE_DEVLINK_PORT_ATTRS_SET_PORT_FLAVOUR
#define HAVE_ETHTOOL_NEW_100G_BITS
#undef NEED_NETDEV_TX_SENT_QUEUE
#undef NEED_IN_TASK
#define HAVE_FLOW_DISSECTOR_KEY_ENC_IP
#endif /* 7.7 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0))
#else /* >= 8.0 */
#undef HAVE_TCF_EXTS_TO_LIST
#undef HAVE_ETHTOOL_NEW_100G_BITS
#define HAVE_NDO_OFFLOAD_STATS
#undef HAVE_RHEL7_EXTENDED_OFFLOAD_STATS
#define HAVE_TCF_EXTS_FOR_EACH_ACTION
/* 7.7 undefs it due to a backport in 7.7+, but 8.0 needs it still */
#define NEED_NETDEV_TX_SENT_QUEUE
#endif /* 8.0 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,1))
#define NEED_IDA_ALLOC_MIN_MAX_RANGE_FREE
#define NEED_FLOW_MATCH
#else /* >= 8.1 */
#define HAVE_ETHTOOL_NEW_100G_BITS
#undef NEED_IDA_ALLOC_MIN_MAX_RANGE_FREE
#undef NEED_FLOW_MATCH
#undef NEED_NETDEV_TX_SENT_QUEUE
#undef NEED_INDIRECT_CALL_WRAPPER_MACROS
#define HAVE_INDIRECT_CALL_WRAPPER_HEADER
#define HAVE_GRETAP_TYPE
#define HAVE_GENEVE_TYPE
#define HAVE_VXLAN_TYPE
#define HAVE_LINKMODE
#endif /* 8.1 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,2))
#else /* >= 8.2 */
#undef NEED_DEVLINK_FLASH_UPDATE_STATUS_NOTIFY
#undef NEED_SKB_FRAG_OFF
#undef NEED_SKB_FRAG_OFF_ADD
#undef NEED_FLOW_INDR_BLOCK_CB_REGISTER
#define HAVE_FLOW_INDR_BLOCK_LOCK
#define HAVE_DEVLINK_PORT_ATTRS_SET_SWITCH_ID
#define HAVE_NETDEV_SB_DEV
#endif /* 8.2 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,3))
#else /* >= 8.3 */
#undef NEED_CPU_LATENCY_QOS_RENAME
#undef NEED_DEVLINK_REGION_CREATE_OPS
#define HAVE_RT_IRQ_SCHED_FIX
#endif /* 8.3 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,4))
#else /* >= 8.4 */
#undef NEED_DEVLINK_PORT_ATTRS_SET_STRUCT
#undef NEED_DEVLINK_FLASH_UPDATE_TIMEOUT_NOTIFY
#undef HAVE_XDP_QUERY_PROG
#define HAVE_AF_XDP_ZC_SUPPORT
#define HAVE_MEM_TYPE_XSK_BUFF_POOL
#define HAVE_NDO_XSK_WAKEUP
#define XSK_UMEM_RETURNS_XDP_DESC
#undef NEED_XSK_UMEM_GET_RX_FRAME_SIZE
#define HAVE_ETHTOOL_COALESCE_PARAMS_SUPPORT
#define HAVE_PTP_FIND_PIN_UNLOCKED
#endif /* 8.4 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,5))
#else /* >= 8.5 */
#undef HAVE_NAPI_BUSY_LOOP
#undef HAVE_XDP_RXQ_INFO_REG_3_PARAMS
#undef NEED_XSK_BUFF_DMA_SYNC_FOR_CPU
#define NO_XDP_QUERY_XSK_UMEM
#undef NEED_XSK_BUFF_POOL_RENAME
#define HAVE_NETDEV_BPF_XSK_POOL
#define HAVE_AF_XDP_NETDEV_UMEM
#define HAVE_DEVLINK_OPS_CREATE_DEL
#endif /* 8.5 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,7))
#else /* >= 8.7 */
#undef NEED_DEVLINK_ALLOC_SETS_DEV
#define HAVE_DEVLINK_SET_STATE_3_PARAM
#endif /* 8.7 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(9,0))
#else /* >= 9.0 */
#define HAVE_XDP_BUFF_RXQ
#endif /* 9.0 */
/*****************************************************************************/
#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(9,1))
#else /* >= 9.1 */
#undef HAVE_PASID_SUPPORT
#endif /* 9.1 */
/*****************************************************************************/
#endif /* _KCOMPAT_RHEL_DEFS_H_ */

View File

@ -0,0 +1,268 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _KCOMPAT_STD_DEFS_H_
#define _KCOMPAT_STD_DEFS_H_
/* This file contains the definitions for what kernel features need backports
* for a given kernel. It targets only the standard stable kernel releases.
* It must check only LINUX_VERSION_CODE and assume the kernel is a standard
* release, and not a custom distribution.
*
* It must define HAVE_<FLAG> and NEED_<FLAG> for features. It must not
* implement any backports, instead leaving the implementation to the
* kcompat_impl.h header.
*
* If a feature can be easily implemented as a replacement macro or fully
* backported, use a NEED_<FLAG> to indicate that the feature needs
* a backport. (If NEED_<FLAG> is undefined, then no backport for that feature
* is needed).
*
* If a feature cannot be easily implemented in kcompat directly, but
* requires drivers to make specific changes such as stripping out an entire
* feature or modifying a function pointer prototype, use a HAVE_<FLAG>.
*/
#ifndef LINUX_VERSION_CODE
#error "LINUX_VERSION_CODE is undefined"
#endif
#ifndef KERNEL_VERSION
#error "KERNEL_VERSION is undefined"
#endif
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0))
#else /* >= 4,8,0 */
#define HAVE_TCF_EXTS_TO_LIST
#define HAVE_PCI_ALLOC_IRQ
#endif /* 4,8,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0))
#define NEED_JIFFIES_64_TIME_IS_MACROS
#else /* >= 4,9,0 */
#define HAVE_KTHREAD_DELAYED_API
#define HAVE_NDO_OFFLOAD_STATS
#define HAVE_INCLUDE_BITFIELD
#endif /* 4,9,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,62))
#define NEED_IN_TASK
#else /* >= 4,9,62 */
#endif /* 4,9,62 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
#else /* >= 4,12,0 */
#define HAVE_NAPI_BUSY_LOOP
#endif /* 4,12,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0))
#else /* >= 4,13,0 */
#define HAVE_FLOW_DISSECTOR_KEY_IP
#endif /* 4,13,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#define NEED_TC_SETUP_QDISC_MQPRIO
#define NEED_NETDEV_XDP_STRUCT
#else /* >= 4,15,0 */
#define HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
#define HAVE_NDO_BPF
#endif /* 4,15,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0))
#define NEED_TC_CLS_CAN_OFFLOAD_AND_CHAIN0
#else /* >= 4,16,0 */
#define HAVE_XDP_BUFF_RXQ
#define HAVE_XDP_RXQ_INFO_REG_3_PARAMS
#endif /* 4,16,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
#define NEED_CONVERT_ART_NS_TO_TSC
#else /* >= 4,17,0 */
#endif /* 4,17,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
#define NEED_MACVLAN_ACCEL_PRIV
#define NEED_MACVLAN_RELEASE_L2FW_OFFLOAD
#define NEED_MACVLAN_SUPPORTS_DEST_FILTER
#else /* >= 4,18,0 */
#define HAVE_DEVLINK_PORT_ATTRS_SET_PORT_FLAVOUR
#endif /* 4,18,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0))
#define NEED_IDA_ALLOC_MIN_MAX_RANGE_FREE
#else /* >= 4,19,0 */
#undef HAVE_TCF_EXTS_TO_LIST
#define HAVE_TCF_EXTS_FOR_EACH_ACTION
#define HAVE_TC_ETF_QOPT_OFFLOAD
#define HAVE_FLOW_DISSECTOR_KEY_ENC_IP
#endif /* 4,19,0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0))
#define NEED_NETDEV_TX_SENT_QUEUE
#else /* >= 4.20.0 */
#define HAVE_VXLAN_TYPE
#define HAVE_LINKMODE
#endif /* 4.20.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0))
#define NEED_INDIRECT_CALL_WRAPPER_MACROS
#else /* >= 5.0.0 */
#define HAVE_GRETAP_TYPE
#define HAVE_GENEVE_TYPE
#define HAVE_INDIRECT_CALL_WRAPPER_HEADER
#endif /* 5.0.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0))
#define NEED_FLOW_MATCH
#else /* >= 5.1.0 */
#define HAVE_ETHTOOL_200G_BITS
#define HAVE_ETHTOOL_NEW_100G_BITS
#endif /* 5.1.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0))
#else /* >= 5.2.0 */
#define HAVE_DEVLINK_PORT_ATTRS_SET_SWITCH_ID
#endif /* 5.2.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0))
#define NEED_DEVLINK_FLASH_UPDATE_STATUS_NOTIFY
#else /* >= 5.3.0 */
#endif /* 5.3.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0))
#define NEED_SKB_FRAG_OFF_ADD
#define NEED_SKB_FRAG_OFF
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,14,241) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#undef NEED_SKB_FRAG_OFF
#endif /* > 4.14.241 && < 4.15.0 */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,19,200) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0))
#undef NEED_SKB_FRAG_OFF
#endif /* > 4.19.200 && < 4.20.0 */
#define NEED_FLOW_INDR_BLOCK_CB_REGISTER
#else /* >= 5.4.0 */
#define HAVE_FLOW_INDR_BLOCK_LOCK
#define HAVE_XSK_UNALIGNED_CHUNK_PLACEMENT
#endif /* 5.4.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0))
#define NEED_DEVLINK_REGION_CREATE_OPS
#define NEED_CPU_LATENCY_QOS_RENAME
#else /* >= 5.7.0 */
#define HAVE_PTP_FIND_PIN_UNLOCKED
#endif /* 5.7.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0))
#define NEED_XSK_UMEM_GET_RX_FRAME_SIZE
#else /* >= 5.8.0 */
#undef HAVE_XSK_UNALIGNED_CHUNK_PLACEMENT
#define HAVE_RT_IRQ_SCHED_FIX
#endif /* 5.8.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0))
#define NEED_DEVLINK_PORT_ATTRS_SET_STRUCT
#define HAVE_XDP_QUERY_PROG
#define NEED_INDIRECT_CALL_3_AND_4
#else /* >= 5.9.0 */
#define HAVE_TASKLET_SETUP
#endif /* 5.9.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0))
#define NEED_DEVLINK_FLASH_UPDATE_TIMEOUT_NOTIFY
#define NEED_XSK_BUFF_DMA_SYNC_FOR_CPU
#define NEED_XSK_BUFF_POOL_RENAME
#else /* >= 5.10.0 */
#define HAVE_UDP_TUNNEL_NIC_SHARED
#define HAVE_NETDEV_BPF_XSK_POOL
#endif /* 5.10.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0))
#else /* >= 5.11.0 */
#define HAVE_XSK_BATCHED_DESCRIPTOR_INTERFACES
#define HAVE_PASID_SUPPORT
#undef HAVE_XDP_RXQ_INFO_REG_3_PARAMS
#define HAVE_XSK_TX_PEEK_RELEASE_DESC_BATCH_3_PARAMS
#endif /* 5.11.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0))
#define NEED_EXPORT_INDIRECT_CALLABLE
#else /* >= 5.12.0 */
#define HAVE_DEVLINK_OPS_CREATE_DEL
#endif /* 5.12.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,13,0))
/* HAVE_KOBJ_IN_MDEV_PARENT_OPS_CREATE
*
* create api changed as part of the commit c2ef2f50ad0c( vfio/mdev: Remove
* kobj from mdev_parent_ops->create())
*
* if flag is defined use the old API else new API
*/
#define HAVE_KOBJ_IN_MDEV_PARENT_OPS_CREATE
#define HAVE_DEV_IN_MDEV_API
#else /* >= 5.13.0 */
#define HAVE_XPS_MAP_TYPE
#endif /* 5.13.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0))
#else /* >= 5.14.0 */
#define HAVE_TTY_WRITE_ROOM_UINT
#endif /* 5.14.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0))
#define NEED_DEVLINK_ALLOC_SETS_DEV
#else /* >= 5.15.0 */
#define HAVE_DEVICE_IN_MDEV_PARENT_OPS
#define NEED_PCI_IOV_VF_ID
#define HAVE_DEVLINK_SET_STATE_3_PARAM
#endif /* 5.15.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,16,0))
#else /* >= 5.16.0 */
#undef HAVE_PASID_SUPPORT
#define HAVE_XSK_BATCHED_RX_ALLOC
#endif /* 5.16.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0))
#else /* >=5.18.0*/
#undef NEED_PCI_IOV_VF_ID
#define HAVE_GTP_SUPPORT
#undef HAVE_XSK_TX_PEEK_RELEASE_DESC_BATCH_3_PARAMS
#endif /* 5.18.0 */
/*****************************************************************************/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0))
#else /* >=6.1.0 */
#define HAVE_FLOW_DISSECTOR_KEY_L2TPV3
#define HAVE_TTY_TERMIOS_CONST_STRUCT
#endif /* 6.1.0 */
#endif /* _KCOMPAT_STD_DEFS_H_ */

View File

@ -0,0 +1,235 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2021 - 2023 Intel Corporation
#
# Helper script to detect if auxiliary bus support. This script
#
# returns 0 when:
# - CONFIG_AUXILIARY_BUS=y
# - auxiliary_bus.h was found
#
# Returning 0 means the driver build/install doesn't need OOT
# auxiliary bus
#
# returns 1 when:
# - CONFIG_AUXILIARY_BUS=n (or any value that's not "=y")
# - kernel configuration was incorrect
# - kernel configuration file was not found
#
# Returning 1 means something bad/unexpected happened and the
# driver build/install should treat this as a failure
#
# returns 2 when:
# - When OOT auxiliary is needed regardless if a previous OOT
# auxiliary was already. This is done because the driver
# always needs to build against auxiliary.o to avoid
# warnings/errors since auxiliary.o is built-in to the
# driver's makefile
#
# Returning 2 means the driver build/install needs OOT auxiliary
# bus
#
# returns 3 when:
# - A file and/or directory does not exist
#
# Returning 3 means something bad/unexpected happened and the
# driver build/install should treat this as a failure
#
# Note: when ksrc and build-kernel are both specified on the
# command line and build-kernel is not in the same location
# as ksrc, then ksrc takes precedence. For example:
# ./check_aux_bus --ksrc=/lib/modules/5.8.0/source --build-kernel=5.10.0
#
# In this case the kernel config file won't be searched for and
# the script will only check to see if the in-tree/OOT auxiliary_bus.h
# file exists at ksrc.
msg()
{
if [ $verbose == 1 ]; then
echo -e $1
fi
}
exit_builtin_auxiliary_enabled() { exit 0; }
exit_kconfig_invalid() { exit 1; }
exit_need_oot_auxiliary() { exit 2; }
exit_not_found_failure() { exit 3; }
find_aux_bus_inc()
{
aux_bus_inc=$(find -L ${ksrc} -name "auxiliary_bus.h")
msg "auxiliary_bus.h location: ${aux_bus_inc}"
}
LINUX_INCLUDE_DIR="include/linux"
set_build_kernel()
{
build_kernel=$(uname -r)
}
find_kernel_source()
{
# All the default places to look for kernel source
test_dirs=(/lib/modules/${build_kernel}/source \
/lib/modules/${build_kernel}/build \
/usr/src/linux-${build_kernel} \
/usr/src/linux-$(echo ${build_kernel} | sed 's/-.*//') \
/usr/src/kernel-headers-${build_kernel} \
/usr/src/kernel-source-${build_kernel} \
/usr/src/linux-$(echo ${build_kernel} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux \
/usr/src/kernels/${build_kernel} \
/usr/src/kernels)
# Save the first valid kernel source path
for dir in "${test_dirs[@]}"; do
if [ -d ${dir}/${LINUX_INCLUDE_DIR} ]; then
ksrc=${dir}
break
fi
done
if [ -z ${ksrc} ]; then
echo "*** Kernel header files not in any of the expected locations."
echo "*** Install the appropriate kernel development package, e.g."
echo "kernel-devel, for building kernel modules and try again"
exit_not_found_failure
fi
}
find_config_file()
{
# only search for kernel .config file if build_kernel is pointing
# in the same tree as ksrc (see not about ksrc and build_kernel
# both set in the scripts header comment)
if [[ "$ksrc" != *"/lib/modules/${build_kernel}"* ]]; then
msg "ksrc=$ksrc not the same as location generated from build_kernel=\"/lib/modules/${build_kernel}\", not searching for kernel .config file"
else
kbuild_dir="/lib/modules/${build_kernel}/build"
file_locations=(${kbuild_dir}/include/generated/autoconf.h \
${kbuild_dir}/include/linux/autoconf.h \
/boot/bmlinux.autoconf.h)
for file in "${file_locations[@]}"; do
if [ -f ${file} ]; then
kconfig=${file}
break
fi
done
if [ -z ${kconfig} ]; then
msg "Kernel config file not found at any of the expected locations."
fi
fi
}
get_config_auxiliary_bus()
{
# CONFIG_AUXILIARY_BUS=0 corresponds to CONFIG_AUXILIARY_BUS=n
# CONFIG_AUXILIARY_BUS=1 corresponds to CONFIG_AUXILIARY_BUS=y
# CONFIG_AUXILIARY_BUS= corresponds to CONFIG_AUXILIARY_BUS not available in the kernel
CONFIG_AUXILIARY_BUS=$(grep CONFIG_AUXILIARY_BUS ${kconfig} | awk -F" " '{print $3}')
msg "CONFIG_AUXILIARY_BUS=${CONFIG_AUXILIARY_BUS}"
}
ksrc=""
build_kernel=""
verbose=0
usage()
{
script=$(basename $0)
echo -e "usage:"
echo -e "\t$script [options]"
echo -e "\n\toptions:"
echo -e "\t -v, --verbose"
echo -e "\t -h, --help"
echo -e "\n\t run script against specified kernel source"
echo -e "\t -k, --ksrc \"/lib/modules/5.12.0/source\""
echo -e "\n\t run script with kernel version (kernel version used to find kernel source programatically)"
echo -e "\t -b, --build-kernel \"5.8.0\""
}
options=$(getopt -o "k:b:vh" --long ksrc:,build-kernel:,verbose,help -- "$@")
eval set -- "$options"
while :; do
case $1 in
-k|--ksrc) ksrc=$2; shift;;
-b|--build-kernel) build_kernel=$2; shift;;
-v|--verbose) verbose=1 ;;
-h|--help) usage && exit 0;;
--) shift; break;;
esac
shift
done
if [ $verbose == 1 ]; then
set -x
fi
# both build_kernel and ksrc are unset so programatically determine build_kernel
if [ -z $build_kernel ] && [ -z $ksrc ]; then
set_build_kernel
fi
# only programatically search for kernel source if ksrc not set on command line
if [ -z $ksrc ]; then
find_kernel_source
fi
find_config_file
if [ ! -z $kconfig ]; then
# if we found the kernel .config file then exit the script based on various
# conditions that depend on the CONFIG_AUXILIARY_BUS string being found
get_config_auxiliary_bus
if [ -z "$CONFIG_AUXILIARY_BUS" ]; then
msg "CONFIG_AUXILIARY_BUS not found in ${kconfig}."
# CONFIG_AUXILIARY_BUS string was not found, so OOT auxiliary is needed
exit_need_oot_auxiliary
elif [ "$CONFIG_AUXILIARY_BUS" = "1" ]; then
msg "CONFIG_AUXILIARY_BUS=y in ${kconfig}."
# CONFIG_AUXILIARY_BUS=y, so OOT auxiliary is not needed
exit_builtin_auxiliary_enabled
else
msg ""
msg "kernel $build_kernel supports auxiliary bus, but CONFIG_AUXILIARY_BUS"
msg "is not set in ${kconfig}. Rebuild your kernel with"
msg "CONFIG_AUXILIARY_BUS=y"
msg ""
# CONFIG_AUXILIARY_BUS is not "=y", but the string was found, so report
# the failure so it can be used to fail build/install
exit_kconfig_invalid
fi
else
if [ ! -d ${ksrc}/${LINUX_INCLUDE_DIR} ] && [ ! -d ${ksrc}/source/${LINUX_INCLUDE_DIR} ]; then
echo "${ksrc}/${LINUX_INCLUDE_DIR} and ${ksrc}/source/${LINUX_INCLUDE_DIR} do not exist"
exit_not_found_failure
fi
# We didn't find a kernel .config file, so check to see if auxiliary_bus.h
# is found in the kernel source include directory
find_aux_bus_inc
if [ -f "$aux_bus_inc" ]; then
# AUXILIARY_MODULE_PREFIX is defined only in out-of-tree auxiliary bus
if [ $(grep -c AUXILIARY_MODULE_PREFIX $aux_bus_inc) -eq 0 ]; then
msg "in-tree auxiliary_bus.h found at ${ksrc}/${LINUX_INCLUDE_DIR}"
# If auxiliary_bus.h is included at ${ksrc} and it isn't our OOT version, then
# don't build OOT auxiliary as part of the driver makefile
exit_builtin_auxiliary_enabled
else
msg "OOT auxiliary_bus.h found at ${ksrc}/${LINUX_INCLUDE_DIR}"
# If auxiliary bus is included at ${ksrc} and it is our OOT version, then
# build OOT auxiliary as part of the driver makefile
exit_need_oot_auxiliary
fi
else
msg "auxiliary_bus.h not found at ${ksrc}/${LINUX_INCLUDE_DIR}"
exit_need_oot_auxiliary
fi
fi

View File

@ -0,0 +1,86 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2020 - 2023 Intel Corporation
#
# Attempt a basic setup of adaptive receive flow steering
# also known as aRFS. aRFS will automatically at runtime
# use ntuple rules to direct receive traffic to the same
# rx queue (matched by queue number) as was used for the
# application that was transmitting. Most useful for
# TCP workloads and latency sensitive TCP connections.
#
# typical usage is (as root):
# set_arfs -s flow_entries eth1 <eth2> <eth3>
#
# to get help:
# set_arfs
usage()
{
echo
echo "Usage: $0 [-s flow_entries] <interface> ..."
echo " Options: "
echo " -s number of socket flow entries"
echo " Examples:"
echo " $0 eth1 eth2 # eth1 and eth2 use default flow_entries"
echo " $0 -s flow_entries eth1 # eth1 use specified flow_entries"
echo
exit 1
}
# offer some help
if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
usage
exit 1
fi
# if -s and a value specified, then use them.
if [ "$1" == "-s" ]; then
FLOW_ENTRIES=$2
shift
shift
fi
# append the interfaces listed to the string with spaces
while [ "$#" -ne "0" ] ; do
IFACES+=" $1"
shift
done
# for now the user must specify interfaces
if [ -z "$IFACES" ]; then
usage
exit 1
fi
# provide a default flow num value, typically 2048 per queue
# is useful, but if there are many queues then maybe a smaller
# value per-queue is good enough.
if [ -z "$FLOW_ENTRIES" ]; then
FLOW_ENTRIES=32768
fi
set_arfs()
{
echo $FLOW_ENTRIES > /proc/sys/net/core/rps_sock_flow_entries
echo -n "done: "
grep -H . /proc/sys/net/core/rps_sock_flow_entries
for IFACE in $IFACES; do
QDIR="/sys/class/net/$IFACE/queues"
QUEUES=`ls -1 -d $QDIR/rx-*`
QUEUES_COUNT=`ls -1 -d $QDIR/rx-* | wc -l`
sockTrack=$((FLOW_ENTRIES / QUEUES_COUNT))
if [ -z `ls $QDIR/rx-0/rps_flow_cnt` ]; then
echo "ERROR: aRFS is not supported on $IFACE"
exit 2
fi
n=0
for i in $QUEUES; do
echo $sockTrack > $i/rps_flow_cnt
echo -n "Queue $((n++)) done: "
grep -H . $i/rps_flow_cnt
done
done
}
set_arfs

View File

@ -0,0 +1,336 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2015 - 2023 Intel Corporation
#
# Affinitize interrupts to cores
#
# typical usage is (as root):
# set_irq_affinity -x local eth1 <eth2> <eth3>
# set_irq_affinity -s eth1
#
# to get help:
# set_irq_affinity
usage()
{
echo
echo "Usage: option -s <interface> to show current settings only"
echo "Usage: $0 [-x|-X] [all|local|remote [<node>]|one <core>|custom|<cores>] <interface> ..."
echo " Options: "
echo " -s Shows current affinity settings"
echo " -x Configure XPS as well as smp_affinity"
echo " -X Disable XPS but set smp_affinity"
echo " [all] is the default value"
echo " [remote [<node>]] can be followed by a specific node number"
echo " Examples:"
echo " $0 -s eth1 # Show settings on eth1"
echo " $0 all eth1 eth2 # eth1 and eth2 to all cores"
echo " $0 one 2 eth1 # eth1 to core 2 only"
echo " $0 local eth1 # eth1 to local cores only"
echo " $0 remote eth1 # eth1 to remote cores only"
echo " $0 custom eth1 # prompt for eth1 interface"
echo " $0 0-7,16-23 eth0 # eth1 to cores 0-7 and 16-23"
echo
exit 1
}
usageX()
{
echo "options -x and -X cannot both be specified, pick one"
exit 1
}
if [ "$1" == "-x" ]; then
XPS_ENA=1
shift
fi
if [ "$1" == "-s" ]; then
SHOW=1
echo Show affinity settings
shift
fi
if [ "$1" == "-X" ]; then
if [ -n "$XPS_ENA" ]; then
usageX
fi
XPS_DIS=2
shift
fi
if [ "$1" == -x ]; then
usageX
fi
if [ -n "$XPS_ENA" ] && [ -n "$XPS_DIS" ]; then
usageX
fi
if [ -z "$XPS_ENA" ]; then
XPS_ENA=$XPS_DIS
fi
SED=`which sed`
if [[ ! -x $SED ]]; then
echo " $0: ERROR: sed not found in path, this script requires sed"
exit 1
fi
num='^[0-9]+$'
# search helpers
NOZEROCOMMA="s/^[0,]*//"
# Vars
AFF=$1
shift
case "$AFF" in
remote) [[ $1 =~ $num ]] && rnode=$1 && shift ;;
one) [[ $1 =~ $num ]] && cnt=$1 && shift ;;
all) ;;
local) ;;
custom) ;;
[0-9]*) ;;
-h|--help) usage ;;
"") usage ;;
*) IFACES=$AFF && AFF=all ;; # Backwards compat mode
esac
# append the interfaces listed to the string with spaces
while [ "$#" -ne "0" ] ; do
IFACES+=" $1"
shift
done
# for now the user must specify interfaces
if [ -z "$IFACES" ]; then
usage
exit 2
fi
notfound()
{
echo $MYIFACE: not found
exit 15
}
# check the interfaces exist
for MYIFACE in $IFACES; do
grep -q $MYIFACE /proc/net/dev || notfound
done
# support functions
build_mask()
{
VEC=$core
if [ $VEC -ge 32 ]
then
MASK_FILL=""
MASK_ZERO="00000000"
let "IDX = $VEC / 32"
for ((i=1; i<=$IDX;i++))
do
MASK_FILL="${MASK_FILL},${MASK_ZERO}"
done
let "VEC -= 32 * $IDX"
MASK_TMP=$((1<<$VEC))
MASK=$(printf "%X%s" $MASK_TMP $MASK_FILL)
else
MASK_TMP=$((1<<$VEC))
MASK=$(printf "%X" $MASK_TMP)
fi
}
show_affinity()
{
# returns the MASK variable
build_mask
SMP_I=`sed -E "${NOZEROCOMMA}" /proc/irq/$IRQ/smp_affinity`
HINT=`sed -E "${NOZEROCOMMA}" /proc/irq/$IRQ/affinity_hint`
printf "ACTUAL %s %d %s <- /proc/irq/$IRQ/smp_affinity\n" $IFACE $core $SMP_I
printf "HINT %s %d %s <- /proc/irq/$IRQ/affinity_hint\n" $IFACE $core $HINT
IRQ_CHECK=`grep '[-,]' /proc/irq/$IRQ/smp_affinity_list`
if [ ! -z $IRQ_CHECK ]; then
printf " WARNING -- SMP_AFFINITY is assigned to multiple cores $IRQ_CHECK\n"
fi
if [ "$SMP_I" != "$HINT" ]; then
printf " WARNING -- SMP_AFFINITY VALUE does not match AFFINITY_HINT \n"
fi
printf "NODE %s %d %s <- /proc/irq/$IRQ/node\n" $IFACE $core `cat /proc/irq/$IRQ/node`
printf "LIST %s %d [%s] <- /proc/irq/$IRQ/smp_affinity_list\n" $IFACE $core `cat /proc/irq/$IRQ/smp_affinity_list`
printf "XPS %s %d %s <- /sys/class/net/%s/queues/tx-%d/xps_cpus\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/xps_cpus` $IFACE $((n-1))
if [ -z `ls /sys/class/net/$IFACE/queues/tx-$((n-1))/xps_rxqs` ]; then
echo "WARNING: xps rxqs not supported on $IFACE"
else
printf "XPSRXQs %s %d %s <- /sys/class/net/%s/queues/tx-%d/xps_rxqs\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/xps_rxqs` $IFACE $((n-1))
fi
printf "TX_MAX %s %d %s <- /sys/class/net/%s/queues/tx-%d/tx_maxrate\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/tx_maxrate` $IFACE $((n-1))
printf "BQLIMIT %s %d %s <- /sys/class/net/%s/queues/tx-%d/byte_queue_limits/limit\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/byte_queue_limits/limit` $IFACE $((n-1))
printf "BQL_MAX %s %d %s <- /sys/class/net/%s/queues/tx-%d/byte_queue_limits/limit_max\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/byte_queue_limits/limit_max` $IFACE $((n-1))
printf "BQL_MIN %s %d %s <- /sys/class/net/%s/queues/tx-%d/byte_queue_limits/limit_min\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/tx-$((n-1))/byte_queue_limits/limit_min` $IFACE $((n-1))
if [ -z `ls /sys/class/net/$IFACE/queues/rx-$((n-1))/rps_flow_cnt` ]; then
echo "WARNING: aRFS is not supported on $IFACE"
else
printf "RPSFCNT %s %d %s <- /sys/class/net/%s/queues/rx-%d/rps_flow_cnt\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/rx-$((n-1))/rps_flow_cnt` $IFACE $((n-1))
fi
if [ -z `ls /sys/class/net/$IFACE/queues/rx-$((n-1))/rps_cpus` ]; then
echo "WARNING: rps_cpus is not available on $IFACE"
else
printf "RPSCPU %s %d %s <- /sys/class/net/%s/queues/rx-%d/rps_cpus\n" $IFACE $core `cat /sys/class/net/$IFACE/queues/rx-$((n-1))/rps_cpus` $IFACE $((n-1))
fi
echo
}
set_affinity()
{
# returns the MASK variable
build_mask
printf "%s" $MASK > /proc/irq/$IRQ/smp_affinity
printf "%s %d %s -> /proc/irq/$IRQ/smp_affinity\n" $IFACE $core $MASK
SMP_I=`sed -E "${NOZEROCOMMA}" /proc/irq/$IRQ/smp_affinity`
if [ "$SMP_I" != "$MASK" ]; then
printf " ACTUAL\t%s %d %s <- /proc/irq/$IRQ/smp_affinity\n" $IFACE $core $SMP_I
printf " WARNING -- SMP_AFFINITY setting failed\n"
fi
case "$XPS_ENA" in
1)
printf "%s %d %s -> /sys/class/net/%s/queues/tx-%d/xps_cpus\n" $IFACE $core $MASK $IFACE $((n-1))
printf "%s" $MASK > /sys/class/net/$IFACE/queues/tx-$((n-1))/xps_cpus
;;
2)
MASK=0
printf "%s %d %s -> /sys/class/net/%s/queues/tx-%d/xps_cpus\n" $IFACE $core $MASK $IFACE $((n-1))
printf "%s" $MASK > /sys/class/net/$IFACE/queues/tx-$((n-1))/xps_cpus
;;
*)
esac
}
# Allow usage of , or -
#
parse_range () {
RANGE=${@//,/ }
RANGE=${RANGE//-/..}
LIST=""
for r in $RANGE; do
# eval lets us use vars in {#..#} range
[[ $r =~ '..' ]] && r="$(eval echo {$r})"
LIST+=" $r"
done
echo $LIST
}
# Affinitize interrupts
#
doaff()
{
CORES=$(parse_range $CORES)
ncores=$(echo $CORES | wc -w)
n=1
# this script only supports interrupt vectors in pairs,
# modification would be required to support a single Tx or Rx queue
# per interrupt vector
queues="${IFACE}-.*TxRx"
irqs=$(grep "$queues" /proc/interrupts | cut -f1 -d:)
[ -z "$irqs" ] && irqs=$(grep $IFACE /proc/interrupts | cut -f1 -d:)
[ -z "$irqs" ] && irqs=$(for i in `ls -1 /sys/class/net/${IFACE}/device/msi_irqs | sort -n` ;do grep -w $i: /proc/interrupts | egrep -v 'fdir|async|misc|ctrl' | cut -f 1 -d :; done)
[ -z "$irqs" ] && echo "Error: Could not find interrupts for $IFACE"
if [ "$SHOW" == "1" ] ; then
echo "TYPE IFACE CORE MASK -> FILE"
echo "============================"
else
echo "IFACE CORE MASK -> FILE"
echo "======================="
fi
for IRQ in $irqs; do
[ "$n" -gt "$ncores" ] && n=1
j=1
# much faster than calling cut for each
for i in $CORES; do
[ $((j++)) -ge $n ] && break
done
core=$i
if [ "$SHOW" == "1" ] ; then
show_affinity
else
set_affinity
fi
((n++))
done
}
# these next 2 lines would allow script to auto-determine interfaces
#[ -z "$IFACES" ] && IFACES=$(ls /sys/class/net)
#[ -z "$IFACES" ] && echo "Error: No interfaces up" && exit 1
# echo IFACES is $IFACES
CORES=$(</sys/devices/system/cpu/online)
[ "$CORES" ] || CORES=$(grep ^proc /proc/cpuinfo | cut -f2 -d:)
# Core list for each node from sysfs
node_dir=/sys/devices/system/node
for i in $(ls -d $node_dir/node*); do
i=${i/*node/}
corelist[$i]=$(<$node_dir/node${i}/cpulist)
done
for IFACE in $IFACES; do
# echo $IFACE being modified
dev_dir=/sys/class/net/$IFACE/device
[ -e $dev_dir/numa_node ] && node=$(<$dev_dir/numa_node)
[ "$node" ] && [ "$node" -gt 0 ] || node=0
case "$AFF" in
local)
CORES=${corelist[$node]}
;;
remote)
[ "$rnode" ] || { [ $node -eq 0 ] && rnode=1 || rnode=0; }
CORES=${corelist[$rnode]}
;;
one)
[ -n "$cnt" ] || cnt=0
CORES=$cnt
;;
all)
CORES=$CORES
;;
custom)
echo -n "Input cores for $IFACE (ex. 0-7,15-23): "
read CORES
;;
[0-9]*)
CORES=$AFF
;;
*)
usage
exit 1
;;
esac
# call the worker function
doaff
done
# check for irqbalance running
IRQBALANCE_ON=`ps ax | grep -v grep | grep -q irqbalance; echo $?`
if [ "$IRQBALANCE_ON" == "0" ] ; then
echo " WARNING: irqbalance is running and will"
echo " likely override this script's affinitization."
echo " Please stop the irqbalance service and/or execute"
echo " 'killall irqbalance'"
exit 2
fi

View File

@ -0,0 +1,56 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2019 - 2023 Intel Corporation
#
# Script to setup mechanism for Tx queue selection based on Rx queue(s) map.
# This is done by configuring Rx queue(s) map per Tx queue via sysfs. This
# Rx queue(s) map is used during selection of Tx queue in
# data path (net/core/dev.c:get_xps_queue).
#
# typical usage is (as root):
# set_xps_rxqs <ethX>
#
# to get help:
# set_xps_rxqs
iface=$1
if [ -z "$iface" ]; then
echo "Usage: $0 <interface>"
exit 1
fi
CHECK () {
"$@"
if [ $? -ne 0 ]; then
echo "Error in command ${1}, execution aborted, but some changes may have already been made!" >&2
exit 1
fi
}
CPUMASK () {
cpu=$1
if [ $cpu -ge 32 ]; then
mask_fill=""
mask_zero="00000000"
let "pow = $cpu / 32"
for ((i=1; i<=pow; i++)); do
mask_fill="${mask_fill},${mask_zero}"
done
let "cpu -= 32 * $pow"
mask_tmp=$((1 << cpu))
mask=$(printf "%X%s" $mask_tmp $mask_fill)
else
mask_tmp=$((1 << cpu))
mask=$(printf "%X" $mask_tmp)
fi
echo $mask
}
for i in /sys/class/net/$iface/queues/tx-*/xps_rxqs; do
j=$(echo $i | cut -d'/' -f7 | cut -d'-' -f2)
mask=$(CPUMASK $j)
echo ${mask} > $i
CHECK echo ${mask} > $i
done

1
LingYaoSNIC/README.md Normal file
View File

@ -0,0 +1 @@
中移自研“灵耀”智能网卡驱动固件

Some files were not shown because too many files have changed in this diff Show More