root/drivers/net/ethernet/amd/pds_core/core.h
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2023 Advanced Micro Devices, Inc */

#ifndef _PDSC_H_
#define _PDSC_H_

#include <linux/debugfs.h>
#include <net/devlink.h>

#include <linux/pds/pds_common.h>
#include <linux/pds/pds_core_if.h>
#include <linux/pds/pds_adminq.h>
#include <linux/pds/pds_intr.h>

#define PDSC_DRV_DESCRIPTION    "AMD/Pensando Core Driver"

#define PDSC_WATCHDOG_SECS      5
#define PDSC_QUEUE_NAME_MAX_SZ  16
#define PDSC_ADMINQ_MAX_LENGTH  16      /* must be a power of two */
#define PDSC_NOTIFYQ_LENGTH     64      /* must be a power of two */
#define PDSC_TEARDOWN_RECOVERY  false
#define PDSC_TEARDOWN_REMOVING  true
#define PDSC_SETUP_RECOVERY     false
#define PDSC_SETUP_INIT         true

struct pdsc_dev_bar {
        void __iomem *vaddr;
        phys_addr_t bus_addr;
        unsigned long len;
        int res_index;
};

struct pdsc;

struct pdsc_vf {
        struct pds_auxiliary_dev *padev;
        struct pdsc *vf;
        u16     index;
        __le16  vif_types[PDS_DEV_TYPE_MAX];
};

struct pdsc_devinfo {
        u8 asic_type;
        u8 asic_rev;
        char fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN + 1];
        char serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN + 1];
};

struct pdsc_queue {
        struct pdsc_q_info *info;
        u64 dbval;
        u16 head_idx;
        u16 tail_idx;
        u8 hw_type;
        unsigned int index;
        unsigned int num_descs;
        u64 dbell_count;
        u64 features;
        unsigned int type;
        unsigned int hw_index;
        union {
                void *base;
                struct pds_core_admin_cmd *adminq;
        };
        dma_addr_t base_pa;     /* must be page aligned */
        unsigned int desc_size;
        unsigned int pid;
        char name[PDSC_QUEUE_NAME_MAX_SZ];
};

#define PDSC_INTR_NAME_MAX_SZ           32

struct pdsc_intr_info {
        char name[PDSC_INTR_NAME_MAX_SZ];
        unsigned int index;
        unsigned int vector;
        void *data;
};

struct pdsc_cq_info {
        void *comp;
};

struct pdsc_buf_info {
        struct page *page;
        dma_addr_t dma_addr;
        u32 page_offset;
        u32 len;
};

struct pdsc_q_info {
        union {
                void *desc;
                struct pdsc_admin_cmd *adminq_desc;
        };
        unsigned int bytes;
        unsigned int nbufs;
        struct pdsc_buf_info bufs[PDS_CORE_MAX_FRAGS];
        struct completion completion;
        void *dest;
};

struct pdsc_cq {
        struct pdsc_cq_info *info;
        struct pdsc_queue *bound_q;
        struct pdsc_intr_info *bound_intr;
        u16 tail_idx;
        bool done_color;
        unsigned int num_descs;
        unsigned int desc_size;
        void *base;
        dma_addr_t base_pa;     /* must be page aligned */
} ____cacheline_aligned_in_smp;

struct pdsc_qcq {
        struct pdsc *pdsc;
        void *q_base;
        dma_addr_t q_base_pa;   /* might not be page aligned */
        void *cq_base;
        dma_addr_t cq_base_pa;  /* might not be page aligned */
        u32 q_size;
        u32 cq_size;
        bool armed;
        unsigned int flags;

        struct work_struct work;
        struct pdsc_queue q;
        struct pdsc_cq cq;
        int intx;

        u32 accum_work;
        struct dentry *dentry;
};

struct pdsc_viftype {
        char *name;
        bool supported;
        bool enabled;
        int dl_id;
        int vif_id;
        struct pds_auxiliary_dev *padev;
};

