diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c')
-rw-r--r-- | drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c new file mode 100644 index 0000000..994d38c --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c @@ -0,0 +1,381 @@ +/* Copyright 2008-2013 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. + */ + +#ifdef CONFIG_FSL_DPAA_ETH_DEBUG +#define pr_fmt(fmt) \ + KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ + KBUILD_BASENAME".c", __LINE__, __func__ +#else +#define pr_fmt(fmt) \ + KBUILD_MODNAME ": " fmt +#endif + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include "dpaa_eth.h" +#include "dpaa_eth_common.h" +#include "dpaa_eth_base.h" +#include "lnxwrp_fsl_fman.h" /* fm_get_rx_extra_headroom(), fm_get_max_frm() */ +#include "mac.h" + +#define DPA_DESCRIPTION "FSL DPAA Proxy initialization driver" + +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_DESCRIPTION(DPA_DESCRIPTION); + +static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev); +#ifdef CONFIG_PM + +static int proxy_suspend(struct device *dev) +{ + struct proxy_device *proxy_dev = dev_get_drvdata(dev); + struct mac_device *mac_dev = proxy_dev->mac_dev; + int err = 0; + + err = fm_port_suspend(mac_dev->port_dev[RX]); + if (err) + goto port_suspend_failed; + + err = fm_port_suspend(mac_dev->port_dev[TX]); + if (err) + err = fm_port_resume(mac_dev->port_dev[RX]); + +port_suspend_failed: + return err; +} + +static int proxy_resume(struct device *dev) +{ + struct proxy_device *proxy_dev = dev_get_drvdata(dev); + struct mac_device *mac_dev = proxy_dev->mac_dev; + int err = 0; + + err = fm_port_resume(mac_dev->port_dev[TX]); + if (err) + goto port_resume_failed; + + err = fm_port_resume(mac_dev->port_dev[RX]); + if (err) + err = fm_port_suspend(mac_dev->port_dev[TX]); + +port_resume_failed: + return err; +} + +static const struct dev_pm_ops proxy_pm_ops = { + .suspend = proxy_suspend, + .resume = proxy_resume, +}; + +#define PROXY_PM_OPS (&proxy_pm_ops) + +#else /* CONFIG_PM */ + +#define PROXY_PM_OPS NULL + +#endif /* CONFIG_PM */ + +static int dpaa_eth_proxy_probe(struct platform_device *_of_dev) +{ + int err = 0, i; + struct device *dev; + struct device_node *dpa_node; + struct dpa_bp *dpa_bp; + struct list_head proxy_fq_list; + size_t count; + struct fm_port_fqs port_fqs; + struct dpa_buffer_layout_s *buf_layout = NULL; + struct mac_device *mac_dev; + struct proxy_device *proxy_dev; + + dev = &_of_dev->dev; + + dpa_node = dev->of_node; + + if (!of_device_is_available(dpa_node)) + return -ENODEV; + + /* Get the buffer pools assigned to this interface */ + dpa_bp = dpa_bp_probe(_of_dev, &count); + if (IS_ERR(dpa_bp)) + return PTR_ERR(dpa_bp); + + mac_dev = dpa_mac_probe(_of_dev); + if (IS_ERR(mac_dev)) + return PTR_ERR(mac_dev); + + proxy_dev = devm_kzalloc(dev, sizeof(*proxy_dev), GFP_KERNEL); + if (!proxy_dev) { + dev_err(dev, "devm_kzalloc() failed\n"); + return -ENOMEM; + } + + proxy_dev->mac_dev = mac_dev; + dev_set_drvdata(dev, proxy_dev); + + /* We have physical ports, so we need to establish + * the buffer layout. + */ + buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout), + GFP_KERNEL); + if (!buf_layout) { + dev_err(dev, "devm_kzalloc() failed\n"); + return -ENOMEM; + } + dpa_set_buffers_layout(mac_dev, buf_layout); + + INIT_LIST_HEAD(&proxy_fq_list); + + memset(&port_fqs, 0, sizeof(port_fqs)); + + err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, RX); + if (!err) + err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, + TX); + if (err < 0) { + devm_kfree(dev, buf_layout); + return err; + } + + /* Proxy initializer - Just configures the MAC on behalf of + * another partition. + */ + dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs, + buf_layout, dev); + + /* Proxy interfaces need to be started, and the allocated + * memory freed + */ + devm_kfree(dev, buf_layout); + devm_kfree(dev, dpa_bp); + + /* Free FQ structures */ + devm_kfree(dev, port_fqs.rx_defq); + devm_kfree(dev, port_fqs.rx_errq); + devm_kfree(dev, port_fqs.tx_defq); + devm_kfree(dev, port_fqs.tx_errq); + + for_each_port_device(i, mac_dev->port_dev) { + err = fm_port_enable(mac_dev->port_dev[i]); + if (err) + goto port_enable_fail; + } + + dev_info(dev, "probed MAC device with MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", + mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], + mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]); + + return 0; /* Proxy interface initialization ended */ + +port_enable_fail: + for_each_port_device(i, mac_dev->port_dev) + fm_port_disable(mac_dev->port_dev[i]); + dpa_eth_proxy_remove(_of_dev); + + return err; +} + +int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev, + struct net_device *net_dev) +{ + struct mac_device *mac_dev; + int _errno; + + mac_dev = proxy_dev->mac_dev; + + _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev), + net_dev->dev_addr); + if (_errno < 0) + return _errno; + + return 0; +} +EXPORT_SYMBOL(dpa_proxy_set_mac_address); + +int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev, + struct net_device *net_dev) +{ + struct mac_device *mac_dev = proxy_dev->mac_dev; + int _errno; + + if (!!(net_dev->flags & IFF_PROMISC) != mac_dev->promisc) { + mac_dev->promisc = !mac_dev->promisc; + _errno = mac_dev->set_promisc(mac_dev->get_mac_handle(mac_dev), + mac_dev->promisc); + if (unlikely(_errno < 0)) + netdev_err(net_dev, "mac_dev->set_promisc() = %d\n", + _errno); + } + + _errno = mac_dev->set_multi(net_dev, mac_dev); + if (unlikely(_errno < 0)) + return _errno; + + return 0; +} +EXPORT_SYMBOL(dpa_proxy_set_rx_mode); + +int dpa_proxy_start(struct net_device *net_dev) +{ + struct mac_device *mac_dev; + const struct dpa_priv_s *priv; + struct proxy_device *proxy_dev; + int _errno; + int i; + + priv = netdev_priv(net_dev); + proxy_dev = (struct proxy_device *)priv->peer; + mac_dev = proxy_dev->mac_dev; + + _errno = mac_dev->init_phy(net_dev, mac_dev); + if (_errno < 0) { + if (netif_msg_drv(priv)) + netdev_err(net_dev, "init_phy() = %d\n", + _errno); + return _errno; + } + + for_each_port_device(i, mac_dev->port_dev) { + _errno = fm_port_enable(mac_dev->port_dev[i]); + if (_errno) + goto port_enable_fail; + } + + _errno = mac_dev->start(mac_dev); + if (_errno < 0) { + if (netif_msg_drv(priv)) + netdev_err(net_dev, "mac_dev->start() = %d\n", + _errno); + goto port_enable_fail; + } + + return _errno; + +port_enable_fail: + for_each_port_device(i, mac_dev->port_dev) + fm_port_disable(mac_dev->port_dev[i]); + + return _errno; +} +EXPORT_SYMBOL(dpa_proxy_start); + +int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev) +{ + struct mac_device *mac_dev = proxy_dev->mac_dev; + const struct dpa_priv_s *priv = netdev_priv(net_dev); + int _errno, i, err; + + _errno = mac_dev->stop(mac_dev); + if (_errno < 0) { + if (netif_msg_drv(priv)) + netdev_err(net_dev, "mac_dev->stop() = %d\n", + _errno); + return _errno; + } + + for_each_port_device(i, mac_dev->port_dev) { + err = fm_port_disable(mac_dev->port_dev[i]); + _errno = err ? err : _errno; + } + + if (mac_dev->phy_dev) + phy_disconnect(mac_dev->phy_dev); + mac_dev->phy_dev = NULL; + + return _errno; +} +EXPORT_SYMBOL(dpa_proxy_stop); + +static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev) +{ + struct device *dev = &of_dev->dev; + struct proxy_device *proxy_dev = dev_get_drvdata(dev); + + kfree(proxy_dev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id dpa_proxy_match[] = { + { + .compatible = "fsl,dpa-ethernet-init" + }, + {} +}; +MODULE_DEVICE_TABLE(of, dpa_proxy_match); + +static struct platform_driver dpa_proxy_driver = { + .driver = { + .name = KBUILD_MODNAME "-proxy", + .of_match_table = dpa_proxy_match, + .owner = THIS_MODULE, + .pm = PROXY_PM_OPS, + }, + .probe = dpaa_eth_proxy_probe, + .remove = dpa_eth_proxy_remove +}; + +static int __init __cold dpa_proxy_load(void) +{ + int _errno; + + pr_info(DPA_DESCRIPTION "\n"); + + /* Initialize dpaa_eth mirror values */ + dpa_rx_extra_headroom = fm_get_rx_extra_headroom(); + dpa_max_frm = fm_get_max_frm(); + + _errno = platform_driver_register(&dpa_proxy_driver); + if (unlikely(_errno < 0)) { + pr_err(KBUILD_MODNAME + ": %s:%hu:%s(): platform_driver_register() = %d\n", + KBUILD_BASENAME".c", __LINE__, __func__, _errno); + } + + pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", + KBUILD_BASENAME".c", __func__); + + return _errno; +} +module_init(dpa_proxy_load); + +static void __exit __cold dpa_proxy_unload(void) +{ + platform_driver_unregister(&dpa_proxy_driver); + + pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", + KBUILD_BASENAME".c", __func__); +} +module_exit(dpa_proxy_unload); |