[RFC,7/8] soc/fman: Add FMan Port Support
From: Igal.Liberman <hidden>
Date: 2015-03-11 09:29:25
Also in:
netdev
Subsystem:
freescale soc drivers, the rest · Maintainers:
Christophe Leroy, Linus Torvalds
From: Madalin Bucur <redacted> Signed-off-by: Igal Liberman <redacted> --- drivers/soc/fsl/fman/Kconfig | 49 + drivers/soc/fsl/fman/Makefile | 2 +- drivers/soc/fsl/fman/fm.c | 590 +++++++- drivers/soc/fsl/fman/fm_common.h | 192 +++ drivers/soc/fsl/fman/fm_drv.c | 184 ++- drivers/soc/fsl/fman/fm_drv.h | 2 + drivers/soc/fsl/fman/fm_port_drv.c | 540 +++++++ drivers/soc/fsl/fman/inc/fm_ext.h | 58 + drivers/soc/fsl/fman/inc/fm_port_ext.h | 650 +++++++++ drivers/soc/fsl/fman/inc/fsl_fman_drv.h | 156 ++ drivers/soc/fsl/fman/port/Makefile | 2 +- drivers/soc/fsl/fman/port/fm_port.c | 2427 +++++++++++++++++++++++++++++++ drivers/soc/fsl/fman/port/fm_port.h | 743 ++++++++++ 13 files changed, 5591 insertions(+), 4 deletions(-) create mode 100644 drivers/soc/fsl/fman/fm_port_drv.c create mode 100644 drivers/soc/fsl/fman/inc/fm_port_ext.h create mode 100644 drivers/soc/fsl/fman/port/fm_port.c create mode 100644 drivers/soc/fsl/fman/port/fm_port.h
diff --git a/drivers/soc/fsl/fman/Kconfig b/drivers/soc/fsl/fman/Kconfig
index 60114ee..c0b989b 100644
--- a/drivers/soc/fsl/fman/Kconfig
+++ b/drivers/soc/fsl/fman/Kconfig@@ -33,6 +33,55 @@ config FSL_FMAN_RTC help Freescale DPAA FMan Real Time Clock (PTP) support +if FSL_FMAN_MAC + +config FMAN_PFC + bool "FMan v3 PFC support (EXPERIMENTAL)" + depends on FSL_FMAN_MAC + default n + help + This option enables Priority Flow Control (PFC) support on + FMan v3 ports. Do not enable this option on platforms that do + not have FMan v3 as this feature is not supported. + Data Center Bridging defines Classes of Service that are + flow-controlled using PFC pause frames. + +if FMAN_PFC +config FMAN_PFC_COS_COUNT + int "Number of PFC Classes of Service" + depends on FMAN_PFC + range 1 4 + default "3" + help + The number of Classes of Service controlled by PFC. + +config FMAN_PFC_QUANTA_0 + int "The pause quanta for PFC CoS 0" + depends on FMAN_PFC && FSL_FMAN + range 0 65535 + default "65535" + +config FMAN_PFC_QUANTA_1 + int "The pause quanta for PFC CoS 1" + depends on FMAN_PFC && FSL_FMAN + range 0 65535 + default "65535" + +config FMAN_PFC_QUANTA_2 + int "The pause quanta for PFC CoS 2" + depends on FMAN_PFC && FSL_FMAN + range 0 65535 + default "65535" + +config FMAN_PFC_QUANTA_3 + int "The pause quanta for PFC CoS 3" + depends on FMAN_PFC && FSL_FMAN + range 0 65535 + default "65535" + +endif # FMAN_PFC +endif # FSL_FMAN_MAC + config FSL_FM_MAX_FRAME_SIZE int "Maximum L2 frame size" depends on FSL_FMAN
diff --git a/drivers/soc/fsl/fman/Makefile b/drivers/soc/fsl/fman/Makefile
index e360781..a2b1ce8 100644
--- a/drivers/soc/fsl/fman/Makefile
+++ b/drivers/soc/fsl/fman/Makefile@@ -4,7 +4,7 @@ subdir-ccflags-$(CONFIG_FSL_FMAN) += -I$(srctree)/drivers/soc/fsl/fman/flib \ obj-$(CONFIG_FSL_FMAN) += fsl_fman.o -fsl_fman-objs := fman.o fm_muram.o fm.o fm_drv.o +fsl_fman-objs := fman.o fm_muram.o fm.o fm_drv.o fm_port_drv.o obj-$(CONFIG_FSL_FMAN_PORT) += port/ obj-$(CONFIG_FSL_FMAN_MAC) += mac/
diff --git a/drivers/soc/fsl/fman/fm.c b/drivers/soc/fsl/fman/fm.c
index 7095dc2..9623261 100644
--- a/drivers/soc/fsl/fman/fm.c
+++ b/drivers/soc/fsl/fman/fm.c@@ -458,11 +458,36 @@ static void qmi_err_event(struct fm_t *p_fm) static void dma_err_event(struct fm_t *p_fm) { - uint32_t status; + uint32_t status, com_id; + uint8_t tnum; + uint8_t port_id; + uint8_t relative_port_id; + uint16_t liodn; struct fman_dma_regs __iomem *dma_rg = p_fm->p_fm_dma_regs; status = fman_get_dma_err_event(dma_rg); + if (status & DMA_STATUS_BUS_ERR) { + com_id = fman_get_dma_com_id(dma_rg); + port_id = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >> + DMA_TRANSFER_PORTID_SHIFT)); + HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info. + major_rev, + relative_port_id, + port_id); + tnum = + (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >> + DMA_TRANSFER_TNUM_SHIFT); + liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK); + ASSERT(p_fm->p_fm_state_struct-> + ports_types[port_id] != + FM_PORT_TYPE_DUMMY); + p_fm->f_bus_error(p_fm->h_app, + p_fm->p_fm_state_struct-> + ports_types[port_id], + relative_port_id, + fman_get_dma_addr(dma_rg), tnum, liodn); + } if (status & DMA_STATUS_FM_SPDAT_ECC) p_fm->f_exception(p_fm->h_app, FM_EX_DMA_SINGLE_PORT_ECC); if (status & DMA_STATUS_READ_ECC)
@@ -793,6 +818,33 @@ int fm_get_port_prefetch_cfg(void *h_fm, uint8_t port_num, return 0; } +int fm_set_congestion_group_pfc_priority(void *h_fm, + uint32_t congestion_group_id, + uint8_t priority_bit_map) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + uint32_t reg_num; + + if (congestion_group_id > p_fm->intg->fm_port_num_of_cg) { + pr_err("Congestion group ID bigger than %d\n", + p_fm->intg->fm_port_num_of_cg); + return -EDOM; + } + + ASSERT(p_fm->base_addr); + reg_num = + (p_fm->intg->fm_port_num_of_cg - 1 - congestion_group_id) / 4; + + fman_set_congestion_group_pfc_priority((uint32_t __iomem + *)((p_fm->base_addr + + FM_MM_CGP)), + congestion_group_id, + priority_bit_map, + reg_num); + + return 0; +} + uintptr_t fm_get_pcd_prs_base_addr(void *h_fm) { struct fm_t *p_fm = (struct fm_t *)h_fm;
@@ -964,6 +1016,538 @@ uint8_t fm_get_id(void *h_fm) return p_fm->p_fm_state_struct->fm_id; } +int fm_set_num_of_riscs_per_port(void *h_fm, uint8_t port_id, + uint8_t num_of_fman_ctrls, + uint32_t or_fman_ctrl) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + struct fman_fpm_regs __iomem *fpm_rg; + + if (!((num_of_fman_ctrls > 0) && (num_of_fman_ctrls < 3))) + return -ENOSYS; + + fpm_rg = p_fm->p_fm_fpm_regs; + + if (!p_fm->p_fm_fpm_regs) { + pr_warn("Either IPC or 'base_address' is required!\n"); + return -ENOSYS; + } + + fman_set_num_of_riscs_per_port(fpm_rg, + port_id, + num_of_fman_ctrls, or_fman_ctrl); + + return 0; +} + +int fm_get_set_port_params(void *h_fm, + struct fm_inter_module_port_init_params_t + *p_port_params) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + int err; + unsigned long int_flags; + uint8_t port_id = p_port_params->port_id, mac_id; + struct fman_rg fman_rg; + + fman_rg.bmi_rg = p_fm->p_fm_bmi_regs; + fman_rg.qmi_rg = p_fm->p_fm_qmi_regs; + fman_rg.fpm_rg = p_fm->p_fm_fpm_regs; + fman_rg.dma_rg = p_fm->p_fm_dma_regs; + + ASSERT(IN_RANGE(1, port_id, 63)); + + spin_lock_irqsave(p_fm->spinlock, int_flags); + + p_fm->p_fm_state_struct->ports_types[port_id] = + p_port_params->port_type; + + err = + fm_set_num_of_tasks(p_fm, p_port_params->port_id, + &p_port_params->num_of_tasks, + &p_port_params->num_of_extra_tasks, true); + if (err) { + spin_unlock_irqrestore(p_fm->spinlock, int_flags); + return err; + } +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_fm->p_fm_state_struct->rev_info.major_rev != 4) +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + /* for transmit&O/H ports */ + if (p_port_params->port_type != FM_PORT_TYPE_RX) { + uint8_t enq_th; + uint8_t deq_th; + + /* update qmi ENQ/DEQ threshold */ + p_fm->p_fm_state_struct->accumulated_num_of_deq_tnums += + p_port_params->deq_pipeline_depth; + enq_th = fman_get_qmi_enq_th(fman_rg.qmi_rg); + /* if enq_th is too big, we reduce it to the max value + * that is still 0 + */ + if (enq_th >= + (p_fm->intg->qmi_max_num_of_tnums - + p_fm->p_fm_state_struct-> + accumulated_num_of_deq_tnums)) { + enq_th = (uint8_t)( + p_fm->intg-> + qmi_max_num_of_tnums - + p_fm->p_fm_state_struct-> + accumulated_num_of_deq_tnums - 1); + fman_set_qmi_enq_th(fman_rg.qmi_rg, enq_th); + } + + deq_th = fman_get_qmi_deq_th(fman_rg.qmi_rg); + /* if deq_th is too small, we enlarge it to the min + * value that is still 0. + * depTh may not be larger than 63 + * (p_fm->intg->qmi_max_num_of_tnums-1). + */ + if ((deq_th <= + p_fm->p_fm_state_struct-> + accumulated_num_of_deq_tnums) && + (deq_th < + p_fm->intg-> + qmi_max_num_of_tnums - 1)) { + deq_th = (uint8_t)(p_fm-> + p_fm_state_struct-> + accumulated_num_of_deq_tnums + + 1); + fman_set_qmi_deq_th(fman_rg.qmi_rg, deq_th); + } + } +#ifdef FM_LOW_END_RESTRICTION + if (p_fm->p_fm_state_struct->rev_info.major_rev == 0x4) { + if ((port_id == 0x1) || (port_id == 0x29)) { + if (p_fm->p_fm_state_struct->low_end_restriction) { + spin_unlock_irqrestore(p_fm->spinlock, + int_flags); + pr_err("OP#0 cant work with Tx Port1\n"); + return -EAGAIN; + } + p_fm->p_fm_state_struct->low_end_restriction = true; + } + } +#endif /* FM_LOW_END_RESTRICTION */ + + err = fm_set_size_of_fifo(p_fm, + p_port_params->port_id, + &p_port_params->size_of_fifo, + &p_port_params->extra_size_of_fifo, true); + if (err) { + spin_unlock_irqrestore(p_fm->spinlock, int_flags); + return err; + } + + err = fm_set_num_of_open_dmas(p_fm, + p_port_params->port_id, + &p_port_params->num_of_open_dmas, + &p_port_params->num_of_extra_open_dmas, + true); + if (err) { + spin_unlock_irqrestore(p_fm->spinlock, + (unsigned long)int_flags); + return err; + } + + fman_set_liodn_per_port(&fman_rg, + port_id, + p_port_params->liodn_base, + p_port_params->liodn_offset); + + if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) + fman_set_order_restoration_per_port(fman_rg.fpm_rg, + port_id, + !!((p_port_params-> + port_type == + FM_PORT_TYPE_RX))); + + HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev, + mac_id, + port_id); + + if (p_port_params->max_frame_length >= + p_fm->p_fm_state_struct->mac_max_frame_lengths[mac_id]) { + p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id] = + p_port_params->max_frame_length; + } else { + pr_warn("Port max_frame_length is smaller than MAC current MTU\n"); + spin_unlock_irqrestore(p_fm->spinlock, + (unsigned long)int_flags); + return -EDOM; + } + + fm_get_physical_muram_base(p_fm, &p_port_params-> + fm_muram_phys_base_addr); + spin_unlock_irqrestore(p_fm->spinlock, (unsigned long)int_flags); + + return 0; +} + +void fm_free_port_params(void *h_fm, + struct fm_inter_module_port_free_params_t + *p_port_params) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + unsigned long int_flags; + uint8_t port_id = p_port_params->port_id; + uint8_t num_of_tasks, num_of_dmas, mac_id; + uint16_t size_of_fifo; + struct fman_qmi_regs __iomem *qmi_rg = p_fm->p_fm_qmi_regs; + struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs; + + ASSERT(IN_RANGE(1, port_id, 63)); + + spin_lock_irqsave(p_fm->spinlock, int_flags); + + p_fm->p_fm_state_struct->ports_types[port_id] = + FM_PORT_TYPE_DUMMY; + + /* free num_of_tasks */ + num_of_tasks = fman_get_num_of_tasks(bmi_rg, port_id); + ASSERT(p_fm->p_fm_state_struct->accumulated_num_of_tasks >= + num_of_tasks); + p_fm->p_fm_state_struct->accumulated_num_of_tasks -= num_of_tasks; + + /* free num_of_open_dmas */ + num_of_dmas = fman_get_num_of_dmas(bmi_rg, port_id); + ASSERT(p_fm->p_fm_state_struct->accumulated_num_of_open_dmas >= + num_of_dmas); + p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -= num_of_dmas; + +#ifdef FM_HAS_TOTAL_DMAS + if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) { + /* update total num of DMA's with committed number + * of open DMAS, and max uncommitted pool. + */ + fman_set_num_of_open_dmas(bmi_rg, + port_id, + 1, + 0, + (uint8_t) + (p_fm->p_fm_state_struct-> + accumulated_num_of_open_dmas + + p_fm->p_fm_state_struct-> + extra_open_dmas_pool_size + )); + } +#endif /* FM_HAS_TOTAL_DMAS */ + + /* free size_of_fifo */ + size_of_fifo = fman_get_size_of_fifo(bmi_rg, port_id); + ASSERT(p_fm->p_fm_state_struct->accumulated_fifo_size >= + (size_of_fifo * BMI_FIFO_UNITS)); + p_fm->p_fm_state_struct->accumulated_fifo_size -= + (size_of_fifo * BMI_FIFO_UNITS); + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_fm->p_fm_state_struct->rev_info.major_rev != 4) +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + /* for transmit&O/H ports */ + if (p_port_params->port_type != FM_PORT_TYPE_RX) { + uint8_t enq_th; + uint8_t deq_th; + + /* update qmi ENQ/DEQ threshold */ + p_fm->p_fm_state_struct->accumulated_num_of_deq_tnums -= + p_port_params->deq_pipeline_depth; + + /* p_fm->p_fm_state_struct-> + * accumulated_num_of_deq_tnums is now smaller, + * so we can enlarge enq_th + */ + enq_th = + (uint8_t)(p_fm->intg->qmi_max_num_of_tnums - + p_fm->p_fm_state_struct-> + accumulated_num_of_deq_tnums - 1); + + /* p_fm->p_fm_state_struct-> + * accumulated_num_of_deq_tnums is now smaller, + * so we can reduce deq_th + */ + deq_th = + (uint8_t)(p_fm->p_fm_state_struct-> + accumulated_num_of_deq_tnums + 1); + + fman_set_qmi_enq_th(qmi_rg, enq_th); + fman_set_qmi_deq_th(qmi_rg, deq_th); + } + + HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev, + mac_id, + port_id); + + p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id] = 0; + +#ifdef FM_LOW_END_RESTRICTION + if (p_fm->p_fm_state_struct->rev_info.major_rev == 0x4) { + if ((port_id == 0x1) || (port_id == 0x29)) + p_fm->p_fm_state_struct->low_end_restriction = false; + } +#endif /* FM_LOW_END_RESTRICTION */ + spin_unlock_irqrestore(p_fm->spinlock, int_flags); +} + +int fm_is_port_stalled(void *h_fm, uint8_t port_id, + bool *p_is_stalled) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs; + + if (!p_fm->base_addr) { + pr_warn("'base_address' is required!\n"); + return -ENOSYS; + } + + *p_is_stalled = fman_is_port_stalled(fpm_rg, port_id); + + return 0; +} + +int fm_resume_stalled_port(void *h_fm, uint8_t port_id) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + int err; + bool is_stalled; + struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs; + + if (!p_fm->base_addr) { + pr_warn("'base_address' is required!"); + return -ENOSYS; + } + if (p_fm->p_fm_state_struct->rev_info.major_rev >= 6) { + pr_warn("Not available for this FM revision!\n"); + return -EAGAIN; + } + /* Get port status */ + err = fm_is_port_stalled(h_fm, port_id, &is_stalled); + if (err) { + pr_err("Can't get port status\n"); + return -ENOSYS; + } + if (!is_stalled) + return 0; + + fman_resume_stalled_port(fpm_rg, port_id); + + return 0; +} + +int fm_set_size_of_fifo(void *h_fm, + uint8_t port_id, + uint32_t *p_size_of_fifo, + uint32_t *p_extra_size_of_fifo, + bool initial_config) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs; + uint32_t size_of_fifo = *p_size_of_fifo, extra_size_of_fifo = + *p_extra_size_of_fifo; + uint16_t current_val = 0, current_extra_val = 0; + + ASSERT(IN_RANGE(1, port_id, 63)); + + if (!initial_config) { + /* !initial_config - runtime change of existing value. + * - read the current FIFO and extra FIFO size + */ + current_extra_val = + fman_get_size_of_extra_fifo(bmi_rg, port_id); + current_val = fman_get_size_of_fifo(bmi_rg, port_id); + } + + if (extra_size_of_fifo > current_extra_val) { + if (extra_size_of_fifo && + !p_fm->p_fm_state_struct->extra_fifo_pool_size) + /* if this is the first time a port + * requires extra_fifo_pool_size, + * the total extra_fifo_pool_size + * must be initialized to 1 buffer per port + */ + p_fm->p_fm_state_struct->extra_fifo_pool_size = + p_fm->intg->num_of_rx_ports * BMI_FIFO_UNITS; + + p_fm->p_fm_state_struct->extra_fifo_pool_size = + max(p_fm->p_fm_state_struct->extra_fifo_pool_size, + extra_size_of_fifo); + } + + /* check that there are enough uncommitted fifo size */ + if ((p_fm->p_fm_state_struct->accumulated_fifo_size - current_val + + size_of_fifo) > + (p_fm->p_fm_state_struct->total_fifo_size - + p_fm->p_fm_state_struct->extra_fifo_pool_size)) { + pr_err("Requested fifo size and extra size exceed total FIFO size.\n"); + return -EAGAIN; + } + /* update accumulated */ + ASSERT(p_fm->p_fm_state_struct->accumulated_fifo_size >= + current_val); + p_fm->p_fm_state_struct->accumulated_fifo_size -= current_val; + p_fm->p_fm_state_struct->accumulated_fifo_size += size_of_fifo; + fman_set_size_of_fifo(bmi_rg, port_id, size_of_fifo, + extra_size_of_fifo); + + return 0; +} + +int fm_set_num_of_tasks(void *h_fm, + uint8_t port_id, + uint8_t *p_num_of_tasks, + uint8_t *p_num_of_extra_tasks, bool initial_config) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs; + uint8_t current_val = 0, current_extra_val = 0, num_of_tasks = + *p_num_of_tasks, num_of_extra_tasks = *p_num_of_extra_tasks; + + ASSERT(IN_RANGE(1, port_id, 63)); + + if (!initial_config) { + /* !initial_config - runtime change of existing value. + * - read the current number of tasks + */ + current_val = fman_get_num_of_tasks(bmi_rg, port_id); + current_extra_val = + fman_get_num_extra_tasks(bmi_rg, port_id); + } + + if (num_of_extra_tasks > current_extra_val) + p_fm->p_fm_state_struct->extra_tasks_pool_size = + (uint8_t)max(p_fm->p_fm_state_struct->extra_tasks_pool_size, + num_of_extra_tasks); + + /* check that there are enough uncommitted tasks */ + if ((p_fm->p_fm_state_struct->accumulated_num_of_tasks - current_val + + num_of_tasks) > + (p_fm->p_fm_state_struct->total_num_of_tasks - + p_fm->p_fm_state_struct->extra_tasks_pool_size)) { + pr_err("Requested num_of_tasks and extra tasks pool for fm%d exceed total num_of_tasks.\n", + p_fm->p_fm_state_struct->fm_id); + return -EAGAIN; + } + ASSERT(p_fm->p_fm_state_struct-> + accumulated_num_of_tasks >= + current_val); + /* update accumulated */ + p_fm->p_fm_state_struct->accumulated_num_of_tasks -= + current_val; + p_fm->p_fm_state_struct->accumulated_num_of_tasks += + num_of_tasks; + fman_set_num_of_tasks(bmi_rg, port_id, num_of_tasks, + num_of_extra_tasks); + + return 0; +} + +int fm_set_num_of_open_dmas(void *h_fm, + uint8_t port_id, + uint8_t *p_num_of_open_dmas, + uint8_t *p_num_of_extra_open_dmas, + bool initial_config) +{ + struct fm_t *p_fm = (struct fm_t *)h_fm; + struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs; + uint8_t num_of_open_dmas = *p_num_of_open_dmas, + num_of_extra_open_dmas = *p_num_of_extra_open_dmas; + uint8_t total_num_dmas = 0, current_val = 0, current_extra_val = 0; + + ASSERT(IN_RANGE(1, port_id, 63)); + + if (!initial_config) { + /* !initial_config - runtime change of existing value. + * - read the current number of open Dma's + */ + current_extra_val = + fman_get_num_extra_dmas(bmi_rg, port_id); + current_val = fman_get_num_of_dmas(bmi_rg, port_id); + } + + /* it's illegal to be in a state where this is + * not the first set and no value is specified + */ + ASSERT(initial_config || num_of_open_dmas); + if (!num_of_open_dmas) { + /* !num_of_open_dmas - first configuration according + * to values in regs.- read the current number of + * open Dma's + */ + current_extra_val = + fman_get_num_extra_dmas(bmi_rg, port_id); + current_val = fman_get_num_of_dmas(bmi_rg, port_id); + /* This is the first configuration and user did not + * specify value (!num_of_open_dmas), reset values will be used + * and we just save these values for resource management + */ + p_fm->p_fm_state_struct->extra_open_dmas_pool_size = + (uint8_t)max(p_fm->p_fm_state_struct-> + extra_open_dmas_pool_size, + current_extra_val); + p_fm->p_fm_state_struct->accumulated_num_of_open_dmas += + current_val; + *p_num_of_open_dmas = current_val; + *p_num_of_extra_open_dmas = current_extra_val; + return 0; + } + + if (num_of_extra_open_dmas > current_extra_val) + p_fm->p_fm_state_struct->extra_open_dmas_pool_size = + (uint8_t)max(p_fm->p_fm_state_struct-> + extra_open_dmas_pool_size, + num_of_extra_open_dmas); + +#ifdef FM_HAS_TOTAL_DMAS + if ((p_fm->p_fm_state_struct->rev_info.major_rev < 6) && + (p_fm->p_fm_state_struct->accumulated_num_of_open_dmas - + current_val + num_of_open_dmas > + p_fm->p_fm_state_struct->max_num_of_open_dmas)) { + pr_err("Requested num_of_open_dmas for fm%d exceeds total num_of_open_dmas.\n", + p_fm->p_fm_state_struct->fm_id); + return -EAGAIN; + } +#else + if ((p_fm->p_fm_state_struct->rev_info.major_rev >= 6) && + #ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 + !((p_fm->p_fm_state_struct->rev_info.major_rev == 6) && + (p_fm->p_fm_state_struct->rev_info.minor_rev == 0)) && +#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ + (p_fm->p_fm_state_struct->accumulated_num_of_open_dmas - + current_val + num_of_open_dmas > + p_fm->intg->dma_thresh_max_commq + 1)) { + pr_err("Requested num_of_open_dmas for fm%d exceeds DMA Command queue (%d)\n", + p_fm->p_fm_state_struct->fm_id, + p_fm->intg->dma_thresh_max_commq + 1); + return -EAGAIN; + } +#endif /* FM_HAS_TOTAL_DMAS */ + else { + ASSERT(p_fm->p_fm_state_struct-> + accumulated_num_of_open_dmas >= + current_val); + /* update acummulated */ + p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -= + current_val; + p_fm->p_fm_state_struct->accumulated_num_of_open_dmas += + num_of_open_dmas; + +#ifdef FM_HAS_TOTAL_DMAS + if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) + total_num_dmas = + (uint8_t)(p_fm->p_fm_state_struct-> + accumulated_num_of_open_dmas + + p_fm->p_fm_state_struct-> + extra_open_dmas_pool_size); +#endif /* FM_HAS_TOTAL_DMAS */ + fman_set_num_of_open_dmas(bmi_rg, + port_id, + num_of_open_dmas, + num_of_extra_open_dmas, + total_num_dmas); + } + + return 0; +} + int fm_reset_mac(void *h_fm, enum fm_mac_type type, uint8_t mac_id) { struct fm_t *p_fm = (struct fm_t *)h_fm;
@@ -1160,6 +1744,7 @@ static int init_fm_qmi(struct fm_t *p_fm) void *fm_config(struct fm_params_t *p_fm_param) { struct fm_t *p_fm; + uint8_t i; uintptr_t base_addr; if (!((p_fm_param->firmware.p_code && p_fm_param->firmware.size) ||
@@ -1184,6 +1769,9 @@ void *fm_config(struct fm_params_t *p_fm_param) /* Initialize FM parameters which will be kept by the driver */ p_fm->p_fm_state_struct->fm_id = p_fm_param->fm_id; + for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS; i++) + p_fm->p_fm_state_struct->ports_types[i] = FM_PORT_TYPE_DUMMY; + /* Allocate the FM driver's parameters structure */ p_fm->p_fm_drv_param = kzalloc(sizeof(*p_fm->p_fm_drv_param), GFP_KERNEL);
diff --git a/drivers/soc/fsl/fman/fm_common.h b/drivers/soc/fsl/fman/fm_common.h
index 75ba185..fdc20fe 100644
--- a/drivers/soc/fsl/fman/fm_common.h
+++ b/drivers/soc/fsl/fman/fm_common.h@@ -42,6 +42,25 @@ #define CLS_PLAN_NUM_PER_GRP 8 +/* PCD CTRL Parameters Page */ +struct fm_pcd_ctrl_params_page_t { + uint8_t reserved0[16]; + uint8_t reserved1[24]; + uint8_t reserved2[12]; + uint32_t misc; + uint32_t errors_discard_mask; + uint32_t discard_mask; + uint8_t reserved3[180]; +} __attribute__((__packed__)); + +/* Defines used for manipulation CC and BMI */ +#define UPDATE_NIA_PNEN 0x80000000 +#define UPDATE_NIA_PNDN 0x20000000 +#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000 +#define UPDATE_NIA_FENE 0x04000000 +#define UPDATE_NIA_CMNE 0x02000000 +#define UPDATE_NIA_FPNE 0x01000000 + /* list_object * Macro to get the struct (object) for this entry. * type - The type of the struct (object) this list
@@ -54,6 +73,12 @@ #define list_object(p_list, type, member) \ ((type *)((char *)(p_list) - member_offset(type, member))) +#define FM_LIODN_OFFSET_MASK 0x3FF + +/* NIA Description */ +/* V3 only */ +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 + /* Enum for inter-module interrupts registration */ enum fm_event_modules { FM_MOD_PRS = 0, /* Parser event */
@@ -169,6 +194,59 @@ static inline bool TRY_LOCK(spinlock_t *spinlock, volatile bool *p_flag) #define FM_LIODN_OFFSET_MASK 0x3FF +/* NIA Description */ +#define NIA_ENG_MASK 0x007C0000 +#define NIA_AC_MASK 0x0003ffff + +#define NIA_ORDER_RESTOR 0x00800000 +#define NIA_ENG_FM_CTL 0x00000000 +#define NIA_ENG_PRS 0x00440000 +#define NIA_ENG_BMI 0x00500000 +#define NIA_ENG_QMI_ENQ 0x00540000 +#define NIA_ENG_QMI_DEQ 0x00580000 + +#define NIA_FM_CTL_AC_HC 0x0000000C +#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008 +#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A +#define NIA_FM_CTL_AC_POP_TO_N_STEP 0x0000000e +#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER 0x00000010 +#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME 0x00000018 +#define NIA_FM_CTL_AC_POST_BMI_FETCH 0x00000012 +#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME 0x0000001A +#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME 0x0000001E +#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR 0x00000014 +#define NIA_FM_CTL_AC_POST_BMI_ENQ 0x00000022 +#define NIA_FM_CTL_AC_POST_TX 0x00000024 +/* V3 only */ +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME 0x0000002A +#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP 0x0000002C + +#define NIA_BMI_AC_ENQ_FRAME 0x00000002 +#define NIA_BMI_AC_TX_RELEASE 0x000002C0 +#define NIA_BMI_AC_RELEASE 0x000000C0 +#define NIA_BMI_AC_DISCARD 0x000000C1 +#define NIA_BMI_AC_TX 0x00000274 +#define NIA_BMI_AC_FETCH 0x00000208 +#define NIA_BMI_AC_MASK 0x000003FF + +#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202 + +#define GET_NIA_BMI_AC_ENQ_FRAME(GET_NIA_BMI_AC_ENQ_FRAME, errata_A006675)\ + (errata_A006675 ? \ + ((uint32_t)(NIA_ENG_FM_CTL | \ + NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)) : \ + ((uint32_t)(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) +#define GET_NIA_BMI_AC_DISCARD_FRAME(h_fm_pcd, errata_A006675) \ + (errata_A006675 ? \ + ((uint32_t)(NIA_ENG_FM_CTL | \ + NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME)) : \ + ((uint32_t)(NIA_ENG_BMI | NIA_BMI_AC_DISCARD))) +#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME(errata_A006675) \ + (errata_A006675 ? \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME) :\ + (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + /* Description CTRL Parameters Page defines */ #define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000 #define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100
@@ -199,6 +277,20 @@ do { \ } \ } while (0) +#define HW_PORT_ID_TO_SW_PORT_ID(major, _mac_id, port_id) \ +do { \ + if (port_id >= BASE_TX_PORTID) \ + _mac_id = (uint8_t)(port_id - BASE_TX_PORTID); \ + else if (port_id >= BASE_RX_PORTID) \ + _mac_id = (uint8_t)(port_id - BASE_RX_PORTID); \ + else if (port_id >= BASE_OH_PORTID(major)) \ + _mac_id = (uint8_t)(port_id - BASE_OH_PORTID(major)); \ + else { \ + _mac_id = (uint8_t)DUMMY_PORT_ID; \ + ASSERT(true); \ + } \ +} while (0) + #define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) #define BMI_FIFO_UNITS 0x100
@@ -284,6 +376,17 @@ int fm_pcd_prs_include_port_in_statistics(void *p_fm_pcd, uint8_t port_id, bool include); +/* Common API for FM-Port module */ + +enum fm_port_gpr_func_type { + FM_PORT_GPR_EMPTY = 0, + FM_PORT_GPR_MURAM_PAGE +}; + +int fm_port_set_gpr_func(void *h_fm_port, + enum fm_port_gpr_func_type gpr_func, + void **p_value); + /* Function fm_register_intr * Description Used to register * an inter-module event handler to be processed by FM
@@ -322,6 +425,55 @@ enum fm_mac_type { FM_MAC_1G /* 1G MAC */ }; +/* Description Structure for port-FM communication + * during fm_port_init. Fields commented 'IN' are passed + * by the port module to be used by the FM module. + * Fields commented 'OUT' will be filled by FM before returning to port. + * Some fields are optional (depending on configuration) and + * will be analized by the port and FM modules accordingly. + */ +struct fm_inter_module_port_init_params_t { + uint8_t port_id; + /* IN. port Id */ + enum fm_port_type port_type; + /* IN. Port type */ + enum fm_port_speed port_speed; + /* IN. Port speed */ + /* IN. Port's requested resource*/ + uint16_t liodn_offset; + /* IN. Port's requested resource */ + uint8_t num_of_tasks; + /* IN. Port's requested resource */ + uint8_t num_of_extra_tasks; + /* IN. Port's requested resource */ + uint8_t num_of_open_dmas; + /* IN. Port's requested resource */ + uint8_t num_of_extra_open_dmas; + /* IN. Port's requested resource */ + uint32_t size_of_fifo; + /* IN. Port's requested resource */ + uint32_t extra_size_of_fifo; + /* IN. Port's requested resource */ + uint8_t deq_pipeline_depth; + /* IN. Port's max frame length. */ + uint16_t max_frame_length; + /* IN. Irrelevant for P4080 rev 1. + * LIODN base for this port, to be + * used together with LIODN offset. + */ + uint16_t liodn_base; + /* OUT. FM-MURAM physical address*/ + struct fm_phys_addr_t fm_muram_phys_base_addr; +}; + +/* Description Structure for port-FM communication during fm_port_free.*/ +struct fm_inter_module_port_free_params_t { + uint8_t port_id; /* IN. port Id */ + enum fm_port_type port_type; /* IN. Port type */ + enum fm_port_speed port_speed; /* IN. Port speed */ + uint8_t deq_pipeline_depth; /* IN. Port's requested resource */ +}; + /* Function fm_get_pcd_prs_base_addr * Description Get the base address of the Parser from the FM module * Param[in] h_fm A handle to an FM Module.
@@ -384,6 +536,29 @@ uint16_t fm_get_clock_freq(void *h_fm); */ uint8_t fm_get_id(void *h_fm); +/* Function fm_get_set_port_params + * Description Used by FM-PORT driver to pass and receive parameters between + * PORT and FM modules. + * Param[in] h_fm A handle to an FM Module. + * Param[in,out] p_port_params A structure of FM Port parameters. + * Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_init(). + */ +int fm_get_set_port_params(void *h_fm, + struct fm_inter_module_port_init_params_t + *p_port_params); + +/* Function fm_free_port_params + * Description Used by FM-PORT driver to free port's resources within the FM. + * Param[in] h_fm A handle to an FM Module. + * Param[in,out] p_port_params A structure of FM Port parameters. + * Return None. + * Cautions Allowed only following fm_init(). + */ +void fm_free_port_params(void *h_fm, + struct fm_inter_module_port_free_params_t + *p_port_params); + /* Function fm_set_num_of_riscs_per_port * Description Used by FM-PORT driver to pass parameter between * PORT and FM modules for working with number of RISC..
@@ -448,5 +623,22 @@ int fm_get_port_prefetch_cfg(void *h_fm, uint8_t port_num, int fm_set_mac_max_frame(void *h_fm, enum fm_mac_type type, uint8_t mac_id, uint16_t mtu); +int fm_set_num_of_open_dmas(void *h_fm, + uint8_t port_id, + uint8_t *p_num_of_open_dmas, + uint8_t *p_num_of_extra_open_dmas, + bool initial_config); +int fm_set_num_of_tasks(void *h_fm, + uint8_t port_id, + uint8_t *p_num_of_tasks, + uint8_t *p_num_of_extra_tasks, + bool initial_config); +int fm_set_size_of_fifo(void *h_fm, + uint8_t port_id, + uint32_t *p_size_of_fifo, + uint32_t *p_extra_size_of_fifo, + bool initial_config); + +uint32_t fm_get_bmi_max_fifo_size(void *h_fm); #endif /* __FM_COMMON_H */
diff --git a/drivers/soc/fsl/fman/fm_drv.c b/drivers/soc/fsl/fman/fm_drv.c
index cacd318..827367a 100644
--- a/drivers/soc/fsl/fman/fm_drv.c
+++ b/drivers/soc/fsl/fman/fm_drv.c@@ -271,6 +271,73 @@ static int init_fm_pcd_dev(struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev) } #endif +static int fill_rest_fm_info(struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev) +{ +#define FM_BMI_PPIDS_OFFSET 0x00080304 +#define FM_DMA_PLR_OFFSET 0x000c2060 +#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4 +#define DMA_HIGH_LIODN_MASK 0x0FFF0000 +#define DMA_LOW_LIODN_MASK 0x00000FFF +#define DMA_LIODN_SHIFT 16 + +/* These need to be moved to FLib: */ + struct plr_t { + uint32_t plr[32]; + } __attribute__((__packed__)); + + struct ppids_t { + volatile uint32_t fmbm_ppid[63]; + } __attribute__((__packed__)); + + struct plr_t *p_plr; + struct ppids_t *p_ppids; + int i; + uint32_t fm_rev; + + fm_rev = (uint32_t)(*((volatile uint32_t *) + UINT_TO_PTR(p_lnx_wrp_fm_dev->fm_base_addr + + FM_FPM_IP_REV_1_OFFSET))); + fm_rev &= 0xffff; + + p_plr = + (struct plr_t *)UINT_TO_PTR(p_lnx_wrp_fm_dev->fm_base_addr + + FM_DMA_PLR_OFFSET); +#ifdef MODULE + for (i = 0; i < FM_MAX_NUM_OF_PARTITIONS / 2; i++) + p_plr->plr[i] = 0; +#endif /* MODULE */ + + for (i = 0; i < FM_MAX_NUM_OF_PARTITIONS; i++) { + uint16_t liodn_base; + + liodn_base = (uint16_t)((i % 2) ? + (p_plr->plr[i / 2] & DMA_LOW_LIODN_MASK) : + ((p_plr->plr[i / 2] & DMA_HIGH_LIODN_MASK) >> + DMA_LIODN_SHIFT)); +#ifdef FM_PARTITION_ARRAY + p_lnx_wrp_fm_dev->params.liodn_base_per_port[i] = liodn_base; +#endif /* FM_PARTITION_ARRAY */ + + if (((i >= FIRST_RX_PORT) && (i <= LAST_RX_PORT)) || + ((i >= FIRST_TX_PORT) && (i <= FIRST_TX_PORT)) || + ((i >= FIRST_OP_PORT( + p_lnx_wrp_fm_dev->fm_rev_info.major_rev)) && + (i <= LAST_OP_PORT))) + p_lnx_wrp_fm_dev->ports[i].port_params.liodn_base = + liodn_base; + } + + p_ppids = (struct ppids_t *) + UINT_TO_PTR(p_lnx_wrp_fm_dev->fm_base_addr + + FM_BMI_PPIDS_OFFSET); + + for (i = FIRST_RX_PORT; i <= LAST_RX_PORT; i++) + p_lnx_wrp_fm_dev->ports[i].port_params.specific_params. + rx_params.liodn_offset = (u16)(p_ppids->fmbm_ppid[i - 1]); + + return 0; +} + /** *find_fman_microcode - find the Fman microcode *
@@ -681,7 +748,7 @@ static int configure_fm_dev(struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev) p_lnx_wrp_fm_dev->params.f_bus_error = lnxwrp_fm_dev_bus_error_cb; p_lnx_wrp_fm_dev->params.h_app = p_lnx_wrp_fm_dev; - return 0; + return fill_rest_fm_info(p_lnx_wrp_fm_dev); } static int init_fm_dev(struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev)
@@ -999,6 +1066,121 @@ void *fm_get_rtc_handle(struct fm *fm) EXPORT_SYMBOL(fm_get_rtc_handle); #endif +struct fm_port *fm_port_bind(struct device *fm_port_dev) +{ + return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev))); +} +EXPORT_SYMBOL(fm_port_bind); + +void fm_port_unbind(struct fm_port *port) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + put_device(p_lnx_wrp_fm_port_dev->dev); +} +EXPORT_SYMBOL(fm_port_unbind); + +void *fm_port_get_handle(const struct fm_port *port) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + return (void *)p_lnx_wrp_fm_port_dev->h_dev; +} +EXPORT_SYMBOL(fm_port_get_handle); + +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + *base_addr = p_lnx_wrp_fm_port_dev->port_params.base_addr; +} +EXPORT_SYMBOL(fm_port_get_base_addr); + +#ifdef CONFIG_FSL_FMAN_PCD +void fm_port_pcd_bind(struct fm_port *port, struct fm_port_pcd_param *params) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + p_lnx_wrp_fm_port_dev->pcd_owner_params.cba = params->cba; + p_lnx_wrp_fm_port_dev->pcd_owner_params.cbf = params->cbf; + p_lnx_wrp_fm_port_dev->pcd_owner_params.dev = params->dev; +} +EXPORT_SYMBOL(fm_port_pcd_bind); +#endif + +void fm_port_get_buff_layout_ext_params(struct fm_port *port, + struct fm_port_params *params) +{ + /* TODO - Should this function be removed? */ + params->data_align = 0; +} +EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params); + +int fm_get_tx_port_channel(struct fm_port *port) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + return p_lnx_wrp_fm_port_dev->tx_ch; +} +EXPORT_SYMBOL(fm_get_tx_port_channel); + +int fm_port_set_rate_limit(struct fm_port *port, + uint16_t max_burst_size, uint32_t rate_limit) +{ + struct fm_port_rate_limit_t param; + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + int err = 0; + + param.max_burst_size = max_burst_size; + param.rate_limit = rate_limit; + param.rate_limit_divider = 0; + + err = fm_port_set_rate_lim(p_lnx_wrp_fm_port_dev->h_dev, ¶m); + return err; +} +EXPORT_SYMBOL(fm_port_set_rate_limit); + +int fm_port_del_rate_limit(struct fm_port *port) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + fm_port_delete_rate_limit(p_lnx_wrp_fm_port_dev->h_dev); + return 0; +} +EXPORT_SYMBOL(fm_port_del_rate_limit); + +#ifdef CONFIG_FMAN_PFC +int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port, + uint8_t prio, uint8_t wq) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + int err; + + /* CONFIG_FMAN_PFC must not be used for FMan V2 platforms */ + if (p_lnx_wrp_fm_port_dev->fm_rev_info.major_rev < 6) { + WARN_ON(true); + return -EINVAL; + } + + err = fm_port_set_pfc_priorities_mapping_to_qman_wq( + p_lnx_wrp_fm_port_dev->h_dev, prio, wq); + if (unlikely(err < 0)) + pr_err("fm_port_set_pfc_priorities_mapping_to_qman_wq() = 0x%08x\n", + err); + + return err; +} +EXPORT_SYMBOL(fm_port_set_pfc_priorities_mapping_to_qman_wq); +#endif + void fm_mutex_lock(void) { mutex_lock(&lnxwrp_mutex);
diff --git a/drivers/soc/fsl/fman/fm_drv.h b/drivers/soc/fsl/fman/fm_drv.h
index 3905795..e362421 100644
--- a/drivers/soc/fsl/fman/fm_drv.h
+++ b/drivers/soc/fsl/fman/fm_drv.h@@ -75,7 +75,9 @@ struct lnx_wrp_fm_port_dev_t { uint64_t phys_base_addr; uint64_t base_addr; /* Port's *virtual* address */ resource_size_t mem_size; + struct fm_port_params_t port_params; #ifdef CONFIG_FSL_FMAN_PCD + struct fm_port_pcd_param pcd_owner_params; enum lnx_wrp_fm_port_pcd_def_use_case def_pcd; #endif struct fm_buffer_prefix_content_t buff_prefix_content;
diff --git a/drivers/soc/fsl/fman/fm_port_drv.c b/drivers/soc/fsl/fman/fm_port_drv.c
new file mode 100644
index 0000000..fda15c2
--- /dev/null
+++ b/drivers/soc/fsl/fman/fm_port_drv.c@@ -0,0 +1,540 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * 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. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*File lnxwrp_fm_port.c + *Description FMD wrapper - FMan port functions. + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/cdev.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "fm_common.h" +#include "fsl_fman_drv.h" +#include "fm_port_ext.h" +#include "fm_drv.h" + +static struct lnx_wrp_fm_port_dev_t +*read_fm_port_dev_tree_node(struct platform_device *of_dev) +{ + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev; + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev; + struct device_node *fm_node, *port_node; + struct resource res; + const uint32_t *uint32_prop; + int _errno = 0, lenp; + enum fm_port_type port_type; + enum fm_port_speed port_speed; + u8 cell_index; + + port_node = of_node_get(of_dev->dev.of_node); + + /* Get the FM node */ + fm_node = of_get_parent(port_node); + if (unlikely(!fm_node)) { + pr_err("of_get_parent() = %d\n", _errno); + return NULL; + } + + p_lnx_wrp_fm_dev = dev_get_drvdata(&of_find_device_by_node(fm_node)-> + dev); + of_node_put(fm_node); + + /* if fm_probe() failed, no point in going further with port probing */ + if (!p_lnx_wrp_fm_dev) + return NULL; + + uint32_prop = + (uint32_t *)of_get_property(port_node, "cell-index", &lenp); + if (unlikely(!uint32_prop)) { + pr_err("of_get_property(%s, cell-index) failed\n", + port_node->full_name); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + cell_index = (u8)*uint32_prop; + + p_lnx_wrp_fm_port_dev = &p_lnx_wrp_fm_dev->ports[cell_index]; + p_lnx_wrp_fm_port_dev->id = cell_index; + p_lnx_wrp_fm_port_dev->port_params.port_id = + p_lnx_wrp_fm_port_dev->id; + + if (of_device_is_compatible(port_node, "fsl,fman-v2-port-oh") || + of_device_is_compatible(port_node, "fsl,fman-v3-port-oh")) { + port_type = FM_PORT_TYPE_OP; + port_speed = FM_PORT_SPEED_OP; + + } else if (of_device_is_compatible(port_node, + "fsl,fman-v3-port-tx") || + of_device_is_compatible(port_node, + "fsl,fman-v2-port-tx")) { + if (cell_index >= TX_10G_PORT_BASE) + port_speed = FM_PORT_SPEED_10G; + else + port_speed = FM_PORT_SPEED_1G; + port_type = FM_PORT_TYPE_TX; + + } else if (of_device_is_compatible(port_node, + "fsl,fman-v3-port-rx") || + of_device_is_compatible(port_node, + "fsl,fman-v2-port-rx")) { + if (cell_index >= RX_10G_PORT_BASE) + port_speed = FM_PORT_SPEED_10G; + else + port_speed = FM_PORT_SPEED_1G; + port_type = FM_PORT_TYPE_RX; + if (p_lnx_wrp_fm_dev->pcd_active) + p_lnx_wrp_fm_port_dev->def_pcd = + p_lnx_wrp_fm_dev->def_pcd; + + } else { + pr_err("Illegal port type\n"); + return NULL; + } + + p_lnx_wrp_fm_port_dev->port_params.port_type = port_type; + p_lnx_wrp_fm_port_dev->port_params.port_speed = port_speed; + + if (port_type == FM_PORT_TYPE_OP || port_type == FM_PORT_TYPE_TX) { + uint32_t qman_channel_id; + + qman_channel_id = get_qman_channel_id(p_lnx_wrp_fm_dev, + cell_index, + port_type, + port_speed); + + if (qman_channel_id == 0) { + pr_err("incorrect qman-channel-id\n"); + return NULL; + } + p_lnx_wrp_fm_port_dev->tx_ch = qman_channel_id; + p_lnx_wrp_fm_port_dev->port_params.specific_params. + non_rx_params.qm_channel = qman_channel_id; + } + + _errno = of_address_to_resource(port_node, 0, &res); + if (unlikely(_errno < 0)) { + pr_err("of_address_to_resource() = %d\n", _errno); + return NULL; + } + + p_lnx_wrp_fm_port_dev->dev = &of_dev->dev; + p_lnx_wrp_fm_port_dev->base_addr = 0; + p_lnx_wrp_fm_port_dev->phys_base_addr = res.start; + p_lnx_wrp_fm_port_dev->mem_size = res.end + 1 - res.start; + p_lnx_wrp_fm_port_dev->port_params.h_fm = p_lnx_wrp_fm_dev->h_dev; + p_lnx_wrp_fm_port_dev->h_lnx_wrp_fm_dev = (void *)p_lnx_wrp_fm_dev; + + of_node_put(port_node); + + p_lnx_wrp_fm_port_dev->active = true; + + return p_lnx_wrp_fm_port_dev; +} + +static int configure_fm_port_dev(struct lnx_wrp_fm_port_dev_t + *p_lnx_wrp_fm_port_dev) +{ + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev = + (struct lnx_wrp_fm_dev_t *)p_lnx_wrp_fm_port_dev->h_lnx_wrp_fm_dev; + struct resource *dev_res; + + if (!p_lnx_wrp_fm_port_dev->active) { + pr_err("FM port not configured!!!\n"); + return -ENOSYS; + } + + dev_res = + __devm_request_region(p_lnx_wrp_fm_dev->dev, p_lnx_wrp_fm_dev->res, + p_lnx_wrp_fm_port_dev->phys_base_addr, + p_lnx_wrp_fm_port_dev->mem_size, + "fman-port-hc"); + if (unlikely(!dev_res)) { + pr_err("__devm_request_region() failed\n"); + return -ENOSYS; + } + p_lnx_wrp_fm_port_dev->base_addr = + PTR_TO_UINT(devm_ioremap + (p_lnx_wrp_fm_dev->dev, + p_lnx_wrp_fm_port_dev->phys_base_addr, + p_lnx_wrp_fm_port_dev->mem_size)); + if (unlikely(p_lnx_wrp_fm_port_dev->base_addr == 0)) + pr_err("devm_ioremap() failed\n"); + + p_lnx_wrp_fm_port_dev->port_params.base_addr = + p_lnx_wrp_fm_port_dev->base_addr; + + return 0; +} + +static int init_fm_port_dev(struct lnx_wrp_fm_port_dev_t + *p_lnx_wrp_fm_port_dev) +{ + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev = + (struct lnx_wrp_fm_dev_t *)p_lnx_wrp_fm_port_dev-> + h_lnx_wrp_fm_dev; + + if (!p_lnx_wrp_fm_port_dev->active || p_lnx_wrp_fm_port_dev->h_dev) + return -ENOSYS; + + p_lnx_wrp_fm_port_dev->h_dev = + fm_port_config(&p_lnx_wrp_fm_port_dev->port_params); + if (!p_lnx_wrp_fm_port_dev->h_dev) { + pr_err("FM-port\n"); + return -ENOSYS; + } + + if (fm_get_revision(p_lnx_wrp_fm_dev->h_dev, + &p_lnx_wrp_fm_port_dev->fm_rev_info) != 0) { + pr_err("FM-port\n"); + return -ENOSYS; + } + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if ((p_lnx_wrp_fm_port_dev->fm_rev_info.major_rev != 4) && + (p_lnx_wrp_fm_port_dev->port_params.port_type == + FM_PORT_TYPE_TX)) { + int err_code = 0; + + err_code = + fm_port_cfg_deq_high_priority(p_lnx_wrp_fm_port_dev-> + h_dev, true); + if (err_code != 0) + return -err_code; + err_code = + fm_port_cfg_deq_prefetch_option + (p_lnx_wrp_fm_port_dev->h_dev, FM_PORT_DEQ_FULL_PREFETCH); + if (err_code != 0) + return -err_code; + } +#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + +#ifdef FM_BCB_ERRATA_BMI_SW001 +/* Configure BCB workaround on Rx ports, only for B4860 rev1 */ +#define SVR_SECURITY_MASK 0x00080000 +#define SVR_PERSONALITY_MASK 0x0000FF00 +#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK) +#define SVR_B4860_REV1_VALUE 0x86800010 + + if ((p_lnx_wrp_fm_port_dev->fm_rev_info.major_rev >= 6) && + (p_lnx_wrp_fm_port_dev->port_params.port_type == + FM_PORT_TYPE_RX)){ + unsigned int svr; + + svr = mfspr(SPRN_SVR); + + if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE) + fm_port_cfg_bcb_wa(p_lnx_wrp_fm_port_dev->h_dev); + } +#endif /* FM_BCB_ERRATA_BMI_SW001 */ + + fm_port_cfg_buf_prefix_content(p_lnx_wrp_fm_port_dev->h_dev, + &p_lnx_wrp_fm_port_dev-> + buff_prefix_content); + + if (fm_port_init(p_lnx_wrp_fm_port_dev->h_dev) != 0) + return -ENOSYS; + +/** + * FMan Fifo sizes behind the scene": + * Using the following formulae (*), under a set of simplifying assumptions (.): + * . all ports are configured in Normal Mode (rather than Independent Mode) + * . the DPAA Eth driver allocates buffers of size: + * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE + * + DPA_HASH_RESULTS_SIZE, i.e.: + * MAXFRM + 2 + 16 + sizeof(fm_prs_result_t) + 16, i.e.: + * MAXFRM + 66 + * . excessive buffer pools not accounted for + * + **for Rx ports on P4080: + * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256)*256 + 7*256 + * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + **for Rx ports on P1023: + * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256))*256 + 7*256, + * if at least 2 bpools are configured + * . IFSZ = 8*256, if only a single bpool is configured + * + **for Tx ports: + * . IFSZ = ceil(frame_size / 256)*256 + 3*256 + * + FMBM_TFP[DPDE]*256, i.e.: + * IFSZ = ceil(MAXFRM / 256)*256 + 3 x 256 + FMBM_TFP[DPDE]*256 + * + **for OH ports on P4080: + * . IFSZ = ceil(frame_size / 256)*256 + 1*256 + FMBM_PP[MXT]*256 + **for OH ports on P1023: + * . IFSZ = ceil(frame_size / 256)*256 + 3*256 + FMBM_TFP[DPDE]*256 + **for both P4080 and P1023: + * . (conservative decisions, assuming that BMI must bring the entire + * frame, not only the frame header) + * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + * . for P4080/P5020/P3041/P2040, DPDE is: + * > 0 or 1, for 1Gb ports, HW default: 0 + * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3 + * . for P1023, DPDE should be 1 + * + * . for P1023, MXT is in range (0..31) + * . for P4080, MXT is in range (0..63) + * + */ + return 0; +} + +void fm_set_rx_port_params(struct fm_port *port, struct fm_port_params *params) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + int i; + + p_lnx_wrp_fm_port_dev->port_params.specific_params. + rx_params.err_fqid = params->errq; + p_lnx_wrp_fm_port_dev->port_params.specific_params.rx_params. + dflt_fqid = params->defq; + p_lnx_wrp_fm_port_dev->port_params.specific_params.rx_params. + ext_buf_pools.num_of_pools_used = params->num_pools; + for (i = 0; i < params->num_pools; i++) { + p_lnx_wrp_fm_port_dev->port_params.specific_params. + rx_params.ext_buf_pools.ext_buf_pool[i].id = + params->pool_param[i].id; + p_lnx_wrp_fm_port_dev->port_params.specific_params. + rx_params.ext_buf_pools.ext_buf_pool[i].size = + params->pool_param[i].size; + } + + p_lnx_wrp_fm_port_dev->buff_prefix_content.priv_data_size = + params->priv_data_size; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_prs_result = + params->parse_results; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_hash_result = + params->hash_results; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_time_stamp = + params->time_stamp; + p_lnx_wrp_fm_port_dev->buff_prefix_content.data_align = + params->data_align; + + init_fm_port_dev(p_lnx_wrp_fm_port_dev); +} +EXPORT_SYMBOL(fm_set_rx_port_params); + +/* this function is called from oh_probe as well, thus it contains oh port + * specific parameters (make sure everything is checked) + **/ +void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev = + (struct lnx_wrp_fm_port_dev_t *)port; + + p_lnx_wrp_fm_port_dev->port_params.specific_params.non_rx_params. + err_fqid = params->errq; + p_lnx_wrp_fm_port_dev->port_params.specific_params.non_rx_params. + dflt_fqid = params->defq; + + p_lnx_wrp_fm_port_dev->buff_prefix_content.priv_data_size = + params->priv_data_size; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_prs_result = + params->parse_results; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_hash_result = + params->hash_results; + p_lnx_wrp_fm_port_dev->buff_prefix_content.pass_time_stamp = + params->time_stamp; + p_lnx_wrp_fm_port_dev->buff_prefix_content.data_align = + params->data_align; + + init_fm_port_dev(p_lnx_wrp_fm_port_dev); +} +EXPORT_SYMBOL(fm_set_tx_port_params); + +static void free_fm_port_dev(struct lnx_wrp_fm_port_dev_t + *p_lnx_wrp_fm_port_dev) +{ + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev = + (struct lnx_wrp_fm_dev_t *)p_lnx_wrp_fm_port_dev->h_lnx_wrp_fm_dev; + + if (!p_lnx_wrp_fm_port_dev->active) + return; + + if (p_lnx_wrp_fm_port_dev->h_dev) + fm_port_free((struct fm_port *)p_lnx_wrp_fm_port_dev); + + devm_iounmap(p_lnx_wrp_fm_dev->dev, + UINT_TO_PTR(p_lnx_wrp_fm_port_dev->base_addr)); + __devm_release_region(p_lnx_wrp_fm_dev->dev, p_lnx_wrp_fm_dev->res, + p_lnx_wrp_fm_port_dev->phys_base_addr, + p_lnx_wrp_fm_port_dev->mem_size); +} + +static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev; + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev; + struct device *dev; + + dev = &of_dev->dev; + + p_lnx_wrp_fm_port_dev = read_fm_port_dev_tree_node(of_dev); + if (!p_lnx_wrp_fm_port_dev) + return -EIO; + /* Port can be inactive, thus will not be probed: + * - in performance mode, OH ports are disabled ... + **/ + if (!p_lnx_wrp_fm_port_dev->active) + return 0; + + if (configure_fm_port_dev(p_lnx_wrp_fm_port_dev) != 0) + return -EIO; + + dev_set_drvdata(dev, p_lnx_wrp_fm_port_dev); + + p_lnx_wrp_fm_dev = (struct lnx_wrp_fm_dev_t *)p_lnx_wrp_fm_port_dev-> + h_lnx_wrp_fm_dev; + + if (p_lnx_wrp_fm_port_dev->port_params.port_type == + FM_PORT_TYPE_RX) { + snprintf(p_lnx_wrp_fm_port_dev->name, + sizeof(p_lnx_wrp_fm_port_dev->name), + "%s-port-rx%d", + p_lnx_wrp_fm_dev->name, p_lnx_wrp_fm_port_dev->id); + } else if (p_lnx_wrp_fm_port_dev->port_params.port_type == + FM_PORT_TYPE_TX) { + snprintf(p_lnx_wrp_fm_port_dev->name, + sizeof(p_lnx_wrp_fm_port_dev->name), + "%s-port-tx%d", + p_lnx_wrp_fm_dev->name, p_lnx_wrp_fm_port_dev->id); + } else if (p_lnx_wrp_fm_port_dev->port_params.port_type == + FM_PORT_TYPE_OP) { + snprintf(p_lnx_wrp_fm_port_dev->name, + sizeof(p_lnx_wrp_fm_port_dev->name), + "%s-port-oh%d", + p_lnx_wrp_fm_dev->name, p_lnx_wrp_fm_port_dev->id + 1); + } +#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 + if (p_lnx_wrp_fm_port_dev->fm_rev_info.major_rev < 6 && + p_lnx_wrp_fm_port_dev->fm_rev_info.major_rev != 4) + fm_disable_rams_ecc(p_lnx_wrp_fm_dev->h_dev); +#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */ + + pr_debug("%s probed\n", p_lnx_wrp_fm_port_dev->name); + + return 0; +} + +static int fm_port_remove(struct platform_device *of_dev) +{ + struct lnx_wrp_fm_port_dev_t *p_lnx_wrp_fm_port_dev; + struct lnx_wrp_fm_dev_t *p_lnx_wrp_fm_dev; + struct device *dev; + + dev = &of_dev->dev; + p_lnx_wrp_fm_port_dev = dev_get_drvdata(dev); + + p_lnx_wrp_fm_dev = (struct lnx_wrp_fm_dev_t *)p_lnx_wrp_fm_port_dev-> + h_lnx_wrp_fm_dev; + + free_fm_port_dev(p_lnx_wrp_fm_port_dev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id fm_port_match[] = { + { + .compatible = "fsl,fman-v3-port-oh"}, + { + .compatible = "fsl,fman-v2-port-oh"}, + { + .compatible = "fsl,fman-v3-port-rx"}, + { + .compatible = "fsl,fman-v2-port-rx"}, + { + .compatible = "fsl,fman-v3-port-tx"}, + { + .compatible = "fsl,fman-v2-port-tx"}, + {} +}; + +#ifndef MODULE +MODULE_DEVICE_TABLE(of, fm_port_match); +#endif /* !MODULE */ + +static struct platform_driver fm_port_driver = { + .driver = { + .name = "fsl-fman-port", + .of_match_table = fm_port_match, + .owner = THIS_MODULE, + }, + .probe = fm_port_probe, + .remove = fm_port_remove +}; + +int lnxwrp_fm_port_init(void) +{ + /* Register to the DTB for basic FM port API */ + if (platform_driver_register(&fm_port_driver)) + return -ENODEV; + + return 0; +} + +void lnxwrp_fm_port_free(void) +{ + platform_driver_unregister(&fm_port_driver); +} + +static int __init __cold fm_port_load(void) +{ + if (lnxwrp_fm_port_init() != 0) { + pr_crit("Failed to init FM Ports wrapper!\n"); + return -ENODEV; + } + + pr_info("Freescale FM Ports module\n"); + + return 0; +} + +static void __exit __cold fm_port_unload(void) +{ + lnxwrp_fm_port_free(); +} + +module_init(fm_port_load); +module_exit(fm_port_unload);
diff --git a/drivers/soc/fsl/fman/inc/fm_ext.h b/drivers/soc/fsl/fman/inc/fm_ext.h
index 3d1c86c..01e00dc 100644
--- a/drivers/soc/fsl/fman/inc/fm_ext.h
+++ b/drivers/soc/fsl/fman/inc/fm_ext.h@@ -58,6 +58,64 @@ enum fm_port_speed { #define FM_MAX_NUM_OF_PARTITIONS 64 /* Maximum number of partitions */ #define FM_PHYS_ADDRESS_SIZE 6 /* FM Physical address size */ +/* FM Frame descriptor macros */ +/* Frame queue Context Override */ +#define FM_FD_CMD_FCO 0x80000000 +#define FM_FD_CMD_RPD 0x40000000 /* Read Prepended Data */ +/* Update Prepended Data */ +#define FM_FD_CMD_UPD 0x20000000 +#define FM_FD_CMD_DTC 0x10000000 /* Do L4 Checksum */ +/* Didn't calculate L4 Checksum */ +#define FM_FD_CMD_DCL4C 0x10000000 +/* Confirmation Frame Queue */ +#define FM_FD_CMD_CFQ 0x00ffffff + +/* Not for Rx-Port! Unsupported Format */ +#define FM_FD_ERR_UNSUPPORTED_FORMAT 0x04000000 +/* Not for Rx-Port! Length Error */ +#define FM_FD_ERR_LENGTH 0x02000000 +#define FM_FD_ERR_DMA 0x01000000 /* DMA Data error */ + +/* IPR frame (not error) */ +#define FM_FD_IPR 0x00000001 +/* IPR non-consistent-sp */ +#define FM_FD_ERR_IPR_NCSP (0x00100000 | FM_FD_IPR) +/* IPR error */ +#define FM_FD_ERR_IPR (0x00200000 | FM_FD_IPR) +/* IPR timeout */ +#define FM_FD_ERR_IPR_TO (0x00300000 | FM_FD_IPR) + +/* Rx FIFO overflow, FCS error, code error, running disparity error + * (SGMII and TBI modes), FIFO parity error. PHY Sequence error, + * PHY error control character detected. + */ +#define FM_FD_ERR_PHYSICAL 0x00080000 +/* Frame too long OR Frame size exceeds max_length_frame */ +#define FM_FD_ERR_SIZE 0x00040000 +/* classification discard */ +#define FM_FD_ERR_CLS_DISCARD 0x00020000 +/* Extract Out of Frame */ +#define FM_FD_ERR_EXTRACTION 0x00008000 +/* No Scheme Selected */ +#define FM_FD_ERR_NO_SCHEME 0x00004000 +/* Keysize Overflow */ +#define FM_FD_ERR_KEYSIZE_OVERFLOW 0x00002000 +/* Frame color is red */ +#define FM_FD_ERR_COLOR_RED 0x00000800 +/* Frame color is yellow */ +#define FM_FD_ERR_COLOR_YELLOW 0x00000400 +/* Parser Time out Exceed */ +#define FM_FD_ERR_PRS_TIMEOUT 0x00000080 +/* Invalid Soft Parser instruction */ +#define FM_FD_ERR_PRS_ILL_INSTRUCT 0x00000040 +/* Header error was identified during parsing */ +#define FM_FD_ERR_PRS_HDR_ERR 0x00000020 +/* Frame parsed beyind 256 first bytes */ +#define FM_FD_ERR_BLOCK_LIMIT_EXCEEDED 0x00000008 + +/* non Frame-Manager error */ +#define FM_FD_RX_STATUS_ERR_NON_FM 0x00400000 + /* FM physical Address */ struct fm_phys_addr_t { uint8_t high; /* High part of the physical address */
diff --git a/drivers/soc/fsl/fman/inc/fm_port_ext.h b/drivers/soc/fsl/fman/inc/fm_port_ext.h
new file mode 100644
index 0000000..27204ab
--- /dev/null
+++ b/drivers/soc/fsl/fman/inc/fm_port_ext.h@@ -0,0 +1,650 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * 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. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*File fm_port_ext.h + *FM-Port Application Programming Interface. + */ +#ifndef __FM_PORT_EXT +#define __FM_PORT_EXT + +#include "service.h" +#include "fm_pcd_ext.h" +#include "fm_ext.h" +#include "net_ext.h" + +/* FM Port API + * The FM uses a general module called "port" to represent a Tx port (MAC), + * an Rx port (MAC) or Offline Parsing port. + * The number of ports in an FM varies between SOCs. + * The SW driver manages these ports as sub-modules of the FM,i.e. after an + * FM is initialized, its ports may be initialized and operated upon. + * The port is initialized aware of its type, but other functions on a port + * may be indifferent to its type. When necessary, the driver verifies + * coherence and returns error if applicable. + * On initialization, user specifies the port type and it's index (relative + * to the port's type) - always starting at 0. + */ + +/* An enum for defining port PCD modes. */ +enum fm_port_pcd_support { + FM_PORT_PCD_SUPPORT_NONE = 0 /* BMI to BMI, PCD is not used */ + , FM_PORT_PCD_SUPPORT_PRS_ONLY /* Use only Parser */ +}; + +/* Port interrupts */ +enum fm_port_exceptions { + FM_PORT_EXCEPTION_IM_BUSY /* Independent-Mode Rx-BUSY */ +}; + +/* General FM Port defines */ +/* Number of 4 bytes words in parser result */ +#define FM_PORT_PRS_RESULT_NUM_OF_WORDS 8 +/* @} */ + +/* FM Frame error */ +/* Frame Descriptor errors */ +/* Not for Rx-Port! Unsupported Format */ +#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT FM_FD_ERR_UNSUPPORTED_FORMAT +/* Not for Rx-Port! Length Error */ +#define FM_PORT_FRM_ERR_LENGTH FM_FD_ERR_LENGTH +/* DMA Data error */ +#define FM_PORT_FRM_ERR_DMA FM_FD_ERR_DMA +/* non Frame-Manager error; probably come from SEC that was chained to FM */ +#define FM_PORT_FRM_ERR_NON_FM FM_FD_RX_STATUS_ERR_NON_FM + /* IPR error */ +#define FM_PORT_FRM_ERR_IPRE (FM_FD_ERR_IPR & ~FM_FD_IPR) +/* IPR non-consistent-sp */ +#define FM_PORT_FRM_ERR_IPR_NCSP (FM_FD_ERR_IPR_NCSP & \ + ~FM_FD_IPR) + +/* Obsolete; will be removed in the future */ +#define FM_PORT_FRM_ERR_IPFE 0 + +/* Rx FIFO overflow, FCS error, code error, running disparity + * error (SGMII and TBI modes), FIFO parity error. + * PHY Sequence error, PHY error control character detected. + **/ +#define FM_PORT_FRM_ERR_PHYSICAL FM_FD_ERR_PHYSICAL +/* Frame too long OR Frame size exceeds max_length_frame */ +#define FM_PORT_FRM_ERR_SIZE FM_FD_ERR_SIZE +/* indicates a classifier "drop" operation */ +#define FM_PORT_FRM_ERR_CLS_DISCARD FM_FD_ERR_CLS_DISCARD +/* Extract Out of Frame */ +#define FM_PORT_FRM_ERR_EXTRACTION FM_FD_ERR_EXTRACTION +/* No Scheme Selected */ +#define FM_PORT_FRM_ERR_NO_SCHEME FM_FD_ERR_NO_SCHEME +/* Keysize Overflow */ +#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW FM_FD_ERR_KEYSIZE_OVERFLOW +/* Frame color is red */ +#define FM_PORT_FRM_ERR_COLOR_RED FM_FD_ERR_COLOR_RED +/* Frame color is yellow */ +#define FM_PORT_FRM_ERR_COLOR_YELLOW FM_FD_ERR_COLOR_YELLOW +/* Parser Time out Exceed */ +#define FM_PORT_FRM_ERR_PRS_TIMEOUT FM_FD_ERR_PRS_TIMEOUT +/* Invalid Soft Parser instruction */ +#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT FM_FD_ERR_PRS_ILL_INSTRUCT +/* Header error was identified during parsing */ +#define FM_PORT_FRM_ERR_PRS_HDR_ERR FM_FD_ERR_PRS_HDR_ERR +/* Frame parsed beyind 256 first bytes */ +#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED FM_FD_ERR_BLOCK_LIMIT_EXCEEDED +/* FPM Frame Processing Timeout Exceeded */ +#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001 + +/* FM Port Initialization Unit */ + +/*Description Exceptions user callback routine, will be called upon an + * exception passing the exception identification. + * Param[in] h_app - User's application descriptor. + * Param[in] exception - The exception. + */ +typedef void (fm_port_exception_cb) (void *h_app, + enum fm_port_exceptions exception); + +/* A structure for additional Rx port parameters */ +struct fm_port_rx_params_t { + uint32_t err_fqid; /* Error Queue Id. */ + uint32_t dflt_fqid; /* Default Queue Id. */ + uint16_t liodn_offset; /* Port's LIODN offset. */ + /* Which external buffer pools are used + * (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. + */ + struct fm_ext_pools_t ext_buf_pools; +}; + +/* A structure for additional non-Rx port parameters*/ +struct fm_port_non_rx_params_t { + /* Error Queue Id. */ + uint32_t err_fqid; + /* For Tx - Default Confirmation queue, 0 means no Tx confirmation + * for processed frames. For OP port - default Rx queue. + */ + uint32_t dflt_fqid; + /* QM-channel dedicated to this port; will be used + * by the FM for dequeue. + */ + uint32_t qm_channel; +}; + +/* A union for additional parameters depending on port type*/ +union fm_port_specific_params_u { + /* Rx port parameters structure */ + struct fm_port_rx_params_t rx_params; + /* Non-Rx port parameters structure */ + struct fm_port_non_rx_params_t non_rx_params; +}; + +/* A structure representing FM initialization parameters*/ +struct fm_port_params_t { + uintptr_t base_addr; + /* Virtual Address of memory mapped FM Port registers.*/ + void *h_fm; + /* A handle to the FM object this port related to */ + enum fm_port_type port_type; + /* Port type */ + enum fm_port_speed port_speed; + /* Port speed */ + uint8_t port_id; + /* Port Id - relative to type; + * NOTE: When configuring Offline Parsing port for FMANv3 devices, + * it is highly recommended NOT to use port_id=0 due to lack of HW + * resources on port_id=0. + */ + uint16_t liodn_base; + /* Irrelevant for P4080 rev 1. LIODN base for this port, to be + * used together with LIODN offset. + */ + union fm_port_specific_params_u specific_params; + /* Additional parameters depending on port type. */ + fm_port_exception_cb *f_exception; + /* Relevant for IM only Callback routine to be called on + * BUSY exception. + */ + void *h_app; + /* A handle to an application layer object; This handle will be + * passed by the driver upon calling the above callbacks + */ +}; + +struct fm_port; + +/*Function fm_port_config + *Description Creates a descriptor for the FM PORT module. + * The routine returns a handle (descriptor) to the FM PORT object. + * This descriptor must be passed as first parameter to all other + * FM PORT function calls. + * No actual initialization or configuration of FM hardware is + * done by this routine. + * Param[in] p_fm_port_params - Pointer to data structure of parameters + * Retval Handle to FM object, or NULL for Failure. + */ +void *fm_port_config(struct fm_port_params_t *p_fm_port_params); + +/*Function fm_port_init + *Description Initializes the FM PORT module by defining the + * software structure + * and configuring the hardware registers. + * Param[in] h_fm_port - FM PORT module descriptor + *Return 0 on success; Error code otherwise. + */ +int fm_port_init(void *h_fm_port); + +/*Function fm_port_free + *Description Frees all resources that were assigned to FM PORT module. + * Calling this routine invalidates the descriptor. + * Param[in] h_fm_port - FM PORT module descriptor + *Return 0 on success; Error code otherwise. + */ +int fm_port_free(struct fm_port *port); + +/* Configuration functions used to change default values. */ + +/* enum for defining QM frame dequeue*/ +enum fm_port_deq_type { + /* Dequeue from the SP channel - with priority precedence, + * and Intra-Class Scheduling respected. + */ + FM_PORT_DEQ_TYPE1, + /* Dequeue from the SP channel - with active FQ precedence, + * and Intra-Class Scheduling respected. + */ + FM_PORT_DEQ_TYPE2, + /* Dequeue from the SP channel - with active FQ precedence, + * and override Intra-Class Scheduling + */ + FM_PORT_DEQ_TYPE3 +}; + +/* enum for defining QM frame dequeue*/ +enum fm_port_deq_prefetch_option { + /* QMI preforms a dequeue action for a single frame only + * when a dedicated portID Tnum is waiting. + */ + FM_PORT_DEQ_NO_PREFETCH, + /* QMI preforms a dequeue action for 3 frames when one + * dedicated port_id tnum is waiting. + */ + FM_PORT_DEQ_PARTIAL_PREFETCH, + /* QMI preforms a dequeue action for 3 frames when + * no dedicated port_id tnums are waiting. + */ + FM_PORT_DEQ_FULL_PREFETCH +}; + +/* enum for defining port default color*/ +enum fm_port_color { + FM_PORT_COLOR_GREEN, /* Default port color is green */ + FM_PORT_COLOR_YELLOW, /* Default port color is yellow */ + FM_PORT_COLOR_RED, /* Default port color is red */ + FM_PORT_COLOR_OVERRIDE /* Ignore color */ +}; + +/* A structure for defining Dual Tx rate limiting scale*/ +enum fm_port_dual_rate_limiter_scale_down { + /* Use only single rate limiter */ + FM_PORT_DUAL_RATE_LIMITER_NONE = 0, + /* Divide high rate limiter by 2 */ + FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, + /* Divide high rate limiter by 4 */ + FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, + /* Divide high rate limiter by 8 */ + FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 +}; + +/* A structure for defining FM port resources*/ +struct fm_port_rsrc_t { + uint32_t num; /* Committed required resource */ + uint32_t extra; /* Extra (not committed) required resource */ +}; + +/* A structure for defining Tx rate limiting*/ +struct fm_port_rate_limit_t { + /* in KBytes for Tx ports, in frames for OP ports. (note that + * for early chips burst size is rounded up to a multiply of 1000 + * frames). + */ + uint16_t max_burst_size; + /* in Kb/sec for Tx ports, in frame/sec for OP ports. + * Rate limit refers to data rate (rather than line rate). + */ + uint32_t rate_limit; + /* For OP ports only. Not-valid for some earlier chip revisions */ + enum fm_port_dual_rate_limiter_scale_down rate_limit_divider; +}; + +/*Function fm_port_cfg_deq_high_priority + *Description Calling this routine changes the dequeue priority in the + * internal driver data base from its default configuration + * 1G: [DEFAULT_PORT_deq_high_priority_1G] + * 10G: [DEFAULT_PORT_deq_high_priority_10G] + * May be used for Non-Rx ports only + * Param[in] h_fm_port A handle to a FM Port module. + * Param[in] high_pri true to select high priority, false for + * normal operation. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_config() and before + * fm_port_init(). + */ +int fm_port_cfg_deq_high_priority(void *h_fm_port, bool high_pri); + +/*Function fm_port_cfg_deq_prefetch_option + *Description Calling this routine changes the dequeue prefetch option + parameter in the + * internal driver data base from its default configuration + * [DEFAULT_PORT_deq_prefetch_option] + * Note: Available for some chips only + * May be used for Non-Rx ports only + * Param[in] h_fm_port A handle to a FM Port module. + * Param[in] deq_prefetch_option New option + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_config() and before + * fm_port_init(). + */ +int fm_port_cfg_deq_prefetch_option(void *h_fm_port, + enum fm_port_deq_prefetch_option + deq_prefetch_option); + +/*Function fm_port_cfg_buf_prefix_content + *Description Defines the structure, size and content of the + * application buffer. + * The prefix will + * In Tx ports, if 'pass_prs_result', the application + * should set a value to their offsets in the prefix of + * the FM will save the first 'priv_data_size', than, + * depending on 'pass_prs_result' and 'pass_time_stamp', + * copy parse result and timeStamp, and the packet itself + * (in this order), to the application buffer, and to offset. + * Calling this routine changes the buffer margins definitions + * in the internal driver data base from its default + * configuration: + * Data size: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE] + * Pass Parser result: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_ + * PASS_PRS_RESULT]. + * Pass timestamp: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_ + * TIME_STAMP]. + * May be used for all ports + * Param[in] h_fm_port A handle to a FM Port module. + * Param[in,out] p_fm_buffer_prefix_content A structure of parameters + * describing the + * structure of the buffer. + * Out parameter: Start margin - + * offset + * of data from start of + * external buffer. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_config() and before + * fm_port_init(). + */ +int fm_port_cfg_buf_prefix_content(void *h_fm_port, + struct fm_buffer_prefix_content_t * + p_fm_buffer_prefix_content); + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 +/*Function fm_port_cfg_bcb_wa + *Description Configures BCB errata workaround. + * When BCB errata is applicable, the workaround is always + * performed by FM Controller. Thus, this functions doesn't + * actually enable errata workaround but rather allows driver + * to perform adjustments required due to errata workaround + * execution in FM controller. + * Applying BCB workaround also configures FM_PORT_FRM_ERR_PHYSICAL + * errors to be discarded. Thus FM_PORT_FRM_ERR_PHYSICAL can't be + * set by FM_PORT_SetErrorsRoute() function. + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_config() and before + * fm_port_init(). + */ +int fm_port_cfg_bcb_wa(void *h_fm_port); +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + +/* FM Port Runtime control unit API functions, definitions and enums. */ + +/* Structure for Port congestion groups parameters */ +struct fm_port_congestion_grps_t { + bool pfc_priorities_en[FM_PORT_NUM_OF_CONGESTION_GRPS] + /* a matrix that represents the map between the CG ids + * defined in 'congestionGrpsToConsider' to the priorties + * mapping array. + */ + [FM_MAX_NUM_OF_PFC_PRIORITIES]; +}; + +/*Function fm_port_get_buffer_time_stamp + *Description Returns the time stamp in the data buffer. + * Relevant for Rx ports for getting the buffer time stamp. + * See fm_port_cfg_buf_prefix_content for data buffer prefix + * configuration. + * Param[in] port - FM PORT module descriptor + * Param[in] p_data - A pointer to the data buffer. + *Return A pointer to the hash result on success, NULL otherwise. + * Cautions Allowed only following fm_port_init(). + */ +u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port, char *p_data); + +/*Function fm_port_disable + *Description Gracefully disable an FM port. The port will not start new + * tasks after all + * tasks associated with the port are terminated. + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + * This is a blocking routine, it returns after port is + * gracefully stopped, i.e. the port will not except new frames, + * but it will finish all frames or tasks which were already began + */ +int fm_port_disable(struct fm_port *port); + +int fm_port_suspend(struct fm_port *port); +/*Function fm_port_enable + *Description A runtime routine provided to allow disable/enable of port. + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + */ +int fm_port_enable(struct fm_port *port); + +int fm_port_resume(struct fm_port *port); +/*Function fm_port_set_rate_lim + *Description Calling this routine enables rate limit algorithm. + * By default, this functionality is disabled. + * Note that rate-limit mechanism uses the FM time stamp. + * The selected rate limit specified here would be + * rounded DOWN to the nearest 16M. + * May be used for Tx and OP ports only + * Param[in] h_fm_port A handle to a FM Port module. + * Param[in] p_rate_lim A structure of rate limit parameters + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + * If rate limit is set on a port that need to send PFC frames, + * it might violate the stop transmit timing. + */ +int fm_port_set_rate_lim(void *h_fm_port, struct fm_port_rate_limit_t + *p_rate_lim); + +/*Function fm_port_delete_rate_limit + *Description Calling this routine disables and clears rate limit + * initialization. + * May be used for Tx and OP ports only + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + */ +int fm_port_delete_rate_limit(void *h_fm_port); + +/*Group FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime + * Control Unit + *Description FM Port PCD Runtime control unit API functions, + * definitions and enums. + */ + +/* Union for defining port protocol parameters for parser*/ +union fm_pcd_hdr_prs_opts_u { + /* MPLS */ + struct { + /* When this bit is set, the last MPLS label will be + * interpreted as described in HW spec table. When the bit + * is cleared, the parser will advance to MPLS next parse + */ + bool label_interpretation_enable; + /* must be equal or higher than IPV4 */ + enum net_header_type next_parse; + } mpls_prs_options; + /* VLAN */ + struct { + /* User defined Tag Protocol Identifier, to be recognized + * on VLAN TAG on top of 0x8100 and 0x88A8 + */ + uint16_t tag_protocol_id1; + /* User defined Tag Protocol Identifier, to be recognized + * on VLAN TAG on top of 0x8100 and 0x88A8 + */ + uint16_t tag_protocol_id2; + } vlan_prs_options; + /* PPP */ + struct { + /* Check validity of MTU according to RFC2516 */ + bool enable_mtu_check; + } pppoe_prs_options; + + /* IPV6 */ + struct { + /* true to enable routing header, otherwise ignore */ + bool routing_hdr_enable; + } ipv6_prs_options; + + /* UDP */ + struct { + /* true to ignore pad in checksum */ + bool pad_ignore_checksum; + } udp_prs_options; + + /* TCP */ + struct { + /* true to ignore pad in checksum */ + bool pad_ignore_checksum; + } tcp_prs_options; +}; + +/* A structure for defining each header for the parser*/ +struct fm_pcd_prs_additional_hdr_params_t { + enum net_header_type hdr; /* Selected header */ + bool err_disable; /* true to disable error indication */ + uint8_t index_per_hdr; /* Normally 0, if more than one sw parser + * attachments exists for the same header, + * (in the main sw parser code) use this + * index to distinguish between them. + */ + bool use_prs_opts; /* true to use parser options. */ + /* A union according to header type, + * defining the parser options selected. + */ + union fm_pcd_hdr_prs_opts_u prs_opts; +}; + +/* struct for defining port PCD parameters*/ +struct fm_port_pcd_prs_params_t { + /* The private info provides a method of inserting + * port information into the parser result. This information + * may be extracted by Keygen and be used for frames + * distribution when a per-port distinction is required, + * it may also be used as a port logical id for analyzing + * incoming frames. + */ + uint8_t prs_result_private_info; + /* Number of bytes from beginning of packet to start parsing */ + uint8_t parsing_offset; + /* The type of the first header expected at 'parsing_offset' */ + enum net_header_type first_prs_hdr; + /* true to include this port in the parser statistics; + * NOTE: this field is not valid when the FM is in "guest" mode + * and IPC is not available. + */ + bool include_in_prs_statistics; + /* Normally 0, some headers may get special parameters */ + uint8_t num_of_hdrs_with_additional_params; + /* 'num_of_hdrs_with_additional_params' structures of additional + * parameters for each header that requires them + */ + struct fm_pcd_prs_additional_hdr_params_t + additional_params[FM_PCD_PRS_NUM_OF_HDRS]; + /* true to configure user selection of Ethertype to + * indicate a VLAN tag (in addition to the TPID values 0x8100 and + * 0x88A8). + */ + bool set_vlan_tpid1; + uint16_t vlan_tpid1; /* extra tag to use if set_vlan_tpid1=true. */ + bool set_vlan_tpid2; /* true to configure user selection of + * Ethertype to indicate a VLAN tag + * (in addition to the TPID values 0x8100 and + * 0x88A8). + */ + uint16_t vlan_tpid2; /* extra tag to use if set_vlan_tpid1=true. */ +}; + +/* struct for defining port PCD parameters*/ +struct fm_port_pcd_params_t { + enum fm_port_pcd_support pcd_support; + /* Relevant for Rx and offline ports only. + * Describes the active PCD engines for this port. + */ + struct fm_port_pcd_prs_params_t *p_prs_params; + /* Parser parameters for this port */ +}; + +/* A structure for defining the Parser starting point*/ +struct fm_pcd_prs_start_t { + uint8_t parsing_offset; /* Number of bytes from beginning of packet + * to start parsing + */ + /* The type of the first header axpected at 'parsing_offset' */ + enum net_header_type first_prs_hdr; +}; + +/*Function fm_port_set_pcd + *Description Calling this routine defines the port's PCD configuration. + * It changes it from its default configuration which is PCD + * disabled (BMI to BMI) and configures it according to the passed + * parameters. + * May be used for Rx and OP ports only + * Param[in] h_fm_port A handle to a FM Port module. + * Param[in] p_fm_port_pcd A Structure of parameters defining the + * port's PCD configuration. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + */ +int fm_port_set_pcd(void *h_fm_port, + struct fm_port_pcd_params_t *p_fm_port_pcd); + +/*Function fm_port_delete_pcd + *Description Calling this routine releases the port's PCD configuration. + * The port returns to its default configuration which is PCD + * disabled (BMI to BMI) and all PCD configuration is removed. + * May be used for Rx and OP ports which are + * in PCD mode only + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + */ +int fm_port_delete_pcd(void *h_fm_port); + +/*Function fm_port_attach_pcd + *Description This routine may be called after fm_port_detach_pcd was called, + * to return to the originally configured PCD support flow. + * The couple of routines are used to allow PCD configuration + * changes that demand that PCD will not be used while changes + * take place. + * May be used for Rx and OP ports which are + * in PCD mode only + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_init(). + */ +int fm_port_attach_pcd(void *h_fm_port); + +/*Function fm_port_detach_pcd + *Description Calling this routine detaches the port from its PCD + * functionality. + * The port returns to its default flow which is BMI to BMI. + * May be used for Rx and OP ports which are + * in PCD mode only + * Param[in] h_fm_port A handle to a FM Port module. + *Return 0 on success; Error code otherwise. + * Cautions Allowed only following fm_port_attach_pcd(). + */ +int fm_port_detach_pcd(void *h_fm_port); + +#ifdef NCSW_BACKWARD_COMPATIBLE_API +#define fm_port_cfg_tx_fifo_deq_pipeline_depth \ +fm_port_cfg_fifo_deq_pipeline_depth +#endif /* NCSW_BACKWARD_COMPATIBLE_API */ + +#endif /* __FM_PORT_EXT */
diff --git a/drivers/soc/fsl/fman/inc/fsl_fman_drv.h b/drivers/soc/fsl/fman/inc/fsl_fman_drv.h
index 4bef301..6df8f7d 100644
--- a/drivers/soc/fsl/fman/inc/fsl_fman_drv.h
+++ b/drivers/soc/fsl/fman/inc/fsl_fman_drv.h@@ -45,6 +45,50 @@ /* FM device opaque structure used for type checking */ struct fm; +/* A structure .., */ +struct fm_port; + +typedef int (*alloc_pcd_fqids)(struct device *dev, uint32_t num, + uint8_t alignment, uint32_t *base_fqid); + +typedef int (*free_pcd_fqids) (struct device *dev, uint32_t base_fqid); + +struct fm_port_pcd_param { + alloc_pcd_fqids cba; + free_pcd_fqids cbf; + struct device *dev; +}; + +/* A structure of information about each of the external + * buffer pools used by the port, + */ +struct fm_port_pool_param { + uint8_t id; /* External buffer pool id */ + uint16_t size; /* External buffer pool buffer size*/ +}; + +/* structure for additional port parameters */ +struct fm_port_params { + uint32_t errq; /* Error Queue Id. */ + uint32_t defq; /* For Tx and HC - Default Confirmation queue, + * 0 means no Tx conf for processed frames. + * For Rx and OP - default Rx queue. + */ + uint8_t num_pools; /* Number of pools use by this port */ + struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /* Parameters for each pool */ + uint16_t priv_data_size; /* Area that user may save for his own + * need (E.g. save the SKB) + */ + bool parse_results; /* Put the parser-results in the Rx/Tx buffer */ + bool hash_results; /* Put the hash-results in the Rx/Tx buffer */ + bool time_stamp; /* Put the time-stamp in the Rx/Tx buffer */ + uint16_t data_align; /* value for selecting a data alignment + * (must be a power of 2); + * if write optimization is used, must be >= 16. + */ +}; + /* fm_bind * Bind to a specific FM device. *
@@ -67,6 +111,78 @@ void *fm_get_rtc_handle(struct fm *fm); #endif struct resource *fm_get_mem_region(struct fm *fm); +/* fm_port_bind + * Bind to a specific FM-port device (may be Rx or Tx port). + * fm_port_dev - the OF handle of the FM port device. + * Return A handle of the FM port device. + * Allowed only after the port was created. + */ +struct fm_port *fm_port_bind(struct device *fm_port_dev); + +/* fm_port_unbind + * Un-bind from a specific FM-port device (may be Rx or Tx port). + * port - A handle of the FM port device. + * Allowed only after the port was created. + */ +void fm_port_unbind(struct fm_port *port); + +/* fm_set_rx_port_params + * Configure parameters for a specific Rx FM-port device. + * port - A handle of the FM port device. + * params - Rx port parameters + * Allowed only after the port is binded. + */ +void fm_set_rx_port_params(struct fm_port *port, struct fm_port_params *params); + +/* fm_port_pcd_bind + * Bind as a listener on a port PCD. + * port - A handle of the FM port device. + * params - PCD port parameters + * Allowed only after the port is binded. + */ +void fm_port_pcd_bind(struct fm_port *port, struct fm_port_pcd_param *params); + +/* fm_port_get_buff_layout_ext_params + * Get data_align from the device tree chosen node if applied. + * This function will only update these two parameters. + * When this port has no such parameters in the device tree + * values will be set to 0. + * port - A handle of the FM port device. + * params - PCD port parameters + * Allowed only after the port is binded. + */ +void fm_port_get_buff_layout_ext_params(struct fm_port *port, + struct fm_port_params *params); + +/* fm_get_tx_port_channel + * Get qman-channel number for this Tx port. + * port - A handle of the FM port device. + * Return qman-channel number for this Tx port. + * Allowed only after the port is binded. + */ +int fm_get_tx_port_channel(struct fm_port *port); + +/* fm_set_tx_port_params + * Configure parameters for a specific Tx FM-port device + * port - A handle of the FM port device. + * params - Tx port parameters + * Allowed only after the port is binded. + */ +void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params); + +void *fm_port_get_handle(const struct fm_port *port); + +/* fm_port_get_base_address + * + * Get base address of this port. Useful for accessing + * port-specific registers (i.e., not common ones). + * + * port - A handle of the FM port device. + * + * base_addr - The port's base addr (virtual address). + */ +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr); + /* fm_mutex_lock * * Lock function required before any FMD/LLD call.
@@ -91,6 +207,46 @@ u16 fm_get_max_frm(void); */ int fm_get_rx_extra_headroom(void); +/* fm_port_set_rate_limit + * + * Configure Shaper parameter on FM-port device (Tx port). + * + * port - A handle of the FM port device. + * max_burst_size - Value of maximum burst size allowed. + * rate_limit - The required rate value. + * + * Allowed only after the port is initialized. + */ +int fm_port_set_rate_limit(struct fm_port *port, + uint16_t max_burst_size, uint32_t rate_limit); +/* fm_port_set_rate_limit + * + * Delete Shaper configuration on FM-port device (Tx port). + * + * port - A handle of the FM port device. + * + * Allowed only after the port is initialized. + */ +int fm_port_del_rate_limit(struct fm_port *port); + +#ifdef CONFIG_FMAN_PFC +/* fm_port_set_pfc_priorities_mapping_to_qman_wq + * + * Associate a QMan Work Queue with a PFC priority on this + * FM-port device (Tx port). + * + * port - A handle of the FM port device. + * + * prio - The PFC priority. + * + * wq - The Work Queue associated with the PFC priority. + * + * Allowed only after the port is initialized. + */ +int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port, + uint8_t prio, uint8_t wq); +#endif + /* default values for initializing PTP 1588 timer clock */ /* power of 2 for better performance */ #define DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT 2
diff --git a/drivers/soc/fsl/fman/port/Makefile b/drivers/soc/fsl/fman/port/Makefile
index 0062fed..3949b3e 100644
--- a/drivers/soc/fsl/fman/port/Makefile
+++ b/drivers/soc/fsl/fman/port/Makefile@@ -1,3 +1,3 @@ obj-$(CONFIG_FSL_FMAN_PORT) += fsl_fman_port.o -fsl_fman_port-objs := fman_port.o +fsl_fman_port-objs := fman_port.o fm_port.o
diff --git a/drivers/soc/fsl/fman/port/fm_port.c b/drivers/soc/fsl/fman/port/fm_port.c
new file mode 100644
index 0000000..eaf33f4
--- /dev/null
+++ b/drivers/soc/fsl/fman/port/fm_port.c@@ -0,0 +1,2427 @@ +/* + * Copyright 2008 - 2015 Freescale Semiconductor Inc. + * + * 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. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* File fm_port.c + * Description FM driver routines implementation. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "service.h" +#include "fm_muram_ext.h" + +#include "fman_common.h" +#include "fm_port.h" + +#include <linux/string.h> +#include <linux/slab.h> + +/* static functions */ + +static int check_init_parameters(struct fm_port_t *p_fm_port) +{ + struct fm_port_drv_param_t *p_params = p_fm_port-> + p_fm_port_drv_param; + struct fman_port_cfg *p_dflt_config = &p_params->dflt_cfg; + uint32_t unused_mask; + + /* Rx only */ + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + /* external buffer pools */ + if (!p_params->ext_buf_pools.num_of_pools_used) { + pr_err("ext_buf_pools.num_of_pools_used=0. At least one buffer pool must be defined\n"); + return -EDOM; + } + + if (fm_sp_check_buf_pools_params(&p_params->ext_buf_pools, + p_params->p_backup_bm_pools, + &p_params->buf_pool_depletion, + p_fm_port->port_intg->max_num_of_ext_pools, + p_fm_port->port_intg->bm_max_num_of_pools) != 0) + return -EDOM; + /* Check that part of IC that needs copying is small enough + * to enter start margin + */ + if (p_params->int_context.size && + (p_params->int_context.size + + p_params->int_context.ext_buf_offset > + p_params->buf_margins.start_margins)) { + pr_err("int_context.size is larger than start margins\n"); + return -EDOM; + } + + if ((p_params->liodn_offset != DPAA_LIODN_DONT_OVERRIDE) && + (p_params->liodn_offset & ~FM_LIODN_OFFSET_MASK)) { + pr_err("liodn_offset is larger than %d\n", + FM_LIODN_OFFSET_MASK + 1); + } +#ifdef FM_NO_BACKUP_POOLS + if ((p_fm_port->fm_rev_info.major_rev != 4) && + (p_fm_port->fm_rev_info.major_rev < 6)) + if (p_fm_port->p_fm_port_drv_param-> + p_backup_bm_pools) { + pr_err("BackupBmPools\n"); + return -ENOSYS; + } +#endif /* FM_NO_BACKUP_POOLS */ + } + + /* Non Rx ports */ + else { + if (p_params->deq_sub_portal >= + p_fm_port->port_intg->fm_max_num_of_sub_portals) { + pr_err("deq_sub_portal has to be in the range of 0 - %d\n", + p_fm_port->port_intg->fm_max_num_of_sub_portals); + return -EDOM; + } + + /* to protect HW internal-context from overwrite */ + if ((p_params->int_context.size) && + (p_params->int_context.int_context_offset < + MIN_TX_INT_OFFSET)) { + pr_err("non-Rx int_context.int_context_offset can't be smaller than %d\n", + MIN_TX_INT_OFFSET); + return -EDOM; + } + + if ((p_fm_port->port_type == FM_PORT_TYPE_TX) || + /* in O/H DEFAULT_NOT_SUPPORTED indicates that + * it is not supported and should not be checked + */ + (p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth != DEFAULT_NOT_SUPPORTED)) { + /* Check that not larger than 8 */ + if ((!p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth) || + (p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth > + MAX_FIFO_PIPELINE_DEPTH)) { + pr_err("fifoDeqPipelineDepth can't be larger than %d\n", + MAX_FIFO_PIPELINE_DEPTH); + return -EDOM; + } + } + } + + /* Rx Or Offline Parsing */ + if ((p_fm_port->port_type == FM_PORT_TYPE_RX) || + (p_fm_port->port_type == FM_PORT_TYPE_OP)) { + if (!p_params->dflt_fqid) { + pr_err("dflt_fqid must be between 1 and 2^24-1\n"); + return -EDOM; + } + } + + /* All ports */ + /* common BMI registers values */ + /* Check that Queue Id is not larger than 2^24, and is not 0 */ + if ((p_params->err_fqid & ~0x00FFFFFF) || !p_params->err_fqid) { + pr_err("err_fqid must be between 1 and 2^24-1\n"); + return -EDOM; + } + if (p_params->dflt_fqid & ~0x00FFFFFF) { + pr_err("dflt_fqid must be between 1 and 2^24-1\n"); + return -EDOM; + } + + /* Rx only */ + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + if (p_dflt_config->rx_pri_elevation % BMI_FIFO_UNITS) { + pr_err("rx_fifo_pri_elevation_level has to be divisible by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + if ((p_dflt_config->rx_pri_elevation < BMI_FIFO_UNITS) || + (p_dflt_config->rx_pri_elevation > + p_fm_port->port_intg->max_port_fifo_size)) { + pr_err("rx_fifo_pri_elevation_level not in range of 256 - %d\n", + p_fm_port->port_intg->max_port_fifo_size); + return -EDOM; + } + if (p_dflt_config->rx_fifo_thr % BMI_FIFO_UNITS) { + pr_err("rx_fifo_threshold must be div by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + if ((p_dflt_config->rx_fifo_thr < BMI_FIFO_UNITS) || + (p_dflt_config->rx_fifo_thr > + p_fm_port->port_intg->max_port_fifo_size)) { + pr_err("rx_fifo_threshold has to be in the range of 256 - %d\n", + p_fm_port->port_intg->max_port_fifo_size); + return -EDOM; + } + + /* Check that not larger than 16 */ + if (p_dflt_config->rx_cut_end_bytes > FRAME_END_DATA_SIZE) { + pr_err("cut_bytes_from_end can't be larger than %d\n", + FRAME_END_DATA_SIZE); + return -EDOM; + } + + if (fm_sp_check_buf_margins(&p_params->buf_margins) != 0) + return -EDOM; + + /* extra FIFO size (allowed only to Rx ports) */ + if (p_params->set_size_of_fifo && + (p_fm_port->fifo_bufs.extra % BMI_FIFO_UNITS)) { + pr_err("fifo_bufs.extra has to be divisible by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + + if (p_params->buf_pool_depletion.pools_grp_mode_enable && + !p_params->buf_pool_depletion.num_of_pools) { + pr_err("buf_pool_depletion.num_of_pools can not be 0 when pools_grp_mode_enable=true\n"); + return -EDOM; + } +#ifdef FM_CSI_CFED_LIMIT + if (p_fm_port->fm_rev_info.major_rev == 4) { + /* Check that not larger than 16 */ + if (p_dflt_config->rx_cut_end_bytes + + p_dflt_config->checksum_bytes_ignore > + FRAME_END_DATA_SIZE) { + pr_err("cheksum_last_bytes_ignore + cut_bytes_from_end can't be larger than %d\n", + FRAME_END_DATA_SIZE); + return -EDOM; + } + } +#endif /* FM_CSI_CFED_LIMIT */ + } + + /* Non Rx ports */ + /* extra FIFO size (allowed only to Rx ports) */ + else if (p_fm_port->fifo_bufs.extra) { + pr_err(" No fifo_bufs.extra for non Rx ports\n"); + return -EDOM; + } + + /* Tx only */ + if (p_fm_port->port_type == FM_PORT_TYPE_TX) { + if (p_dflt_config->tx_fifo_min_level % BMI_FIFO_UNITS) { + pr_err("tx_fifo_min_fill_level has to be divisible by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + if (p_dflt_config->tx_fifo_min_level > + (p_fm_port->port_intg->max_port_fifo_size - 256)) { + pr_err("tx_fifo_min_fill_level has to be in the range of 0 - %d\n", + (p_fm_port->port_intg->max_port_fifo_size - + 256)); + return -EDOM; + } + if (p_dflt_config->tx_fifo_low_comf_level % BMI_FIFO_UNITS) { + pr_err("tx_fifo_low_comf_level has to be divisible by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + if ((p_dflt_config->tx_fifo_low_comf_level < BMI_FIFO_UNITS) || + (p_dflt_config->tx_fifo_low_comf_level > + p_fm_port->port_intg->max_port_fifo_size)) { + pr_err("tx_fifo_low_comf_level has to be in the range of 256 - %d\n", + p_fm_port->port_intg->max_port_fifo_size); + return -EDOM; + } + if (p_fm_port->port_speed == FM_PORT_SPEED_1G) + if (p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth > 2) { + pr_err("fifoDeqPipelineDepth for 1G can't be larger than 2\n"); + return -EDOM; + } + } + + /* Non Tx Ports */ + /* If discard override was selected , no frames may be discarded. */ + else if (p_dflt_config->discard_override && p_params-> + errors_to_discard) { + pr_err("errors_to_discard is not empty, but frm_discard_override selected (all discarded frames to be enqueued to error queue).\n"); + return -ENOSYS; + } + + /* Rx and Offline parsing */ + if ((p_fm_port->port_type == FM_PORT_TYPE_RX) || + (p_fm_port->port_type == FM_PORT_TYPE_OP)) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + unused_mask = BMI_STATUS_OP_MASK_UNUSED; + else + unused_mask = BMI_STATUS_RX_MASK_UNUSED; + + /* Check that no common bits with BMI_STATUS_MASK_UNUSED */ + if (p_params->errors_to_discard & unused_mask) { + pr_err("errors_to_discard contains undefined bits\n"); + return -ENOSYS; + } + } + + /* Offline Ports */ +#ifdef FM_OP_OPEN_DMA_MIN_LIMIT + if ((p_fm_port->fm_rev_info.major_rev >= 6) && + (p_fm_port->port_type == FM_PORT_TYPE_OP) && + p_params->set_num_of_open_dmas && + (p_fm_port->open_dmas.num < MIN_NUM_OF_OP_DMAS)) { + pr_err("For Offline port, open_dmas.num can't be smaller than %d\n", + MIN_NUM_OF_OP_DMAS); + return -EDOM; + } +#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */ + + /* Offline Ports */ + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { +#ifndef FM_FRAME_END_PARAMS_FOR_OP + if ((p_fm_port->fm_rev_info.major_rev < 6) && + (p_fm_port->p_fm_port_drv_param-> + cheksum_last_bytes_ignore != + DEFAULT_NOT_SUPPORTED)) { + /* this is an indication that user called config + * for this mode which is not supported in this + * integration + */ + pr_err("cheksum_last_bytes_ignore is available for Rx&Tx ports only\n"); + return -EDOM; + } +#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ + +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if ((!((p_fm_port->fm_rev_info.major_rev == 4) || + (p_fm_port->fm_rev_info.major_rev >= 6))) && + (p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth != DEFAULT_NOT_SUPPORTED)) { + /* this is an indication that user called config for + * this mode which is not supported in this integration + **/ + pr_err("fifoDeqPipelineDepth is available for Tx ports only\n"); + return -ENOSYS; + } +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + } + + /* All ports */ + + /* Check that not larger than 16 */ + if ((p_params->cheksum_last_bytes_ignore > FRAME_END_DATA_SIZE) && + ((p_params->cheksum_last_bytes_ignore != DEFAULT_NOT_SUPPORTED))) { + pr_err("cheksum_last_bytes_ignore can't be larger than %d\n", + FRAME_END_DATA_SIZE); + return -EDOM; + } + + if (fm_sp_check_int_context_params(&p_params->int_context) != 0) + return -EDOM; + + /* common BMI registers values */ + if (p_params->set_num_of_tasks && + ((!p_fm_port->tasks.num) || + (p_fm_port->tasks.num > MAX_NUM_OF_TASKS))) { + pr_err("tasks.num can't be larger than %d\n", + MAX_NUM_OF_TASKS); + return -EDOM; + } + if (p_params->set_num_of_tasks && + (p_fm_port->tasks.extra > MAX_NUM_OF_EXTRA_TASKS)) { + pr_err("tasks.extra can't be larger than %d\n", + MAX_NUM_OF_EXTRA_TASKS); + return -EDOM; + } + if (p_params->set_num_of_open_dmas && + ((!p_fm_port->open_dmas.num) || + (p_fm_port->open_dmas.num > MAX_NUM_OF_DMAS))) { + pr_err("open_dmas.num can't be larger than %d\n", + MAX_NUM_OF_DMAS); + return -EDOM; + } + if (p_params->set_num_of_open_dmas && + (p_fm_port->open_dmas.extra > MAX_NUM_OF_EXTRA_DMAS)) { + pr_err("open_dmas.extra can't be larger than %d\n", + MAX_NUM_OF_EXTRA_DMAS); + return -EDOM; + } + if (p_params->set_size_of_fifo && + (!p_fm_port->fifo_bufs.num || (p_fm_port->fifo_bufs.num > + p_fm_port->port_intg->max_port_fifo_size))) { + pr_err("fifo_bufs.num has to be in the range of 256 - %d\n", + p_fm_port->port_intg->max_port_fifo_size); + return -EDOM; + } + if (p_params->set_size_of_fifo && + (p_fm_port->fifo_bufs.num % BMI_FIFO_UNITS)) { + pr_err("fifo_bufs.num has to be divisible by %d\n", + BMI_FIFO_UNITS); + return -EDOM; + } + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_fm_port->fm_rev_info.major_rev == 4) + if (p_fm_port->p_fm_port_drv_param->deq_prefetch_option != + DEFAULT_NOT_SUPPORTED) { + /* this is an indication that user called config + * for this mode which is not supported in this + * integration + **/ + pr_err("deq_prefetch_option\n"); + return -ENOSYS; + } +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + return 0; +} + +/* Checks if p_fm_port driver parameters were initialized + * returns 0 if success else returns error code + */ +static int is_init_done(struct fm_port_drv_param_t *p_fm_port_drv_parameters) +{ + if (!p_fm_port_drv_parameters) + return 0; + return -ENOSYS; +} + +static int verify_size_of_fifo(struct fm_port_t *p_fm_port) +{ + uint32_t min_fifo_size_required = 0, opt_fifo_size_for_b2b = 0; + + /* TX PORTS */ + if (p_fm_port->port_type == FM_PORT_TYPE_TX) { + min_fifo_size_required = (uint32_t) + (ROUND_UP(p_fm_port->max_frame_length, + BMI_FIFO_UNITS) + (3 * BMI_FIFO_UNITS)); + + min_fifo_size_required += + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.tx_fifo_deq_pipeline_depth * BMI_FIFO_UNITS; + + opt_fifo_size_for_b2b = min_fifo_size_required; + + /* Add some margin for back-to-back capability to improve + * performance, allows the hardware to pipeline new frame dma + * while the previous frame not yet transmitted. + */ + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + opt_fifo_size_for_b2b += 3 * BMI_FIFO_UNITS; + else + opt_fifo_size_for_b2b += 2 * BMI_FIFO_UNITS; + } + + /* RX PORTS */ + else if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + if (p_fm_port->fm_rev_info.major_rev == 4) { + if (p_fm_port->rx_pools_params.num_of_pools == 1) + min_fifo_size_required = 8 * BMI_FIFO_UNITS; + else + min_fifo_size_required = (uint32_t) + (ROUND_UP + (p_fm_port-> + rx_pools_params.second_largest_buf_size, + BMI_FIFO_UNITS) + (7 * BMI_FIFO_UNITS)); + } else { + if (p_fm_port->fm_rev_info.major_rev >= 6) + min_fifo_size_required = (uint32_t) + (ROUND_UP(p_fm_port->max_frame_length, + BMI_FIFO_UNITS) + (5 * BMI_FIFO_UNITS)); + /* 4 according to spec + 1 for FOF>0 */ + else + min_fifo_size_required = (uint32_t) + (ROUND_UP(min(p_fm_port->max_frame_length, + p_fm_port->rx_pools_params. + largest_buf_size), + BMI_FIFO_UNITS) + (7 * BMI_FIFO_UNITS)); + } + + opt_fifo_size_for_b2b = min_fifo_size_required; + + /* Add some margin for back-to-back capability to improve + * performance,allows the hardware to pipeline new frame dma + * while the previous frame not yet transmitted. + */ + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + opt_fifo_size_for_b2b += 8 * BMI_FIFO_UNITS; + else + opt_fifo_size_for_b2b += 3 * BMI_FIFO_UNITS; + } + + /* For O/H ports, check fifo size and update if necessary */ + else if (p_fm_port->port_type == FM_PORT_TYPE_OP) { + if (p_fm_port->fm_rev_info.major_rev >= 6) { + opt_fifo_size_for_b2b = (uint32_t)(ROUND_UP( + p_fm_port->max_frame_length, + BMI_FIFO_UNITS) + + ((p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth + 5) * + BMI_FIFO_UNITS)); + min_fifo_size_required = opt_fifo_size_for_b2b; + /* 4 according to spec + 1 for FOF>0 */ + } else { + opt_fifo_size_for_b2b = + (uint32_t)((p_fm_port->tasks.num + 2) * BMI_FIFO_UNITS); + min_fifo_size_required = opt_fifo_size_for_b2b; + } + } + + ASSERT(min_fifo_size_required > 0); + ASSERT(opt_fifo_size_for_b2b >= min_fifo_size_required); + + /* Verify the size */ + if (p_fm_port->fifo_bufs.num < min_fifo_size_required) + pr_debug("FIFO size should be enlarged to %d bytes\n", + min_fifo_size_required); + else if (p_fm_port->fifo_bufs.num < opt_fifo_size_for_b2b) + pr_debug("For b2b processing,FIFO may be enlarged to %d bytes\n", + opt_fifo_size_for_b2b); + + return 0; +} + +static void fm_port_drv_param_free(struct fm_port_t *p_fm_port) +{ + kfree(p_fm_port->p_fm_port_drv_param); + p_fm_port->p_fm_port_drv_param = NULL; +} + +static int set_ext_buffer_pools(struct fm_port_t *p_fm_port) +{ + struct fm_ext_pools_t *p_ext_buf_pools = + &p_fm_port->p_fm_port_drv_param->ext_buf_pools; + struct fm_buf_pool_depletion_t *p_buf_pool_depletion = + &p_fm_port->p_fm_port_drv_param->buf_pool_depletion; + uint8_t ordered_array[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + uint16_t sizes_array[BM_MAX_NUM_OF_POOLS]; + int i = 0, j = 0, err; + struct fman_port_bpools bpools; + + memset(&ordered_array, 0, + sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); + memset(&sizes_array, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); + memcpy(&p_fm_port->ext_buf_pools, p_ext_buf_pools, + sizeof(struct fm_ext_pools_t)); + + fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(p_ext_buf_pools, + ordered_array, + sizes_array); + + /* Prepare flibs bpools structure */ + memset(&bpools, 0, sizeof(struct fman_port_bpools)); + bpools.count = p_ext_buf_pools->num_of_pools_used; + bpools.counters_enable = true; + for (i = 0; i < p_ext_buf_pools->num_of_pools_used; i++) { + bpools.bpool[i].bpid = ordered_array[i]; + bpools.bpool[i].size = sizes_array[ordered_array[i]]; + /* functionality available only for some derivatives + * (limited by config) + */ + if (p_fm_port->p_fm_port_drv_param->p_backup_bm_pools) + for (j = 0; j < p_fm_port->p_fm_port_drv_param-> + p_backup_bm_pools->num_of_backup_pools; j++) + if (ordered_array[i] == + p_fm_port->p_fm_port_drv_param-> + p_backup_bm_pools->pool_ids[j]) { + bpools.bpool[i].is_backup = true; + break; + } + } + + /* save pools parameters for later use */ + p_fm_port->rx_pools_params.num_of_pools = + p_ext_buf_pools->num_of_pools_used; + p_fm_port->rx_pools_params.largest_buf_size = + sizes_array[ordered_array[p_ext_buf_pools-> + num_of_pools_used - 1]]; + p_fm_port->rx_pools_params.second_largest_buf_size = + sizes_array[ordered_array[p_ext_buf_pools-> + num_of_pools_used - 2]]; + + /* FMBM_RMPD reg. - pool depletion */ + if (p_buf_pool_depletion->pools_grp_mode_enable) { + bpools.grp_bp_depleted_num = p_buf_pool_depletion-> +num_of_pools; + for (i = 0; i < p_fm_port->port_intg->bm_max_num_of_pools; + i++) { + if (p_buf_pool_depletion->pools_to_consider[i]) { + for (j = 0; j < p_ext_buf_pools-> + num_of_pools_used; j++) { + if (i == ordered_array[j]) { + bpools.bpool[j]. + grp_bp_depleted = true; + break; + } + } + } + } + } + + if (p_buf_pool_depletion->single_pool_mode_enable) { + for (i = 0; i < p_fm_port->port_intg->bm_max_num_of_pools; + i++) { + if (p_buf_pool_depletion-> + pools_to_consider_for_single_mode[i]) { + for (j = 0; j < p_ext_buf_pools-> + num_of_pools_used; j++) { + if (i == ordered_array[j]) { + bpools.bpool[j]. + single_bp_depleted = true; + break; + } + } + } + } + } + /* fill QbbPEV */ + if ((p_fm_port->fm_rev_info.major_rev >= 6) && + (p_buf_pool_depletion->pools_grp_mode_enable || + p_buf_pool_depletion->single_pool_mode_enable)) { + for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++) { + if (p_buf_pool_depletion->pfc_priorities_en[i] == + true) { + bpools.bpool[i].pfc_priorities_en = true; + } + } + } + + /* Issue flibs function */ + err = fman_port_set_bpools(&p_fm_port->port, &bpools); + if (err != 0) { + pr_err("fman_port_set_bpools\n"); + return -EDOM; + } + + kfree(p_fm_port->p_fm_port_drv_param->p_backup_bm_pools); + + return 0; +} + +static int init_low_level_driver(struct fm_port_t *p_fm_port) +{ + struct fm_port_drv_param_t *p_drv_params = p_fm_port-> + p_fm_port_drv_param; + struct fman_port_params port_params; + uint32_t tmp_val; + + /* Set up flibs parameters and issue init function */ + + memset(&port_params, 0, sizeof(struct fman_port_params)); + port_params.discard_mask = p_drv_params->errors_to_discard; + port_params.dflt_fqid = p_drv_params->dflt_fqid; + port_params.err_fqid = p_drv_params->err_fqid; + port_params.deq_sp = p_drv_params->deq_sub_portal; + port_params.dont_release_buf = p_drv_params->dont_release_buf; + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + port_params.err_mask = + (RX_ERRS_TO_ENQ & ~port_params.discard_mask); + if (p_drv_params->forward_reuse_int_context) + p_drv_params->dflt_cfg.rx_fd_bits = + (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24); + break; + + case (FM_PORT_TYPE_OP): + port_params.err_mask = + (OP_ERRS_TO_ENQ & ~port_params.discard_mask); + break; + break; + + default: + break; + } + + tmp_val = (uint32_t)((p_fm_port->internal_buf_offset % + OFFSET_UNITS) ? (p_fm_port-> + internal_buf_offset / OFFSET_UNITS + + 1) : (p_fm_port->internal_buf_offset / + OFFSET_UNITS)); + p_fm_port->internal_buf_offset = (uint8_t)(tmp_val * OFFSET_UNITS); + p_drv_params->dflt_cfg.int_buf_start_margin = + p_fm_port->internal_buf_offset; + + p_drv_params->dflt_cfg.ext_buf_start_margin = + p_drv_params->buf_margins.start_margins; + p_drv_params->dflt_cfg.ext_buf_end_margin = + p_drv_params->buf_margins.end_margins; + + p_drv_params->dflt_cfg.ic_ext_offset = + p_drv_params->int_context.ext_buf_offset; + p_drv_params->dflt_cfg.ic_int_offset = + p_drv_params->int_context.int_context_offset; + p_drv_params->dflt_cfg.ic_size = p_drv_params->int_context.size; + + p_drv_params->dflt_cfg.stats_counters_enable = true; + p_drv_params->dflt_cfg.perf_counters_enable = true; + p_drv_params->dflt_cfg.queue_counters_enable = true; + + p_drv_params->dflt_cfg.perf_cnt_params.task_val = + (uint8_t)p_fm_port->tasks.num; + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + p_drv_params->dflt_cfg.perf_cnt_params.queue_val = 0; + else + p_drv_params->dflt_cfg.perf_cnt_params.queue_val = 1; + p_drv_params->dflt_cfg.perf_cnt_params.dma_val = + (uint8_t)p_fm_port->open_dmas.num; + p_drv_params->dflt_cfg.perf_cnt_params.fifo_val = + p_fm_port->fifo_bufs.num; + + if (0 != + fman_port_init(&p_fm_port->port, &p_drv_params->dflt_cfg, + &port_params)) { + pr_err("fman_port_init\n"); + return -ENODEV; + } + + /* from QMIInit */ + if (p_fm_port->port_type != FM_PORT_TYPE_RX) { + if (p_drv_params->deq_prefetch_option == + FM_PORT_DEQ_NO_PREFETCH) + fm_set_port_prefetch_cfg(p_fm_port->h_fm, + p_fm_port->port_id, false); + else + fm_set_port_prefetch_cfg(p_fm_port->h_fm, + p_fm_port->port_id, true); + } + + /* The code bellow is a trick so the FM will not release the buffer + * to BM nor will try to enqueue the frame to QM + */ + if (p_fm_port->port_type == FM_PORT_TYPE_TX) { + if (!p_drv_params->dflt_fqid && p_drv_params-> + dont_release_buf) { + /* override fmbm_tcfqid 0 with a false non-0 value. + * This will force FM to act according to tfene. + * Otherwise, if fmbm_tcfqid is 0 the FM will release + * buffers to BM regardless of fmbm_tfene + */ + WRITE_UINT32(p_fm_port->port.bmi_regs->tx.fmbm_tcfqid, + 0xFFFFFF); + WRITE_UINT32(p_fm_port->port.bmi_regs->tx.fmbm_tfene, + NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + } + } + + return 0; +} + +static int additional_prs_params(struct fm_port_t *p_fm_port, + struct fm_pcd_prs_additional_hdr_params_t + *p_hdr_params, uint32_t + *p_soft_seq_attach_reg) +{ + uint8_t hdr_num, ipv4_hdr_num; + union fm_pcd_hdr_prs_opts_u *p_prs_opts; + uint32_t tmp_reg = *p_soft_seq_attach_reg; + + if (IS_PRIVATE_HEADER(p_hdr_params->hdr)) { + pr_err("No additional parameters for private or special headers.\n"); + return -ENOSYS; + } + + if (p_hdr_params->err_disable) + tmp_reg |= PRS_HDR_ERROR_DIS; + + /* Set parser options */ + if (p_hdr_params->use_prs_opts) { + p_prs_opts = &p_hdr_params->prs_opts; + switch (p_hdr_params->hdr) { + case (HEADER_TYPE_MPLS): + if (p_prs_opts-> + mpls_prs_options.label_interpretation_enable) + tmp_reg |= PRS_HDR_MPLS_LBL_INTER_EN; + GET_PRS_HDR_NUM(hdr_num, + p_prs_opts-> + mpls_prs_options.next_parse); + if (hdr_num == ILLEGAL_HDR_NUM) + return -EDOM; + GET_PRS_HDR_NUM(ipv4_hdr_num, HEADER_TYPE_IPV4); + if (hdr_num < ipv4_hdr_num) { + pr_err("Header must be equal or higher than IPV4\n"); + return -EDOM; + } + tmp_reg |= + ((uint32_t)hdr_num * + PRS_HDR_ENTRY_SIZE) << + PRS_HDR_MPLS_NEXT_HDR_SHIFT; + break; + case (HEADER_TYPE_PPPOE): + if (p_prs_opts->pppoe_prs_options.enable_mtu_check) + tmp_reg |= PRS_HDR_PPPOE_MTU_CHECK_EN; + break; + case (HEADER_TYPE_IPV6): + if (p_prs_opts->ipv6_prs_options.routing_hdr_enable) + tmp_reg |= PRS_HDR_IPV6_ROUTE_HDR_EN; + break; + case (HEADER_TYPE_TCP): + if (p_prs_opts->tcp_prs_options.pad_ignore_checksum) + tmp_reg |= PRS_HDR_TCP_PAD_REMOVAL; + else + tmp_reg &= ~PRS_HDR_TCP_PAD_REMOVAL; + break; + case (HEADER_TYPE_UDP): + if (p_prs_opts->udp_prs_options.pad_ignore_checksum) + tmp_reg |= PRS_HDR_UDP_PAD_REMOVAL; + else + tmp_reg &= ~PRS_HDR_UDP_PAD_REMOVAL; + break; + default: + pr_err("Invalid header\n"); + return -ENOSYS; + } + } + + return 0; +} + +static int set_pcd(struct fm_port_t *p_fm_port, + struct fm_port_pcd_params_t *p_pcd_params) +{ + int err = 0; + uint32_t tmp_reg; + + uint32_t __iomem *p_bmi_nia = NULL; + uint32_t __iomem *p_bmi_prs_nia = NULL; + uint32_t __iomem *p_bmi_prs_start_offset = NULL; + uint32_t __iomem *p_bmi_init_prs_result = NULL; + uint32_t __iomem *p_bmi_cc_base = NULL; + uint8_t hdr_num, l3_hdr_num, gre_hdr_num; + int i; + uint32_t tmp_hxs[FM_PCD_PRS_NUM_OF_HDRS]; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -ENODEV; + } + + p_fm_port->pcd_engines = 0; + + /* initialize p_fm_port->pcd_engines field in port's structure */ + switch (p_pcd_params->pcd_support) { + case (FM_PORT_PCD_SUPPORT_NONE): + pr_err("No PCD configuration required if FM_PORT_PCD_SUPPORT_NONE selected\n"); + return -ENOSYS; + case (FM_PORT_PCD_SUPPORT_PRS_ONLY): + p_fm_port->pcd_engines |= FM_PCD_PRS; + break; + default: + pr_err("invalid pcd_support\n"); + return -ENOSYS; + } + + if ((p_fm_port->pcd_engines & FM_PCD_PRS) && + (p_pcd_params->p_prs_params->num_of_hdrs_with_additional_params > + FM_PCD_PRS_NUM_OF_HDRS)) { + pr_err("Port parser num_of_hdrs_with_additional_params may not exceed %d\n", + FM_PCD_PRS_NUM_OF_HDRS); + return -EDOM; + } + + /* check that parameters exist for each and only each defined engine */ + if (!!(p_fm_port->pcd_engines & FM_PCD_PRS) != + !!p_pcd_params->p_prs_params) { + pr_err("PCD initialization structure is not consistent with pcd_support\n"); + return -ENOSYS; + } + + /* get PCD registers pointers */ + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + p_bmi_nia = &p_fm_port->port.bmi_regs->rx.fmbm_rfne; + p_bmi_prs_nia = &p_fm_port->port.bmi_regs->rx.fmbm_rfpne; + p_bmi_prs_start_offset = &p_fm_port->port.bmi_regs-> + rx.fmbm_rpso; + p_bmi_init_prs_result = &p_fm_port->port.bmi_regs-> + rx.fmbm_rprai[0]; + p_bmi_cc_base = &p_fm_port->port.bmi_regs->rx.fmbm_rccb; + break; + case (FM_PORT_TYPE_OP): + p_bmi_nia = &p_fm_port->port.bmi_regs->oh.fmbm_ofne; + p_bmi_prs_nia = &p_fm_port->port.bmi_regs->oh.fmbm_ofpne; + p_bmi_prs_start_offset = &p_fm_port->port.bmi_regs-> + oh.fmbm_opso; + p_bmi_init_prs_result = &p_fm_port->port.bmi_regs-> + oh.fmbm_oprai[0]; + p_bmi_cc_base = &p_fm_port->port.bmi_regs->oh.fmbm_occb; + break; + default: + pr_err("Invalid port type\n"); + return -ENOSYS; + } + + /* configure NIA after BMI */ + + /* rfne may contain FDCS bits, so first we read them. */ + p_fm_port->saved_bmi_nia = GET_UINT32(*p_bmi_nia) & BMI_RFNE_FDCS_MASK; + + if (p_fm_port->pcd_engines & FM_PCD_PRS) { + ASSERT(p_pcd_params->p_prs_params); + /* if PRS is used it is always first */ + GET_PRS_HDR_NUM(hdr_num, p_pcd_params-> + p_prs_params->first_prs_hdr); + if (hdr_num == ILLEGAL_HDR_NUM) { + pr_err("Unsupported header.\n"); + return -ENOSYS; + } + p_fm_port->saved_bmi_nia |= + (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdr_num)); + /* set after parser NIA */ + tmp_reg = 0; + switch (p_pcd_params->pcd_support) { + case (FM_PORT_PCD_SUPPORT_PRS_ONLY): + WRITE_UINT32(*p_bmi_prs_nia, + GET_NIA_BMI_AC_ENQ_FRAME( + p_fm_port->h_fm_pcd, + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.errata_A006675)); + break; + default: + pr_err("Invalid PCD support\n"); + return -ENOSYS; + } + + /* set start parsing offset */ + WRITE_UINT32(*p_bmi_prs_start_offset, + p_pcd_params->p_prs_params->parsing_offset); + + /* Parser port parameters */ + + /* stop before configuring */ + WRITE_UINT32(p_fm_port->p_fm_port_prs_regs->pcac, + PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_fm_port->p_fm_port_prs_regs->pcac) & + PRS_CAC_ACTIVE) + ; + + /* set soft seq attachment register */ + memset(tmp_hxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t)); + + /* set MPLS default next header - HW reset workaround */ + GET_PRS_HDR_NUM(hdr_num, HEADER_TYPE_MPLS); + tmp_hxs[hdr_num] |= PRS_HDR_MPLS_LBL_INTER_EN; + GET_PRS_HDR_NUM(l3_hdr_num, HEADER_TYPE_USER_DEFINED_L3); + tmp_hxs[hdr_num] |= + (uint32_t)l3_hdr_num << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + + /* for GRE, disable errors */ + GET_PRS_HDR_NUM(gre_hdr_num, HEADER_TYPE_GRE); + tmp_hxs[gre_hdr_num] |= PRS_HDR_ERROR_DIS; + + /* For UDP remove PAD from L4 checksum calculation */ + GET_PRS_HDR_NUM(hdr_num, HEADER_TYPE_UDP); + tmp_hxs[hdr_num] |= PRS_HDR_UDP_PAD_REMOVAL; + /* For TCP remove PAD from L4 checksum calculation */ + GET_PRS_HDR_NUM(hdr_num, HEADER_TYPE_TCP); + tmp_hxs[hdr_num] |= PRS_HDR_TCP_PAD_REMOVAL; + + /* config additional params for specific headers */ + for (i = 0; i < p_pcd_params->p_prs_params-> + num_of_hdrs_with_additional_params; i++) { + GET_PRS_HDR_NUM(hdr_num, + p_pcd_params->p_prs_params-> + additional_params[i].hdr); + if (hdr_num == ILLEGAL_HDR_NUM) + return -EDOM; + if (hdr_num == NO_HDR_NUM) { + pr_err("Private headers may not use additional parameters\n"); + return -EDOM; + } + + err = + additional_prs_params(p_fm_port, + &p_pcd_params->p_prs_params-> + additional_params[i], + &tmp_hxs[hdr_num]); + if (err) + return -EDOM; + } + + /* set tpid. */ + tmp_reg = PRS_TPID_DFLT; + if (p_pcd_params->p_prs_params->set_vlan_tpid1) { + tmp_reg &= PRS_TPID2_MASK; + tmp_reg |= + (uint32_t)p_pcd_params->p_prs_params-> + vlan_tpid1 << PRS_PCTPID_SHIFT; + } + if (p_pcd_params->p_prs_params->set_vlan_tpid2) { + tmp_reg &= PRS_TPID1_MASK; + tmp_reg |= + (uint32_t)p_pcd_params->p_prs_params->vlan_tpid2; + } + WRITE_UINT32(p_fm_port->p_fm_port_prs_regs->pctpid, tmp_reg); + + /* enable parser */ + WRITE_UINT32(p_fm_port->p_fm_port_prs_regs->pcac, 0); + + if (p_pcd_params->p_prs_params->prs_result_private_info) + p_fm_port->private_info = + p_pcd_params->p_prs_params->prs_result_private_info; + + } /* end parser */ + else + p_fm_port->private_info = 0; + + WRITE_UINT32(*p_bmi_prs_start_offset, + GET_UINT32(*p_bmi_prs_start_offset) + + p_fm_port->internal_buf_offset); + + /* set initial parser result - used for all engines */ + for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++) { + if (!i) + WRITE_UINT32(*(p_bmi_init_prs_result), + (uint32_t)(((uint32_t)p_fm_port-> + private_info << + BMI_PR_PORTID_SHIFT) + | BMI_PRS_RESULT_HIGH)); + else { + if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2) + WRITE_UINT32(*(p_bmi_init_prs_result + i), + BMI_PRS_RESULT_HIGH); + else + WRITE_UINT32(*(p_bmi_init_prs_result + i), + BMI_PRS_RESULT_LOW); + } + } + + return 0; +} + +static int delete_pcd(struct fm_port_t *p_fm_port) +{ + uint32_t __iomem *p_bmi_nia = NULL; + uint32_t __iomem *p_bmi_prs_start_offset = NULL; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -ENODEV; + } + + if (!p_fm_port->pcd_engines) { + pr_err("called for non PCD port\n"); + return -ENODEV; + } + + /* get PCD registers pointers */ + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + p_bmi_nia = &p_fm_port->port.bmi_regs->rx.fmbm_rfne; + p_bmi_prs_start_offset = &p_fm_port->port.bmi_regs-> + rx.fmbm_rpso; + break; + case (FM_PORT_TYPE_OP): + p_bmi_nia = &p_fm_port->port.bmi_regs->oh.fmbm_ofne; + p_bmi_prs_start_offset = &p_fm_port->port.bmi_regs-> + oh.fmbm_opso; + break; + default: + pr_err("Invalid port type\n"); + return -ENODEV; + } + + if ((GET_UINT32(*p_bmi_nia) & + GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME( + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.errata_A006675)) != + GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME(p_fm_port-> + p_fm_port_drv_param-> + dflt_cfg.errata_A006675)) + pr_err("port has to be detached previousely\n"); + return -ENODEV; + + if (p_fm_port->pcd_engines | FM_PCD_PRS) { + WRITE_UINT32(*p_bmi_prs_start_offset, 0); + + /* stop parser */ + WRITE_UINT32(p_fm_port->p_fm_port_prs_regs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_fm_port->p_fm_port_prs_regs->pcac) & + PRS_CAC_ACTIVE) + ; + } + + p_fm_port->pcd_engines = 0; + + return 0; +} + +static int attach_pcd(struct fm_port_t *p_fm_port) +{ + uint32_t __iomem *p_bmi_nia = NULL; + + /* get PCD registers pointers */ + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + p_bmi_nia = &p_fm_port->port.bmi_regs->oh.fmbm_ofne; + else + p_bmi_nia = &p_fm_port->port.bmi_regs->rx.fmbm_rfne; + + /* check that current NIA is BMI to BMI */ + if ((GET_UINT32(*p_bmi_nia) & ~BMI_RFNE_FDCS_MASK) != + GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME(p_fm_port->p_fm_port_drv_param-> + dflt_cfg.errata_A006675)) { + pr_err("may be called only for ports in BMI-to-BMI state.\n"); + return -ENODEV; + } + + if (p_fm_port->required_action & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (fm_set_num_of_riscs_per_port + (p_fm_port->h_fm, p_fm_port->port_id, 1, + p_fm_port->or_fman_ctrl) != 0) + return -ENOSYS; + + if (p_fm_port->required_action & UPDATE_NIA_CMNE) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + WRITE_UINT32(p_fm_port->port.bmi_regs->oh.fmbm_ocmne, + p_fm_port->saved_bmi_cmne); + else + WRITE_UINT32(p_fm_port->port.bmi_regs->rx.fmbm_rcmne, + p_fm_port->saved_bmi_cmne); + } + + if (p_fm_port->required_action & UPDATE_NIA_PNEN) + WRITE_UINT32(p_fm_port->p_fm_port_qmi_regs->fmqm_pnen, + p_fm_port->saved_qmi_pnen); + + if (p_fm_port->required_action & UPDATE_NIA_FENE) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + WRITE_UINT32(p_fm_port->port.bmi_regs->oh.fmbm_ofene, + p_fm_port->saved_bmi_fene); + else + WRITE_UINT32(p_fm_port->port.bmi_regs->rx.fmbm_rfene, + p_fm_port->saved_bmi_fene); + } + + if (p_fm_port->required_action & UPDATE_NIA_FPNE) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + WRITE_UINT32(p_fm_port->port.bmi_regs->oh.fmbm_ofpne, + p_fm_port->saved_bmi_fpne); + else + WRITE_UINT32(p_fm_port->port.bmi_regs->rx.fmbm_rfpne, + p_fm_port->saved_bmi_fpne); + } + + WRITE_UINT32(*p_bmi_nia, p_fm_port->saved_bmi_nia); + + if (p_fm_port->required_action & UPDATE_NIA_PNDN) { + p_fm_port->orig_non_rx_qmi_regs_pndn = + GET_UINT32(p_fm_port->port.qmi_regs->fmqm_pndn); + WRITE_UINT32(p_fm_port->port.qmi_regs->fmqm_pndn, + p_fm_port->saved_non_rx_qmi_regs_pndn); + } + + return 0; +} + +static int detach_pcd(struct fm_port_t *p_fm_port) +{ + uint32_t __iomem *p_bmi_nia = NULL; + + /* get PCD registers pointers */ + if (p_fm_port->required_action & UPDATE_NIA_PNDN) + WRITE_UINT32(p_fm_port->port.qmi_regs->fmqm_pndn, + p_fm_port->orig_non_rx_qmi_regs_pndn); + + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + p_bmi_nia = &p_fm_port->port.bmi_regs->oh.fmbm_ofne; + else + p_bmi_nia = &p_fm_port->port.bmi_regs->rx.fmbm_rfne; + + WRITE_UINT32(*p_bmi_nia, + (p_fm_port->saved_bmi_nia & BMI_RFNE_FDCS_MASK) | + GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME(p_fm_port-> + p_fm_port_drv_param-> + dflt_cfg.errata_A006675)); + + if (p_fm_port->required_action & UPDATE_NIA_FENE) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + WRITE_UINT32(p_fm_port->port.bmi_regs->oh.fmbm_ofene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + else + WRITE_UINT32(p_fm_port->port.bmi_regs->rx.fmbm_rfene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + } + + if (p_fm_port->required_action & UPDATE_NIA_PNEN) + WRITE_UINT32(p_fm_port->port.qmi_regs->fmqm_pnen, + NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + + if (p_fm_port->required_action & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (fm_set_num_of_riscs_per_port( + p_fm_port->h_fm, p_fm_port->port_id, 2, + p_fm_port->or_fman_ctrl) != 0) + return -ENOSYS; + + p_fm_port->required_action = 0; + + return 0; +} + +static struct fm_port_intg_t *set_port_intg_params(struct fm_port_t *p_fm_port) +{ + struct fm_port_intg_t *intg; + uint32_t bmi_max_fifo_size; + + intg = kzalloc(sizeof(*intg), GFP_KERNEL); + if (!intg) + return NULL; + + bmi_max_fifo_size = fm_get_bmi_max_fifo_size(p_fm_port->h_fm); + + intg->max_port_fifo_size = + MAX_PORT_FIFO_SIZE(bmi_max_fifo_size); + + switch (p_fm_port->fm_rev_info.major_rev) { + case FM_IP_BLOCK_P2_P3_P5: + case FM_IP_BLOCK_P4: + intg->max_num_of_ext_pools = 4; + intg->fm_max_num_of_sub_portals = 12; + intg->bm_max_num_of_pools = 64; + break; + + case FM_IP_BLOCK_P1: + intg->max_num_of_ext_pools = 4; + intg->fm_max_num_of_sub_portals = 7; + intg->bm_max_num_of_pools = 8; + break; + + case FM_IP_BLOCK_B_T: + intg->max_num_of_ext_pools = 8; + intg->fm_max_num_of_sub_portals = 16; + intg->bm_max_num_of_pools = 64; + break; + + default: + pr_err("Unsupported FMan version\n"); + kfree(intg); + return NULL; + } + + return intg; +} + +/* Inter-module API routines */ + +int fm_port_set_gpr_func(void *h_fm_port, + enum fm_port_gpr_func_type gpr_func, + void **p_value) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + uint32_t muram_page_offset; + + if (p_fm_port->gpr_func != FM_PORT_GPR_EMPTY) { + if (p_fm_port->gpr_func != gpr_func) { + pr_err("gpr was assigned with different func\n"); + return -ENOSYS; + } + } else { + switch (gpr_func) { + case (FM_PORT_GPR_MURAM_PAGE): + p_fm_port->p_params_page = + fm_muram_alloc(p_fm_port->p_muram, 256, 8); + if (!p_fm_port->p_params_page) { + pr_err("MURAM alloc for page\n"); + return -ENOMEM; + } + + memset_io(p_fm_port->p_params_page, 0, 256); + muram_page_offset = (uint32_t) + (virt_to_phys + (p_fm_port->p_params_page) - + p_fm_port-> + fm_muram_phys_base_addr); + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + WRITE_UINT32(p_fm_port->p_fm_port_bmi_regs-> + rx_port_bmi_regs.fmbm_rgpr, + muram_page_offset); + break; + case (FM_PORT_TYPE_OP): + WRITE_UINT32(p_fm_port->p_fm_port_bmi_regs-> + oh_port_bmi_regs.fmbm_ogpr, + muram_page_offset); + break; + default: + pr_err("Invalid port type\n"); + return -ENOSYS; + } + break; + default: + return -ENOSYS; + } + p_fm_port->gpr_func = gpr_func; + } + + switch (p_fm_port->gpr_func) { + case (FM_PORT_GPR_MURAM_PAGE): + *p_value = p_fm_port->p_params_page; + break; + default: + return -ENODEV; + } + + return 0; +} + +/* End of inter-module routines */ + +/* API Init unit functions */ +# +void *fm_port_config(struct fm_port_params_t *p_fm_port_params) +{ + struct fm_port_t *p_fm_port; + uintptr_t base_addr = p_fm_port_params->base_addr; +#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 + uint32_t tmp_reg; +#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */ + enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY; + + /* Allocate FM structure */ + p_fm_port = kzalloc(sizeof(*p_fm_port), GFP_KERNEL); + if (!p_fm_port) + return NULL; + + /* Allocate the FM driver's parameters structure */ + p_fm_port->p_fm_port_drv_param = + kzalloc(sizeof(*p_fm_port->p_fm_port_drv_param), + GFP_KERNEL); + if (!p_fm_port->p_fm_port_drv_param) { + kfree(p_fm_port); + pr_err("FM Port driver parameters\n"); + return NULL; + } + + /* Initialize FM port parameters which will be kept by the driver */ + p_fm_port->port_type = p_fm_port_params->port_type; + p_fm_port->port_speed = p_fm_port_params->port_speed; + p_fm_port->port_id = p_fm_port_params->port_id; + p_fm_port->pcd_engines = FM_PCD_NONE; + p_fm_port->f_exception = p_fm_port_params->f_exception; + p_fm_port->h_app = p_fm_port_params->h_app; + p_fm_port->h_fm = p_fm_port_params->h_fm; + + /* get FM revision */ + fm_get_revision(p_fm_port->h_fm, &p_fm_port->fm_rev_info); + + p_fm_port->port_intg = set_port_intg_params(p_fm_port); + if (!p_fm_port->port_intg) { + kfree(p_fm_port->p_fm_port_drv_param); + kfree(p_fm_port); + return NULL; + } + + if (p_fm_port->fm_rev_info.major_rev >= 6) { + if ((p_fm_port->port_type == FM_PORT_TYPE_OP) && + (p_fm_port_params->port_id == FM_OH_PORT_ID)) + pr_debug("Use nonzero portid for OP port\n"); + } + + /* Set up FM port parameters for initialization phase only */ + + /* First, fill in flibs struct */ + /* In order to be aligned with flib port types, we need to translate + * the port type and speed to fman_port_type + */ + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { + fman_port_type = E_FMAN_PORT_TYPE_OP; + } else if (p_fm_port->port_type == FM_PORT_TYPE_TX) { + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + fman_port_type = E_FMAN_PORT_TYPE_TX_10G; + else + fman_port_type = E_FMAN_PORT_TYPE_TX; + } else if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + fman_port_type = E_FMAN_PORT_TYPE_RX_10G; + else + fman_port_type = E_FMAN_PORT_TYPE_RX; + } + fman_port_defconfig(&p_fm_port->p_fm_port_drv_param->dflt_cfg, + fman_port_type); + /* Overwrite some integration specific parameters */ + p_fm_port->p_fm_port_drv_param->dflt_cfg.rx_pri_elevation = + DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV( + p_fm_port->port_intg->max_port_fifo_size); + p_fm_port->p_fm_port_drv_param->dflt_cfg.rx_fifo_thr = + p_fm_port->p_fm_port_drv_param->rx_fifo_threshold = + DFLT_PORT_RX_FIFO_THRESHOLD( + p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_intg->max_port_fifo_size); + + p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006675 = false; + +#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || \ +defined(FM_ERROR_VSP_NO_MATCH_SW006) + if (p_fm_port->fm_rev_info.major_rev >= 6) + p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006675 = + true; +#endif + if ((p_fm_port->fm_rev_info.major_rev == 6) && + ((p_fm_port->fm_rev_info.minor_rev == 0) || + (p_fm_port->fm_rev_info.minor_rev == 3))) + p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006320 = + true; + else + p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006320 = + false; + + /* Excessive Threshold register - exists for pre-FMv3 chips only */ + if (p_fm_port->fm_rev_info.major_rev < 6) { +#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC + p_fm_port->p_fm_port_drv_param->dflt_cfg. + excessive_threshold_register = true; +#endif /* FM_NO_RESTRICT_ON_ACCESS_RSRC */ + p_fm_port->p_fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd = + false; + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.fmbm_tfne_has_features = + false; + } else { + p_fm_port->p_fm_port_drv_param->dflt_cfg. + excessive_threshold_register = false; + p_fm_port->p_fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd = + true; + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.fmbm_tfne_has_features = true; + } + if (p_fm_port->fm_rev_info.major_rev == 4) + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.qmi_deq_options_support = false; + else + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.qmi_deq_options_support = true; + + /* Continue with other parameters */ + p_fm_port->p_fm_port_drv_param->base_addr = base_addr; + /* set memory map pointers */ + p_fm_port->p_fm_port_qmi_regs = + (struct fm_port_qmi_regs_t __iomem *)UINT_TO_PTR(base_addr + + QMI_PORT_REGS_OFFSET); + p_fm_port->p_fm_port_bmi_regs = + (union fm_port_bmi_regs_u __iomem *)UINT_TO_PTR(base_addr + + BMI_PORT_REGS_OFFSET); + p_fm_port->p_fm_port_prs_regs = + (struct fm_port_prs_regs_t __iomem *)UINT_TO_PTR(base_addr + + PRS_PORT_REGS_OFFSET); + + p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.priv_data_size = + DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE; + p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.pass_prs_result = + DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT; + p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.pass_time_stamp = + DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP; + p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.pass_all_other_pcd_info = + DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP; + p_fm_port->p_fm_port_drv_param->buffer_prefix_content.data_align = + DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN; + p_fm_port->p_fm_port_drv_param->liodn_base = + p_fm_port_params->liodn_base; + p_fm_port->p_fm_port_drv_param->cheksum_last_bytes_ignore = + DEFAULT_PORT_cheksum_last_bytes_ignore; + + p_fm_port->max_frame_length = DEFAULT_PORT_max_frame_length; + /* resource distribution. */ + + p_fm_port->fifo_bufs.num = + DFLT_PORT_NUM_OF_FIFO_BUFS(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed) * BMI_FIFO_UNITS; + p_fm_port->fifo_bufs.extra = + DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS * BMI_FIFO_UNITS; + + p_fm_port->open_dmas.num = + DFLT_PORT_NUM_OF_OPEN_DMAS(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed); + p_fm_port->open_dmas.extra = + DFLT_PORT_EXTRA_NUM_OF_OPEN_DMAS(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed); + p_fm_port->tasks.num = + DFLT_PORT_NUM_OF_TASKS(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed); + p_fm_port->tasks.extra = + DFLT_PORT_EXTRA_NUM_OF_TASKS(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed); + +#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 + if ((p_fm_port->fm_rev_info.major_rev == 6) && + (p_fm_port->fm_rev_info.minor_rev == 0) && + ((p_fm_port->port_type == FM_PORT_TYPE_OP) || + ((p_fm_port->port_type == FM_PORT_TYPE_TX) && + (p_fm_port->port_speed == FM_PORT_SPEED_1G)))) { + p_fm_port->open_dmas.num = 16; + p_fm_port->open_dmas.extra = 0; + } +#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ + + /* Port type specific initialization: */ + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + /* Initialize FM port parameters for initialization phase only*/ + p_fm_port->p_fm_port_drv_param->cut_bytes_from_end = + DEFAULT_PORT_cut_bytes_from_end; + p_fm_port->p_fm_port_drv_param->en_buf_pool_depletion = + false; + p_fm_port->p_fm_port_drv_param->frm_discard_override = + DEFAULT_PORT_frm_discard_override; + + p_fm_port->p_fm_port_drv_param->rx_fifo_pri_elevation_level = + DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(p_fm_port->port_intg-> + max_port_fifo_size); + p_fm_port->p_fm_port_drv_param->rx_fifo_threshold = + DFLT_PORT_RX_FIFO_THRESHOLD(p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_intg-> + max_port_fifo_size); + + p_fm_port->p_fm_port_drv_param->buf_margins.end_margins = + DEFAULT_PORT_BUF_MARGINS_END_MAARGINS; + p_fm_port->p_fm_port_drv_param->errors_to_discard = + DEFAULT_PORT_errors_to_discard; + p_fm_port->p_fm_port_drv_param->forward_reuse_int_context = + DEFAULT_PORT_FORWARD_INT_CONTENT_REUSE; + break; + + case (FM_PORT_TYPE_TX): + if (p_fm_port->port_speed == FM_PORT_SPEED_1G) { + p_fm_port->p_fm_port_drv_param->dont_release_buf = + false; +#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 + if (p_fm_port->fm_rev_info.major_rev >= 6) { + tmp_reg = 0x00001013; + WRITE_UINT32(p_fm_port->p_fm_port_bmi_regs-> + tx_port_bmi_regs.fmbm_tfp, + tmp_reg); + } +#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */ + } + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) { + p_fm_port->p_fm_port_drv_param->tx_fifo_min_fill_level + = DFLT_PORT_TX_FIFO_MIN_FILL_LEVEL; + p_fm_port->p_fm_port_drv_param->tx_fifo_low_comf_level + = DFLT_PORT_TX_FIFO_LOW_COMF_LEVEL; + + p_fm_port->p_fm_port_drv_param->deq_type = + DEFAULT_PORT_deq_type; + p_fm_port->p_fm_port_drv_param->deq_prefetch_option = + DEFAULT_PORT_deq_prefetch_option; + } + p_fm_port->p_fm_port_drv_param->deq_high_priority = + DFLT_PORT_DEQ_HIGH_PRIORITY(p_fm_port->port_speed); + p_fm_port->p_fm_port_drv_param->deq_byte_cnt = + DFLT_PORT_DEQ_BYTE_CNT(p_fm_port->port_speed); + p_fm_port->p_fm_port_drv_param->dflt_cfg. + tx_fifo_deq_pipeline_depth = (uint8_t) + DFLT_PORT_FIFO_DEQ_PIPELINE_DEPTH( + p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed); + break; + case (FM_PORT_TYPE_OP): + p_fm_port->p_fm_port_drv_param->errors_to_discard = + DEFAULT_PORT_errors_to_discard; + break; + + default: + kfree(p_fm_port->p_fm_port_drv_param); + kfree(p_fm_port); + pr_err("Invalid port type\n"); + return NULL; + } + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_fm_port->fm_rev_info.major_rev == 4) + p_fm_port->p_fm_port_drv_param->deq_prefetch_option = + (enum fm_port_deq_prefetch_option)DEFAULT_NOT_SUPPORTED; +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_RX): + /* Initialize FM port parameters for initialization phase only*/ + memcpy(&p_fm_port->p_fm_port_drv_param->ext_buf_pools, + &p_fm_port_params-> + specific_params.rx_params.ext_buf_pools, + sizeof(struct fm_ext_pools_t)); + p_fm_port->p_fm_port_drv_param->err_fqid + = p_fm_port_params->specific_params.rx_params.err_fqid; + p_fm_port->p_fm_port_drv_param->dflt_fqid + = p_fm_port_params->specific_params.rx_params.dflt_fqid; + p_fm_port->p_fm_port_drv_param->liodn_offset + = p_fm_port_params->specific_params.rx_params.liodn_offset; + break; + case (FM_PORT_TYPE_OP): + case (FM_PORT_TYPE_TX): + p_fm_port->p_fm_port_drv_param->err_fqid = + p_fm_port_params->specific_params.non_rx_params.err_fqid; + p_fm_port->p_fm_port_drv_param->deq_sub_portal = + (uint8_t)(p_fm_port_params->specific_params.non_rx_params. + qm_channel & QMI_DEQ_CFG_SUBPORTAL_MASK); + p_fm_port->p_fm_port_drv_param->dflt_fqid = + p_fm_port_params->specific_params.non_rx_params.dflt_fqid; + break; + default: + kfree(p_fm_port->p_fm_port_drv_param); + kfree(p_fm_port); + pr_err("Invalid port type\n"); + return NULL; + } + + memset(p_fm_port->name, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (snprintf(p_fm_port->name, MODULE_NAME_SIZE, "FM-%d-port-%s-%d", + fm_get_id(p_fm_port->h_fm), + ((p_fm_port->port_type == FM_PORT_TYPE_OP) ? "OP" : + ((p_fm_port->port_type == FM_PORT_TYPE_TX) ? + ((p_fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-TX" : + "1g-TX") : + ((p_fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-RX" : + "1g-RX"))), + p_fm_port->port_id) == 0) { + kfree(p_fm_port->p_fm_port_drv_param); + kfree(p_fm_port); + pr_err("sprintf failed\n"); + return NULL; + } + + p_fm_port->spinlock = kmalloc(sizeof(spinlock_t), GFP_KERNEL); + if (!p_fm_port->spinlock) { + kfree(p_fm_port->p_fm_port_drv_param); + kfree(p_fm_port); + pr_err("Spin lock init failed\n"); + return NULL; + } + + spin_lock_init(p_fm_port->spinlock); + + return p_fm_port; +} + +/* Function fm_port_init + * Description Initializes the FM module + * Param[in] h_fm_port - FM module descriptor + * Return 0 on success; Error code otherwise. + */ +int fm_port_init(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + struct fm_port_drv_param_t *p_drv_params; + int err_code; + struct fm_inter_module_port_init_params_t fm_params; + struct fm_revision_info_t rev_info; + int ret, ret_err; + enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (!ret) + return -ENOSYS; + + err_code = + fm_sp_build_buffer_structure(&p_fm_port->p_fm_port_drv_param-> + int_context, + &p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content, + &p_fm_port->p_fm_port_drv_param-> + buf_margins, + &p_fm_port->buffer_offsets, + &p_fm_port->internal_buf_offset); + if (err_code != 0) + return -err_code; +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + if (p_fm_port->fm_rev_info.major_rev >= 6 && + (p_fm_port->p_fm_port_drv_param->bcb_workaround) && + ((p_fm_port->port_type == FM_PORT_TYPE_RX) && + (p_fm_port->port_speed == FM_PORT_SPEED_1G))) { + p_fm_port->p_fm_port_drv_param->errors_to_discard |= + FM_PORT_FRM_ERR_PHYSICAL; + if (!p_fm_port->fifo_bufs.num) + p_fm_port->fifo_bufs.num = + DFLT_PORT_NUM_OF_FIFO_BUFS( + p_fm_port->fm_rev_info.major_rev, + p_fm_port->port_type, + p_fm_port->port_speed) * + BMI_FIFO_UNITS; + p_fm_port->fifo_bufs.num += 4 * 1024; + } +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + + ret_err = check_init_parameters(p_fm_port); + if (ret_err) + return ret_err; + + p_drv_params = p_fm_port->p_fm_port_drv_param; + + /* Set up flibs port structure */ + memset(&p_fm_port->port, 0, sizeof(struct fman_port)); + /* In order to be aligned with flib port types, we need to translate + * the port type and speed to fman_port_type + */ + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { + fman_port_type = E_FMAN_PORT_TYPE_OP; + } else if (p_fm_port->port_type == FM_PORT_TYPE_TX) { + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + fman_port_type = E_FMAN_PORT_TYPE_TX_10G; + else + fman_port_type = E_FMAN_PORT_TYPE_TX; + } else if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + if (p_fm_port->port_speed == FM_PORT_SPEED_10G) + fman_port_type = E_FMAN_PORT_TYPE_RX_10G; + else + fman_port_type = E_FMAN_PORT_TYPE_RX; + } + p_fm_port->port.type = fman_port_type; + fm_get_revision(p_fm_port->h_fm, &rev_info); + p_fm_port->port.fm_rev_maj = rev_info.major_rev; + p_fm_port->port.fm_rev_min = rev_info.minor_rev; + p_fm_port->port.bmi_regs = (union fman_port_bmi_regs __iomem *) + UINT_TO_PTR(p_drv_params->base_addr + BMI_PORT_REGS_OFFSET); + p_fm_port->port.qmi_regs = (struct fman_port_qmi_regs __iomem *) + UINT_TO_PTR(p_drv_params->base_addr + QMI_PORT_REGS_OFFSET); + p_fm_port->port.ext_pools_num = + (uint8_t)((rev_info.major_rev == 4) ? 4 : 8); + p_fm_port->p_fm_port_prs_regs = (struct fm_port_prs_regs_t __iomem *) + UINT_TO_PTR(p_drv_params->base_addr + PRS_PORT_REGS_OFFSET); + + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + /* Call the external Buffer routine which also checks fifo + * size and updates it if necessary + */ + /* define external buffer pools and pool depletion */ + err_code = set_ext_buffer_pools(p_fm_port); + if (err_code) + return -err_code; + /* check if the largest external buffer pool is large enough */ + if (p_drv_params->buf_margins.start_margins + + MIN_EXT_BUF_SIZE + + p_drv_params->buf_margins.end_margins > + p_fm_port->rx_pools_params.largest_buf_size) { + pr_err("buf_margins.start_margins (%d) + minimum buf size (64) + buf_margins.end_margins (%d) is larger than maximum external buffer size (%d)\n", + p_drv_params->buf_margins.start_margins, + p_drv_params->buf_margins.end_margins, + p_fm_port->rx_pools_params.largest_buf_size); + return -ENOSYS; + } + } + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { + { +#ifdef FM_NO_OP_OBSERVED_POOLS + struct fm_revision_info_t rev_info; + + fm_get_revision(p_fm_port->h_fm, &rev_info); + if ((rev_info.major_rev == 4) && + (p_drv_params->en_buf_pool_depletion)) +#endif /* FM_NO_OP_OBSERVED_POOLS */ + { + /* define external buffer pools */ + err_code = set_ext_buffer_pools(p_fm_port); + if (err_code) + return -err_code; + } + } + } + + /* Call FM module routine for communicating parameters */ + + memset(&fm_params, 0, sizeof(fm_params)); + fm_params.port_id = p_fm_port->port_id; + fm_params.port_type = (enum fm_port_type)p_fm_port->port_type; + fm_params.port_speed = (enum fm_port_speed)p_fm_port->port_speed; + fm_params.num_of_tasks = (uint8_t)p_fm_port->tasks.num; + fm_params.num_of_extra_tasks = (uint8_t)p_fm_port->tasks.extra; + fm_params.num_of_open_dmas = (uint8_t)p_fm_port->open_dmas.num; + fm_params.num_of_extra_open_dmas = (uint8_t)p_fm_port->open_dmas.extra; + + if (p_fm_port->fifo_bufs.num) { + err_code = verify_size_of_fifo(p_fm_port); + if (err_code != 0) + return -err_code; + } + fm_params.size_of_fifo = p_fm_port->fifo_bufs.num; + fm_params.extra_size_of_fifo = p_fm_port->fifo_bufs.extra; + fm_params.liodn_offset = p_drv_params->liodn_offset; + fm_params.liodn_base = p_drv_params->liodn_base; + fm_params.deq_pipeline_depth = + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.tx_fifo_deq_pipeline_depth; + fm_params.max_frame_length = p_fm_port->max_frame_length; +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { + if (!((p_fm_port->fm_rev_info.major_rev == 4) || + (p_fm_port->fm_rev_info.major_rev >= 6))) + /* OP ports do not have fifoDeqPipelineDepth, + * but it is needed only + *for deq threshold calculation. + */ + fm_params.deq_pipeline_depth = 2; + } +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + + err_code = fm_get_set_port_params(p_fm_port->h_fm, &fm_params); + if (err_code) + return -err_code; + + /* get params for use in init */ + p_fm_port->fm_muram_phys_base_addr = + (phys_addr_t)((uint64_t)(fm_params.fm_muram_phys_base_addr.low) | + ((uint64_t)(fm_params.fm_muram_phys_base_addr.high) << + 32)); + p_fm_port->p_muram = fm_get_muram_pointer(p_fm_port->h_fm); + + err_code = init_low_level_driver(p_fm_port); + if (err_code != 0) + return -err_code; + + fm_port_drv_param_free(p_fm_port); + + if ((p_fm_port->fm_rev_info.major_rev >= 6) && + ((p_fm_port->port_type == FM_PORT_TYPE_RX) || + (p_fm_port->port_type == FM_PORT_TYPE_OP))) { + struct fm_pcd_ctrl_params_page_t __iomem *p_params_page; + + fm_port_set_gpr_func(p_fm_port, FM_PORT_GPR_MURAM_PAGE, + (void **)&p_params_page); + ASSERT(p_params_page); + + WRITE_UINT32(p_params_page->misc, + FM_CTL_PARAMS_PAGE_ALWAYS_ON); +#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 + if (p_fm_port->fm_rev_info.major_rev >= 6 && + p_fm_port->port_type == FM_PORT_TYPE_OP) { + WRITE_UINT32(p_params_page->misc, + (GET_UINT32(p_params_page->misc) | + FM_CTL_PARAMS_PAGE_OP_FIX_EN)); + WRITE_UINT32(p_params_page->discard_mask, + GET_UINT32(p_fm_port->p_fm_port_bmi_regs-> + oh_port_bmi_regs.fmbm_ofsdm)); + } +#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */ +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_fm_port->fm_rev_info.major_rev >= 6) { + if (p_fm_port->port_type == FM_PORT_TYPE_OP) + WRITE_UINT32(p_params_page-> + errors_discard_mask, + (GET_UINT32(p_fm_port-> + p_fm_port_bmi_regs-> + oh_port_bmi_regs.fmbm_ofsdm) | + GET_UINT32(p_fm_port-> + p_fm_port_bmi_regs-> + oh_port_bmi_regs. + fmbm_ofsem))); + else + WRITE_UINT32(p_params_page-> + errors_discard_mask, + (GET_UINT32(p_fm_port-> + p_fm_port_bmi_regs-> + rx_port_bmi_regs.fmbm_rfsdm) | + GET_UINT32(p_fm_port-> + p_fm_port_bmi_regs-> + rx_port_bmi_regs.fmbm_rfsem))); + } +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + } + + return 0; +} + +void *fm_port_get_handle(const struct fm_port *port); + +/* Function fm_port_free + * Description Frees all resources that were assigned to FM module. + * Calling this routine invalidates the descriptor. + * Param[in] h_fm_port - FM module descriptor + * Return 0 on success; Error code otherwise. + */ +int fm_port_free(struct fm_port *port) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + struct fm_inter_module_port_free_params_t fm_params; + + if (p_fm_port->pcd_engines) { + pr_err("Trying to free a port with PCD. fm_port_delete_pcd must be called first.\n"); + return -ENOSYS; + } + + if (p_fm_port->enabled) { + if (fm_port_disable(port) != 0) { + pr_err("fm_port_disable FAILED\n"); + return -ENOSYS; + } + } + + fm_port_drv_param_free(p_fm_port); + + fm_params.port_id = p_fm_port->port_id; + fm_params.port_type = (enum fm_port_type)p_fm_port->port_type; + fm_params.deq_pipeline_depth = + p_fm_port->p_fm_port_drv_param-> + dflt_cfg.tx_fifo_deq_pipeline_depth; + + fm_free_port_params(p_fm_port->h_fm, &fm_params); + + if (p_fm_port->fm_rev_info.major_rev >= 6 && p_fm_port->p_params_page) + fm_muram_free_mem(p_fm_port->p_muram, p_fm_port-> + p_params_page); + + kfree(p_fm_port->spinlock); + + kfree(p_fm_port); + + return 0; +} + +/* API Advanced Init unit functions */ + +int fm_port_cfg_deq_high_priority(void *h_fm_port, bool high_pri) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (!ret) + return -ENOSYS; + + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + pr_err("not available for Rx ports\n"); + return -ENOMEM; + } + + p_fm_port->p_fm_port_drv_param->dflt_cfg.deq_high_pri = high_pri; + + return 0; +} + +int fm_port_cfg_deq_prefetch_option(void *h_fm_port, + enum fm_port_deq_prefetch_option + deq_prefetch_option) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (!ret) + return -ENOSYS; + + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + pr_err("not available for Rx ports\n"); + return -ENODEV; + } + p_fm_port->p_fm_port_drv_param->dflt_cfg.deq_prefetch_opt = + (enum fman_port_deq_prefetch)deq_prefetch_option; + + return 0; +} + +int fm_port_cfg_buf_prefix_content(void *h_fm_port, + struct fm_buffer_prefix_content_t * + p_fm_buffer_prefix_content) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (!ret) + return -ENOSYS; + + memcpy(&p_fm_port->p_fm_port_drv_param->buffer_prefix_content, + p_fm_buffer_prefix_content, + sizeof(struct fm_buffer_prefix_content_t)); + /* if data_align was not initialized by user, + * we return to driver's default + **/ + if (!p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.data_align) + p_fm_port->p_fm_port_drv_param-> + buffer_prefix_content.data_align = + DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN; + + return 0; +} + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 +int fm_port_cfg_bcb_wa(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (!ret) + return -ENOSYS; + + p_fm_port->p_fm_port_drv_param->bcb_workaround = true; + + return 0; +} +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + +/* API Run-time Control unit functions */ + +u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port, char *p_data) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return NULL; + + if (p_fm_port->buffer_offsets.time_stamp_offset == ILLEGAL_BASE) + return NULL; + + return (uint64_t *)PTR_MOVE(p_data, + p_fm_port-> + buffer_offsets.time_stamp_offset); +} +EXPORT_SYMBOL(fm_port_get_buffer_time_stamp); + +int fm_port_disable(struct fm_port *port) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + err = fman_port_disable(&p_fm_port->port); + if (err == -EBUSY) { + pr_debug("%s: BMI or QMI is Busy. Port forced down\n", + p_fm_port->name); + err = 0; + } + + p_fm_port->enabled = false; + + return err; +} +EXPORT_SYMBOL(fm_port_disable); + +int fm_port_suspend(struct fm_port *port) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + err = fman_port_disable(&p_fm_port->port); + if (err == -EBUSY) { + pr_debug("%s: BMI or QMI is Busy. Port forced down\n", + p_fm_port->name); + err = 0; + } + + p_fm_port->enabled = false; + + return err; +} +EXPORT_SYMBOL(fm_port_suspend); + +int fm_port_enable(struct fm_port *port) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + /* Used by fm_port_free routine as indication + * if to disable port. Thus set it to true prior + * to enabling itself. This way if part of enable + * process fails there will be still things + * to disable during Free. For example, if BMI + * enable succeeded but QMI failed, still BMI + * needs to be disabled by Free. + */ + p_fm_port->enabled = true; + + err = fman_port_enable(&p_fm_port->port); + + return err; +} +EXPORT_SYMBOL(fm_port_enable); + +int fm_port_resume(struct fm_port *port) +{ + struct fm_port_t *p_fm_port = + (struct fm_port_t *)fm_port_get_handle(port); + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + /* Used by fm_port_free routine as indication + * if to disable port. Thus set it to true prior + * to enabling itself. This way if part of enable + * process fails there will be still things + * to disable during Free. For example, if BMI + * enable succeeded but QMI failed, still BMI + * needs to be disabled by Free. + */ + p_fm_port->enabled = true; + + err = fman_port_enable(&p_fm_port->port); + + return err; +} +EXPORT_SYMBOL(fm_port_resume); + +int fm_port_set_rate_lim(void *h_fm_port, struct fm_port_rate_limit_t + *p_rate_limit) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + uint8_t factor, count_unit_bit; + uint16_t base_gran; + struct fman_port_rate_limiter params; + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + switch (p_fm_port->port_type) { + case (FM_PORT_TYPE_TX): + base_gran = BMI_RATE_LIMIT_GRAN_TX; + break; + case (FM_PORT_TYPE_OP): + base_gran = BMI_RATE_LIMIT_GRAN_OP; + break; + default: + pr_err("available for Tx and Offline parsing ports only"); + return -ENODEV; + } + /* TimeStamp per nano seconds units */ + count_unit_bit = (uint8_t)fm_get_time_stamp_scale(p_fm_port->h_fm); + /* normally, we use 1 usec as the reference count */ + factor = 1; + /* if ratelimit is too small for a 1usec factor, multiply the factor */ + while (p_rate_limit->rate_limit < base_gran / factor) { + if (count_unit_bit == 31) { + pr_err("Rate limit is too small\n"); + return -EDOM; + } + count_unit_bit++; + factor <<= 1; + } + /* if ratelimit is too large for a 1usec factor, + * it is also larger than max rate + */ + if (p_rate_limit->rate_limit > + ((uint32_t)base_gran * (1 << 10) * (uint32_t)factor)) { + pr_err("Rate limit is too large\n"); + return -EDOM; + } + + if (!p_rate_limit->max_burst_size || + (p_rate_limit->max_burst_size > BMI_RATE_LIMIT_MAX_BURST_SIZE)) { + pr_err("max_burst_size must be between 1K and %dk\n", + BMI_RATE_LIMIT_MAX_BURST_SIZE); + return -EDOM; + } + + params.count_1micro_bit = (uint8_t)fm_get_time_stamp_scale(p_fm_port-> + h_fm); + params.high_burst_size_gran = false; + params.burst_size = p_rate_limit->max_burst_size; + params.rate = p_rate_limit->rate_limit; + params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE; + + if (p_fm_port->port_type == FM_PORT_TYPE_OP) { +#ifndef FM_NO_ADVANCED_RATE_LIMITER + + if ((p_fm_port->fm_rev_info.major_rev == 4) || + (p_fm_port->fm_rev_info.major_rev >= 6)) { + params.high_burst_size_gran = true; + } else +#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */ + { + if (p_rate_limit->rate_limit_divider != + FM_PORT_DUAL_RATE_LIMITER_NONE) { + pr_err("fm_port_configDualRateLimitScaleDown\n"); + return -ENOSYS; + } + + if (p_rate_limit->max_burst_size % 1000) { + p_rate_limit->max_burst_size = + (uint16_t)((p_rate_limit->max_burst_size / + 1000) + 1); + pr_debug("rate_limit.max_burst_size rounded up to %d\n", + (p_rate_limit->max_burst_size / + 1000 + 1) * 1000); + } else { + p_rate_limit->max_burst_size = + (uint16_t)(p_rate_limit->max_burst_size / + 1000); + } + } + params.rate_factor = + (enum fman_port_rate_limiter_scale_down)p_rate_limit-> + rate_limit_divider; + params.burst_size = p_rate_limit->max_burst_size; + } + + err = fman_port_set_rate_limiter(&p_fm_port->port, ¶ms); + if (err != 0) { + pr_err("fman_port_set_rate_limiter\n"); + return -EDOM; + } + + return 0; +} + +int fm_port_delete_rate_limit(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int err, ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if (p_fm_port->port_type == FM_PORT_TYPE_RX) { + pr_err("available for Tx and Offline parsing ports only\n"); + return -ENODEV; + } + + err = fman_port_delete_rate_limiter(&p_fm_port->port); + if (err != 0) { + pr_err("fman_port_set_rate_limiter\n"); + return -EDOM; + } + return 0; +} + +/* API Run-time PCD Control unit functions */ + +int fm_port_attach_pcd(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + int err = 0; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -EDOM; + } + + if (!TRY_LOCK(p_fm_port->spinlock, &p_fm_port->lock)) { + pr_debug("FM Port Try Lock - BUSY\n"); + return -EBUSY; + } + + err = attach_pcd(h_fm_port); + RELEASE_LOCK(p_fm_port->lock); + + return err; +} + +int fm_port_detach_pcd(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + int err = 0; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -ENOSYS; + } + + if (!TRY_LOCK(p_fm_port->spinlock, &p_fm_port->lock)) { + pr_debug("FM Port Try Lock - BUSY\n"); + return -EBUSY; + } + + err = detach_pcd(h_fm_port); + if (err != 0) { + RELEASE_LOCK(p_fm_port->lock); + return err; + } + + RELEASE_LOCK(p_fm_port->lock); + + return 0; +} + +int fm_port_set_pcd(void *h_fm_port, + struct fm_port_pcd_params_t *p_pcd_param) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int err = 0; + struct fm_port_pcd_params_t modified_pcd_params, *p_pcd_params; + struct fm_pcd_ctrl_params_page_t __iomem *p_params_page; + int ret; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -ENODEV; + } + + if (!TRY_LOCK(p_fm_port->spinlock, &p_fm_port->lock)) { + pr_debug("FM Port Try Lock - BUSY\n"); + return -EBUSY; + } + + p_fm_port->h_fm_pcd = fm_get_pcd_handle(p_fm_port->h_fm); + ASSERT(p_fm_port->h_fm_pcd); + + memcpy(&modified_pcd_params, p_pcd_param, + sizeof(struct fm_port_pcd_params_t)); + p_pcd_params = &modified_pcd_params; + + if (!fm_pcd_lock_try_lock_all(p_fm_port->h_fm_pcd)) { + RELEASE_LOCK(p_fm_port->lock); + pr_debug("Try LockAll - BUSY\n"); + return -EBUSY; + } + + err = set_pcd(h_fm_port, p_pcd_params); + if (err) { + fm_pcd_lock_unlock_all(p_fm_port->h_fm_pcd); + RELEASE_LOCK(p_fm_port->lock); + return err; + } + + if ((p_fm_port->pcd_engines & FM_PCD_PRS) && + (p_pcd_params->p_prs_params->include_in_prs_statistics)) { + err = + fm_pcd_prs_include_port_in_statistics(p_fm_port->h_fm_pcd, + p_fm_port-> + port_id, + true); + if (err) { + delete_pcd(p_fm_port); + fm_pcd_lock_unlock_all(p_fm_port->h_fm_pcd); + RELEASE_LOCK(p_fm_port->lock); + return err; + } + p_fm_port->include_in_prs_statistics = true; + } + + fm_pcd_lock_unlock_all(p_fm_port->h_fm_pcd); + + if (p_fm_port->fm_rev_info.major_rev >= 6) { + fm_port_set_gpr_func(p_fm_port, FM_PORT_GPR_MURAM_PAGE, + (void **)&p_params_page); + ASSERT(p_params_page); + } + + err = attach_pcd(h_fm_port); + if (err) { + delete_pcd(p_fm_port); + RELEASE_LOCK(p_fm_port->lock); + return err; + } + + RELEASE_LOCK(p_fm_port->lock); + + return err; +} + +int fm_port_delete_pcd(void *h_fm_port) +{ + struct fm_port_t *p_fm_port = (struct fm_port_t *)h_fm_port; + int ret; + int err = 0; + + ret = is_init_done(p_fm_port->p_fm_port_drv_param); + if (ret) + return ret; + + if ((p_fm_port->port_type != FM_PORT_TYPE_RX) && + (p_fm_port->port_type != FM_PORT_TYPE_OP)) { + pr_err("available for Rx and offline parsing ports only\n"); + return -ENODEV; + } + + if (!TRY_LOCK(p_fm_port->spinlock, &p_fm_port->lock)) { + pr_debug("FM Port Try Lock - BUSY\n"); + return -EBUSY; + } + + err = detach_pcd(h_fm_port); + if (err) { + RELEASE_LOCK(p_fm_port->lock); + return err; + } + + /* we do it anyway, instead of checking if included */ + if ((p_fm_port->pcd_engines & FM_PCD_PRS) && + p_fm_port->include_in_prs_statistics) { + fm_pcd_prs_include_port_in_statistics(p_fm_port->h_fm_pcd, + p_fm_port-> + port_id, + false); + p_fm_port->include_in_prs_statistics = false; + } + + if (!fm_pcd_lock_try_lock_all(p_fm_port->h_fm_pcd)) { + RELEASE_LOCK(p_fm_port->lock); + pr_debug("Try LockAll - BUSY\n"); + return -EBUSY; + } + + err = delete_pcd(h_fm_port); + fm_pcd_lock_unlock_all(p_fm_port->h_fm_pcd); + if (err) { + RELEASE_LOCK(p_fm_port->lock); + return err; + } + + RELEASE_LOCK(p_fm_port->lock); + + return err; +}
diff --git a/drivers/soc/fsl/fman/port/fm_port.h b/drivers/soc/fsl/fman/port/fm_port.h
new file mode 100644
index 0000000..7b0a878
--- /dev/null
+++ b/drivers/soc/fsl/fman/port/fm_port.h@@ -0,0 +1,743 @@ +/* + * Copyright 2008 - 2015 Freescale Semiconductor Inc. + * + * 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. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* FM Port internal structures and definitions. */ +#ifndef __FM_PORT_H +#define __FM_PORT_H + +#include "service.h" + +#include "fm_common.h" +#include "fm_sp_common.h" +#include "fsl_fman_sp.h" +#include "fm_port_ext.h" +#include "fsl_fman_port.h" + +#define MIN_EXT_BUF_SIZE 64 +#define DATA_ALIGNMENT 64 +#define MAX_LIODN_OFFSET 64 + +#define MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) \ + min((u32)bmi_max_fifo_size, (u32)1024 * BMI_FIFO_UNITS) + +/* Memory Map defines */ +#define BMI_PORT_REGS_OFFSET 0 +#define QMI_PORT_REGS_OFFSET 0x400 +#define PRS_PORT_REGS_OFFSET 0x800 + +/* defaults */ +#define DFLT_PORT_DEQ_HIGH_PRIORITY(speed) \ + ((speed == FM_PORT_SPEED_10G) ? true : false) +#define DEFAULT_PORT_deq_type FM_PORT_DEQ_TYPE1 +#define DEFAULT_PORT_deq_prefetch_option FM_PORT_DEQ_FULL_PREFETCH +#define DEFAULT_PORT_deq_prefetch_option_HC FM_PORT_DEQ_NO_PREFETCH +#define DFLT_PORT_DEQ_BYTE_CNT(speed) \ + ((speed == FM_PORT_SPEED_10G) ? 0x1400 : 0x400) +#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE \ +DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE +#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT \ +DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_PASS_PRS_RESULT +#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP \ +DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_PASS_TIME_STAMP +#define DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN \ +DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN +#define DEFAULT_PORT_cheksum_last_bytes_ignore 0 +#define DEFAULT_PORT_cut_bytes_from_end 4 + +#define DEFAULT_PORT_frm_discard_override false + +#define DEFAULT_PORT_FORWARD_INT_CONTENT_REUSE false +#define DEFAULT_PORT_BUF_MARGINS_END_MAARGINS 0 +#define DEFAULT_PORT_sync_req true +#define DEFAULT_PORT_color FM_PORT_COLOR_GREEN +#define DEFAULT_PORT_errors_to_discard \ +FM_PORT_FRM_ERR_CLS_DISCARD +#define DEFAULT_PORT_exception IM_EV_BSY +#define DEFAULT_PORT_max_frame_length 9600 + +#define DEFAULT_NOT_SUPPORTED 0xff + +#define DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(bmi_max_fifo_size) \ + MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) + +#define DFLT_PORT_RX_FIFO_THRESHOLD(major, bmi_max_fifo_size) \ + (major == 6 ? \ + MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) : \ + (MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) * 3 / 4)) \ + +#define DFLT_PORT_TX_FIFO_MIN_FILL_LEVEL 0 +#define DFLT_PORT_TX_FIFO_LOW_COMF_LEVEL (5 * 1024) + +/* OP - 2, 10G - 4, 1G (FMAN V3 - 2, FMAN V2 - 1) */ +#define DFLT_PORT_FIFO_DEQ_PIPELINE_DEPTH(major, type, speed) \ + ((type == FM_PORT_TYPE_OP) ? 2 : \ + ((speed == FM_PORT_SPEED_10G) ? 4 : \ + ((major >= 6) ? 2 : 1))) + +#define DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS 0 + +/* FMAN V3: OP - 6, 10G (RX/TX 16), 1G (RX/TX) 4 + * FMAN V2: OP - 3, 10G (TX/TX 16), 1G (RX/TX) 3 + */ +#define DFLT_PORT_NUM_OF_TASKS(major, type, speed) \ + ((major >= 6) ? \ + ((type == FM_PORT_TYPE_OP) ? 6 : \ + ((speed == FM_PORT_SPEED_10G) ? 16 : 4)) : \ + ((speed == FM_PORT_SPEED_10G) ? 16 : 3)) + +/* FMAN V3: 0 for all ports + * FMAN V2: RX 10G - 8, RX 1G 2, TX/OP - 0 + */ +#define DFLT_PORT_EXTRA_NUM_OF_TASKS(major, type, speed) \ + ((major >= 6) ? 0 : \ + ((type == FM_PORT_TYPE_RX) ? \ + ((speed == FM_PORT_SPEED_10G) ? 8 : 2) : 0)) + +/* FMAN V3: 10G RX - 8, 1G RX - 2, 10G TX - 12, 1G TX 3, OP - 6 + * FMAN V2: 10G RX/TX - 8, 1G(TX/RX)/OP - 1 + */ +#define DFLT_PORT_NUM_OF_OPEN_DMAS(major, type, speed) \ + ((major >= 6) ? \ + ((type == FM_PORT_TYPE_RX) ? \ + ((speed == FM_PORT_SPEED_10G) ? 8 : 2) : \ + ((type == FM_PORT_TYPE_TX) ? \ + ((speed == FM_PORT_SPEED_10G) ? 12 : 3) : 4)) : \ + ((speed == FM_PORT_SPEED_10G) ? 8 : 1)) + +/* FMAN V3: 0 for all ports + * FMAN V2: RX 10G - 8, 1G RX/TX & OP - 1 + */ +#define DFLT_PORT_EXTRA_NUM_OF_OPEN_DMAS(major, type, speed) \ + ((major >= 6) ? 0 : \ + ((speed == FM_PORT_SPEED_10G) ? 8 : 1)) + +/* FMAN V3: 10G RX - 96, 10G TX 64, 1G/OP 50 + * FMAN V2: 10G - 48, 1G RX 45, 1G TX 44, OP = 8 + */ +#define DFLT_PORT_NUM_OF_FIFO_BUFS(major, type, speed) \ + (major >= 6 ? \ + (((speed == FM_PORT_SPEED_10G) ? \ + ((type == FM_PORT_TYPE_RX) ? (96) : (64)) : (50))) : \ + ((speed == FM_PORT_SPEED_10G) ? 48 : \ + ((type == FM_PORT_TYPE_OP) ? 8 : \ + ((type == FM_PORT_TYPE_RX) ? 45 : 44)))) \ + +#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256 + +#define FM_OH_PORT_ID 1 + +/* Memory Mapped Registers */ + +struct fm_port_rx_bmi_regs_t { + uint32_t fmbm_rcfg; /* Rx Configuration */ + uint32_t fmbm_rst; /* Rx Status */ + uint32_t fmbm_rda; /* Rx DMA attributes*/ + uint32_t fmbm_rfp; /* Rx FIFO Parameters*/ + uint32_t fmbm_rfed; /* Rx Frame End Data*/ + uint32_t fmbm_ricp; /* Rx Internal Context Parameters*/ + uint32_t fmbm_rim; /* Rx Internal Buffer Margins*/ + uint32_t fmbm_rebm; /* Rx External Buffer Margins*/ + uint32_t fmbm_rfne; /* Rx Frame Next Engine*/ + uint32_t fmbm_rfca; /* Rx Frame Command Attributes.*/ + uint32_t fmbm_rfpne; /* Rx Frame Parser Next Engine*/ + uint32_t fmbm_rpso; /* Rx Parse Start Offset*/ + uint32_t fmbm_rpp; /* Rx Policer Profile */ + uint32_t fmbm_rccb; /* Rx Coarse Classification Base */ + uint32_t fmbm_reth; /* Rx Excessive Threshold */ + uint32_t reserved1[0x01]; + /* (0x03C) */ + uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /* Rx Parse Results Array Initialization*/ + uint32_t fmbm_rfqid; /* Rx Frame Queue ID*/ + uint32_t fmbm_refqid; /* Rx Error Frame Queue ID*/ + uint32_t fmbm_rfsdm; /* Rx Frame Status Discard Mask*/ + uint32_t fmbm_rfsem; /* Rx Frame Status Error Mask*/ + uint32_t fmbm_rfene; /* Rx Frame Enqueue Next Engine */ + uint32_t reserved2[0x02]; + /* (0x074-0x078) */ + /* Rx Frame Continuous Mode Next Engine */ + uint32_t fmbm_rcmne; + uint32_t reserved3[0x20]; + /* (0x080 0x0FF) */ + uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /* Buffer Manager pool Information-*/ + uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /* Allocate Counter-*/ + uint32_t reserved4[0x08]; + /* 0x130/0x140 - 0x15F reserved -*/ + uint32_t + fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS / 32]; + /* Congestion Group Map*/ + uint32_t fmbm_rmpd; /* BM Pool Depletion */ + uint32_t reserved5[0x1F]; + /* (0x184 0x1FF) */ + uint32_t fmbm_rstc; /* Rx Statistics Counters*/ + uint32_t fmbm_rfrc; /* Rx Frame Counter*/ + uint32_t fmbm_rfbc; /* Rx Bad Frames Counter*/ + uint32_t fmbm_rlfc; /* Rx Large Frames Counter*/ + uint32_t fmbm_rffc; /* Rx Filter Frames Counter*/ + uint32_t fmbm_rfcd; /* Rx Frame Discard Counter*/ + uint32_t fmbm_rfldec; /* Rx Frames List DMA Error Counter*/ + uint32_t fmbm_rodc;/* Rx Out of Buffers Discard Counter-*/ + uint32_t fmbm_rbdc; /* Rx Buffers Deallocate Counter-*/ + uint32_t fmbm_rpec; /* Rx RX Prepare to enqueue Counter-*/ + uint32_t reserved6[0x16]; + /* (0x228 0x27F) */ + uint32_t fmbm_rpc; /* Rx Performance Counters*/ + uint32_t fmbm_rpcp; /* Rx Performance Count Parameters*/ + uint32_t fmbm_rccn; /* Rx Cycle Counter*/ + uint32_t fmbm_rtuc; /* Rx Tasks Utilization Counter*/ + uint32_t fmbm_rrquc;/* Rx Receive Queue Utilization Counter*/ + uint32_t fmbm_rduc; /* Rx DMA Utilization Counter*/ + uint32_t fmbm_rfuc; /* Rx FIFO Utilization Counter*/ + uint32_t fmbm_rpac; /* Rx Pause Activation Counter*/ + uint32_t reserved7[0x18]; + /* (0x2A0-0x2FF) */ + uint32_t fmbm_rdcfg[0x3]; + /* Rx Debug-*/ + uint32_t fmbm_rgpr; /* Rx General Purpose Register. */ + uint32_t reserved8[0x3a]; + /* (0x310-0x3FF) */ +} __attribute__((__packed__)); + +struct fm_port_tx_bmi_regs_t { + uint32_t fmbm_tcfg; /* Tx Configuration */ + uint32_t fmbm_tst; /* Tx Status */ + uint32_t fmbm_tda; /* Tx DMA attributes */ + uint32_t fmbm_tfp; /* Tx FIFO Parameters */ + uint32_t fmbm_tfed; /* Tx Frame End Data */ + uint32_t fmbm_ticp; /* Tx Internal Context Parameters */ + uint32_t fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */ + uint32_t fmbm_tfca; /* Tx Frame Command attribute. */ + uint32_t fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */ + uint32_t fmbm_tfeqid; /* Tx Frame Error Queue ID */ + uint32_t fmbm_tfene; /* Tx Frame Enqueue Next Engine */ + uint32_t fmbm_trlmts; /* Tx Rate Limiter Scale */ + uint32_t fmbm_trlmt; /* Tx Rate Limiter */ + uint32_t fmbm_tccb; /* Tx Coarse Classification Base */ + uint32_t reserved0[0x0e]; + /* (0x038-0x070) */ + uint32_t fmbm_tfne; /* Tx Frame Next Engine */ + uint32_t fmbm_tpfcm[0x02]; + /* Tx Priority based Flow Control (PFC) Mapping */ + /* Tx Frame Continuous Mode Next Engine */ + uint32_t fmbm_tcmne; + uint32_t reserved2[0x60]; + /* (0x080-0x200) */ + uint32_t fmbm_tstc; /* Tx Statistics Counters */ + uint32_t fmbm_tfrc; /* Tx Frame Counter */ + uint32_t fmbm_tfdc; /* Tx Frames Discard Counter */ + uint32_t fmbm_tfledc; /* Tx Frame Length error discard counter */ + /* Tx Frame unsupported format discard Counter */ + uint32_t fmbm_tfufdc; + uint32_t fmbm_tbdc; /* Tx Buffers Deallocate Counter */ + uint32_t reserved3[0x1A]; + /* (0x218-0x280) */ + uint32_t fmbm_tpc; /* Tx Performance Counters*/ + uint32_t fmbm_tpcp; /* Tx Performance Count Parameters*/ + uint32_t fmbm_tccn; /* Tx Cycle Counter*/ + uint32_t fmbm_ttuc; /* Tx Tasks Utilization Counter*/ + /* Tx Transmit Confirm Queue Utilization Counter*/ + uint32_t fmbm_ttcquc; + uint32_t fmbm_tduc; /* Tx DMA Utilization Counter*/ + uint32_t fmbm_tfuc; /* Tx FIFO Utilization Counter*/ + uint32_t reserved4[16];/* (0x29C-0x2FF) */ + uint32_t fmbm_tdcfg[0x3]; + /* Tx Debug-*/ + uint32_t fmbm_tgpr; /* O/H General Purpose Register */ + uint32_t reserved5[0x3a]; + /* (0x310-0x3FF) */ +} __attribute__((__packed__)); + +struct fm_port_oh_bmi_regs_t { + uint32_t fmbm_ocfg; /* O/H Configuration */ + uint32_t fmbm_ost; /* O/H Status */ + uint32_t fmbm_oda; /* O/H DMA attributes */ + uint32_t fmbm_oicp; /* O/H Internal Context Parameters*/ + uint32_t fmbm_ofdne; /* O/H Frame Dequeue Next Engine */ + uint32_t fmbm_ofne; /* O/H Frame Next Engine */ + uint32_t fmbm_ofca; /* O/H Frame Command Attributes. */ + uint32_t fmbm_ofpne; /* O/H Frame Parser Next Engine */ + uint32_t fmbm_opso; /* O/H Parse Start Offset */ + uint32_t fmbm_opp; /* O/H Policer Profile */ + uint32_t fmbm_occb; /* O/H Coarse Classification base */ + uint32_t fmbm_oim; /* O/H Internal margins*/ + uint32_t fmbm_ofp; /* O/H Fifo Parameters*/ + uint32_t fmbm_ofed; /* O/H Frame End Data*/ + uint32_t reserved0[2]; /* (0x038 - 0x03F) */ + uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /* O/H Parse Results Array Initialization */ + uint32_t fmbm_ofqid; /* O/H Frame Queue ID */ + uint32_t fmbm_oefqid; /* O/H Error Frame Queue ID */ + uint32_t fmbm_ofsdm; /* O/H Frame Status Discard Mask */ + uint32_t fmbm_ofsem; /* O/H Frame Status Error Mask */ + uint32_t fmbm_ofene; /* O/H Frame Enqueue Next Engine */ + uint32_t fmbm_orlmts; /* O/H Rate Limiter Scale */ + uint32_t fmbm_orlmt; /* O/H Rate Limiter */ + uint32_t fmbm_ocmne; /* O/H Continuous Mode Next Engine*/ + uint32_t reserved1[0x20]; + /* (0x080 - 0x0FF) */ + /* Buffer Manager Observed Pool Information */ + uint32_t fmbm_oebmpi[2]; + uint32_t reserved2[0x16]; + /* (0x108 - 0x15F) */ + uint32_t fmbm_ocgm; /* Observed Congestion Group Map */ + uint32_t reserved3[0x7]; + /* (0x164 - 0x17F) */ + uint32_t fmbm_ompd; /* Observed BMan Pool Depletion */ + uint32_t reserved4[0x1F]; + /* (0x184 - 0x1FF) */ + uint32_t fmbm_ostc; /* O/H Statistics Counters */ + uint32_t fmbm_ofrc; /* O/H Frame Counter */ + uint32_t fmbm_ofdc; /* O/H Frames Discard Counter */ + /* O/H Frames Length Error Discard Counter */ + uint32_t fmbm_ofledc; + /* O/H Frames Unsupported Format Discard Counter */ + uint32_t fmbm_ofufdc; + uint32_t fmbm_offc; /* O/H Filter Frames Counter */ + uint32_t fmbm_ofwdc; /* - Rx Frames WRED Discard Counter*/ + /* O/H Frames List DMA Error Counter */ + uint32_t fmbm_ofldec; + /* O/H Buffers Deallocate Counter */ + uint32_t fmbm_obdc; + /* O/H Out of Buffers Discard Counter */ + uint32_t fmbm_oodc; + /* O/H Prepare to enqueue Counter */ + uint32_t fmbm_opec; + uint32_t reserved5[0x15]; + /* ( - 0x27F) */ + uint32_t fmbm_opc; /* O/H Performance Counters */ + uint32_t fmbm_opcp; /* O/H Performance Count Parameters*/ + uint32_t fmbm_occn; /* O/H Cycle Counter */ + uint32_t fmbm_otuc; /* O/H Tasks Utilization Counter */ + uint32_t fmbm_oduc; /* O/H DMA Utilization Counter */ + uint32_t fmbm_ofuc; /* O/H FIFO Utilization Counter */ + uint32_t reserved6[26];/* (0x298-0x2FF) */ + uint32_t fmbm_odcfg[0x3]; + /* O/H Debug (only 1 in P1023) */ + uint32_t fmbm_ogpr; /* O/H General Purpose Register. */ + uint32_t reserved7[0x3a]; + /* (0x310 0x3FF) */ +} __attribute__((__packed__)); + +union fm_port_bmi_regs_u { + struct fm_port_rx_bmi_regs_t rx_port_bmi_regs; + struct fm_port_tx_bmi_regs_t tx_port_bmi_regs; + struct fm_port_oh_bmi_regs_t oh_port_bmi_regs; +} __attribute__((__packed__)); + +struct fm_port_non_rx_qmi_regs_t { + /* 0xn024 - 0x02B */ + uint32_t reserved1[2]; + /* PortID n Dequeue NIA Register */ + uint32_t fmqm_pndn; + /* PortID n Dequeue Config Register */ + uint32_t fmqm_pndc; + /* PortID n Dequeue Total Frame Counter */ + uint32_t fmqm_pndtfc; + /* PortID n Dequeue FQID from Default Counter */ + uint32_t fmqm_pndfdc; + /* PortID n Dequeue Confirm Counter */ + uint32_t fmqm_pndcc; +} __attribute__((__packed__)); + +struct fm_port_qmi_regs_t { + /* PortID n Configuration Register */ + uint32_t fmqm_pnc; + /* PortID n Status Register */ + uint32_t fmqm_pns; + /* PortID n Task Status Register */ + uint32_t fmqm_pnts; + /* 0xn00C - 0xn01B */ + uint32_t reserved0[4]; + /* PortID n Enqueue NIA Register */ + uint32_t fmqm_pnen; + /* PortID n Enqueue Total Frame Counter */ + uint32_t fmqm_pnetfc; + /* Registers for Tx Hc&Op ports */ + struct fm_port_non_rx_qmi_regs_t non_rx_qmi_regs; +} __attribute__((__packed__)); + +struct fm_port_prs_regs_t { + struct { + /* Soft Sequence Attachment */ + uint32_t softseq_attach; + } __attribute__((__packed__)) hdrs[FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t reserved0[0x378]; + /* Parse Internal Memory Configuration Access Control Register */ + uint32_t pcac; + /* Parse Internal Memory Configured TPID Register */ + uint32_t pctpid; +} __attribute__((__packed__)); + +/* Registers bit fields */ + +/* BMI defines */ +#define BMI_PORT_CFG_EN 0x80000000 +#define BMI_PORT_CFG_FDOVR 0x02000000 +#define BMI_PORT_CFG_IM 0x01000000 +#define BMI_PORT_STATUS_BSY 0x80000000 +#define BMI_COUNTERS_EN 0x80000000 + +#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000 +#define BMI_PORT_RFNE_FRWD_RPD 0x40000000 +#define BMI_RFNE_FDCS_MASK 0xFF000000 + +#define BMI_CMD_MR_LEAC 0x00200000 +#define BMI_CMD_MR_SLEAC 0x00100000 +#define BMI_CMD_MR_MA 0x00080000 +#define BMI_CMD_MR_DEAS 0x00040000 +#define BMI_CMD_RX_MR_DEF \ +(BMI_CMD_MR_LEAC | \ +BMI_CMD_MR_SLEAC | \ +BMI_CMD_MR_MA | \ +BMI_CMD_MR_DEAS) +#define BMI_CMD_ATTR_ORDER 0x80000000 +#define BMI_CMD_ATTR_SYNC 0x02000000 +#define BMI_CMD_ATTR_MODE_MISS_ALIGN_ADDR_EN 0x00080000 +#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000 +#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000 +#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00 + +#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 +#define BMI_STATUS_RX_MASK_UNUSED \ +(uint32_t)(~(FM_PORT_FRM_ERR_DMA | \ +FM_PORT_FRM_ERR_PHYSICAL | \ +FM_PORT_FRM_ERR_SIZE | \ +FM_PORT_FRM_ERR_CLS_DISCARD | \ +FM_PORT_FRM_ERR_EXTRACTION | \ +FM_PORT_FRM_ERR_NO_SCHEME | \ +FM_PORT_FRM_ERR_COLOR_RED | \ +FM_PORT_FRM_ERR_COLOR_YELLOW | \ +FM_PORT_FRM_ERR_PRS_TIMEOUT | \ +FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ +FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ +FM_PORT_FRM_ERR_PRS_HDR_ERR | \ +FM_PORT_FRM_ERR_IPRE | \ +FM_PORT_FRM_ERR_IPR_NCSP | \ +FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW)) + +#define BMI_STATUS_OP_MASK_UNUSED \ + (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \ + ~(FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)) + +#define BMI_RATE_LIMIT_EN 0x80000000 +#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000 +#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001 +#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002 +#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003 + +#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000 + +#define BMI_PRS_RESULT_HIGH 0x00000000 +#define BMI_PRS_RESULT_LOW 0xFFFFFFFF + +#define RX_ERRS_TO_ENQ \ +(FM_PORT_FRM_ERR_DMA | \ +FM_PORT_FRM_ERR_PHYSICAL | \ +FM_PORT_FRM_ERR_SIZE | \ +FM_PORT_FRM_ERR_EXTRACTION | \ +FM_PORT_FRM_ERR_NO_SCHEME | \ +FM_PORT_FRM_ERR_PRS_TIMEOUT | \ +FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ +FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ +FM_PORT_FRM_ERR_PRS_HDR_ERR | \ +FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \ +FM_PORT_FRM_ERR_IPRE) + +#define OP_ERRS_TO_ENQ \ +(RX_ERRS_TO_ENQ | \ +FM_PORT_FRM_ERR_LENGTH | \ +FM_PORT_FRM_ERR_NON_FM | \ +FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) + +#define BMI_RX_FIFO_PRI_ELEVATION_MASK 0x03FF0000 +#define BMI_RX_FIFO_THRESHOLD_MASK 0x000003FF +#define BMI_TX_FIFO_MIN_FILL_MASK 0x03FF0000 +#define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000F000 +#define BMI_TX_LOW_COMF_MASK 0x000003FF + +/* shifts */ +#define BMI_PORT_CFG_MS_SEL_SHIFT 16 +#define BMI_DMA_ATTR_IC_CACHE_SHIFT FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT +#define BMI_DMA_ATTR_HDR_CACHE_SHIFT FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT +#define BMI_DMA_ATTR_SG_CACHE_SHIFT FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT + +#define BMI_IM_FOF_SHIFT 28 +#define BMI_PR_PORTID_SHIFT 24 + +#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 +#define BMI_RX_FIFO_THRESHOLD_SHIFT 0 + +#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 +#define BMI_RX_FRAME_END_CUT_SHIFT 16 + +#define BMI_IC_SIZE_SHIFT FMAN_SP_IC_SIZE_SHIFT + +#define BMI_INT_BUF_MARG_SHIFT 28 + +#define BMI_EXT_BUF_MARG_END_SHIFT FMAN_SP_EXT_BUF_MARG_END_SHIFT + +#define BMI_CMD_ATTR_COLOR_SHIFT 26 +#define BMI_CMD_ATTR_COM_MODE_SHIFT 16 +#define BMI_CMD_ATTR_MACCMD_SHIFT 8 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15 +#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12 +#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8 + +#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24 + +#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 +#define BMI_TX_LOW_COMF_SHIFT 0 + +#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 +#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16 +#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 +#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0 + +#define BMI_MAX_BURST_SHIFT 16 +#define BMI_COUNT_RATE_UNIT_SHIFT 16 + +/* sizes */ +#define FRAME_END_DATA_SIZE 16 +#define FRAME_OFFSET_UNITS 16 +#define MIN_TX_INT_OFFSET 16 +#define MAX_FRAME_OFFSET 64 +#define MAX_FIFO_PIPELINE_DEPTH 8 +#define MAX_PERFORMANCE_TASK_COMP 64 +#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 +#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 +#define MAX_PERFORMANCE_DMA_COMP 16 +#define MAX_NUM_OF_TASKS 64 +#define MAX_NUM_OF_EXTRA_TASKS 8 +#define MAX_NUM_OF_DMAS 16 +#define MAX_NUM_OF_EXTRA_DMAS 8 +#define MAX_BURST_SIZE 1024 +#define MIN_NUM_OF_OP_DMAS 2 + +/* QMI defines */ +/* masks */ +#define QMI_PORT_CFG_EN 0x80000000 +#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 +#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 +#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 + +#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000 +#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0 +#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0 +#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000 + +#define QMI_DEQ_CFG_PRI 0x80000000 +#define QMI_DEQ_CFG_TYPE1 0x10000000 +#define QMI_DEQ_CFG_TYPE2 0x20000000 +#define QMI_DEQ_CFG_TYPE3 0x30000000 + +#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f +#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20 + +/* PARSER defines */ +/* masks */ +#define PRS_HDR_ERROR_DIS 0x00000800 +#define PRS_HDR_SW_PRS_EN 0x00000400 +#define PRS_CP_OFFSET_MASK 0x0000000F +#define PRS_TPID1_MASK 0xFFFF0000 +#define PRS_TPID2_MASK 0x0000FFFF +#define PRS_TPID_DFLT 0x91009100 + +#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000 +#define PRS_HDR_IPV6_ROUTE_HDR_EN 0x00008000 +#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000 +#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000 +#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000 +#define PRS_CAC_STOP 0x00000001 +#define PRS_CAC_ACTIVE 0x00000100 + +/* shifts */ +#define PRS_PCTPID_SHIFT 16 +#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22 +#define PRS_HDR_ETH_BC_SHIFT 28 +#define PRS_HDR_ETH_MC_SHIFT 24 +#define PRS_HDR_VLAN_STACKED_SHIFT 16 +#define PRS_HDR_MPLS_STACKED_SHIFT 16 +#define PRS_HDR_IPV4_1_BC_SHIFT 28 +#define PRS_HDR_IPV4_1_MC_SHIFT 24 +#define PRS_HDR_IPV4_2_UC_SHIFT 20 +#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16 +#define PRS_HDR_IPV6_1_MC_SHIFT 24 +#define PRS_HDR_IPV6_2_UC_SHIFT 20 +#define PRS_HDR_IPV6_2_MC_SHIFT 16 + +#define PRS_HDR_ETH_BC_MASK 0x0fffffff +#define PRS_HDR_ETH_MC_MASK 0xf0ffffff +#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff +#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff +#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff +#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff +#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff + +/* others */ +#define PRS_HDR_ENTRY_SIZE 8 +#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF + +#define IPSEC_SW_PATCH_START 0x20 +#define SCTP_SW_PATCH_START 0x4D +#define DCCP_SW_PATCH_START 0x41 + +/* Additional defines */ + +struct fm_port_drv_param_t { + struct fman_port_cfg dflt_cfg; + uint32_t dflt_fqid; + uint32_t err_fqid; + uintptr_t base_addr; + uint8_t deq_sub_portal; + bool deq_high_priority; + enum fm_port_deq_type deq_type; + enum fm_port_deq_prefetch_option deq_prefetch_option; + uint16_t deq_byte_cnt; + uint8_t cheksum_last_bytes_ignore; + uint8_t cut_bytes_from_end; + struct fm_buf_pool_depletion_t buf_pool_depletion; + bool frm_discard_override; + bool en_rate_limit; + struct fm_port_rate_limit_t rate_limit; + enum fm_port_dual_rate_limiter_scale_down rate_limit_divider; + bool en_buf_pool_depletion; + uint16_t liodn_offset; + uint16_t liodn_base; + struct fm_ext_pools_t ext_buf_pools; + enum fm_dma_swap_option dma_swap_data; + uint32_t tx_fifo_min_fill_level; + uint32_t tx_fifo_low_comf_level; + uint32_t rx_fifo_pri_elevation_level; + uint32_t rx_fifo_threshold; + struct fm_sp_buf_margins_t buf_margins; + struct fm_sp_int_context_data_copy_t int_context; + bool sync_req; + enum fm_port_color color; + uint32_t errors_to_discard; + uint32_t errors_to_enq; + bool forward_reuse_int_context; + struct fm_buffer_prefix_content_t buffer_prefix_content; + struct fm_backup_bm_pools_t *p_backup_bm_pools; + bool dont_release_buf; + bool set_num_of_tasks; + bool set_num_of_open_dmas; + bool set_size_of_fifo; + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + bool bcb_workaround; +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ +}; + +struct fm_port_rx_pools_params_t { + uint8_t num_of_pools; + uint16_t second_largest_buf_size; + uint16_t largest_buf_size; +}; + +struct fm_port_intg_t { + uint32_t max_port_fifo_size; + uint32_t max_num_of_ext_pools; + uint32_t fm_max_num_of_sub_portals; + uint32_t bm_max_num_of_pools; +}; + +/* PCD Engines */ +/* No PCD Engine indicated */ +#define FM_PCD_NONE 0 +/* Parser indicated */ +#define FM_PCD_PRS 0x80000000 + +struct fm_port_t { + struct fman_port port; + void *h_fm; + void *h_fm_pcd; + struct muram_info *p_muram; + struct fm_revision_info_t fm_rev_info; + uint8_t port_id; + enum fm_port_type port_type; + enum fm_port_speed port_speed; + int enabled; + char name[MODULE_NAME_SIZE]; + uint16_t fm_clk_freq; + struct fm_port_qmi_regs_t __iomem *p_fm_port_qmi_regs; + + union fm_port_bmi_regs_u __iomem *p_fm_port_bmi_regs; + struct fm_port_prs_regs_t __iomem *p_fm_port_prs_regs; + /* The optional engines are devined avobe */ + uint32_t pcd_engines; + uint32_t saved_bmi_nia; + uint8_t private_info; + struct fm_sp_buffer_offsets_t buffer_offsets; + + volatile bool lock; + /* Spinlock for port use */ + spinlock_t *spinlock; + fm_port_exception_cb *f_exception; + void *h_app; + uint8_t internal_buf_offset; + uint32_t exceptions; + bool polling; + struct fm_ext_pools_t ext_buf_pools; + uint32_t required_action; + uint32_t saved_qmi_pnen; + uint32_t saved_bmi_fene; + uint32_t saved_bmi_fpne; + uint32_t saved_bmi_cmne; + uint32_t saved_non_rx_qmi_regs_pndn; + uint32_t orig_non_rx_qmi_regs_pndn; + bool include_in_prs_statistics; + uint16_t max_frame_length; + uint32_t or_fman_ctrl; + struct fm_port_rsrc_t open_dmas; + struct fm_port_rsrc_t tasks; + struct fm_port_rsrc_t fifo_bufs; + struct fm_port_rx_pools_params_t rx_pools_params; + phys_addr_t fm_muram_phys_base_addr; + enum fm_port_gpr_func_type gpr_func; + struct fm_pcd_ctrl_params_page_t __iomem *p_params_page; + + struct fm_port_drv_param_t *p_fm_port_drv_param; + + struct fm_port_intg_t *port_intg; + +}; + +#endif /* __FM_PORT_H */
--
1.7.9.5