lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <23a1112f-32db-4034-b1ec-ba8617f58d34@gmx.net>
Date: Thu, 17 Apr 2025 12:32:20 +0200
From: Stefan Wahren <wahrenst@....net>
To: Lukasz Majewski <lukma@...x.de>, Andrew Lunn <andrew+netdev@...n.ch>,
 davem@...emloft.net, Eric Dumazet <edumazet@...gle.com>,
 Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
 Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
 Conor Dooley <conor+dt@...nel.org>, Shawn Guo <shawnguo@...nel.org>
Cc: Sascha Hauer <s.hauer@...gutronix.de>,
 Pengutronix Kernel Team <kernel@...gutronix.de>,
 Fabio Estevam <festevam@...il.com>,
 Richard Cochran <richardcochran@...il.com>, netdev@...r.kernel.org,
 devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
 imx@...ts.linux.dev, linux-arm-kernel@...ts.infradead.org,
 Simon Horman <horms@...nel.org>
Subject: Re: [net-next v5 4/6] net: mtip: The L2 switch driver for imx287

Hi Lukasz,

Am 14.04.25 um 16:01 schrieb Lukasz Majewski:
> This patch series provides support for More Than IP L2 switch embedded
> in the imx287 SoC.
>
> This is a two port switch (placed between uDMA[01] and MAC-NET[01]),
> which can be used for offloading the network traffic.
>
> It can be used interchangeably with current FEC driver - to be more
> specific: one can use either of it, depending on the requirements.
>
> The biggest difference is the usage of DMA - when FEC is used, separate
> DMAs are available for each ENET-MAC block.
> However, with switch enabled - only the DMA0 is used to send/receive data
> to/form switch (and then switch sends them to respecitive ports).
>
> Signed-off-by: Lukasz Majewski <lukma@...x.de>
> ---
> Changes for v2:
>
> - Remove not needed comments
> - Restore udelay(10) for switch reset (such delay is explicitly specifed
>    in the documentation
> - Add COMPILE_TEST
> - replace pr_* with dev_*
> - Use for_each_available_child_of_node_scoped()
> - Use devm_* function for memory allocation
> - Remove printing information about the HW and SW revision of the driver
> - Use devm_regulator_get_optional()
> - Change compatible prefix from 'fsl' to more up to date 'nxp'
> - Remove .owner = THIS_MODULE
> - Use devm_platform_ioremap_resource(pdev, 0);
> - Use devm_request_irq()
> - Use devm_regulator_get_enable_optional()
> - Replace clk_prepare_enable() and devm_clk_get() with single
>    call to devm_clk_get_optional_enabled()
> - Cleanup error patch when function calls in probe fail
> - Refactor the mtip_reset_phy() to serve as mdio bus reset callback
> - Add myself as the MTIP L2 switch maintainer (squashed the separated
>    commit)
> - More descriptive help paragraphs (> 4 lines)
>
> Changes for v3:
> - Remove 'bridge_offloading' module parameter (to bridge ports just after probe)
> - Remove forward references
> - Fix reverse christmas tree formatting in functions
> - Convert eligible comments to kernel doc format
> - Remove extra MAC address validation check at esw_mac_addr_static()
> - Remove mtip_print_link_status() and replace it with phy_print_status()
> - Avoid changing phy device state in the driver (instead use functions
>    exported by the phy API)
> - Do not print extra information regarding PHY (which is printed by phylib) -
>    e.g. net lan0: lan0: MTIP eth L2 switch 1e:ce:a5:0b:4c:12
> - Remove VERSION from the driver - now we rely on the SHA1 in Linux
>    mainline tree
> - Remove zeroing of the net device private area (shall be already done
>    during allocation)
> - Refactor the code to remove mtip_ndev_setup()
> - Use -ENOMEM instead of -1 return code when allocation fails
> - Replace dev_info() with dev_dbg() to reduce number of information print
>    on normal operation
> - Return ret instead of 0 from mtip_ndev_init()
> - Remove fep->mii_timeout flag from the driver
> - Remove not used stop_gpr_* fields in mtip_devinfo struct
> - Remove platform_device_id description for mtipl2sw driver
> - Add MODULE_DEVICE_TABLE() for mtip_of_match
> - Remove MODULE_ALIAS()
>
> Changes for v4:
> - Rename imx287 with imx28 (as the former is not used in kernel anymore)
> - Reorder the place where ENET interface is initialized - without this
>    change the enet_out clock has default (25 MHz) value, which causes
>    issues during reset (RMII's 50 MHz is required for proper PHY reset).
> - Use PAUR instead of PAUR register to program MAC address
> - Replace eth_mac_addr() with eth_hw_addr_set()
> - Write to HW the randomly generated MAC address (if required)
> - Adjust the reset code
> - s/read_atable/mtip_read_atable/g and s/write_atable/mtip_write_atable/g
> - Add clk_disable() and netif_napi_del() when errors occur during
>    mtip_open() - refactor the error handling path.
> - Refactor the mtip_set_multicast_list() to write (now) correct values to
>    ENET-FEC registers.
> - Replace dev_warn() with dev_err()
> - Use GPIO_ACTIVE_LOW to indicate polarity in DTS
> - Refactor code to check if network device is the switch device
> - Remove mtip_port_dev_check()
> - Refactor mtip_ndev_port_link() avoid starting HW offloading for bridge
>    when MTIP ports are parts of two distinct bridges
> - Replace del_timer() with timer_delete_sync()
>
> Changes for v5:
> - Fix spelling in Kconfig
> - Replace tmp with reg or register name
> - Replace tmpaddr with mac_addr
> - Use mac address assignment (from registers) code similar to fec_main.c (as it
>    shall handle properly generic endianess)
> - Add description for fep: in the mtip_update_atable_static() kernel doc
> - Replace writel(bdp, &fep->cur_rx) with fep->cur_rx = bdp;
> - Fix spelling of transmit
> - Remove not needed white spaces in mtipl2sw.h
> - Remove '_t' from struct mtip_addr_table_t
> - Provide proper alignment in the mtipl2sw.h
> - Add blank line after local header in mtipl2sw_br.c
> - Use %p instead of %x (and cast) for fep in debug message
> - Disable L2 switch in-HW offloading when only one
>    of eligible ports is removed from the bridge
> - Sort includes in the patch set alphabethically
> - Introduce FEC_QUIRK_SWAP_FRAME to avoid #ifdef for imx28 proper operation
> - Move 'mtip_port_info g_info' to struct switch_enet_private
> - Replace some unsigned int with u32 (on data fields with 32 bit size)
> - Remove not relevant comments from mtip_enet_init()
> - Refactor functions definitions to be void when no other
>    value than 0 is returned.
> - Use capital letters in HEX constants
> - Use u32 instead of unsigned int when applicable
> - Add error handling code after the dma_map_single() is called
> - The MCF_FEC_MSCR register can be written unconditionally
>    for all supported platforms.
> - Use IS_ENABLED() instead of #ifdef in mtip_timeout()
> - Replace dev_info() with dev_warn_ratelimited() in mtip_switch_rx()
> - Add code to handle situation when there is no memory
> - Remove kfree(fep->mii_bus->irq)
> - Provide more verbose output of mdio_{read|write} functions
> - Handle error when clk_enable() fails in mtip_open()
> - Use dev_dbg() at mtip_set_multicast_list()
> - Simplify the mtip_is_switch_netdev_port() function to return condition check value
> - Add dev_dbg() when of_get_mac_address() fails (as it may not be provided)
> - Remove return ret; in mtip_register_notifiers()
> - Replace int to bool in mtipl2sw_mgnt.c file's function definitions
> - Replace unsigned int/long with u32 where applicable (where access to
>    32 bit registers is performed)
> - Refactor code in mtip_{read|write}_atable() to be more readable
> - Remove code added for not (yet) supported IMX's vf610 SoC
> - Remove do { } while(); loop from mtip_interrupt() function
> - Introduce MTIP_PORT_FORWARDING_INIT to indicate intial value for
>    port forwarding
> - Replace 'unsigned long' to 'u32' in mtipl2sw.h
> - Replace 'unsigned short' to 'u16' in mtipl2sw.h
> - use %#x in dev_dbg()
> - Call SET_NETDEV_DEV() macro to set network device' parent - otherwise
>    phy_attach_direct() will fail.
> ---
>   MAINTAINERS                                   |    7 +
>   drivers/net/ethernet/freescale/Kconfig        |    1 +
>   drivers/net/ethernet/freescale/Makefile       |    1 +
>   drivers/net/ethernet/freescale/mtipsw/Kconfig |   13 +
>   .../net/ethernet/freescale/mtipsw/Makefile    |    3 +
>   .../net/ethernet/freescale/mtipsw/mtipl2sw.c  | 1990 +++++++++++++++++
>   .../net/ethernet/freescale/mtipsw/mtipl2sw.h  |  788 +++++++
>   .../ethernet/freescale/mtipsw/mtipl2sw_br.c   |  120 +
>   .../ethernet/freescale/mtipsw/mtipl2sw_mgnt.c |  449 ++++
>   9 files changed, 3372 insertions(+)
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/Kconfig
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/Makefile
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw.h
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw_br.c
>   create mode 100644 drivers/net/ethernet/freescale/mtipsw/mtipl2sw_mgnt.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1248443035f4..af4e42a33c99 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9448,6 +9448,13 @@ S:	Maintained
>   F:	Documentation/devicetree/bindings/i2c/i2c-mpc.yaml
>   F:	drivers/i2c/busses/i2c-mpc.c
>   
> +FREESCALE MTIP ETHERNET SWITCH DRIVER
> +M:	Lukasz Majewski <lukma@...x.de>
> +L:	netdev@...r.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/net/nxp,imx28-mtip-switch.yaml
> +F:	drivers/net/ethernet/freescale/mtipsw/*
> +
>   FREESCALE QORIQ DPAA ETHERNET DRIVER
>   M:	Madalin Bucur <madalin.bucur@....com>
>   L:	netdev@...r.kernel.org
> diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
> index a2d7300925a8..056a11c3a74e 100644
> --- a/drivers/net/ethernet/freescale/Kconfig
> +++ b/drivers/net/ethernet/freescale/Kconfig
> @@ -60,6 +60,7 @@ config FEC_MPC52xx_MDIO
>   
>   source "drivers/net/ethernet/freescale/fs_enet/Kconfig"
>   source "drivers/net/ethernet/freescale/fman/Kconfig"
> +source "drivers/net/ethernet/freescale/mtipsw/Kconfig"
>   
>   config FSL_PQ_MDIO
>   	tristate "Freescale PQ MDIO"
> diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
> index de7b31842233..0e6cacb0948a 100644
> --- a/drivers/net/ethernet/freescale/Makefile
> +++ b/drivers/net/ethernet/freescale/Makefile
> @@ -25,3 +25,4 @@ obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/
>   obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/
>   
>   obj-y += enetc/
> +obj-y += mtipsw/
> diff --git a/drivers/net/ethernet/freescale/mtipsw/Kconfig b/drivers/net/ethernet/freescale/mtipsw/Kconfig
> new file mode 100644
> index 000000000000..0ae58e7b1ca6
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/mtipsw/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config FEC_MTIP_L2SW
> +	tristate "MoreThanIP L2 switch support to FEC driver"
> +	depends on OF
> +	depends on NET_SWITCHDEV
> +	depends on BRIDGE
> +	depends on ARCH_MXS || COMPILE_TEST
I think we should align the dependencies with FEC:

depends on SOC_IMX28 || COMPILE_TEST
> +	help
> +	  This enables support for the MoreThan IP L2 switch on i.MX
> +	  SoCs (e.g. iMX287). It offloads bridging to this IP block's
> +	  hardware and allows switch management with standard Linux tools.
> +	  This switch driver can be used interchangeable with the already
> +	  available FEC driver, depending on the use case's requirements.
> diff --git a/drivers/net/ethernet/freescale/mtipsw/Makefile b/drivers/net/ethernet/freescale/mtipsw/Makefile
> new file mode 100644
> index 000000000000..4d69db2226a6
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/mtipsw/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_FEC_MTIP_L2SW) += mtipl2sw.o mtipl2sw_mgnt.o mtipl2sw_br.o
> diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
> new file mode 100644
> index 000000000000..50f5a0c1bc8c
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c
> @@ -0,0 +1,1990 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + *  L2 switch Controller (Ethernet L2 switch) driver for MTIP block.
> + *
> + *  Copyright (C) 2025 DENX Software Engineering GmbH
> + *  Lukasz Majewski <lukma@...x.de>
> + *
> + *  Based on a previous work by:
> + *
> + *  Copyright 2010-2012 Freescale Semiconductor, Inc.
> + *  Alison Wang (b18965@...escale.com)
> + *  Jason Jin (Jason.jin@...escale.com)
> + *
> + *  Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved.
> + *  Shrek Wu (B16972@...escale.com)
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/etherdevice.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of_mdio.h>
> +#include <linux/of_net.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/rtnetlink.h>
> +#include <linux/skbuff.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +
> +#include "mtipl2sw.h"
> +
> +static void swap_buffer(void *bufaddr, int len)
> +{
> +	int i;
> +	unsigned int *buf = bufaddr;
> +
> +	for (i = 0; i < len; i += 4, buf++)
> +		swab32s(buf);
> +}
> +
> +struct mtip_devinfo {
> +	u32 quirks;
> +};
> +
> +static void mtip_enet_init(struct switch_enet_private *fep, int port)
> +{
> +	void __iomem *enet_addr = fep->enet_addr;
> +	u32 mii_speed, holdtime, reg;
> +
> +	if (port == 2)
> +		enet_addr += MCF_ESW_ENET_PORT_OFFSET;
> +
> +	reg = MCF_FEC_RCR_PROM | MCF_FEC_RCR_MII_MODE |
> +		MCF_FEC_RCR_MAX_FL(1522);
> +
> +	if (fep->phy_interface[port - 1]  == PHY_INTERFACE_MODE_RMII)
> +		reg |= MCF_FEC_RCR_RMII_MODE;
> +
> +	writel(reg, enet_addr + MCF_FEC_RCR);
> +
> +	writel(MCF_FEC_TCR_FDEN, enet_addr + MCF_FEC_TCR);
> +	writel(MCF_FEC_ECR_ETHER_EN, enet_addr + MCF_FEC_ECR);
> +
> +	mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
> +	mii_speed--;
> +
> +	holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
> +
> +	fep->phy_speed = mii_speed << 1 | holdtime << 8;
> +
> +	writel(fep->phy_speed, enet_addr + MCF_FEC_MSCR);
> +}
> +
> +static void mtip_setup_mac(struct net_device *dev)
> +{
> +	struct mtip_ndev_priv *priv = netdev_priv(dev);
> +	struct switch_enet_private *fep = priv->fep;
> +	unsigned char *iap, mac_addr[ETH_ALEN];
> +
> +	/* Use MAC address from DTS */
> +	iap = &fep->mac[priv->portnum - 1][0];
> +
> +	/* Use MAC address set by bootloader */
> +	if (!is_valid_ether_addr(iap)) {
> +		*((__be32 *)&mac_addr[0]) =
> +			cpu_to_be32(readl(fep->enet_addr + MCF_FEC_PALR));
> +		*((__be16 *)&mac_addr[4]) =
> +			cpu_to_be16(readl(fep->enet_addr +
> +					  MCF_FEC_PAUR) >> 16);
> +		iap = &mac_addr[0];
> +	}
> +
> +	/* Use random MAC address */
> +	if (!is_valid_ether_addr(iap)) {
> +		eth_hw_addr_random(dev);
> +		dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
> +			 dev->dev_addr);
> +		iap = (unsigned char *)dev->dev_addr;
> +	}
> +
> +	/* Adjust MAC if using macaddr (and increment if needed) */
> +	eth_hw_addr_gen(dev, iap, priv->portnum - 1);
> +}
> +
> +/**
> + * crc8_calc - calculate CRC for MAC storage
> + *
> + * @pmacaddress: A 6-byte array with the MAC address. The first byte is
> + *               the first byte transmitted.
> + *
> + * Calculate Galois Field Arithmetic CRC for Polynom x^8+x^2+x+1.
> + * It omits the final shift in of 8 zeroes a "normal" CRC would do
> + * (getting the remainder).
> + *
> + *  Examples (hexadecimal values):<br>
> + *   10-11-12-13-14-15  => CRC=0xc2
> + *   10-11-cc-dd-ee-00  => CRC=0xe6
> + *
> + * Return: The 8-bit CRC in bits 7:0
> + */
> +static int crc8_calc(unsigned char *pmacaddress)
> +{
> +	int byt; /* byte index */
> +	int bit; /* bit index */
> +	int crc = 0x12;
> +	int inval;
> +
> +	for (byt = 0; byt < ETH_ALEN; byt++) {
> +		inval = (((int)pmacaddress[byt]) & 0xFF);
> +		/* shift bit 0 to bit 8 so all our bits
> +		 * travel through bit 8
> +		 * (simplifies below calc)
> +		 */
> +		inval <<= 8;
> +
> +		for (bit = 0; bit < 8; bit++) {
> +			/* next input bit comes into d7 after shift */
> +			crc |= inval & 0x100;
> +			if (crc & 0x01)
> +				/* before shift  */
> +				crc ^= 0x1C0;
> +
> +			crc >>= 1;
> +			inval >>= 1;
> +		}
> +	}
> +	/* upper bits are clean as we shifted in zeroes! */
> +	return crc;
> +}
> +
> +static void mtip_read_atable(struct switch_enet_private *fep, int index,
> +			     u32 *read_lo, u32 *read_hi)
> +{
> +	struct addr_table64b_entry *atable_base =
> +		fep->hwentry->mtip_table64b_entry;
> +
> +	*read_lo = readl(&atable_base[index].lo);
> +	*read_hi = readl(&atable_base[index].hi);
> +}
> +
> +static void mtip_write_atable(struct switch_enet_private *fep, int index,
> +			      u32 write_lo, u32 write_hi)
> +{
> +	struct addr_table64b_entry *atable_base =
> +		fep->hwentry->mtip_table64b_entry;
> +
> +	writel(write_lo, &atable_base[index].lo);
> +	writel(write_hi, &atable_base[index].hi);
> +}
> +
> +/**
> + * mtip_portinfofifo_read - Read element from receive FIFO
> + *
> + * @fep: Structure describing switch
> + *
> + * Read one element from the HW receive FIFO (Queue)
> + * if available and return it.
> + *
> + * Return: mtip_port_info or NULL if no data is available.
> + */
> +static
> +struct mtip_port_info *mtip_portinfofifo_read(struct switch_enet_private *fep)
> +{
> +	struct mtip_port_info *info = &fep->g_info;
> +	struct switch_t *fecp = fep->hwp;
> +	u32 reg;
> +
> +	reg = readl(&fecp->ESW_LSR);
> +	if (reg == 0) {
> +		dev_dbg(&fep->pdev->dev, "%s: ESW_LSR = 0x%x\n", __func__, reg);
> +		return NULL;
> +	}
> +
> +	/* read word from FIFO */
> +	info->maclo = readl(&fecp->ESW_LREC0);
> +	if (info->maclo == 0) {
> +		dev_dbg(&fep->pdev->dev, "%s: mac lo 0x%x\n", __func__,
> +			info->maclo);
> +		return NULL;
> +	}
> +
> +	/* read 2nd word from FIFO */
> +	reg = readl(&fecp->ESW_LREC1);
> +	info->machi = reg & 0xFFFF;
> +	info->hash  = (reg >> 16) & 0xFF;
> +	info->port  = (reg >> 24) & 0xF;
> +
> +	return info;
> +}
> +
> +static void mtip_atable_get_entry_port_number(struct switch_enet_private *fep,
> +					      unsigned char *mac_addr, u8 *port)
> +{
> +	int block_index, block_index_end, entry;
> +	u32 mac_addr_lo, mac_addr_hi;
> +	u32 read_lo, read_hi;
> +
> +	mac_addr_lo = (u32)((mac_addr[3] << 24) | (mac_addr[2] << 16) |
> +			    (mac_addr[1] << 8) | mac_addr[0]);
> +	mac_addr_hi = (u32)((mac_addr[5] << 8) | (mac_addr[4]));
> +
> +	block_index = GET_BLOCK_PTR(crc8_calc(mac_addr));
> +	block_index_end = block_index + ATABLE_ENTRY_PER_SLOT;
> +
> +	/* now search all the entries in the selected block */
> +	for (entry = block_index; entry < block_index_end; entry++) {
> +		mtip_read_atable(fep, entry, &read_lo, &read_hi);
> +		*port = MTIP_PORT_FORWARDING_INIT;
> +
> +		if (read_lo == mac_addr_lo &&
> +		    ((read_hi & 0x0000FFFF) ==
> +		     (mac_addr_hi & 0x0000FFFF))) {
> +			/* found the correct address */
> +			if ((read_hi & (1 << 16)) && (!(read_hi & (1 << 17))))
> +				*port = AT_EXTRACT_PORT(read_hi);
> +			break;
> +		}
> +	}
> +
> +	dev_dbg(&fep->pdev->dev, "%s: MAC: %pM PORT: 0x%x\n", __func__,
> +		mac_addr, *port);
> +}
> +
> +/* Clear complete MAC Look Up Table */
> +void mtip_clear_atable(struct switch_enet_private *fep)
> +{
> +	int index;
> +
> +	for (index = 0; index < 2048; index++)
There are a lot of defines for this magic number, please use one of them
> +		mtip_write_atable(fep, index, 0, 0);
> +}
> +
> +/**
> + * mtip_update_atable_static - Update switch static address table
> + *
> + * @mac_addr: Pointer to the array containing MAC address to
> + *            be put as static entry
> + * @port:     Port bitmask numbers to be added in static entry,
> + *            valid values are 1-7
> + * @priority: The priority for the static entry in table
> + *
> + * @fep:      Pointer to the structure describing the switch
> + *
> + * Updates MAC address lookup table with a static entry.
> + *
> + * Searches if the MAC address is already there in the block and replaces
> + * the older entry with the new one. If MAC address is not there then puts
> + * a new entry in the first empty slot available in the block.
> + *
> + * Return: 0 for a successful update else -ENOSPC when no slot available
> + */
> +static int mtip_update_atable_static(unsigned char *mac_addr, unsigned int port,
> +				     unsigned int priority,
> +				     struct switch_enet_private *fep)
> +{
> +	unsigned long block_index, entry, index_end;
> +	u32 write_lo, write_hi, read_lo, read_hi;
> +
> +	write_lo = (u32)((mac_addr[3] << 24) | (mac_addr[2] << 16) |
> +			 (mac_addr[1] << 8) | mac_addr[0]);
> +	write_hi = (u32)(0 | (port << AT_SENTRY_PORTMASK_shift) |
> +			 (priority << AT_SENTRY_PRIO_shift) |
> +			 (AT_ENTRY_TYPE_STATIC << AT_ENTRY_TYPE_shift) |
> +			 (AT_ENTRY_RECORD_VALID << AT_ENTRY_VALID_shift) |
> +			 (mac_addr[5] << 8) | (mac_addr[4]));
> +
> +	block_index = GET_BLOCK_PTR(crc8_calc(mac_addr));
> +	index_end = block_index + ATABLE_ENTRY_PER_SLOT;
> +	/* Now search all the entries in the selected block */
> +	for (entry = block_index; entry < index_end; entry++) {
> +		mtip_read_atable(fep, entry, &read_lo, &read_hi);
> +		/* MAC address matched, so update the
> +		 * existing entry
> +		 * even if its a dynamic one
> +		 */
> +		if (read_lo == write_lo &&
> +		    ((read_hi & 0x0000FFFF) ==
> +		     (write_hi & 0x0000FFFF))) {
> +			mtip_write_atable(fep, entry, write_lo, write_hi);
> +			return 0;
> +		} else if (!(read_hi & (1 << 16))) {
> +			/* Fill this empty slot (valid bit zero),
> +			 * assuming no holes in the block
> +			 */
> +			mtip_write_atable(fep, entry, write_lo, write_hi);
> +			fep->at_curr_entries++;
> +			return 0;
> +		}
> +	}
> +
> +	/* No space available for this static entry */
> +	return -ENOSPC;
> +}
> +
> +static bool mtip_update_atable_dynamic1(u32 write_lo, u32 write_hi,
> +					int block_index, unsigned int port,
> +					unsigned int curr_time,
> +					struct switch_enet_private *fep)
> +{
> +	unsigned long entry, index_end;
> +	int time, timeold, indexold;
> +	u32 read_lo, read_hi;
> +	unsigned long conf;
> +
> +	/* prepare update port and timestamp */
> +	conf = AT_ENTRY_RECORD_VALID << AT_ENTRY_VALID_shift;
> +	conf |= AT_ENTRY_TYPE_DYNAMIC << AT_ENTRY_TYPE_shift;
> +	conf |= curr_time << AT_DENTRY_TIME_shift;
> +	conf |= port << AT_DENTRY_PORT_shift;
> +	conf |= write_hi;
> +
> +	/* linear search through all slot
> +	 * entries and update if found
> +	 */
> +	index_end = block_index + ATABLE_ENTRY_PER_SLOT;
> +	/* Now search all the entries in the selected block */
> +	for (entry = block_index; entry < index_end; entry++) {
> +		mtip_read_atable(fep, entry, &read_lo, &read_hi);
> +		if (read_lo == write_lo &&
> +		    ((read_hi & 0x0000FFFF) ==
> +		     (write_hi & 0x0000FFFF))) {
> +			/* found correct address,
> +			 * update timestamp.
> +			 */
> +			mtip_write_atable(fep, entry, write_lo, conf);
> +
> +			return false;
> +		} else if (!(read_hi & (1 << 16))) {
> +			/* slot is empty, then use it
> +			 * for new entry
> +			 * Note: There are no holes,
> +			 * therefore cannot be any
> +			 * more that need to be compared.
> +			 */
> +			mtip_write_atable(fep, entry, write_lo, conf);
> +			/* statistics (we do it between writing
> +			 *  .hi an .lo due to
> +			 * hardware limitation...
> +			 */
> +			fep->at_curr_entries++;
> +			/* newly inserted */
> +
> +			return true;
> +		}
> +	}
> +
> +	/* No more entry available in block overwrite oldest */
> +	timeold = 0;
> +	indexold = 0;
> +	for (entry = block_index; entry < index_end; entry++) {
> +		mtip_read_atable(fep, entry, &read_lo, &read_hi);
> +		time = AT_EXTRACT_TIMESTAMP(read_hi);
> +		dev_dbg(&fep->pdev->dev, "%s : time %x currtime %x\n",
> +			__func__, time, curr_time);
> +		time = TIMEDELTA(curr_time, time);
> +		if (time > timeold) {
> +			/* is it older ? */
> +			timeold = time;
> +			indexold = entry;
> +		}
> +	}
> +
> +	mtip_write_atable(fep, indexold, write_lo, conf);
> +
> +	/* Statistics (do it inbetween writing to .lo and .hi */
> +	fep->at_block_overflows++;
> +	dev_err(&fep->pdev->dev, "%s update time, at_block_overflows %x\n",
> +		__func__, fep->at_block_overflows);
> +	/* newly inserted */
> +	return true;
> +}
> +
> +/* dynamicms MAC address table learn and migration */
> +static void
> +mtip_atable_dynamicms_learn_migration(struct switch_enet_private *fep,
> +				      int curr_time, unsigned char *mac,
> +				      u8 *rx_port)
> +{
> +	u8 port = MTIP_PORT_FORWARDING_INIT;
> +	struct mtip_port_info *port_info;
> +	u32 rx_mac_lo, rx_mac_hi;
> +	unsigned long flags;
> +	int index;
> +
> +	spin_lock_irqsave(&fep->learn_lock, flags);
> +
> +	if (mac && is_valid_ether_addr(mac)) {
> +		rx_mac_lo = (u32)((mac[3] << 24) | (mac[2] << 16) |
> +				  (mac[1] << 8) | mac[0]);
> +		rx_mac_hi = (u32)((mac[5] << 8) | (mac[4]));
> +	}
> +
> +	port_info = mtip_portinfofifo_read(fep);
> +	while (port_info) {
> +		/* get block index from lookup table */
> +		index = GET_BLOCK_PTR(port_info->hash);
> +		mtip_update_atable_dynamic1(port_info->maclo, port_info->machi,
> +					    index, port_info->port,
> +					    curr_time, fep);
> +
> +		if (mac && is_valid_ether_addr(mac) &&
> +		    port == MTIP_PORT_FORWARDING_INIT) {
> +			if (rx_mac_lo == port_info->maclo &&
> +			    rx_mac_hi == port_info->machi) {
> +				/* The newly learned MAC is the source of
> +				 * our filtered frame.
> +				 */
> +				port = (u8)port_info->port;
> +			}
> +		}
> +		port_info = mtip_portinfofifo_read(fep);
> +	}
> +
> +	if (rx_port)
> +		*rx_port = port;
> +
> +	spin_unlock_irqrestore(&fep->learn_lock, flags);
> +}
> +
> +static void mtip_aging_timer(struct timer_list *t)
> +{
> +	struct switch_enet_private *fep = from_timer(fep, t, timer_aging);
> +
> +	if (fep)
> +		fep->curr_time = mtip_timeincrement(fep->curr_time);
> +
> +	mod_timer(&fep->timer_aging,
> +		  jiffies + msecs_to_jiffies(LEARNING_AGING_INTERVAL));
I'm not sure that fep can actually be NULL. If it's possible please 
return in order to avoid a NULL pointer deference here, otherwise drop 
the check.

Thanks

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