2026-01-21 18:59:54 +08:00

234 lines
6.0 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei Hifc PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HIFC_EQS_H
#define HIFC_EQS_H
#define HIFC_MAX_AEQS 3
#define HIFC_MAX_CEQS 32
#define HIFC_EQ_MAX_PAGES 8
#define HIFC_AEQE_SIZE 64
#define HIFC_CEQE_SIZE 4
#define HIFC_AEQE_DESC_SIZE 4
#define HIFC_AEQE_DATA_SIZE \
(HIFC_AEQE_SIZE - HIFC_AEQE_DESC_SIZE)
#define HIFC_DEFAULT_AEQ_LEN 4096
#define HIFC_DEFAULT_CEQ_LEN 8192
#define HIFC_MIN_AEQ_LEN 64
#define HIFC_MAX_AEQ_LEN (512 * 1024)
#define HIFC_MIN_CEQ_LEN 64
#define HIFC_MAX_CEQ_LEN (1024 * 1024)
#define HIFC_CEQ_ID_CMDQ 0
#define EQ_IRQ_NAME_LEN 64
/* EQ registers */
#define HIFC_AEQ_MTT_OFF_BASE_ADDR 0x200
#define HIFC_CEQ_MTT_OFF_BASE_ADDR 0x400
#define HIFC_EQ_MTT_OFF_STRIDE 0x40
#define HIFC_CSR_AEQ_MTT_OFF(id) \
(HIFC_AEQ_MTT_OFF_BASE_ADDR + (id) * HIFC_EQ_MTT_OFF_STRIDE)
#define HIFC_CSR_CEQ_MTT_OFF(id) \
(HIFC_CEQ_MTT_OFF_BASE_ADDR + (id) * HIFC_EQ_MTT_OFF_STRIDE)
#define HIFC_CSR_EQ_PAGE_OFF_STRIDE 8
#define HIFC_AEQ_HI_PHYS_ADDR_REG(q_id, pg_num) \
(HIFC_CSR_AEQ_MTT_OFF(q_id) + \
(pg_num) * HIFC_CSR_EQ_PAGE_OFF_STRIDE)
#define HIFC_AEQ_LO_PHYS_ADDR_REG(q_id, pg_num) \
(HIFC_CSR_AEQ_MTT_OFF(q_id) + \
(pg_num) * HIFC_CSR_EQ_PAGE_OFF_STRIDE + 4)
#define HIFC_CEQ_HI_PHYS_ADDR_REG(q_id, pg_num) \
(HIFC_CSR_CEQ_MTT_OFF(q_id) + \
(pg_num) * HIFC_CSR_EQ_PAGE_OFF_STRIDE)
#define HIFC_CEQ_LO_PHYS_ADDR_REG(q_id, pg_num) \
(HIFC_CSR_CEQ_MTT_OFF(q_id) + \
(pg_num) * HIFC_CSR_EQ_PAGE_OFF_STRIDE + 4)
#define HIFC_EQ_HI_PHYS_ADDR_REG(type, q_id, pg_num) \
((u32)((type == HIFC_AEQ) ? \
HIFC_AEQ_HI_PHYS_ADDR_REG(q_id, pg_num) : \
HIFC_CEQ_HI_PHYS_ADDR_REG(q_id, pg_num)))
#define HIFC_EQ_LO_PHYS_ADDR_REG(type, q_id, pg_num) \
((u32)((type == HIFC_AEQ) ? \
HIFC_AEQ_LO_PHYS_ADDR_REG(q_id, pg_num) : \
HIFC_CEQ_LO_PHYS_ADDR_REG(q_id, pg_num)))
#define HIFC_AEQ_CTRL_0_ADDR_BASE 0xE00
#define HIFC_AEQ_CTRL_1_ADDR_BASE 0xE04
#define HIFC_AEQ_CONS_IDX_0_ADDR_BASE 0xE08
#define HIFC_AEQ_CONS_IDX_1_ADDR_BASE 0xE0C
#define HIFC_EQ_OFF_STRIDE 0x80
#define HIFC_CSR_AEQ_CTRL_0_ADDR(idx) \
(HIFC_AEQ_CTRL_0_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_AEQ_CTRL_1_ADDR(idx) \
(HIFC_AEQ_CTRL_1_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_AEQ_CONS_IDX_ADDR(idx) \
(HIFC_AEQ_CONS_IDX_0_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_AEQ_PROD_IDX_ADDR(idx) \
(HIFC_AEQ_CONS_IDX_1_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CEQ_CTRL_0_ADDR_BASE 0x1000
#define HIFC_CEQ_CTRL_1_ADDR_BASE 0x1004
#define HIFC_CEQ_CONS_IDX_0_ADDR_BASE 0x1008
#define HIFC_CEQ_CONS_IDX_1_ADDR_BASE 0x100C
#define HIFC_CSR_CEQ_CTRL_0_ADDR(idx) \
(HIFC_CEQ_CTRL_0_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_CEQ_CTRL_1_ADDR(idx) \
(HIFC_CEQ_CTRL_1_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_CEQ_CONS_IDX_ADDR(idx) \
(HIFC_CEQ_CONS_IDX_0_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
#define HIFC_CSR_CEQ_PROD_IDX_ADDR(idx) \
(HIFC_CEQ_CONS_IDX_1_ADDR_BASE + (idx) * HIFC_EQ_OFF_STRIDE)
enum hifc_eq_type {
HIFC_AEQ,
HIFC_CEQ
};
enum hifc_eq_intr_mode {
HIFC_INTR_MODE_ARMED,
HIFC_INTR_MODE_ALWAYS,
};
enum hifc_eq_ci_arm_state {
HIFC_EQ_NOT_ARMED,
HIFC_EQ_ARMED,
};
struct hifc_eq_work {
struct work_struct work;
void *data;
};
struct hifc_ceq_tasklet_data {
void *data;
};
struct hifc_eq {
struct hifc_hwdev *hwdev;
u16 q_id;
enum hifc_eq_type type;
u32 page_size;
u32 orig_page_size;
u32 eq_len;
u32 cons_idx;
u16 wrapped;
u16 elem_size;
u16 num_pages;
u32 num_elem_in_pg;
struct irq_info eq_irq;
char irq_name[EQ_IRQ_NAME_LEN];
dma_addr_t *dma_addr;
u8 **virt_addr;
dma_addr_t *dma_addr_for_free;
u8 **virt_addr_for_free;
struct hifc_eq_work aeq_work;
struct tasklet_struct ceq_tasklet;
struct hifc_ceq_tasklet_data ceq_tasklet_data;
u64 hard_intr_jif;
u64 soft_intr_jif;
};
struct hifc_aeq_elem {
u8 aeqe_data[HIFC_AEQE_DATA_SIZE];
u32 desc;
};
enum hifc_aeq_cb_state {
HIFC_AEQ_HW_CB_REG = 0,
HIFC_AEQ_HW_CB_RUNNING,
HIFC_AEQ_SW_CB_REG,
HIFC_AEQ_SW_CB_RUNNING,
};
struct hifc_aeqs {
struct hifc_hwdev *hwdev;
hifc_aeq_hwe_cb aeq_hwe_cb[HIFC_MAX_AEQ_EVENTS];
hifc_aeq_swe_cb aeq_swe_cb[HIFC_MAX_AEQ_SW_EVENTS];
unsigned long aeq_hw_cb_state[HIFC_MAX_AEQ_EVENTS];
unsigned long aeq_sw_cb_state[HIFC_MAX_AEQ_SW_EVENTS];
struct hifc_eq aeq[HIFC_MAX_AEQS];
u16 num_aeqs;
struct workqueue_struct *workq;
};
enum hifc_ceq_cb_state {
HIFC_CEQ_CB_REG = 0,
HIFC_CEQ_CB_RUNNING,
};
struct hifc_ceqs {
struct hifc_hwdev *hwdev;
hifc_ceq_event_cb ceq_cb[HIFC_MAX_CEQ_EVENTS];
void *ceq_data[HIFC_MAX_CEQ_EVENTS];
unsigned long ceq_cb_state[HIFC_MAX_CEQ_EVENTS];
struct hifc_eq ceq[HIFC_MAX_CEQS];
u16 num_ceqs;
};
int hifc_aeqs_init(struct hifc_hwdev *hwdev, u16 num_aeqs,
struct irq_info *msix_entries);
void hifc_aeqs_free(struct hifc_hwdev *hwdev);
int hifc_ceqs_init(struct hifc_hwdev *hwdev, u16 num_ceqs,
struct irq_info *msix_entries);
void hifc_ceqs_free(struct hifc_hwdev *hwdev);
void hifc_get_ceq_irqs(struct hifc_hwdev *hwdev, struct irq_info *irqs,
u16 *num_irqs);
void hifc_get_aeq_irqs(struct hifc_hwdev *hwdev, struct irq_info *irqs,
u16 *num_irqs);
void hifc_dump_aeq_info(struct hifc_hwdev *hwdev);
#endif