/* No state flags set means we are in a steady running state */
enum pdsc_state_flags {
        PDSC_S_FW_DEAD,             /* stopped, wait on startup or recovery */
        PDSC_S_INITING_DRIVER,      /* initial startup from probe */
        PDSC_S_STOPPING_DRIVER,     /* driver remove */

        /* leave this as last */
        PDSC_S_STATE_SIZE
};

struct pdsc {
        struct pci_dev *pdev;
        struct dentry *dentry;
        struct device *dev;
        struct pdsc_dev_bar bars[PDS_CORE_BARS_MAX];
        struct pds_auxiliary_dev *padev;
        struct pdsc_vf *vfs;
        int num_vfs;
        int vf_id;
        int hw_index;
        int uid;

        unsigned long state;
        u8 fw_status;
        u8 fw_generation;
        unsigned long last_fw_time;
        u32 last_hb;
        struct timer_list wdtimer;
        unsigned int wdtimer_period;
        struct work_struct health_work;
        struct devlink_health_reporter *fw_reporter;
        u32 fw_recoveries;

        struct pdsc_devinfo dev_info;
        struct pds_core_dev_identity dev_ident;
        unsigned int nintrs;
        struct pdsc_intr_info *intr_info;       /* array of nintrs elements */

        struct workqueue_struct *wq;

        unsigned int devcmd_timeout;
        struct mutex devcmd_lock;       /* lock for dev_cmd operations */
        struct mutex config_lock;       /* lock for configuration operations */
        spinlock_t adminq_lock;         /* lock for adminq operations */
        refcount_t adminq_refcnt;
        struct pds_core_dev_info_regs __iomem *info_regs;
        struct pds_core_dev_cmd_regs __iomem *cmd_regs;
        struct pds_core_intr __iomem *intr_ctrl;
        u64 __iomem *intr_status;
        u64 __iomem *db_pages;
        dma_addr_t phy_db_pages;
        u64 __iomem *kern_dbpage;

        struct pdsc_qcq adminqcq;
        struct pdsc_qcq notifyqcq;
        u64 last_eid;
        struct pdsc_viftype *viftype_status;
        struct work_struct pci_reset_work;
};

/** enum pds_core_dbell_bits - bitwise composition of dbell values.
 *
 * @PDS_CORE_DBELL_QID_MASK:    unshifted mask of valid queue id bits.
 * @PDS_CORE_DBELL_QID_SHIFT:   queue id shift amount in dbell value.
 * @PDS_CORE_DBELL_QID:         macro to build QID component of dbell value.
 *
 * @PDS_CORE_DBELL_RING_MASK:   unshifted mask of valid ring bits.
 * @PDS_CORE_DBELL_RING_SHIFT:  ring shift amount in dbell value.
 * @PDS_CORE_DBELL_RING:        macro to build ring component of dbell value.
 *
 * @PDS_CORE_DBELL_RING_0:      ring zero dbell component value.
 * @PDS_CORE_DBELL_RING_1:      ring one dbell component value.
 * @PDS_CORE_DBELL_RING_2:      ring two dbell component value.
 * @PDS_CORE_DBELL_RING_3:      ring three dbell component value.
 *
 * @PDS_CORE_DBELL_INDEX_MASK:  bit mask of valid index bits, no shift needed.
 */
enum pds_core_dbell_bits {
        PDS_CORE_DBELL_QID_MASK         = 0xffffff,
        PDS_CORE_DBELL_QID_SHIFT                = 24,

#define PDS_CORE_DBELL_QID(n) \
        (((u64)(n) & PDS_CORE_DBELL_QID_MASK) << PDS_CORE_DBELL_QID_SHIFT)

        PDS_CORE_DBELL_RING_MASK                = 0x7,
        PDS_CORE_DBELL_RING_SHIFT               = 16,

#define PDS_CORE_DBELL_RING(n) \
        (((u64)(n) & PDS_CORE_DBELL_RING_MASK) << PDS_CORE_DBELL_RING_SHIFT)

