diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/fman.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fman/fman.c | 258 |
1 files changed, 84 insertions, 174 deletions
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 4aefe2438969..11887458f050 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -1,41 +1,13 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later /* - * 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. + * Copyright 2008 - 2015 Freescale Semiconductor Inc. + * Copyright 2020 NXP */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "fman.h" -#include "fman_muram.h" - #include <linux/fsl/guts.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/module.h> @@ -46,9 +18,12 @@ #include <linux/interrupt.h> #include <linux/libfdt_env.h> +#include "fman.h" +#include "fman_muram.h" +#include "fman_keygen.h" + /* General defines */ #define FMAN_LIODN_TBL 64 /* size of LIODN table */ -#define MAX_NUM_OF_MACS 10 #define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 #define BASE_RX_PORTID 0x08 #define BASE_TX_PORTID 0x28 @@ -56,6 +31,7 @@ /* Modules registers offsets */ #define BMI_OFFSET 0x00080000 #define QMI_OFFSET 0x00080400 +#define KG_OFFSET 0x000C1000 #define DMA_OFFSET 0x000C2000 #define FPM_OFFSET 0x000C3000 #define IMEM_OFFSET 0x000C4000 @@ -564,79 +540,9 @@ struct fman_cfg { u32 qmi_def_tnums_thresh; }; -/* Structure that holds information received from device tree */ -struct fman_dts_params { - void __iomem *base_addr; /* FMan virtual address */ - struct resource *res; /* FMan memory resource */ - u8 id; /* FMan ID */ - - int err_irq; /* FMan Error IRQ */ - - u16 clk_freq; /* FMan clock freq (In Mhz) */ - - u32 qman_channel_base; /* QMan channels base */ - u32 num_of_qman_channels; /* Number of QMan channels */ - - struct resource muram_res; /* MURAM resource */ -}; - -/** fman_exceptions_cb - * fman - Pointer to FMan - * exception - The exception. - * - * Exceptions user callback routine, will be called upon an exception - * passing the exception identification. - * - * Return: irq status - */ -typedef irqreturn_t (fman_exceptions_cb)(struct fman *fman, - enum fman_exceptions exception); - -/** fman_bus_error_cb - * fman - Pointer to FMan - * port_id - Port id - * addr - Address that caused the error - * tnum - Owner of error - * liodn - Logical IO device number - * - * Bus error user callback routine, will be called upon bus error, - * passing parameters describing the errors and the owner. - * - * Return: IRQ status - */ -typedef irqreturn_t (fman_bus_error_cb)(struct fman *fman, u8 port_id, - u64 addr, u8 tnum, u16 liodn); - -struct fman { - struct device *dev; - void __iomem *base_addr; - struct fman_intr_src intr_mng[FMAN_EV_CNT]; - - struct fman_fpm_regs __iomem *fpm_regs; - struct fman_bmi_regs __iomem *bmi_regs; - struct fman_qmi_regs __iomem *qmi_regs; - struct fman_dma_regs __iomem *dma_regs; - struct fman_hwp_regs __iomem *hwp_regs; - fman_exceptions_cb *exception_cb; - fman_bus_error_cb *bus_error_cb; - /* Spinlock for FMan use */ - spinlock_t spinlock; - struct fman_state_struct *state; - - struct fman_cfg *cfg; - struct muram_info *muram; - /* cam section in muram */ - unsigned long cam_offset; - size_t cam_size; - /* Fifo in MURAM */ - unsigned long fifo_offset; - size_t fifo_size; - - u32 liodn_base[64]; - u32 liodn_offset[64]; - - struct fman_dts_params dts_params; -}; +#ifdef CONFIG_DPAA_ERRATUM_A050385 +static bool fman_has_err_a050385; +#endif static irqreturn_t fman_exceptions(struct fman *fman, enum fman_exceptions exception) @@ -706,6 +612,9 @@ static void set_port_liodn(struct fman *fman, u8 port_id, { u32 tmp; + iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + return; /* set LIODN base for this port */ tmp = ioread32be(&fman->dma_regs->fmdmplr[port_id / 2]); if (port_id % 2) { @@ -716,7 +625,6 @@ static void set_port_liodn(struct fman *fman, u8 port_id, tmp |= liodn_base << DMA_LIODN_SHIFT; } iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]); - iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); } static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg) @@ -1463,8 +1371,7 @@ static void enable_time_stamp(struct fman *fman) { struct fman_fpm_regs __iomem *fpm_rg = fman->fpm_regs; u16 fm_clk_freq = fman->state->fm_clk_freq; - u32 tmp, intgr, ts_freq; - u64 frac; + u32 tmp, intgr, ts_freq, frac; ts_freq = (u32)(1 << fman->state->count1_micro_bit); /* configure timestamp so that bit 8 will count 1 microsecond @@ -1811,6 +1718,7 @@ static int fman_config(struct fman *fman) fman->qmi_regs = base_addr + QMI_OFFSET; fman->dma_regs = base_addr + DMA_OFFSET; fman->hwp_regs = base_addr + HWP_OFFSET; + fman->kg_regs = base_addr + KG_OFFSET; fman->base_addr = base_addr; spin_lock_init(&fman->spinlock); @@ -1925,8 +1833,8 @@ static int fman_reset(struct fman *fman) guts_regs = of_iomap(guts_node, 0); if (!guts_regs) { - dev_err(fman->dev, "%s: Couldn't map %s regs\n", - __func__, guts_node->full_name); + dev_err(fman->dev, "%s: Couldn't map %pOF regs\n", + __func__, guts_node); goto guts_regs; } #define FMAN1_ALL_MACS_MASK 0xFCC00000 @@ -2013,6 +1921,8 @@ static int fman_init(struct fman *fman) fman->liodn_offset[i] = ioread32be(&fman->bmi_regs->fmbm_spliodn[i - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + continue; liodn_base = ioread32be(&fman->dma_regs->fmdmplr[i / 2]); if (i % 2) { /* FMDM_PLR LSB holds LIODN base for odd ports */ @@ -2083,6 +1993,11 @@ static int fman_init(struct fman *fman) /* Init HW Parser */ hwp_init(fman->hwp_regs); + /* Init KeyGen */ + fman->keygen = keygen_init(fman->kg_regs); + if (!fman->keygen) + return -EINVAL; + err = enable(fman, cfg); if (err != 0) return err; @@ -2121,11 +2036,11 @@ static int fman_set_exception(struct fman *fman, /** * fman_register_intr * @fman: A Pointer to FMan device - * @mod: Calling module + * @module: Calling module * @mod_id: Module id (if more than 1 exists, '0' if not) * @intr_type: Interrupt type (error/normal) selection. - * @f_isr: The interrupt service routine. - * @h_src_arg: Argument to be passed to f_isr. + * @isr_cb: The interrupt service routine. + * @src_arg: Argument to be passed to isr_cb. * * Used to register an event handler to be processed by FMan * @@ -2149,7 +2064,7 @@ EXPORT_SYMBOL(fman_register_intr); /** * fman_unregister_intr * @fman: A Pointer to FMan device - * @mod: Calling module + * @module: Calling module * @mod_id: Module id (if more than 1 exists, '0' if not) * @intr_type: Interrupt type (error/normal) selection. * @@ -2400,8 +2315,8 @@ EXPORT_SYMBOL(fman_get_bmi_max_fifo_size); /** * fman_get_revision - * @fman - Pointer to the FMan module - * @rev_info - A structure of revision information parameters. + * @fman: - Pointer to the FMan module + * @rev_info: - A structure of revision information parameters. * * Returns the FM revision * @@ -2434,15 +2349,21 @@ u32 fman_get_qman_channel_id(struct fman *fman, u32 port_id) int i; if (fman->state->rev_info.major >= 6) { - u32 port_ids[] = {0x30, 0x31, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2, 0x3, 0x4, 0x5, 0x7, 0x7}; + static const u32 port_ids[] = { + 0x30, 0x31, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2, 0x3, 0x4, 0x5, 0x7, 0x7 + }; + for (i = 0; i < fman->state->num_of_qman_channels; i++) { if (port_ids[i] == port_id) break; } } else { - u32 port_ids[] = {0x30, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x1, - 0x2, 0x3, 0x4, 0x5, 0x7, 0x7}; + static const u32 port_ids[] = { + 0x30, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x1, + 0x2, 0x3, 0x4, 0x5, 0x7, 0x7 + }; + for (i = 0; i < fman->state->num_of_qman_channels; i++) { if (port_ids[i] == port_id) break; @@ -2499,9 +2420,6 @@ MODULE_PARM_DESC(fsl_fm_rx_extra_headroom, "Extra headroom for Rx buffers"); * buffers when not using jumbo frames. * Must be large enough to accommodate the network MTU, but small enough * to avoid wasting skb memory. - * - * Could be overridden once, at boot-time, via the - * fm_set_max_frm() callback. */ static int fsl_fm_max_frm = FSL_FM_MAX_FRAME_SIZE; module_param(fsl_fm_max_frm, int, 0); @@ -2563,7 +2481,7 @@ EXPORT_SYMBOL(fman_get_rx_extra_headroom); /** * fman_bind - * @dev: FMan OF device pointer + * @fm_dev: FMan OF device pointer * * Bind to a specific FMan device. * @@ -2577,6 +2495,14 @@ struct fman *fman_bind(struct device *fm_dev) } EXPORT_SYMBOL(fman_bind); +#ifdef CONFIG_DPAA_ERRATUM_A050385 +bool fman_has_errata_a050385(void) +{ + return fman_has_err_a050385; +} +EXPORT_SYMBOL(fman_has_errata_a050385); +#endif + static irqreturn_t fman_err_irq(int irq, void *handle) { struct fman *fman = (struct fman *)handle; @@ -2764,59 +2690,42 @@ static struct fman *read_dts_node(struct platform_device *of_dev) { struct fman *fman; struct device_node *fm_node, *muram_node; + void __iomem *base_addr; struct resource *res; u32 val, range[2]; int err, irq; struct clk *clk; u32 clk_rate; - phys_addr_t phys_base_addr; - resource_size_t mem_size; fman = kzalloc(sizeof(*fman), GFP_KERNEL); if (!fman) - return NULL; + return ERR_PTR(-ENOMEM); fm_node = of_node_get(of_dev->dev.of_node); err = of_property_read_u32(fm_node, "cell-index", &val); if (err) { - dev_err(&of_dev->dev, "%s: failed to read cell-index for %s\n", - __func__, fm_node->full_name); + dev_err(&of_dev->dev, "%s: failed to read cell-index for %pOF\n", + __func__, fm_node); goto fman_node_put; } fman->dts_params.id = (u8)val; /* Get the FM interrupt */ - res = platform_get_resource(of_dev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&of_dev->dev, "%s: Can't get FMan IRQ resource\n", - __func__); + err = platform_get_irq(of_dev, 0); + if (err < 0) goto fman_node_put; - } - irq = res->start; + irq = err; /* Get the FM error interrupt */ - res = platform_get_resource(of_dev, IORESOURCE_IRQ, 1); - if (!res) { - dev_err(&of_dev->dev, "%s: Can't get FMan Error IRQ resource\n", - __func__); - goto fman_node_put; - } - fman->dts_params.err_irq = res->start; - - /* Get the FM address */ - res = platform_get_resource(of_dev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&of_dev->dev, "%s: Can't get FMan memory resource\n", - __func__); + err = platform_get_irq(of_dev, 1); + if (err < 0) goto fman_node_put; - } - - phys_base_addr = res->start; - mem_size = resource_size(res); + fman->dts_params.err_irq = err; clk = of_clk_get(fm_node, 0); if (IS_ERR(clk)) { + err = PTR_ERR(clk); dev_err(&of_dev->dev, "%s: Failed to get FM%d clock structure\n", __func__, fman->dts_params.id); goto fman_node_put; @@ -2824,6 +2733,7 @@ static struct fman *read_dts_node(struct platform_device *of_dev) clk_rate = clk_get_rate(clk); if (!clk_rate) { + err = -EINVAL; dev_err(&of_dev->dev, "%s: Failed to determine FM%d clock rate\n", __func__, fman->dts_params.id); goto fman_node_put; @@ -2834,8 +2744,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev) err = of_property_read_u32_array(fm_node, "fsl,qman-channel-range", &range[0], 2); if (err) { - dev_err(&of_dev->dev, "%s: failed to read fsl,qman-channel-range for %s\n", - __func__, fm_node->full_name); + dev_err(&of_dev->dev, "%s: failed to read fsl,qman-channel-range for %pOF\n", + __func__, fm_node); goto fman_node_put; } fman->dts_params.qman_channel_base = range[0]; @@ -2844,9 +2754,10 @@ static struct fman *read_dts_node(struct platform_device *of_dev) /* Get the MURAM base address and size */ muram_node = of_find_matching_node(fm_node, fman_muram_match); if (!muram_node) { + err = -EINVAL; dev_err(&of_dev->dev, "%s: could not find MURAM node\n", __func__); - goto fman_node_put; + goto fman_free; } err = of_address_to_resource(muram_node, 0, @@ -2855,13 +2766,13 @@ static struct fman *read_dts_node(struct platform_device *of_dev) of_node_put(muram_node); dev_err(&of_dev->dev, "%s: of_address_to_resource() = %d\n", __func__, err); - goto fman_node_put; + goto fman_free; } of_node_put(muram_node); - of_node_put(fm_node); - err = devm_request_irq(&of_dev->dev, irq, fman_irq, 0, "fman", fman); + err = devm_request_irq(&of_dev->dev, irq, fman_irq, IRQF_SHARED, + "fman", fman); if (err < 0) { dev_err(&of_dev->dev, "%s: irq %d allocation failed (error = %d)\n", __func__, irq, err); @@ -2879,22 +2790,16 @@ static struct fman *read_dts_node(struct platform_device *of_dev) } } - fman->dts_params.res = - devm_request_mem_region(&of_dev->dev, phys_base_addr, - mem_size, "fman"); - if (!fman->dts_params.res) { - dev_err(&of_dev->dev, "%s: request_mem_region() failed\n", - __func__); - goto fman_free; - } - - fman->dts_params.base_addr = - devm_ioremap(&of_dev->dev, phys_base_addr, mem_size); - if (!fman->dts_params.base_addr) { + base_addr = devm_platform_get_and_ioremap_resource(of_dev, 0, &res); + if (IS_ERR(base_addr)) { + err = PTR_ERR(base_addr); dev_err(&of_dev->dev, "%s: devm_ioremap() failed\n", __func__); goto fman_free; } + fman->dts_params.base_addr = base_addr; + fman->dts_params.res = res; + fman->dev = &of_dev->dev; err = of_platform_populate(fm_node, NULL, NULL, &of_dev->dev); @@ -2904,13 +2809,18 @@ static struct fman *read_dts_node(struct platform_device *of_dev) goto fman_free; } +#ifdef CONFIG_DPAA_ERRATUM_A050385 + fman_has_err_a050385 = + of_property_read_bool(fm_node, "fsl,erratum-a050385"); +#endif + return fman; fman_node_put: of_node_put(fm_node); fman_free: kfree(fman); - return NULL; + return ERR_PTR(err); } static int fman_probe(struct platform_device *of_dev) @@ -2922,8 +2832,8 @@ static int fman_probe(struct platform_device *of_dev) dev = &of_dev->dev; fman = read_dts_node(of_dev); - if (!fman) - return -EIO; + if (IS_ERR(fman)) + return PTR_ERR(fman); err = fman_config(fman); if (err) { |
