brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · 391a1bc Raw
564 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright Sunplus Technology Co., Ltd.3 *       All rights reserved.4 */5 6#include <linux/platform_device.h>7#include <linux/nvmem-consumer.h>8#include <linux/etherdevice.h>9#include <linux/netdevice.h>10#include <linux/spinlock.h>11#include <linux/of_net.h>12#include <linux/reset.h>13#include <linux/clk.h>14#include <linux/of.h>15 16#include "spl2sw_register.h"17#include "spl2sw_define.h"18#include "spl2sw_desc.h"19#include "spl2sw_mdio.h"20#include "spl2sw_phy.h"21#include "spl2sw_int.h"22#include "spl2sw_mac.h"23 24/* net device operations */25static int spl2sw_ethernet_open(struct net_device *ndev)26{27	struct spl2sw_mac *mac = netdev_priv(ndev);28	struct spl2sw_common *comm = mac->comm;29	u32 mask;30 31	netdev_dbg(ndev, "Open port = %x\n", mac->lan_port);32 33	comm->enable |= mac->lan_port;34 35	spl2sw_mac_hw_start(comm);36 37	/* Enable TX and RX interrupts */38	mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0);39	mask &= ~(MAC_INT_TX | MAC_INT_RX);40	writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0);41 42	phy_start(ndev->phydev);43 44	netif_start_queue(ndev);45 46	return 0;47}48 49static int spl2sw_ethernet_stop(struct net_device *ndev)50{51	struct spl2sw_mac *mac = netdev_priv(ndev);52	struct spl2sw_common *comm = mac->comm;53 54	netif_stop_queue(ndev);55 56	comm->enable &= ~mac->lan_port;57 58	phy_stop(ndev->phydev);59 60	spl2sw_mac_hw_stop(comm);61 62	return 0;63}64 65static netdev_tx_t spl2sw_ethernet_start_xmit(struct sk_buff *skb,66					      struct net_device *ndev)67{68	struct spl2sw_mac *mac = netdev_priv(ndev);69	struct spl2sw_common *comm = mac->comm;70	struct spl2sw_skb_info *skbinfo;71	struct spl2sw_mac_desc *txdesc;72	unsigned long flags;73	u32 mapping;74	u32 tx_pos;75	u32 cmd1;76	u32 cmd2;77 78	if (unlikely(comm->tx_desc_full == 1)) {79		/* No TX descriptors left. Wait for tx interrupt. */80		netdev_dbg(ndev, "TX descriptor queue full when xmit!\n");81		return NETDEV_TX_BUSY;82	}83 84	/* If skb size is shorter than ETH_ZLEN (60), pad it with 0. */85	if (unlikely(skb->len < ETH_ZLEN)) {86		if (skb_padto(skb, ETH_ZLEN))87			return NETDEV_TX_OK;88 89		skb_put(skb, ETH_ZLEN - skb->len);90	}91 92	mapping = dma_map_single(&comm->pdev->dev, skb->data,93				 skb->len, DMA_TO_DEVICE);94	if (dma_mapping_error(&comm->pdev->dev, mapping)) {95		ndev->stats.tx_errors++;96		dev_kfree_skb(skb);97		return NETDEV_TX_OK;98	}99 100	spin_lock_irqsave(&comm->tx_lock, flags);101 102	tx_pos = comm->tx_pos;103	txdesc = &comm->tx_desc[tx_pos];104	skbinfo = &comm->tx_temp_skb_info[tx_pos];105	skbinfo->mapping = mapping;106	skbinfo->len = skb->len;107	skbinfo->skb = skb;108 109	/* Set up a TX descriptor */110	cmd1 = TXD_OWN | TXD_SOP | TXD_EOP | (mac->to_vlan << 12) |111	       (skb->len & TXD_PKT_LEN);112	cmd2 = skb->len & TXD_BUF_LEN1;113 114	if (tx_pos == (TX_DESC_NUM - 1))115		cmd2 |= TXD_EOR;116 117	txdesc->addr1 = skbinfo->mapping;118	txdesc->cmd2 = cmd2;119	wmb();	/* Set TXD_OWN after other fields are effective. */120	txdesc->cmd1 = cmd1;121 122	/* Move tx_pos to next position */123	tx_pos = ((tx_pos + 1) == TX_DESC_NUM) ? 0 : tx_pos + 1;124 125	if (unlikely(tx_pos == comm->tx_done_pos)) {126		netif_stop_queue(ndev);127		comm->tx_desc_full = 1;128	}129	comm->tx_pos = tx_pos;130	wmb();		/* make sure settings are effective. */131 132	/* Trigger mac to transmit */133	writel(MAC_TRIG_L_SOC0, comm->l2sw_reg_base + L2SW_CPU_TX_TRIG);134 135	spin_unlock_irqrestore(&comm->tx_lock, flags);136	return NETDEV_TX_OK;137}138 139static void spl2sw_ethernet_set_rx_mode(struct net_device *ndev)140{141	struct spl2sw_mac *mac = netdev_priv(ndev);142 143	spl2sw_mac_rx_mode_set(mac);144}145 146static int spl2sw_ethernet_set_mac_address(struct net_device *ndev, void *addr)147{148	struct spl2sw_mac *mac = netdev_priv(ndev);149	int err;150 151	err = eth_mac_addr(ndev, addr);152	if (err)153		return err;154 155	/* Delete the old MAC address */156	netdev_dbg(ndev, "Old Ethernet (MAC) address = %pM\n", mac->mac_addr);157	if (is_valid_ether_addr(mac->mac_addr)) {158		err = spl2sw_mac_addr_del(mac);159		if (err)160			return err;161	}162 163	/* Set the MAC address */164	ether_addr_copy(mac->mac_addr, ndev->dev_addr);165	return spl2sw_mac_addr_add(mac);166}167 168static void spl2sw_ethernet_tx_timeout(struct net_device *ndev, unsigned int txqueue)169{170	struct spl2sw_mac *mac = netdev_priv(ndev);171	struct spl2sw_common *comm = mac->comm;172	unsigned long flags;173	int i;174 175	netdev_err(ndev, "TX timed out!\n");176	ndev->stats.tx_errors++;177 178	spin_lock_irqsave(&comm->tx_lock, flags);179 180	for (i = 0; i < MAX_NETDEV_NUM; i++)181		if (comm->ndev[i])182			netif_stop_queue(comm->ndev[i]);183 184	spl2sw_mac_soft_reset(comm);185 186	/* Accept TX packets again. */187	for (i = 0; i < MAX_NETDEV_NUM; i++)188		if (comm->ndev[i]) {189			netif_trans_update(comm->ndev[i]);190			netif_wake_queue(comm->ndev[i]);191		}192 193	spin_unlock_irqrestore(&comm->tx_lock, flags);194}195 196static const struct net_device_ops netdev_ops = {197	.ndo_open = spl2sw_ethernet_open,198	.ndo_stop = spl2sw_ethernet_stop,199	.ndo_start_xmit = spl2sw_ethernet_start_xmit,200	.ndo_set_rx_mode = spl2sw_ethernet_set_rx_mode,201	.ndo_set_mac_address = spl2sw_ethernet_set_mac_address,202	.ndo_do_ioctl = phy_do_ioctl,203	.ndo_tx_timeout = spl2sw_ethernet_tx_timeout,204};205 206static void spl2sw_check_mac_vendor_id_and_convert(u8 *mac_addr)207{208	/* Byte order of MAC address of some samples are reversed.209	 * Check vendor id and convert byte order if it is wrong.210	 * OUI of Sunplus: fc:4b:bc211	 */212	if (mac_addr[5] == 0xfc && mac_addr[4] == 0x4b && mac_addr[3] == 0xbc &&213	    (mac_addr[0] != 0xfc || mac_addr[1] != 0x4b || mac_addr[2] != 0xbc)) {214 215		swap(mac_addr[0], mac_addr[5]);216		swap(mac_addr[1], mac_addr[4]);217		swap(mac_addr[2], mac_addr[3]);218	}219}220 221static int spl2sw_nvmem_get_mac_address(struct device *dev, struct device_node *np,222					void *addrbuf)223{224	struct nvmem_cell *cell;225	ssize_t len;226	u8 *mac;227 228	/* Get nvmem cell of mac-address from dts. */229	cell = of_nvmem_cell_get(np, "mac-address");230	if (IS_ERR(cell))231		return PTR_ERR(cell);232 233	/* Read mac address from nvmem cell. */234	mac = nvmem_cell_read(cell, &len);235	nvmem_cell_put(cell);236	if (IS_ERR(mac))237		return PTR_ERR(mac);238 239	if (len != ETH_ALEN) {240		kfree(mac);241		dev_info(dev, "Invalid length of mac address in nvmem!\n");242		return -EINVAL;243	}244 245	/* Byte order of some samples are reversed.246	 * Convert byte order here.247	 */248	spl2sw_check_mac_vendor_id_and_convert(mac);249 250	/* Check if mac address is valid */251	if (!is_valid_ether_addr(mac)) {252		dev_info(dev, "Invalid mac address in nvmem (%pM)!\n", mac);253		kfree(mac);254		return -EINVAL;255	}256 257	ether_addr_copy(addrbuf, mac);258	kfree(mac);259	return 0;260}261 262static u32 spl2sw_init_netdev(struct platform_device *pdev, u8 *mac_addr,263			      struct net_device **r_ndev)264{265	struct net_device *ndev;266	struct spl2sw_mac *mac;267	int ret;268 269	/* Allocate the devices, and also allocate spl2sw_mac,270	 * we can get it by netdev_priv().271	 */272	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*mac));273	if (!ndev) {274		*r_ndev = NULL;275		return -ENOMEM;276	}277	SET_NETDEV_DEV(ndev, &pdev->dev);278	ndev->netdev_ops = &netdev_ops;279	mac = netdev_priv(ndev);280	mac->ndev = ndev;281	ether_addr_copy(mac->mac_addr, mac_addr);282 283	eth_hw_addr_set(ndev, mac_addr);284	dev_info(&pdev->dev, "Ethernet (MAC) address = %pM\n", mac_addr);285 286	ret = register_netdev(ndev);287	if (ret) {288		dev_err(&pdev->dev, "Failed to register net device \"%s\"!\n",289			ndev->name);290		*r_ndev = NULL;291		return ret;292	}293	netdev_dbg(ndev, "Registered net device \"%s\" successfully.\n", ndev->name);294 295	*r_ndev = ndev;296	return 0;297}298 299static struct device_node *spl2sw_get_eth_child_node(struct device_node *ether_np, int id)300{301	struct device_node *port_np;302	int port_id;303 304	for_each_child_of_node(ether_np, port_np) {305		/* It is not a 'port' node, continue. */306		if (strcmp(port_np->name, "port"))307			continue;308 309		if (of_property_read_u32(port_np, "reg", &port_id) < 0)310			continue;311 312		if (port_id == id)313			return port_np;314	}315 316	/* Not found! */317	return NULL;318}319 320static int spl2sw_probe(struct platform_device *pdev)321{322	struct device_node *eth_ports_np;323	struct device_node *port_np;324	struct spl2sw_common *comm;325	struct device_node *phy_np;326	phy_interface_t phy_mode;327	struct net_device *ndev;328	struct spl2sw_mac *mac;329	u8 mac_addr[ETH_ALEN];330	int irq, i, ret;331 332	if (platform_get_drvdata(pdev))333		return -ENODEV;334 335	/* Allocate memory for 'spl2sw_common' area. */336	comm = devm_kzalloc(&pdev->dev, sizeof(*comm), GFP_KERNEL);337	if (!comm)338		return -ENOMEM;339 340	comm->pdev = pdev;341	platform_set_drvdata(pdev, comm);342 343	spin_lock_init(&comm->tx_lock);344	spin_lock_init(&comm->mdio_lock);345	spin_lock_init(&comm->int_mask_lock);346 347	/* Get memory resource 0 from dts. */348	comm->l2sw_reg_base = devm_platform_ioremap_resource(pdev, 0);349	if (IS_ERR(comm->l2sw_reg_base))350		return PTR_ERR(comm->l2sw_reg_base);351 352	/* Get irq resource from dts. */353	ret = platform_get_irq(pdev, 0);354	if (ret < 0)355		return ret;356	irq = ret;357 358	/* Get clock controller. */359	comm->clk = devm_clk_get(&pdev->dev, NULL);360	if (IS_ERR(comm->clk)) {361		dev_err_probe(&pdev->dev, PTR_ERR(comm->clk),362			      "Failed to retrieve clock controller!\n");363		return PTR_ERR(comm->clk);364	}365 366	/* Get reset controller. */367	comm->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);368	if (IS_ERR(comm->rstc)) {369		dev_err_probe(&pdev->dev, PTR_ERR(comm->rstc),370			      "Failed to retrieve reset controller!\n");371		return PTR_ERR(comm->rstc);372	}373 374	/* Enable clock. */375	ret = clk_prepare_enable(comm->clk);376	if (ret)377		return ret;378	udelay(1);379 380	/* Reset MAC */381	reset_control_assert(comm->rstc);382	udelay(1);383	reset_control_deassert(comm->rstc);384	usleep_range(1000, 2000);385 386	/* Request irq. */387	ret = devm_request_irq(&pdev->dev, irq, spl2sw_ethernet_interrupt, 0,388			       dev_name(&pdev->dev), comm);389	if (ret) {390		dev_err(&pdev->dev, "Failed to request irq #%d!\n", irq);391		goto out_clk_disable;392	}393 394	/* Initialize TX and RX descriptors. */395	ret = spl2sw_descs_init(comm);396	if (ret) {397		dev_err(&pdev->dev, "Fail to initialize mac descriptors!\n");398		spl2sw_descs_free(comm);399		goto out_clk_disable;400	}401 402	/* Initialize MAC. */403	spl2sw_mac_init(comm);404 405	/* Initialize mdio bus */406	ret = spl2sw_mdio_init(comm);407	if (ret) {408		dev_err(&pdev->dev, "Failed to initialize mdio bus!\n");409		goto out_clk_disable;410	}411 412	/* Get child node ethernet-ports. */413	eth_ports_np = of_get_child_by_name(pdev->dev.of_node, "ethernet-ports");414	if (!eth_ports_np) {415		dev_err(&pdev->dev, "No ethernet-ports child node found!\n");416		ret = -ENODEV;417		goto out_free_mdio;418	}419 420	for (i = 0; i < MAX_NETDEV_NUM; i++) {421		/* Get port@i of node ethernet-ports. */422		port_np = spl2sw_get_eth_child_node(eth_ports_np, i);423		if (!port_np)424			continue;425 426		/* Get phy-mode. */427		if (of_get_phy_mode(port_np, &phy_mode)) {428			dev_err(&pdev->dev, "Failed to get phy-mode property of port@%d!\n",429				i);430			continue;431		}432 433		/* Get phy-handle. */434		phy_np = of_parse_phandle(port_np, "phy-handle", 0);435		if (!phy_np) {436			dev_err(&pdev->dev, "Failed to get phy-handle property of port@%d!\n",437				i);438			continue;439		}440 441		/* Get mac-address from nvmem. */442		ret = spl2sw_nvmem_get_mac_address(&pdev->dev, port_np, mac_addr);443		if (ret == -EPROBE_DEFER) {444			goto out_unregister_dev;445		} else if (ret) {446			dev_info(&pdev->dev, "Generate a random mac address!\n");447			eth_random_addr(mac_addr);448		}449 450		/* Initialize the net device. */451		ret = spl2sw_init_netdev(pdev, mac_addr, &ndev);452		if (ret)453			goto out_unregister_dev;454 455		ndev->irq = irq;456		comm->ndev[i] = ndev;457		mac = netdev_priv(ndev);458		mac->phy_node = phy_np;459		mac->phy_mode = phy_mode;460		mac->comm = comm;461 462		mac->lan_port = 0x1 << i;	/* forward to port i */463		mac->to_vlan = 0x1 << i;	/* vlan group: i     */464		mac->vlan_id = i;		/* vlan group: i     */465 466		/* Set MAC address */467		ret = spl2sw_mac_addr_add(mac);468		if (ret)469			goto out_unregister_dev;470 471		spl2sw_mac_rx_mode_set(mac);472	}473 474	/* Find first valid net device. */475	for (i = 0; i < MAX_NETDEV_NUM; i++) {476		if (comm->ndev[i])477			break;478	}479	if (i >= MAX_NETDEV_NUM) {480		dev_err(&pdev->dev, "No valid ethernet port!\n");481		ret = -ENODEV;482		goto out_free_mdio;483	}484 485	/* Save first valid net device */486	ndev = comm->ndev[i];487 488	ret = spl2sw_phy_connect(comm);489	if (ret) {490		netdev_err(ndev, "Failed to connect phy!\n");491		goto out_unregister_dev;492	}493 494	/* Add and enable napi. */495	netif_napi_add(ndev, &comm->rx_napi, spl2sw_rx_poll);496	napi_enable(&comm->rx_napi);497	netif_napi_add_tx(ndev, &comm->tx_napi, spl2sw_tx_poll);498	napi_enable(&comm->tx_napi);499	return 0;500 501out_unregister_dev:502	for (i = 0; i < MAX_NETDEV_NUM; i++)503		if (comm->ndev[i])504			unregister_netdev(comm->ndev[i]);505 506out_free_mdio:507	spl2sw_mdio_remove(comm);508 509out_clk_disable:510	clk_disable_unprepare(comm->clk);511	return ret;512}513 514static void spl2sw_remove(struct platform_device *pdev)515{516	struct spl2sw_common *comm;517	int i;518 519	comm = platform_get_drvdata(pdev);520 521	spl2sw_phy_remove(comm);522 523	/* Unregister and free net device. */524	for (i = 0; i < MAX_NETDEV_NUM; i++)525		if (comm->ndev[i])526			unregister_netdev(comm->ndev[i]);527 528	comm->enable = 0;529	spl2sw_mac_hw_stop(comm);530	spl2sw_descs_free(comm);531 532	/* Disable and delete napi. */533	napi_disable(&comm->rx_napi);534	netif_napi_del(&comm->rx_napi);535	napi_disable(&comm->tx_napi);536	netif_napi_del(&comm->tx_napi);537 538	spl2sw_mdio_remove(comm);539 540	clk_disable_unprepare(comm->clk);541}542 543static const struct of_device_id spl2sw_of_match[] = {544	{.compatible = "sunplus,sp7021-emac"},545	{ /* sentinel */ }546};547 548MODULE_DEVICE_TABLE(of, spl2sw_of_match);549 550static struct platform_driver spl2sw_driver = {551	.probe = spl2sw_probe,552	.remove_new = spl2sw_remove,553	.driver = {554		.name = "sp7021_emac",555		.of_match_table = spl2sw_of_match,556	},557};558 559module_platform_driver(spl2sw_driver);560 561MODULE_AUTHOR("Wells Lu <wellslutw@gmail.com>");562MODULE_DESCRIPTION("Sunplus Dual 10M/100M Ethernet driver");563MODULE_LICENSE("GPL");564