        PDS_CORE_DBELL_RING_0           = 0,
        PDS_CORE_DBELL_RING_1           = PDS_CORE_DBELL_RING(1),
        PDS_CORE_DBELL_RING_2           = PDS_CORE_DBELL_RING(2),
        PDS_CORE_DBELL_RING_3           = PDS_CORE_DBELL_RING(3),

        PDS_CORE_DBELL_INDEX_MASK               = 0xffff,
};

static inline void pds_core_dbell_ring(u64 __iomem *db_page,
                                       enum pds_core_logical_qtype qtype,
                                       u64 val)
{
        writeq(val, &db_page[qtype]);
}

int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
                              struct devlink_fmsg *fmsg,
                              struct netlink_ext_ack *extack);
int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
                     struct netlink_ext_ack *extack);
int pdsc_dl_flash_update(struct devlink *dl,
                         struct devlink_flash_update_params *params,
                         struct netlink_ext_ack *extack);
int pdsc_dl_enable_get(struct devlink *dl, u32 id,
                       struct devlink_param_gset_ctx *ctx,
                       struct netlink_ext_ack *extack);
int pdsc_dl_enable_set(struct devlink *dl, u32 id,
                       struct devlink_param_gset_ctx *ctx,
                       struct netlink_ext_ack *extack);
int pdsc_dl_enable_validate(struct devlink *dl, u32 id,
                            union devlink_param_value val,
                            struct netlink_ext_ack *extack);

void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num);

void pdsc_debugfs_create(void);
void pdsc_debugfs_destroy(void);
void pdsc_debugfs_add_dev(struct pdsc *pdsc);
void pdsc_debugfs_del_dev(struct pdsc *pdsc);
void pdsc_debugfs_add_ident(struct pdsc *pdsc);
void pdsc_debugfs_add_viftype(struct pdsc *pdsc);
void pdsc_debugfs_add_irqs(struct pdsc *pdsc);
void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq);
void pdsc_debugfs_del_qcq(struct pdsc_qcq *qcq);

int pdsc_err_to_errno(enum pds_core_status_code code);
bool pdsc_is_fw_running(struct pdsc *pdsc);
bool pdsc_is_fw_good(struct pdsc *pdsc);
int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
                union pds_core_dev_comp *comp, int max_seconds);
int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
                       union pds_core_dev_comp *comp, int max_seconds);
int pdsc_devcmd_init(struct pdsc *pdsc);
int pdsc_devcmd_reset(struct pdsc *pdsc);
int pdsc_dev_init(struct pdsc *pdsc);
void pdsc_dev_uninit(struct pdsc *pdsc);

int pdsc_intr_alloc(struct pdsc *pdsc, char *name,
                    irq_handler_t handler, void *data);
void pdsc_intr_free(struct pdsc *pdsc, int index);
void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq);
int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index,
                   const char *name, unsigned int flags, unsigned int num_descs,
                   unsigned int desc_size, unsigned int cq_desc_size,
                   unsigned int pid, struct pdsc_qcq *qcq);
int pdsc_setup(struct pdsc *pdsc, bool init);
void pdsc_teardown(struct pdsc *pdsc, bool removing);
int pdsc_start(struct pdsc *pdsc);
void pdsc_stop(struct pdsc *pdsc);
void pdsc_health_thread(struct work_struct *work);

int pdsc_register_notify(struct notifier_block *nb);
void pdsc_unregister_notify(struct notifier_block *nb);
void pdsc_notify(unsigned long event, void *data);
int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
                        enum pds_core_vif_types vt,
                        struct pds_auxiliary_dev **pd_ptr);
void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
                         struct pds_auxiliary_dev **pd_ptr);

void pdsc_process_adminq(struct pdsc_qcq *qcq);
void pdsc_work_thread(struct work_struct *work);
irqreturn_t pdsc_adminq_isr(int irq, void *data);

int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,
                         struct netlink_ext_ack *extack);

void pdsc_fw_down(struct pdsc *pdsc);
void pdsc_fw_up(struct pdsc *pdsc);
void pdsc_pci_reset_thread(struct work_struct *work);

#endif /* _PDSC_H_ */