brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 11da139 Raw
386 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later2/*3 * Copyright 2008 - 2015 Freescale Semiconductor Inc.4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 8#include <linux/init.h>9#include <linux/module.h>10#include <linux/of_address.h>11#include <linux/of_platform.h>12#include <linux/of_net.h>13#include <linux/of_mdio.h>14#include <linux/device.h>15#include <linux/phy.h>16#include <linux/netdevice.h>17#include <linux/phy_fixed.h>18#include <linux/phylink.h>19#include <linux/etherdevice.h>20#include <linux/libfdt_env.h>21#include <linux/platform_device.h>22 23#include "mac.h"24#include "fman_mac.h"25#include "fman_dtsec.h"26#include "fman_tgec.h"27#include "fman_memac.h"28 29MODULE_LICENSE("Dual BSD/GPL");30MODULE_DESCRIPTION("FSL FMan MAC API based driver");31 32struct mac_priv_s {33	u8				cell_index;34	struct fman			*fman;35	/* List of multicast addresses */36	struct list_head		mc_addr_list;37	struct platform_device		*eth_dev;38	u16				speed;39};40 41struct mac_address {42	u8 addr[ETH_ALEN];43	struct list_head list;44};45 46static void mac_exception(struct mac_device *mac_dev,47			  enum fman_mac_exceptions ex)48{49	if (ex == FM_MAC_EX_10G_RX_FIFO_OVFL) {50		/* don't flag RX FIFO after the first */51		mac_dev->set_exception(mac_dev->fman_mac,52				       FM_MAC_EX_10G_RX_FIFO_OVFL, false);53		dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n", ex);54	}55 56	dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c",57		__func__, ex);58}59 60int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev)61{62	struct mac_priv_s	*priv;63	struct mac_address	*old_addr, *tmp;64	struct netdev_hw_addr	*ha;65	int			err;66	enet_addr_t		*addr;67 68	priv = mac_dev->priv;69 70	/* Clear previous address list */71	list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) {72		addr = (enet_addr_t *)old_addr->addr;73		err = mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr);74		if (err < 0)75			return err;76 77		list_del(&old_addr->list);78		kfree(old_addr);79	}80 81	/* Add all the addresses from the new list */82	netdev_for_each_mc_addr(ha, net_dev) {83		addr = (enet_addr_t *)ha->addr;84		err = mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr);85		if (err < 0)86			return err;87 88		tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);89		if (!tmp)90			return -ENOMEM;91 92		ether_addr_copy(tmp->addr, ha->addr);93		list_add(&tmp->list, &priv->mc_addr_list);94	}95	return 0;96}97 98static DEFINE_MUTEX(eth_lock);99 100static struct platform_device *dpaa_eth_add_device(int fman_id,101						   struct mac_device *mac_dev)102{103	struct platform_device *pdev;104	struct dpaa_eth_data data;105	struct mac_priv_s	*priv;106	static int dpaa_eth_dev_cnt;107	int ret;108 109	priv = mac_dev->priv;110 111	data.mac_dev = mac_dev;112	data.mac_hw_id = priv->cell_index;113	data.fman_hw_id = fman_id;114 115	mutex_lock(&eth_lock);116	pdev = platform_device_alloc("dpaa-ethernet", dpaa_eth_dev_cnt);117	if (!pdev) {118		ret = -ENOMEM;119		goto no_mem;120	}121 122	pdev->dev.parent = mac_dev->dev;123 124	ret = platform_device_add_data(pdev, &data, sizeof(data));125	if (ret)126		goto err;127 128	ret = platform_device_add(pdev);129	if (ret)130		goto err;131 132	dpaa_eth_dev_cnt++;133	mutex_unlock(&eth_lock);134 135	return pdev;136 137err:138	platform_device_put(pdev);139no_mem:140	mutex_unlock(&eth_lock);141 142	return ERR_PTR(ret);143}144 145static const struct of_device_id mac_match[] = {146	{ .compatible   = "fsl,fman-dtsec", .data = dtsec_initialization },147	{ .compatible   = "fsl,fman-xgec", .data = tgec_initialization },148	{ .compatible	= "fsl,fman-memac", .data = memac_initialization },149	{}150};151MODULE_DEVICE_TABLE(of, mac_match);152 153static int mac_probe(struct platform_device *_of_dev)154{155	int			 err, i, nph;156	int (*init)(struct mac_device *mac_dev, struct device_node *mac_node,157		    struct fman_mac_params *params);158	struct device		*dev;159	struct device_node	*mac_node, *dev_node;160	struct mac_device	*mac_dev;161	struct platform_device	*of_dev;162	struct mac_priv_s	*priv;163	struct fman_mac_params	 params;164	u32			 val;165	u8			fman_id;166	phy_interface_t          phy_if;167 168	dev = &_of_dev->dev;169	mac_node = dev->of_node;170	init = of_device_get_match_data(dev);171 172	mac_dev = devm_kzalloc(dev, sizeof(*mac_dev), GFP_KERNEL);173	if (!mac_dev)174		return -ENOMEM;175	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);176	if (!priv)177		return -ENOMEM;178	platform_set_drvdata(_of_dev, mac_dev);179 180	/* Save private information */181	mac_dev->priv = priv;182	mac_dev->dev = dev;183 184	INIT_LIST_HEAD(&priv->mc_addr_list);185 186	/* Get the FM node */187	dev_node = of_get_parent(mac_node);188	if (!dev_node) {189		dev_err(dev, "of_get_parent(%pOF) failed\n",190			mac_node);191		return -EINVAL;192	}193 194	of_dev = of_find_device_by_node(dev_node);195	if (!of_dev) {196		dev_err(dev, "of_find_device_by_node(%pOF) failed\n", dev_node);197		err = -EINVAL;198		goto _return_of_node_put;199	}200	mac_dev->fman_dev = &of_dev->dev;201 202	/* Get the FMan cell-index */203	err = of_property_read_u32(dev_node, "cell-index", &val);204	if (err) {205		dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);206		err = -EINVAL;207		goto _return_dev_put;208	}209	/* cell-index 0 => FMan id 1 */210	fman_id = (u8)(val + 1);211 212	priv->fman = fman_bind(mac_dev->fman_dev);213	if (!priv->fman) {214		dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);215		err = -ENODEV;216		goto _return_dev_put;217	}218 219	/* Two references have been taken in of_find_device_by_node()220	 * and fman_bind(). Release one of them here. The second one221	 * will be released in mac_remove().222	 */223	put_device(mac_dev->fman_dev);224	of_node_put(dev_node);225	dev_node = NULL;226 227	/* Get the address of the memory mapped registers */228	mac_dev->res = platform_get_mem_or_io(_of_dev, 0);229	if (!mac_dev->res) {230		dev_err(dev, "could not get registers\n");231		err = -EINVAL;232		goto _return_dev_put;233	}234 235	err = devm_request_resource(dev, fman_get_mem_region(priv->fman),236				    mac_dev->res);237	if (err) {238		dev_err_probe(dev, err, "could not request resource\n");239		goto _return_dev_put;240	}241 242	mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,243				      resource_size(mac_dev->res));244	if (!mac_dev->vaddr) {245		dev_err(dev, "devm_ioremap() failed\n");246		err = -EIO;247		goto _return_dev_put;248	}249 250	if (!of_device_is_available(mac_node)) {251		err = -ENODEV;252		goto _return_dev_put;253	}254 255	/* Get the cell-index */256	err = of_property_read_u32(mac_node, "cell-index", &val);257	if (err) {258		dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);259		err = -EINVAL;260		goto _return_dev_put;261	}262	priv->cell_index = (u8)val;263 264	/* Get the MAC address */265	err = of_get_mac_address(mac_node, mac_dev->addr);266	if (err)267		dev_warn(dev, "of_get_mac_address(%pOF) failed\n", mac_node);268 269	/* Get the port handles */270	nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);271	if (unlikely(nph < 0)) {272		dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",273			mac_node);274		err = nph;275		goto _return_dev_put;276	}277 278	if (nph != ARRAY_SIZE(mac_dev->port)) {279		dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",280			mac_node);281		err = -EINVAL;282		goto _return_dev_put;283	}284 285	/* PORT_NUM determines the size of the port array */286	for (i = 0; i < PORT_NUM; i++) {287		/* Find the port node */288		dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);289		if (!dev_node) {290			dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",291				mac_node);292			err = -EINVAL;293			goto _return_dev_arr_put;294		}295 296		of_dev = of_find_device_by_node(dev_node);297		if (!of_dev) {298			dev_err(dev, "of_find_device_by_node(%pOF) failed\n",299				dev_node);300			err = -EINVAL;301			goto _return_dev_arr_put;302		}303		mac_dev->fman_port_devs[i] = &of_dev->dev;304 305		mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);306		if (!mac_dev->port[i]) {307			dev_err(dev, "dev_get_drvdata(%pOF) failed\n",308				dev_node);309			err = -EINVAL;310			goto _return_dev_arr_put;311		}312		/* Two references have been taken in of_find_device_by_node()313		 * and fman_port_bind(). Release one of them here. The second314		 * one will be released in mac_remove().315		 */316		put_device(mac_dev->fman_port_devs[i]);317		of_node_put(dev_node);318		dev_node = NULL;319	}320 321	/* Get the PHY connection type */322	err = of_get_phy_mode(mac_node, &phy_if);323	if (err) {324		dev_warn(dev,325			 "of_get_phy_mode() for %pOF failed. Defaulting to SGMII\n",326			 mac_node);327		phy_if = PHY_INTERFACE_MODE_SGMII;328	}329	mac_dev->phy_if = phy_if;330 331	params.mac_id		= priv->cell_index;332	params.fm		= (void *)priv->fman;333	params.exception_cb	= mac_exception;334	params.event_cb		= mac_exception;335 336	err = init(mac_dev, mac_node, &params);337	if (err < 0)338		goto _return_dev_arr_put;339 340	if (!is_zero_ether_addr(mac_dev->addr))341		dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);342 343	priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);344	if (IS_ERR(priv->eth_dev)) {345		err = PTR_ERR(priv->eth_dev);346		dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",347			priv->cell_index);348		priv->eth_dev = NULL;349	}350 351	return err;352 353_return_dev_arr_put:354	/* mac_dev is kzalloc'ed */355	for (i = 0; i < PORT_NUM; i++)356		put_device(mac_dev->fman_port_devs[i]);357_return_dev_put:358	put_device(mac_dev->fman_dev);359_return_of_node_put:360	of_node_put(dev_node);361	return err;362}363 364static void mac_remove(struct platform_device *pdev)365{366	struct mac_device *mac_dev = platform_get_drvdata(pdev);367	int		   i;368 369	for (i = 0; i < PORT_NUM; i++)370		put_device(mac_dev->fman_port_devs[i]);371	put_device(mac_dev->fman_dev);372 373	platform_device_unregister(mac_dev->priv->eth_dev);374}375 376static struct platform_driver mac_driver = {377	.driver = {378		.name		= KBUILD_MODNAME,379		.of_match_table	= mac_match,380	},381	.probe		= mac_probe,382	.remove_new	= mac_remove,383};384 385builtin_platform_driver(mac_driver);386