From 63290f0998b2e424bf86b7eac63cd92986e928e5 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 22 Sep 2020 16:19:07 +0300 Subject: [PATCH] dpaa2-mac: probe standalone DPMAC objects In upstream, at the moment, we only support DPMAC objects which are connected to DPNIs driver by the Linux kernel. To close the gap (aka driver any other DPMAC object in TYPE_PHY) we build a standalone driver around the dpaa2-mac. Signed-off-by: Ioana Ciornei --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 10 + drivers/net/ethernet/freescale/dpaa2/Makefile | 2 + .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 43 +++ .../net/ethernet/freescale/dpaa2/dpaa2-mac.c | 269 +++++++++++++++++ .../net/ethernet/freescale/dpaa2/dpaa2-mac.h | 1 + .../net/ethernet/freescale/dpaa2/dpmac-cmd.h | 60 +++- drivers/net/ethernet/freescale/dpaa2/dpmac.c | 270 ++++++++++++++++++ drivers/net/ethernet/freescale/dpaa2/dpmac.h | 75 +++++ 8 files changed, 729 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index 3eb4277fd9fe..09c24ef49c8a 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -12,6 +12,16 @@ config FSL_DPAA2_ETH The driver manages network objects discovered on the Freescale MC bus. +config FSL_DPAA2_MAC + tristate "Freescale DPAA2 MAC driver" + depends on FSL_MC_BUS + select PHYLINK + select PCS_LYNX + help + This is the DPAA2 MAC independent driver which aims to support dpmac + fsl_mc devices which are not connected to other objects found in the + root dprc. + if FSL_DPAA2_ETH config FSL_DPAA2_ETH_DCB bool "Data Center Bridging (DCB) Support" diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile index de3bd9fbd138..cb6d069140cb 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile @@ -5,12 +5,14 @@ obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o +obj-$(CONFIG_FSL_DPAA2_MAC) += fsl-dpaa2-mac.o fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpaa2-eth-devlink.o fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_CEETM} += dpaa2-eth-ceetm.o fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o +fsl-dpaa2-mac-objs := dpaa2-mac.o dpmac.o # Needed by the tracing framework CFLAGS_dpaa2-eth.o := -I$(src) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 537a61670a99..270839529f5e 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -16,9 +16,15 @@ #include #include #include +#include #include #include +/* Hack: only here in order to use device_driver_detach. + * To be replaced with the use of MC _ENDPOINT_CHANGED interrupts on all + * connectable objects + */ +#include "../../../../base/base.h" #include "dpaa2-eth.h" #include "dpaa2-eth-ceetm.h" @@ -4059,6 +4065,40 @@ static int dpaa2_eth_poll_link_state(void *arg) return 0; } +static struct device_driver *dpaa2_eth_find_dpmac_driver(void) +{ + struct device_driver *drv = NULL; + struct klist_iter i; + + klist_iter_init_node(&fsl_mc_bus_type.p->klist_drivers, &i, NULL); + while ((drv = next_driver(&i))) { + if (strcmp(drv->name, "fsl_dpaa2_mac") == 0) + goto exit; + } + +exit: + klist_iter_exit(&i); + return drv; +} + +static void dpaa2_eth_dpmac_driver_attach(struct fsl_mc_device *dpmac_dev) +{ + struct device_driver *drv = dpaa2_eth_find_dpmac_driver(); + struct device *dev = &dpmac_dev->dev; + + if (dev && dev->driver == NULL && driver_match_device(drv, dev)) + device_driver_attach(drv, dev); +} + +static void dpaa2_eth_dpmac_driver_detach(struct fsl_mc_device *dpmac_dev) +{ + struct device_driver *drv = dpaa2_eth_find_dpmac_driver(); + struct device *dev = &dpmac_dev->dev; + + if (dev && dev->driver == drv) + device_driver_detach(dev); +} + static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) { struct fsl_mc_device *dpni_dev, *dpmac_dev; @@ -4073,6 +4113,8 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) if (dpaa2_mac_is_type_fixed(dpmac_dev, priv->mc_io)) return 0; + dpaa2_eth_dpmac_driver_detach(dpmac_dev); + mac = kzalloc(sizeof(struct dpaa2_mac), GFP_KERNEL); if (!mac) return -ENOMEM; @@ -4098,6 +4140,7 @@ static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv) return; dpaa2_mac_disconnect(priv->mac); + dpaa2_eth_dpmac_driver_attach(priv->mac->mc_dev); kfree(priv->mac); priv->mac = NULL; } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index 977776c94b4d..c50220eb0a56 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2019 NXP */ +#include +#include #include "dpaa2-eth.h" #include "dpaa2-mac.h" @@ -477,3 +479,270 @@ void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data) *(data + i) = value; } } + +struct dpaa2_mac_link_mode_map { + u64 dpmac_lm; + enum ethtool_link_mode_bit_indices ethtool_lm; +}; + +static const struct dpaa2_mac_link_mode_map dpaa2_mac_lm_map[] = { + {DPMAC_ADVERTISED_10BASET_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT}, + {DPMAC_ADVERTISED_100BASET_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT}, + {DPMAC_ADVERTISED_1000BASET_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT}, + {DPMAC_ADVERTISED_10000BASET_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT}, + {DPMAC_ADVERTISED_AUTONEG, ETHTOOL_LINK_MODE_Autoneg_BIT}, +}; + +static void dpaa2_mac_ksettings_change(struct dpaa2_mac *priv) +{ + struct fsl_mc_device *mc_dev = priv->mc_dev; + struct dpmac_link_cfg link_cfg = { 0 }; + int err, i; + + err = dpmac_get_link_cfg(priv->mc_io, 0, + mc_dev->mc_handle, + &link_cfg); + if (err) { + dev_err(&mc_dev->dev, "dpmac_get_link_cfg() = %d\n", err); + return; + } + + phylink_ethtool_ksettings_get(priv->phylink, &priv->kset); + + priv->kset.base.speed = link_cfg.rate; + priv->kset.base.duplex = !!(link_cfg.options & DPMAC_LINK_OPT_HALF_DUPLEX); + + ethtool_link_ksettings_zero_link_mode(&priv->kset, advertising); + for (i = 0; i < ARRAY_SIZE(dpaa2_mac_lm_map); i++) { + if (link_cfg.advertising & dpaa2_mac_lm_map[i].dpmac_lm) + __set_bit(dpaa2_mac_lm_map[i].ethtool_lm, + priv->kset.link_modes.advertising); + } + + if (link_cfg.options & DPMAC_LINK_OPT_AUTONEG) { + priv->kset.base.autoneg = AUTONEG_ENABLE; + __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + priv->kset.link_modes.advertising); + } else { + priv->kset.base.autoneg = AUTONEG_DISABLE; + __clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + priv->kset.link_modes.advertising); + } + + phylink_ethtool_ksettings_set(priv->phylink, &priv->kset); +} + +static irqreturn_t dpaa2_mac_irq_handler(int irq_num, void *arg) +{ + struct device *dev = (struct device *)arg; + struct fsl_mc_device *dpmac_dev; + struct net_device *net_dev; + struct dpaa2_mac *priv; + u32 status = ~0; + int err; + + dpmac_dev = to_fsl_mc_device(dev); + net_dev = dev_get_drvdata(dev); + priv = netdev_priv(net_dev); + + err = dpmac_get_irq_status(priv->mc_io, 0, dpmac_dev->mc_handle, + DPMAC_IRQ_INDEX, &status); + if (err) { + netdev_err(net_dev, "dpmac_get_irq_status() = %d\n", err); + return IRQ_HANDLED; + } + + rtnl_lock(); + if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) + dpaa2_mac_ksettings_change(priv); + + if (status & DPMAC_IRQ_EVENT_LINK_DOWN_REQ) + phylink_stop(priv->phylink); + + if (status & DPMAC_IRQ_EVENT_LINK_UP_REQ) + phylink_start(priv->phylink); + rtnl_unlock(); + + dpmac_clear_irq_status(priv->mc_io, 0, dpmac_dev->mc_handle, + DPMAC_IRQ_INDEX, status); + + return IRQ_HANDLED; +} + +static int dpaa2_mac_setup_irqs(struct fsl_mc_device *mc_dev) +{ + struct fsl_mc_device_irq *irq; + int err = 0; + + 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 | + DPMAC_IRQ_EVENT_LINK_UP_REQ | + DPMAC_IRQ_EVENT_LINK_DOWN_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 dpaa2_mac_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 int dpaa2_mac_probe(struct fsl_mc_device *mc_dev) +{ + struct device *dev = &mc_dev->dev; + struct fsl_mc_device *peer_dev; + struct net_device *net_dev; + struct dpaa2_mac *priv; + int err; + + /* If the DPMAC is connected to a DPNI from the currect DPRC, then + * there is no need for this standalone MAC driver, the dpaa2-eth will + * take care of anything related to MAC/PHY + */ + // TODO: this should extend to all DPSW / DPDMUX interfaces, not just DPNI + peer_dev = fsl_mc_get_endpoint(mc_dev); + if (!IS_ERR_OR_NULL(peer_dev) && peer_dev->dev.type == &fsl_mc_bus_dpni_type) + return -EPROBE_DEFER; + + net_dev = alloc_etherdev(sizeof(*priv)); + if (!net_dev) { + dev_err(dev, "alloc_etherdev error\n"); + return -ENOMEM; + } + + priv = netdev_priv(net_dev); + priv->mc_dev = mc_dev; + priv->net_dev = net_dev; + + SET_NETDEV_DEV(net_dev, dev); + + // TODO +#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS + snprintf(netdev->name, IFNAMSIZ, "mac%d", mc_dev->obj_desc.id); +#endif + + dev_set_drvdata(dev, net_dev); + + err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io); + if (err) { + if (err == -ENXIO) + err = -EPROBE_DEFER; + else + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); + goto free_netdev; + } + priv->mc_io = mc_dev->mc_io; + + 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 free_portal; + } + + /* If a DPMAC is TYPE_FIXED there is nothing we can do in Linux (all is + * taken care of in the MC firmware. Thus, probe the DPMAC but do + * nothing with it. + */ + if (dpaa2_mac_is_type_fixed(mc_dev, mc_dev->mc_io)) { + fsl_mc_portal_free(mc_dev->mc_io); + return 0; + } + + err = dpaa2_mac_setup_irqs(mc_dev); + if (err) { + err = -EFAULT; + goto free_portal; + } + + err = dpaa2_mac_connect(priv); + if (err) { + dev_err(dev, "Error connecting to the MAC endpoint\n"); + goto free_portal; + } + + return 0; + +free_portal: + fsl_mc_portal_free(mc_dev->mc_io); +free_netdev: + free_netdev(net_dev); + + return err; +} + +static int dpaa2_mac_remove(struct fsl_mc_device *mc_dev) +{ + struct device *dev = &mc_dev->dev; + struct net_device *net_dev = dev_get_drvdata(dev); + struct dpaa2_mac *priv = netdev_priv(net_dev); + + dpaa2_mac_teardown_irqs(mc_dev); + dpaa2_mac_disconnect(priv); + fsl_mc_portal_free(mc_dev->mc_io); + dev_set_drvdata(dev, NULL); + free_netdev(net_dev); + + 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_driver = { + .driver = { + .name = "fsl_dpaa2_mac", + .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_driver); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h index 955a52856210..af6b7ed31215 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -20,6 +20,7 @@ struct dpaa2_mac { struct phylink_config phylink_config; struct phylink *phylink; + struct ethtool_link_ksettings kset; phy_interface_t if_mode; enum dpmac_link_type if_link_type; struct lynx_pcs *pcs; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h index a24b20f76938..326b8b231f6e 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h @@ -20,10 +20,18 @@ #define DPMAC_CMDID_OPEN DPMAC_CMD(0x80c) #define DPMAC_CMDID_GET_ATTR DPMAC_CMD(0x004) + +#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_V2(0x0c2) #define DPMAC_CMDID_SET_LINK_STATE DPMAC_CMD_V2(0x0c3) #define DPMAC_CMDID_GET_COUNTER DPMAC_CMD(0x0c4) - /* Macros for accessing command fields smaller than 1byte */ #define DPMAC_MASK(field) \ GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \ @@ -70,4 +78,54 @@ struct dpmac_rsp_get_counter { __le64 counter; }; +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_link_cfg { + u64 options; + u32 rate; + u32 pad; + u64 advertising; +}; + #endif /* _FSL_DPMAC_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.c b/drivers/net/ethernet/freescale/dpaa2/dpmac.c index d5997b654562..7d6649ae81ed 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.c @@ -181,3 +181,273 @@ int dpmac_get_counter(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, return 0; } + +/** + * 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_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); + cfg->advertising = le64_to_cpu(rsp_params->advertising); + + return 0; +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.h b/drivers/net/ethernet/freescale/dpaa2/dpmac.h index 135f143097a5..6022d9108f1d 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.h @@ -118,6 +118,23 @@ int dpmac_get_attributes(struct fsl_mc_io *mc_io, */ #define DPMAC_ADVERTISED_AUTONEG BIT_ULL(3) +/** + * struct dpmac_link_cfg - Structure representing DPMAC link configuration + * @rate: Link's rate - in Mbps + * @options: Enable/Disable DPMAC link cfg features (bitmap) + * @advertising: Speeds that are advertised for autoneg (bitmap) + */ +struct dpmac_link_cfg { + u32 rate; + u64 options; + u64 advertising; +}; + +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 @@ -223,4 +240,62 @@ enum dpmac_counter_id { int dpmac_get_counter(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, enum dpmac_counter_id id, u64 *value); +/** + * 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 +/** + * IRQ event - Indicate if the phy needs to suspend or resume + */ +#define DPMAC_IRQ_EVENT_LINK_UP_REQ 0x00000004 +#define DPMAC_IRQ_EVENT_LINK_DOWN_REQ 0x00000008 + +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); + #endif /* __FSL_DPMAC_H */ -- 2.17.1