diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.14/704-dpaa2-mac-phy-support-layerscape.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.14/704-dpaa2-mac-phy-support-layerscape.patch | 1888 |
1 files changed, 1888 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.14/704-dpaa2-mac-phy-support-layerscape.patch b/target/linux/layerscape/patches-4.14/704-dpaa2-mac-phy-support-layerscape.patch new file mode 100644 index 0000000000..d76c5abe51 --- /dev/null +++ b/target/linux/layerscape/patches-4.14/704-dpaa2-mac-phy-support-layerscape.patch @@ -0,0 +1,1888 @@ +From 92cf25fe454dd42136e717ba679a9dba740db0e7 Mon Sep 17 00:00:00 2001 +From: Biwen Li <biwen.li@nxp.com> +Date: Tue, 30 Oct 2018 18:26:18 +0800 +Subject: [PATCH 10/40] dpaa2-mac-phy: support layerscape +This is an integrated patch of dpaa2-mac-phy for + layerscape + +Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> +Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com> +Signed-off-by: Constantin Tudor <constantin.tudor@nxp.com> +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com> +Signed-off-by: Itai Katz <itai.katz@freescale.com> +Signed-off-by: J. German Rivera <German.Rivera@freescale.com> +Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com> +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> +Signed-off-by: Biwen Li <biwen.li@nxp.com> +--- + drivers/staging/fsl-dpaa2/mac/Kconfig | 23 + + drivers/staging/fsl-dpaa2/mac/Makefile | 10 + + drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h | 172 ++++++ + drivers/staging/fsl-dpaa2/mac/dpmac.c | 619 ++++++++++++++++++++ + drivers/staging/fsl-dpaa2/mac/dpmac.h | 342 +++++++++++ + drivers/staging/fsl-dpaa2/mac/mac.c | 672 ++++++++++++++++++++++ + 6 files changed, 1838 insertions(+) + create mode 100644 drivers/staging/fsl-dpaa2/mac/Kconfig + create mode 100644 drivers/staging/fsl-dpaa2/mac/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.c + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.h + create mode 100644 drivers/staging/fsl-dpaa2/mac/mac.c + +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/Kconfig +@@ -0,0 +1,23 @@ ++config FSL_DPAA2_MAC ++ tristate "DPAA2 MAC / PHY interface" ++ depends on FSL_MC_BUS && FSL_DPAA2 ++ select MDIO_BUS_MUX_MMIOREG ++ select FSL_XGMAC_MDIO ++ select FIXED_PHY ++ ---help--- ++ Prototype driver for DPAA2 MAC / PHY interface object. ++ This driver works as a proxy between phylib including phy drivers and ++ the MC firmware. It receives updates on link state changes from PHY ++ lib and forwards them to MC and receives interrupt from MC whenever ++ a request is made to change the link state. ++ ++ ++config FSL_DPAA2_MAC_NETDEVS ++ bool "Expose net interfaces for PHYs" ++ default n ++ depends on FSL_DPAA2_MAC ++ ---help--- ++ Exposes macX net interfaces which allow direct control over MACs and ++ PHYs. ++ . ++ Leave disabled if unsure. +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/Makefile +@@ -0,0 +1,10 @@ ++ ++obj-$(CONFIG_FSL_DPAA2_MAC) += dpaa2-mac.o ++ ++dpaa2-mac-objs := mac.o dpmac.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h +@@ -0,0 +1,172 @@ ++/* Copyright 2013-2016 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 the above-listed copyright holders nor the ++ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS OR CONTRIBUTORS 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. ++ */ ++#ifndef _FSL_DPMAC_CMD_H ++#define _FSL_DPMAC_CMD_H ++ ++/* DPMAC Version */ ++#define DPMAC_VER_MAJOR 4 ++#define DPMAC_VER_MINOR 2 ++#define DPMAC_CMD_BASE_VERSION 1 ++#define DPMAC_CMD_ID_OFFSET 4 ++ ++#define DPMAC_CMD(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPMAC_CMDID_CLOSE DPMAC_CMD(0x800) ++#define DPMAC_CMDID_OPEN DPMAC_CMD(0x80c) ++#define DPMAC_CMDID_CREATE DPMAC_CMD(0x90c) ++#define DPMAC_CMDID_DESTROY DPMAC_CMD(0x98c) ++#define DPMAC_CMDID_GET_API_VERSION DPMAC_CMD(0xa0c) ++ ++#define DPMAC_CMDID_GET_ATTR DPMAC_CMD(0x004) ++#define DPMAC_CMDID_RESET DPMAC_CMD(0x005) ++ ++#define DPMAC_CMDID_SET_IRQ_ENABLE DPMAC_CMD(0x012) ++#define DPMAC_CMDID_GET_IRQ_ENABLE DPMAC_CMD(0x013) ++#define DPMAC_CMDID_SET_IRQ_MASK DPMAC_CMD(0x014) ++#define DPMAC_CMDID_GET_IRQ_MASK DPMAC_CMD(0x015) ++#define DPMAC_CMDID_GET_IRQ_STATUS DPMAC_CMD(0x016) ++#define DPMAC_CMDID_CLEAR_IRQ_STATUS DPMAC_CMD(0x017) ++ ++#define DPMAC_CMDID_GET_LINK_CFG DPMAC_CMD(0x0c2) ++#define DPMAC_CMDID_SET_LINK_STATE DPMAC_CMD(0x0c3) ++#define DPMAC_CMDID_GET_COUNTER DPMAC_CMD(0x0c4) ++ ++#define DPMAC_CMDID_SET_PORT_MAC_ADDR DPMAC_CMD(0x0c5) ++ ++/* Macros for accessing command fields smaller than 1byte */ ++#define DPMAC_MASK(field) \ ++ GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \ ++ DPMAC_##field##_SHIFT) ++#define dpmac_set_field(var, field, val) \ ++ ((var) |= (((val) << DPMAC_##field##_SHIFT) & DPMAC_MASK(field))) ++#define dpmac_get_field(var, field) \ ++ (((var) & DPMAC_MASK(field)) >> DPMAC_##field##_SHIFT) ++ ++struct dpmac_cmd_open { ++ u32 dpmac_id; ++}; ++ ++struct dpmac_cmd_create { ++ u32 mac_id; ++}; ++ ++struct dpmac_cmd_destroy { ++ u32 dpmac_id; ++}; ++ ++struct dpmac_cmd_set_irq_enable { ++ u8 enable; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpmac_cmd_get_irq_enable { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_enable { ++ u8 enabled; ++}; ++ ++struct dpmac_cmd_set_irq_mask { ++ u32 mask; ++ u8 irq_index; ++}; ++ ++struct dpmac_cmd_get_irq_mask { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_mask { ++ u32 mask; ++}; ++ ++struct dpmac_cmd_get_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_status { ++ u32 status; ++}; ++ ++struct dpmac_cmd_clear_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_attributes { ++ u8 eth_if; ++ u8 link_type; ++ u16 id; ++ u32 max_rate; ++}; ++ ++struct dpmac_rsp_get_link_cfg { ++ u64 options; ++ u32 rate; ++}; ++ ++#define DPMAC_STATE_SIZE 1 ++#define DPMAC_STATE_SHIFT 0 ++ ++struct dpmac_cmd_set_link_state { ++ u64 options; ++ u32 rate; ++ u32 pad; ++ /* only least significant bit is valid */ ++ u8 up; ++}; ++ ++struct dpmac_cmd_get_counter { ++ u8 type; ++}; ++ ++struct dpmac_rsp_get_counter { ++ u64 pad; ++ u64 counter; ++}; ++ ++struct dpmac_rsp_get_api_version { ++ u16 major; ++ u16 minor; ++}; ++ ++struct dpmac_cmd_set_port_mac_addr { ++ u8 pad[2]; ++ u8 addr[6]; ++}; ++ ++#endif /* _FSL_DPMAC_CMD_H */ +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c +@@ -0,0 +1,619 @@ ++/* Copyright 2013-2016 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 the above-listed copyright holders nor the ++ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS OR CONTRIBUTORS 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. ++ */ ++#include <linux/fsl/mc.h> ++#include "dpmac.h" ++#include "dpmac-cmd.h" ++ ++/** ++ * dpmac_open() - Open a control session for the specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpmac_id: DPMAC unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpmac_create function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmac_id, ++ u16 *token) ++{ ++ struct dpmac_cmd_open *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpmac_cmd_open *)cmd.params; ++ cmd_params->dpmac_id = cpu_to_le32(dpmac_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return err; ++} ++ ++/** ++ * dpmac_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_create() - Create the DPMAC object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @obj_id: Returned object id ++ * ++ * Create the DPMAC object, allocate required resources and ++ * perform required initialization. ++ * ++ * The function accepts an authentication token of a parent ++ * container that this object should be assigned to. The token ++ * can be '0' so the object will be assigned to the default container. ++ * The newly created object can be opened with the returned ++ * object id and using the container's associated tokens and MC portals. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpmac_cfg *cfg, ++ u32 *obj_id) ++{ ++ struct dpmac_cmd_create *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpmac_cmd_create *)cmd.params; ++ cmd_params->mac_id = cpu_to_le32(cfg->mac_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *obj_id = mc_cmd_read_object_id(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_destroy() - Destroy the DPMAC object and release all its resources. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @object_id: The object id; it must be a valid id within the container that ++ * created this object; ++ * ++ * The function accepts the authentication token of the parent container that ++ * created the object (not the one that currently owns the object). The object ++ * is searched within parent using the provided 'object_id'. ++ * All tokens to the object must be closed before calling destroy. ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpmac_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id) ++{ ++ struct dpmac_cmd_destroy *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpmac_cmd_destroy *)cmd.params; ++ cmd_params->dpmac_id = cpu_to_le32(object_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct dpmac_cmd_set_irq_enable *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->enable = en; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en) ++{ ++ struct dpmac_cmd_get_irq_enable *cmd_params; ++ struct dpmac_rsp_get_irq_enable *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_enable *)cmd.params; ++ *en = rsp_params->enabled; ++ ++ return 0; ++} ++ ++/** ++ * dpmac_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct dpmac_cmd_set_irq_mask *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask) ++{ ++ struct dpmac_cmd_get_irq_mask *cmd_params; ++ struct dpmac_rsp_get_irq_mask *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_mask *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_mask *)cmd.params; ++ *mask = le32_to_cpu(rsp_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_get_irq_status() - Get the current status of any pending interrupts. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct dpmac_cmd_get_irq_status *cmd_params; ++ struct dpmac_rsp_get_irq_status *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_clear_irq_status() - Clear a pending interrupt's status ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @status: Bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct dpmac_cmd_clear_irq_status *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_clear_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_attributes - Retrieve DPMAC attributes. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_attr *attr) ++{ ++ struct dpmac_rsp_get_attributes *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_attributes *)cmd.params; ++ attr->eth_if = rsp_params->eth_if; ++ attr->link_type = rsp_params->link_type; ++ attr->id = le16_to_cpu(rsp_params->id); ++ attr->max_rate = le32_to_cpu(rsp_params->max_rate); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_get_link_cfg() - Get Ethernet link configuration ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @cfg: Returned structure with the link configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_cfg *cfg) ++{ ++ struct dpmac_rsp_get_link_cfg *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err = 0; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpmac_rsp_get_link_cfg *)cmd.params; ++ cfg->options = le64_to_cpu(rsp_params->options); ++ cfg->rate = le32_to_cpu(rsp_params->rate); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_set_link_state() - Set the Ethernet link status ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @link_state: Link state configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_state *link_state) ++{ ++ struct dpmac_cmd_set_link_state *cmd_params; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params; ++ cmd_params->options = cpu_to_le64(link_state->options); ++ cmd_params->rate = cpu_to_le32(link_state->rate); ++ cmd_params->up = dpmac_get_field(link_state->up, STATE); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_counter() - Read a specific DPMAC counter ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @type: The requested counter ++ * @counter: Returned counter value ++ * ++ * Return: The requested counter; '0' otherwise. ++ */ ++int dpmac_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpmac_counter type, ++ u64 *counter) ++{ ++ struct dpmac_cmd_get_counter *dpmac_cmd; ++ struct dpmac_rsp_get_counter *dpmac_rsp; ++ struct fsl_mc_command cmd = { 0 }; ++ int err = 0; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER, ++ cmd_flags, ++ token); ++ dpmac_cmd = (struct dpmac_cmd_get_counter *)cmd.params; ++ dpmac_cmd->type = type; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ dpmac_rsp = (struct dpmac_rsp_get_counter *)cmd.params; ++ *counter = le64_to_cpu(dpmac_rsp->counter); ++ ++ return 0; ++} ++ ++/* untested */ ++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 addr[6]) ++{ ++ struct dpmac_cmd_set_port_mac_addr *dpmac_cmd; ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_PORT_MAC_ADDR, ++ cmd_flags, ++ token); ++ dpmac_cmd = (struct dpmac_cmd_set_port_mac_addr *)cmd.params; ++ dpmac_cmd->addr[0] = addr[5]; ++ dpmac_cmd->addr[1] = addr[4]; ++ dpmac_cmd->addr[2] = addr[3]; ++ dpmac_cmd->addr[3] = addr[2]; ++ dpmac_cmd->addr[4] = addr[1]; ++ dpmac_cmd->addr[5] = addr[0]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_api_version() - Get Data Path MAC version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path mac API ++ * @minor_ver: Minor version of data path mac API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct dpmac_rsp_get_api_version *rsp_params; ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_API_VERSION, ++ cmd_flags, ++ 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpmac_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->major); ++ *minor_ver = le16_to_cpu(rsp_params->minor); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.h +@@ -0,0 +1,342 @@ ++/* Copyright 2013-2016 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 the above-listed copyright holders nor the ++ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS OR CONTRIBUTORS 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. ++ */ ++#ifndef __FSL_DPMAC_H ++#define __FSL_DPMAC_H ++ ++/* Data Path MAC API ++ * Contains initialization APIs and runtime control APIs for DPMAC ++ */ ++ ++struct fsl_mc_io; ++ ++int dpmac_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmac_id, ++ u16 *token); ++ ++int dpmac_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * enum dpmac_link_type - DPMAC link type ++ * @DPMAC_LINK_TYPE_NONE: No link ++ * @DPMAC_LINK_TYPE_FIXED: Link is fixed type ++ * @DPMAC_LINK_TYPE_PHY: Link by PHY ID ++ * @DPMAC_LINK_TYPE_BACKPLANE: Backplane link type ++ */ ++enum dpmac_link_type { ++ DPMAC_LINK_TYPE_NONE, ++ DPMAC_LINK_TYPE_FIXED, ++ DPMAC_LINK_TYPE_PHY, ++ DPMAC_LINK_TYPE_BACKPLANE ++}; ++ ++/** ++ * enum dpmac_eth_if - DPMAC Ethrnet interface ++ * @DPMAC_ETH_IF_MII: MII interface ++ * @DPMAC_ETH_IF_RMII: RMII interface ++ * @DPMAC_ETH_IF_SMII: SMII interface ++ * @DPMAC_ETH_IF_GMII: GMII interface ++ * @DPMAC_ETH_IF_RGMII: RGMII interface ++ * @DPMAC_ETH_IF_SGMII: SGMII interface ++ * @DPMAC_ETH_IF_QSGMII: QSGMII interface ++ * @DPMAC_ETH_IF_XAUI: XAUI interface ++ * @DPMAC_ETH_IF_XFI: XFI interface ++ */ ++enum dpmac_eth_if { ++ DPMAC_ETH_IF_MII, ++ DPMAC_ETH_IF_RMII, ++ DPMAC_ETH_IF_SMII, ++ DPMAC_ETH_IF_GMII, ++ DPMAC_ETH_IF_RGMII, ++ DPMAC_ETH_IF_SGMII, ++ DPMAC_ETH_IF_QSGMII, ++ DPMAC_ETH_IF_XAUI, ++ DPMAC_ETH_IF_XFI ++}; ++ ++/** ++ * struct dpmac_cfg - Structure representing DPMAC configuration ++ * @mac_id: Represents the Hardware MAC ID; in case of multiple WRIOP, ++ * the MAC IDs are continuous. ++ * For example: 2 WRIOPs, 16 MACs in each: ++ * MAC IDs for the 1st WRIOP: 1-16, ++ * MAC IDs for the 2nd WRIOP: 17-32. ++ */ ++struct dpmac_cfg { ++ u16 mac_id; ++}; ++ ++int dpmac_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpmac_cfg *cfg, ++ u32 *obj_id); ++ ++int dpmac_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id); ++ ++/** ++ * DPMAC IRQ Index and Events ++ */ ++ ++/** ++ * IRQ index ++ */ ++#define DPMAC_IRQ_INDEX 0 ++/** ++ * IRQ event - indicates a change in link state ++ */ ++#define DPMAC_IRQ_EVENT_LINK_CFG_REQ 0x00000001 ++/** ++ * IRQ event - Indicates that the link state changed ++ */ ++#define DPMAC_IRQ_EVENT_LINK_CHANGED 0x00000002 ++ ++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dpmac_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dpmac_attr - Structure representing DPMAC attributes ++ * @id: DPMAC object ID ++ * @max_rate: Maximum supported rate - in Mbps ++ * @eth_if: Ethernet interface ++ * @link_type: link type ++ */ ++struct dpmac_attr { ++ u16 id; ++ u32 max_rate; ++ enum dpmac_eth_if eth_if; ++ enum dpmac_link_type link_type; ++}; ++ ++int dpmac_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_attr *attr); ++ ++/** ++ * DPMAC link configuration/state options ++ */ ++ ++/** ++ * Enable auto-negotiation ++ */ ++#define DPMAC_LINK_OPT_AUTONEG 0x0000000000000001ULL ++/** ++ * Enable half-duplex mode ++ */ ++#define DPMAC_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL ++/** ++ * Enable pause frames ++ */ ++#define DPMAC_LINK_OPT_PAUSE 0x0000000000000004ULL ++/** ++ * Enable a-symmetric pause frames ++ */ ++#define DPMAC_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL ++ ++/** ++ * struct dpmac_link_cfg - Structure representing DPMAC link configuration ++ * @rate: Link's rate - in Mbps ++ * @options: Enable/Disable DPMAC link cfg features (bitmap) ++ */ ++struct dpmac_link_cfg { ++ u32 rate; ++ u64 options; ++}; ++ ++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_cfg *cfg); ++ ++/** ++ * struct dpmac_link_state - DPMAC link configuration request ++ * @rate: Rate in Mbps ++ * @options: Enable/Disable DPMAC link cfg features (bitmap) ++ * @up: Link state ++ */ ++struct dpmac_link_state { ++ u32 rate; ++ u64 options; ++ int up; ++}; ++ ++int dpmac_set_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_state *link_state); ++ ++/** ++ * enum dpmac_counter - DPMAC counter types ++ * @DPMAC_CNT_ING_FRAME_64: counts 64-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_127: counts 65- to 127-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_255: counts 128- to 255-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_511: counts 256- to 511-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1023: counts 512- to 1023-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1518: counts 1024- to 1518-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1519_MAX: counts 1519-bytes frames and larger ++ * (up to max frame length specified), ++ * good or bad. ++ * @DPMAC_CNT_ING_FRAG: counts frames which are shorter than 64 bytes received ++ * with a wrong CRC ++ * @DPMAC_CNT_ING_JABBER: counts frames longer than the maximum frame length ++ * specified, with a bad frame check sequence. ++ * @DPMAC_CNT_ING_FRAME_DISCARD: counts dropped frames due to internal errors. ++ * Occurs when a receive FIFO overflows. ++ * Includes also frames truncated as a result of ++ * the receive FIFO overflow. ++ * @DPMAC_CNT_ING_ALIGN_ERR: counts frames with an alignment error ++ * (optional used for wrong SFD). ++ * @DPMAC_CNT_EGR_UNDERSIZED: counts frames transmitted that was less than 64 ++ * bytes long with a good CRC. ++ * @DPMAC_CNT_ING_OVERSIZED: counts frames longer than the maximum frame length ++ * specified, with a good frame check sequence. ++ * @DPMAC_CNT_ING_VALID_PAUSE_FRAME: counts valid pause frames (regular and PFC) ++ * @DPMAC_CNT_EGR_VALID_PAUSE_FRAME: counts valid pause frames transmitted ++ * (regular and PFC). ++ * @DPMAC_CNT_ING_BYTE: counts bytes received except preamble for all valid ++ * frames and valid pause frames. ++ * @DPMAC_CNT_ING_MCAST_FRAME: counts received multicast frames. ++ * @DPMAC_CNT_ING_BCAST_FRAME: counts received broadcast frames. ++ * @DPMAC_CNT_ING_ALL_FRAME: counts each good or bad frames received. ++ * @DPMAC_CNT_ING_UCAST_FRAME: counts received unicast frames. ++ * @DPMAC_CNT_ING_ERR_FRAME: counts frames received with an error ++ * (except for undersized/fragment frame). ++ * @DPMAC_CNT_EGR_BYTE: counts bytes transmitted except preamble for all valid ++ * frames and valid pause frames transmitted. ++ * @DPMAC_CNT_EGR_MCAST_FRAME: counts transmitted multicast frames. ++ * @DPMAC_CNT_EGR_BCAST_FRAME: counts transmitted broadcast frames. ++ * @DPMAC_CNT_EGR_UCAST_FRAME: counts transmitted unicast frames. ++ * @DPMAC_CNT_EGR_ERR_FRAME: counts frames transmitted with an error. ++ * @DPMAC_CNT_ING_GOOD_FRAME: counts frames received without error, including ++ * pause frames. ++ * @DPMAC_CNT_ENG_GOOD_FRAME: counts frames transmitted without error, including ++ * pause frames. ++ */ ++enum dpmac_counter { ++ DPMAC_CNT_ING_FRAME_64, ++ DPMAC_CNT_ING_FRAME_127, ++ DPMAC_CNT_ING_FRAME_255, ++ DPMAC_CNT_ING_FRAME_511, ++ DPMAC_CNT_ING_FRAME_1023, ++ DPMAC_CNT_ING_FRAME_1518, ++ DPMAC_CNT_ING_FRAME_1519_MAX, ++ DPMAC_CNT_ING_FRAG, ++ DPMAC_CNT_ING_JABBER, ++ DPMAC_CNT_ING_FRAME_DISCARD, ++ DPMAC_CNT_ING_ALIGN_ERR, ++ DPMAC_CNT_EGR_UNDERSIZED, ++ DPMAC_CNT_ING_OVERSIZED, ++ DPMAC_CNT_ING_VALID_PAUSE_FRAME, ++ DPMAC_CNT_EGR_VALID_PAUSE_FRAME, ++ DPMAC_CNT_ING_BYTE, ++ DPMAC_CNT_ING_MCAST_FRAME, ++ DPMAC_CNT_ING_BCAST_FRAME, ++ DPMAC_CNT_ING_ALL_FRAME, ++ DPMAC_CNT_ING_UCAST_FRAME, ++ DPMAC_CNT_ING_ERR_FRAME, ++ DPMAC_CNT_EGR_BYTE, ++ DPMAC_CNT_EGR_MCAST_FRAME, ++ DPMAC_CNT_EGR_BCAST_FRAME, ++ DPMAC_CNT_EGR_UCAST_FRAME, ++ DPMAC_CNT_EGR_ERR_FRAME, ++ DPMAC_CNT_ING_GOOD_FRAME, ++ DPMAC_CNT_ENG_GOOD_FRAME ++}; ++ ++int dpmac_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpmac_counter type, ++ u64 *counter); ++ ++/** ++ * dpmac_set_port_mac_addr() - Set a MAC address associated with the physical ++ * port. This is not used for filtering, MAC is always in ++ * promiscuous mode, it is passed to DPNIs through DPNI API for ++ * application used. ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @addr: MAC address to set ++ * ++ * Return: The requested counter; '0' otherwise. ++ */ ++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 addr[6]); ++ ++int dpmac_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPMAC_H */ +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/mac.c +@@ -0,0 +1,672 @@ ++/* Copyright 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. ++ */ ++ ++#include <linux/module.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/msi.h> ++#include <linux/rtnetlink.h> ++#include <linux/if_vlan.h> ++ ++#include <uapi/linux/if_bridge.h> ++#include <net/netlink.h> ++ ++#include <linux/of.h> ++#include <linux/of_mdio.h> ++#include <linux/of_net.h> ++#include <linux/phy.h> ++#include <linux/phy_fixed.h> ++ ++#include <linux/fsl/mc.h> ++ ++#include "dpmac.h" ++#include "dpmac-cmd.h" ++ ++struct dpaa2_mac_priv { ++ struct net_device *netdev; ++ struct fsl_mc_device *mc_dev; ++ struct dpmac_attr attr; ++ struct dpmac_link_state old_state; ++}; ++ ++/* TODO: fix the 10G modes, mapping can't be right: ++ * XGMII is paralel ++ * XAUI is serial, using 8b/10b encoding ++ * XFI is also serial but using 64b/66b encoding ++ * they can't all map to XGMII... ++ * ++ * This must be kept in sync with enum dpmac_eth_if. ++ */ ++static phy_interface_t dpaa2_mac_iface_mode[] = { ++ PHY_INTERFACE_MODE_MII, /* DPMAC_ETH_IF_MII */ ++ PHY_INTERFACE_MODE_RMII, /* DPMAC_ETH_IF_RMII */ ++ PHY_INTERFACE_MODE_SMII, /* DPMAC_ETH_IF_SMII */ ++ PHY_INTERFACE_MODE_GMII, /* DPMAC_ETH_IF_GMII */ ++ PHY_INTERFACE_MODE_RGMII, /* DPMAC_ETH_IF_RGMII */ ++ PHY_INTERFACE_MODE_SGMII, /* DPMAC_ETH_IF_SGMII */ ++ PHY_INTERFACE_MODE_QSGMII, /* DPMAC_ETH_IF_QSGMII */ ++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XAUI */ ++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XFI */ ++}; ++ ++static void dpaa2_mac_link_changed(struct net_device *netdev) ++{ ++ struct phy_device *phydev; ++ struct dpmac_link_state state = { 0 }; ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ int err; ++ ++ /* the PHY just notified us of link state change */ ++ phydev = netdev->phydev; ++ ++ state.up = !!phydev->link; ++ if (phydev->link) { ++ state.rate = phydev->speed; ++ ++ if (!phydev->duplex) ++ state.options |= DPMAC_LINK_OPT_HALF_DUPLEX; ++ if (phydev->autoneg) ++ state.options |= DPMAC_LINK_OPT_AUTONEG; ++ ++ netif_carrier_on(netdev); ++ } else { ++ netif_carrier_off(netdev); ++ } ++ ++ if (priv->old_state.up != state.up || ++ priv->old_state.rate != state.rate || ++ priv->old_state.options != state.options) { ++ priv->old_state = state; ++ phy_print_status(phydev); ++ } ++ ++ /* We must interrogate MC at all times, because we don't know ++ * when and whether a potential DPNI may have read the link state. ++ */ ++ err = dpmac_set_link_state(priv->mc_dev->mc_io, 0, ++ priv->mc_dev->mc_handle, &state); ++ if (unlikely(err)) ++ dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err); ++} ++ ++static int dpaa2_mac_open(struct net_device *netdev) ++{ ++ /* start PHY state machine */ ++ phy_start(netdev->phydev); ++ ++ return 0; ++} ++ ++static int dpaa2_mac_stop(struct net_device *netdev) ++{ ++ if (!netdev->phydev) ++ goto done; ++ ++ /* stop PHY state machine */ ++ phy_stop(netdev->phydev); ++ ++ /* signal link down to firmware */ ++ netdev->phydev->link = 0; ++ dpaa2_mac_link_changed(netdev); ++ ++done: ++ return 0; ++} ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ /* we don't support I/O for now, drop the frame */ ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++ ++static int dpaa2_mac_get_link_ksettings(struct net_device *netdev, ++ struct ethtool_link_ksettings *ks) ++{ ++ phy_ethtool_ksettings_get(netdev->phydev, ks); ++ ++ return 0; ++} ++ ++static int dpaa2_mac_set_link_ksettings(struct net_device *netdev, ++ const struct ethtool_link_ksettings *ks) ++{ ++ return phy_ethtool_ksettings_set(netdev->phydev, ks); ++} ++ ++static void dpaa2_mac_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *storage) ++{ ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ u64 tmp; ++ int err; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_MCAST_FRAME, ++ &storage->tx_packets); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_BCAST_FRAME, &tmp); ++ if (err) ++ goto error; ++ storage->tx_packets += tmp; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_UCAST_FRAME, &tmp); ++ if (err) ++ goto error; ++ storage->tx_packets += tmp; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_UNDERSIZED, &storage->tx_dropped); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_BYTE, &storage->tx_bytes); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_ERR_FRAME, &storage->tx_errors); ++ if (err) ++ goto error; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_ALL_FRAME, &storage->rx_packets); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_MCAST_FRAME, &storage->multicast); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_FRAME_DISCARD, ++ &storage->rx_dropped); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_ALIGN_ERR, &storage->rx_errors); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_OVERSIZED, &tmp); ++ if (err) ++ goto error; ++ storage->rx_errors += tmp; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_BYTE, &storage->rx_bytes); ++ if (err) ++ goto error; ++ ++ return; ++error: ++ netdev_err(netdev, "dpmac_get_counter err %d\n", err); ++} ++ ++static struct { ++ enum dpmac_counter id; ++ char name[ETH_GSTRING_LEN]; ++} dpaa2_mac_counters[] = { ++ {DPMAC_CNT_ING_ALL_FRAME, "rx all frames"}, ++ {DPMAC_CNT_ING_GOOD_FRAME, "rx frames ok"}, ++ {DPMAC_CNT_ING_ERR_FRAME, "rx frame errors"}, ++ {DPMAC_CNT_ING_FRAME_DISCARD, "rx frame discards"}, ++ {DPMAC_CNT_ING_UCAST_FRAME, "rx u-cast"}, ++ {DPMAC_CNT_ING_BCAST_FRAME, "rx b-cast"}, ++ {DPMAC_CNT_ING_MCAST_FRAME, "rx m-cast"}, ++ {DPMAC_CNT_ING_FRAME_64, "rx 64 bytes"}, ++ {DPMAC_CNT_ING_FRAME_127, "rx 65-127 bytes"}, ++ {DPMAC_CNT_ING_FRAME_255, "rx 128-255 bytes"}, ++ {DPMAC_CNT_ING_FRAME_511, "rx 256-511 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1023, "rx 512-1023 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1518, "rx 1024-1518 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1519_MAX, "rx 1519-max bytes"}, ++ {DPMAC_CNT_ING_FRAG, "rx frags"}, ++ {DPMAC_CNT_ING_JABBER, "rx jabber"}, ++ {DPMAC_CNT_ING_ALIGN_ERR, "rx align errors"}, ++ {DPMAC_CNT_ING_OVERSIZED, "rx oversized"}, ++ {DPMAC_CNT_ING_VALID_PAUSE_FRAME, "rx pause"}, ++ {DPMAC_CNT_ING_BYTE, "rx bytes"}, ++ {DPMAC_CNT_ENG_GOOD_FRAME, "tx frames ok"}, ++ {DPMAC_CNT_EGR_UCAST_FRAME, "tx u-cast"}, ++ {DPMAC_CNT_EGR_MCAST_FRAME, "tx m-cast"}, ++ {DPMAC_CNT_EGR_BCAST_FRAME, "tx b-cast"}, ++ {DPMAC_CNT_EGR_ERR_FRAME, "tx frame errors"}, ++ {DPMAC_CNT_EGR_UNDERSIZED, "tx undersized"}, ++ {DPMAC_CNT_EGR_VALID_PAUSE_FRAME, "tx b-pause"}, ++ {DPMAC_CNT_EGR_BYTE, "tx bytes"}, ++ ++}; ++ ++static void dpaa2_mac_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) ++ memcpy(data + i * ETH_GSTRING_LEN, ++ dpaa2_mac_counters[i].name, ++ ETH_GSTRING_LEN); ++ break; ++ } ++} ++ ++static void dpaa2_mac_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ int i; ++ int err; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) { ++ err = dpmac_get_counter(priv->mc_dev->mc_io, ++ 0, ++ priv->mc_dev->mc_handle, ++ dpaa2_mac_counters[i].id, &data[i]); ++ if (err) ++ netdev_err(netdev, "dpmac_get_counter[%s] err %d\n", ++ dpaa2_mac_counters[i].name, err); ++ } ++} ++ ++static int dpaa2_mac_get_sset_count(struct net_device *dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return ARRAY_SIZE(dpaa2_mac_counters); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static const struct net_device_ops dpaa2_mac_ndo_ops = { ++ .ndo_open = &dpaa2_mac_open, ++ .ndo_stop = &dpaa2_mac_stop, ++ .ndo_start_xmit = &dpaa2_mac_drop_frame, ++ .ndo_get_stats64 = &dpaa2_mac_get_stats, ++}; ++ ++static const struct ethtool_ops dpaa2_mac_ethtool_ops = { ++ .get_link_ksettings = &dpaa2_mac_get_link_ksettings, ++ .set_link_ksettings = &dpaa2_mac_set_link_ksettings, ++ .get_strings = &dpaa2_mac_get_strings, ++ .get_ethtool_stats = &dpaa2_mac_get_ethtool_stats, ++ .get_sset_count = &dpaa2_mac_get_sset_count, ++}; ++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ ++static void configure_link(struct dpaa2_mac_priv *priv, ++ struct dpmac_link_cfg *cfg) ++{ ++ struct phy_device *phydev = priv->netdev->phydev; ++ ++ if (unlikely(!phydev)) ++ return; ++ ++ phydev->speed = cfg->rate; ++ phydev->duplex = !!(cfg->options & DPMAC_LINK_OPT_HALF_DUPLEX); ++ ++ if (cfg->options & DPMAC_LINK_OPT_AUTONEG) { ++ phydev->autoneg = 1; ++ phydev->advertising |= ADVERTISED_Autoneg; ++ } else { ++ phydev->autoneg = 0; ++ phydev->advertising &= ~ADVERTISED_Autoneg; ++ } ++ ++ phy_start_aneg(phydev); ++} ++ ++static irqreturn_t dpaa2_mac_irq_handler(int irq_num, void *arg) ++{ ++ struct device *dev = (struct device *)arg; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev); ++ struct dpmac_link_cfg link_cfg; ++ u32 status; ++ int err; ++ ++ err = dpmac_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, &status); ++ if (unlikely(err || !status)) ++ return IRQ_NONE; ++ ++ /* DPNI-initiated link configuration; 'ifconfig up' also calls this */ ++ if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) { ++ err = dpmac_get_link_cfg(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ &link_cfg); ++ if (unlikely(err)) ++ goto out; ++ ++ configure_link(priv, &link_cfg); ++ } ++ ++out: ++ dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, status); ++ ++ return IRQ_HANDLED; ++} ++ ++static int setup_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int err = 0; ++ struct fsl_mc_device_irq *irq; ++ ++ err = fsl_mc_allocate_irqs(mc_dev); ++ if (err) { ++ dev_err(&mc_dev->dev, "fsl_mc_allocate_irqs err %d\n", err); ++ return err; ++ } ++ ++ irq = mc_dev->irqs[0]; ++ err = devm_request_threaded_irq(&mc_dev->dev, irq->msi_desc->irq, ++ NULL, &dpaa2_mac_irq_handler, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(&mc_dev->dev), &mc_dev->dev); ++ if (err) { ++ dev_err(&mc_dev->dev, "devm_request_threaded_irq err %d\n", ++ err); ++ goto free_irq; ++ } ++ ++ err = dpmac_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ); ++ if (err) { ++ dev_err(&mc_dev->dev, "dpmac_set_irq_mask err %d\n", err); ++ goto free_irq; ++ } ++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, 1); ++ if (err) { ++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err); ++ goto free_irq; ++ } ++ ++ return 0; ++ ++free_irq: ++ fsl_mc_free_irqs(mc_dev); ++ ++ return err; ++} ++ ++static void teardown_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int err; ++ ++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, 0); ++ if (err) ++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err); ++ ++ fsl_mc_free_irqs(mc_dev); ++} ++ ++static struct device_node *find_dpmac_node(struct device *dev, u16 dpmac_id) ++{ ++ struct device_node *dpmacs, *dpmac = NULL; ++ struct device_node *mc_node = dev->of_node; ++ u32 id; ++ int err; ++ ++ dpmacs = of_find_node_by_name(mc_node, "dpmacs"); ++ if (!dpmacs) { ++ dev_err(dev, "No dpmacs subnode in device-tree\n"); ++ return NULL; ++ } ++ ++ while ((dpmac = of_get_next_child(dpmacs, dpmac))) { ++ err = of_property_read_u32(dpmac, "reg", &id); ++ if (err) ++ continue; ++ if (id == dpmac_id) ++ return dpmac; ++ } ++ ++ return NULL; ++} ++ ++static int dpaa2_mac_probe(struct fsl_mc_device *mc_dev) ++{ ++ struct device *dev; ++ struct dpaa2_mac_priv *priv = NULL; ++ struct device_node *phy_node, *dpmac_node; ++ struct net_device *netdev; ++ phy_interface_t if_mode; ++ int err = 0; ++ ++ dev = &mc_dev->dev; ++ ++ /* prepare a net_dev structure to make the phy lib API happy */ ++ netdev = alloc_etherdev(sizeof(*priv)); ++ if (!netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ err = -ENOMEM; ++ goto err_exit; ++ } ++ priv = netdev_priv(netdev); ++ priv->mc_dev = mc_dev; ++ priv->netdev = netdev; ++ ++ SET_NETDEV_DEV(netdev, dev); ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ snprintf(netdev->name, IFNAMSIZ, "mac%d", mc_dev->obj_desc.id); ++#endif ++ ++ dev_set_drvdata(dev, priv); ++ ++ /* We may need to issue MC commands while in atomic context */ ++ err = fsl_mc_portal_allocate(mc_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, ++ &mc_dev->mc_io); ++ if (err || !mc_dev->mc_io) { ++ dev_dbg(dev, "fsl_mc_portal_allocate error: %d\n", err); ++ err = -EPROBE_DEFER; ++ goto err_free_netdev; ++ } ++ ++ err = dpmac_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, ++ &mc_dev->mc_handle); ++ if (err || !mc_dev->mc_handle) { ++ dev_err(dev, "dpmac_open error: %d\n", err); ++ err = -ENODEV; ++ goto err_free_mcp; ++ } ++ ++ err = dpmac_get_attributes(mc_dev->mc_io, 0, ++ mc_dev->mc_handle, &priv->attr); ++ if (err) { ++ dev_err(dev, "dpmac_get_attributes err %d\n", err); ++ err = -EINVAL; ++ goto err_close; ++ } ++ ++ /* Look up the DPMAC node in the device-tree. */ ++ dpmac_node = find_dpmac_node(dev, priv->attr.id); ++ if (!dpmac_node) { ++ dev_err(dev, "No dpmac@%d subnode found.\n", priv->attr.id); ++ err = -ENODEV; ++ goto err_close; ++ } ++ ++ err = setup_irqs(mc_dev); ++ if (err) { ++ err = -EFAULT; ++ goto err_close; ++ } ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ /* OPTIONAL, register netdev just to make it visible to the user */ ++ netdev->netdev_ops = &dpaa2_mac_ndo_ops; ++ netdev->ethtool_ops = &dpaa2_mac_ethtool_ops; ++ ++ /* phy starts up enabled so netdev should be up too */ ++ netdev->flags |= IFF_UP; ++ ++ err = register_netdev(priv->netdev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev error %d\n", err); ++ err = -ENODEV; ++ goto err_free_irq; ++ } ++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ ++ /* probe the PHY as a fixed-link if there's a phy-handle defined ++ * in the device tree ++ */ ++ phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0); ++ if (!phy_node) { ++ goto probe_fixed_link; ++ } ++ ++ if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) { ++ if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if]; ++ dev_dbg(dev, "\tusing if mode %s for eth_if %d\n", ++ phy_modes(if_mode), priv->attr.eth_if); ++ } else { ++ dev_warn(dev, "Unexpected interface mode %d, will probe as fixed link\n", ++ priv->attr.eth_if); ++ goto probe_fixed_link; ++ } ++ ++ /* try to connect to the PHY */ ++ netdev->phydev = of_phy_connect(netdev, phy_node, ++ &dpaa2_mac_link_changed, 0, if_mode); ++ if (!netdev->phydev) { ++ /* No need for dev_err(); the kernel's loud enough as it is. */ ++ dev_dbg(dev, "Can't of_phy_connect() now.\n"); ++ /* We might be waiting for the MDIO MUX to probe, so defer ++ * our own probing. ++ */ ++ err = -EPROBE_DEFER; ++ goto err_defer; ++ } ++ dev_info(dev, "Connected to %s PHY.\n", phy_modes(if_mode)); ++ ++probe_fixed_link: ++ if (!netdev->phydev) { ++ struct fixed_phy_status status = { ++ .link = 1, ++ /* fixed-phys don't support 10Gbps speed for now */ ++ .speed = 1000, ++ .duplex = 1, ++ }; ++ ++ /* try to register a fixed link phy */ ++ netdev->phydev = fixed_phy_register(PHY_POLL, &status, -1, ++ NULL); ++ if (!netdev->phydev || IS_ERR(netdev->phydev)) { ++ dev_err(dev, "error trying to register fixed PHY\n"); ++ /* So we don't crash unregister_netdev() later on */ ++ netdev->phydev = NULL; ++ err = -EFAULT; ++ goto err_no_phy; ++ } ++ dev_info(dev, "Registered fixed PHY.\n"); ++ } ++ ++ dpaa2_mac_open(netdev); ++ ++ return 0; ++ ++err_defer: ++err_no_phy: ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ unregister_netdev(netdev); ++err_free_irq: ++#endif ++ teardown_irqs(mc_dev); ++err_close: ++ dpmac_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++err_free_mcp: ++ fsl_mc_portal_free(mc_dev->mc_io); ++err_free_netdev: ++ free_netdev(netdev); ++err_exit: ++ return err; ++} ++ ++static int dpaa2_mac_remove(struct fsl_mc_device *mc_dev) ++{ ++ struct device *dev = &mc_dev->dev; ++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev); ++ struct net_device *netdev = priv->netdev; ++ ++ dpaa2_mac_stop(netdev); ++ ++ if (phy_is_pseudo_fixed_link(netdev->phydev)) ++ fixed_phy_unregister(netdev->phydev); ++ else ++ phy_disconnect(netdev->phydev); ++ netdev->phydev = NULL; ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ unregister_netdev(priv->netdev); ++#endif ++ teardown_irqs(priv->mc_dev); ++ dpmac_close(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle); ++ fsl_mc_portal_free(priv->mc_dev->mc_io); ++ free_netdev(priv->netdev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ return 0; ++} ++ ++static const struct fsl_mc_device_id dpaa2_mac_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpmac", ++ }, ++ { .vendor = 0x0 } ++}; ++MODULE_DEVICE_TABLE(fslmc, dpaa2_mac_match_id_table); ++ ++static struct fsl_mc_driver dpaa2_mac_drv = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_mac_probe, ++ .remove = dpaa2_mac_remove, ++ .match_id_table = dpaa2_mac_match_id_table, ++}; ++ ++module_fsl_mc_driver(dpaa2_mac_drv); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DPAA2 PHY proxy interface driver"); |