brintos

brintos / linux-shallow public Read only

0
0
Text · 32.7 KiB · fdebeb2 Raw
1297 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Texas Instruments ICSSG Ethernet Driver4 *5 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/6 * Copyright (C) Siemens AG, 20247 *8 */9 10#include <linux/dma-mapping.h>11#include <linux/dma/ti-cppi5.h>12#include <linux/etherdevice.h>13#include <linux/interrupt.h>14#include <linux/kernel.h>15#include <linux/of.h>16#include <linux/of_mdio.h>17#include <linux/phy.h>18#include <linux/remoteproc/pruss.h>19#include <linux/regmap.h>20#include <linux/remoteproc.h>21 22#include "icssg_prueth.h"23#include "../k3-cppi-desc-pool.h"24 25/* Netif debug messages possible */26#define PRUETH_EMAC_DEBUG       (NETIF_MSG_DRV | \27				 NETIF_MSG_PROBE | \28				 NETIF_MSG_LINK | \29				 NETIF_MSG_TIMER | \30				 NETIF_MSG_IFDOWN | \31				 NETIF_MSG_IFUP | \32				 NETIF_MSG_RX_ERR | \33				 NETIF_MSG_TX_ERR | \34				 NETIF_MSG_TX_QUEUED | \35				 NETIF_MSG_INTR | \36				 NETIF_MSG_TX_DONE | \37				 NETIF_MSG_RX_STATUS | \38				 NETIF_MSG_PKTDATA | \39				 NETIF_MSG_HW | \40				 NETIF_MSG_WOL)41 42#define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)43 44void prueth_cleanup_rx_chns(struct prueth_emac *emac,45			    struct prueth_rx_chn *rx_chn,46			    int max_rflows)47{48	if (rx_chn->desc_pool)49		k3_cppi_desc_pool_destroy(rx_chn->desc_pool);50 51	if (rx_chn->rx_chn)52		k3_udma_glue_release_rx_chn(rx_chn->rx_chn);53}54EXPORT_SYMBOL_GPL(prueth_cleanup_rx_chns);55 56void prueth_cleanup_tx_chns(struct prueth_emac *emac)57{58	int i;59 60	for (i = 0; i < emac->tx_ch_num; i++) {61		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];62 63		if (tx_chn->desc_pool)64			k3_cppi_desc_pool_destroy(tx_chn->desc_pool);65 66		if (tx_chn->tx_chn)67			k3_udma_glue_release_tx_chn(tx_chn->tx_chn);68 69		/* Assume prueth_cleanup_tx_chns() is called at the70		 * end after all channel resources are freed71		 */72		memset(tx_chn, 0, sizeof(*tx_chn));73	}74}75EXPORT_SYMBOL_GPL(prueth_cleanup_tx_chns);76 77void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num)78{79	int i;80 81	for (i = 0; i < num; i++) {82		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];83 84		if (tx_chn->irq)85			free_irq(tx_chn->irq, tx_chn);86		netif_napi_del(&tx_chn->napi_tx);87	}88}89EXPORT_SYMBOL_GPL(prueth_ndev_del_tx_napi);90 91void prueth_xmit_free(struct prueth_tx_chn *tx_chn,92		      struct cppi5_host_desc_t *desc)93{94	struct cppi5_host_desc_t *first_desc, *next_desc;95	dma_addr_t buf_dma, next_desc_dma;96	u32 buf_dma_len;97 98	first_desc = desc;99	next_desc = first_desc;100 101	cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);102	k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);103 104	dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len,105			 DMA_TO_DEVICE);106 107	next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);108	k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);109	while (next_desc_dma) {110		next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,111						       next_desc_dma);112		cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);113		k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);114 115		dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,116			       DMA_TO_DEVICE);117 118		next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);119		k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);120 121		k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);122	}123 124	k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);125}126EXPORT_SYMBOL_GPL(prueth_xmit_free);127 128int emac_tx_complete_packets(struct prueth_emac *emac, int chn,129			     int budget, bool *tdown)130{131	struct net_device *ndev = emac->ndev;132	struct cppi5_host_desc_t *desc_tx;133	struct netdev_queue *netif_txq;134	struct prueth_tx_chn *tx_chn;135	unsigned int total_bytes = 0;136	struct sk_buff *skb;137	dma_addr_t desc_dma;138	int res, num_tx = 0;139	void **swdata;140 141	tx_chn = &emac->tx_chns[chn];142 143	while (true) {144		res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);145		if (res == -ENODATA)146			break;147 148		/* teardown completion */149		if (cppi5_desc_is_tdcm(desc_dma)) {150			if (atomic_dec_and_test(&emac->tdown_cnt))151				complete(&emac->tdown_complete);152			*tdown = true;153			break;154		}155 156		desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,157						     desc_dma);158		swdata = cppi5_hdesc_get_swdata(desc_tx);159 160		/* was this command's TX complete? */161		if (emac->is_sr1 && *(swdata) == emac->cmd_data) {162			prueth_xmit_free(tx_chn, desc_tx);163			continue;164		}165 166		skb = *(swdata);167		prueth_xmit_free(tx_chn, desc_tx);168 169		ndev = skb->dev;170		ndev->stats.tx_packets++;171		ndev->stats.tx_bytes += skb->len;172		total_bytes += skb->len;173		napi_consume_skb(skb, budget);174		num_tx++;175	}176 177	if (!num_tx)178		return 0;179 180	netif_txq = netdev_get_tx_queue(ndev, chn);181	netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);182 183	if (netif_tx_queue_stopped(netif_txq)) {184		/* If the TX queue was stopped, wake it now185		 * if we have enough room.186		 */187		__netif_tx_lock(netif_txq, smp_processor_id());188		if (netif_running(ndev) &&189		    (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=190		     MAX_SKB_FRAGS))191			netif_tx_wake_queue(netif_txq);192		__netif_tx_unlock(netif_txq);193	}194 195	return num_tx;196}197 198static enum hrtimer_restart emac_tx_timer_callback(struct hrtimer *timer)199{200	struct prueth_tx_chn *tx_chns =201			container_of(timer, struct prueth_tx_chn, tx_hrtimer);202 203	enable_irq(tx_chns->irq);204	return HRTIMER_NORESTART;205}206 207static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget)208{209	struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx);210	struct prueth_emac *emac = tx_chn->emac;211	bool tdown = false;212	int num_tx_packets;213 214	num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget,215						  &tdown);216 217	if (num_tx_packets >= budget)218		return budget;219 220	if (napi_complete_done(napi_tx, num_tx_packets)) {221		if (unlikely(tx_chn->tx_pace_timeout_ns && !tdown)) {222			hrtimer_start(&tx_chn->tx_hrtimer,223				      ns_to_ktime(tx_chn->tx_pace_timeout_ns),224				      HRTIMER_MODE_REL_PINNED);225		} else {226			enable_irq(tx_chn->irq);227		}228	}229 230	return num_tx_packets;231}232 233static irqreturn_t prueth_tx_irq(int irq, void *dev_id)234{235	struct prueth_tx_chn *tx_chn = dev_id;236 237	disable_irq_nosync(irq);238	napi_schedule(&tx_chn->napi_tx);239 240	return IRQ_HANDLED;241}242 243int prueth_ndev_add_tx_napi(struct prueth_emac *emac)244{245	struct prueth *prueth = emac->prueth;246	int i, ret;247 248	for (i = 0; i < emac->tx_ch_num; i++) {249		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];250 251		netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll);252		hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC,253			     HRTIMER_MODE_REL_PINNED);254		tx_chn->tx_hrtimer.function = &emac_tx_timer_callback;255		ret = request_irq(tx_chn->irq, prueth_tx_irq,256				  IRQF_TRIGGER_HIGH, tx_chn->name,257				  tx_chn);258		if (ret) {259			netif_napi_del(&tx_chn->napi_tx);260			dev_err(prueth->dev, "unable to request TX IRQ %d\n",261				tx_chn->irq);262			goto fail;263		}264	}265 266	return 0;267fail:268	prueth_ndev_del_tx_napi(emac, i);269	return ret;270}271EXPORT_SYMBOL_GPL(prueth_ndev_add_tx_napi);272 273int prueth_init_tx_chns(struct prueth_emac *emac)274{275	static const struct k3_ring_cfg ring_cfg = {276		.elm_size = K3_RINGACC_RING_ELSIZE_8,277		.mode = K3_RINGACC_RING_MODE_RING,278		.flags = 0,279		.size = PRUETH_MAX_TX_DESC,280	};281	struct k3_udma_glue_tx_channel_cfg tx_cfg;282	struct device *dev = emac->prueth->dev;283	struct net_device *ndev = emac->ndev;284	int ret, slice, i;285	u32 hdesc_size;286 287	slice = prueth_emac_slice(emac);288	if (slice < 0)289		return slice;290 291	init_completion(&emac->tdown_complete);292 293	hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,294					   PRUETH_NAV_SW_DATA_SIZE);295	memset(&tx_cfg, 0, sizeof(tx_cfg));296	tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;297	tx_cfg.tx_cfg = ring_cfg;298	tx_cfg.txcq_cfg = ring_cfg;299 300	for (i = 0; i < emac->tx_ch_num; i++) {301		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];302 303		/* To differentiate channels for SLICE0 vs SLICE1 */304		snprintf(tx_chn->name, sizeof(tx_chn->name),305			 "tx%d-%d", slice, i);306 307		tx_chn->emac = emac;308		tx_chn->id = i;309		tx_chn->descs_num = PRUETH_MAX_TX_DESC;310 311		tx_chn->tx_chn =312			k3_udma_glue_request_tx_chn(dev, tx_chn->name,313						    &tx_cfg);314		if (IS_ERR(tx_chn->tx_chn)) {315			ret = PTR_ERR(tx_chn->tx_chn);316			tx_chn->tx_chn = NULL;317			netdev_err(ndev,318				   "Failed to request tx dma ch: %d\n", ret);319			goto fail;320		}321 322		tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn);323		tx_chn->desc_pool =324			k3_cppi_desc_pool_create_name(tx_chn->dma_dev,325						      tx_chn->descs_num,326						      hdesc_size,327						      tx_chn->name);328		if (IS_ERR(tx_chn->desc_pool)) {329			ret = PTR_ERR(tx_chn->desc_pool);330			tx_chn->desc_pool = NULL;331			netdev_err(ndev, "Failed to create tx pool: %d\n", ret);332			goto fail;333		}334 335		ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);336		if (ret < 0) {337			netdev_err(ndev, "failed to get tx irq\n");338			goto fail;339		}340		tx_chn->irq = ret;341 342		snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d",343			 dev_name(dev), tx_chn->id);344	}345 346	return 0;347 348fail:349	prueth_cleanup_tx_chns(emac);350	return ret;351}352EXPORT_SYMBOL_GPL(prueth_init_tx_chns);353 354int prueth_init_rx_chns(struct prueth_emac *emac,355			struct prueth_rx_chn *rx_chn,356			char *name, u32 max_rflows,357			u32 max_desc_num)358{359	struct k3_udma_glue_rx_channel_cfg rx_cfg;360	struct device *dev = emac->prueth->dev;361	struct net_device *ndev = emac->ndev;362	u32 fdqring_id, hdesc_size;363	int i, ret = 0, slice;364	int flow_id_base;365 366	slice = prueth_emac_slice(emac);367	if (slice < 0)368		return slice;369 370	/* To differentiate channels for SLICE0 vs SLICE1 */371	snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice);372 373	hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,374					   PRUETH_NAV_SW_DATA_SIZE);375	memset(&rx_cfg, 0, sizeof(rx_cfg));376	rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;377	rx_cfg.flow_id_num = max_rflows;378	rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */379 380	/* init all flows */381	rx_chn->dev = dev;382	rx_chn->descs_num = max_desc_num;383 384	rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name,385						     &rx_cfg);386	if (IS_ERR(rx_chn->rx_chn)) {387		ret = PTR_ERR(rx_chn->rx_chn);388		rx_chn->rx_chn = NULL;389		netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret);390		goto fail;391	}392 393	rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn);394	rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev,395							  rx_chn->descs_num,396							  hdesc_size,397							  rx_chn->name);398	if (IS_ERR(rx_chn->desc_pool)) {399		ret = PTR_ERR(rx_chn->desc_pool);400		rx_chn->desc_pool = NULL;401		netdev_err(ndev, "Failed to create rx pool: %d\n", ret);402		goto fail;403	}404 405	flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn);406	if (emac->is_sr1 && !strcmp(name, "rxmgm")) {407		emac->rx_mgm_flow_id_base = flow_id_base;408		netdev_dbg(ndev, "mgm flow id base = %d\n", flow_id_base);409	} else {410		emac->rx_flow_id_base = flow_id_base;411		netdev_dbg(ndev, "flow id base = %d\n", flow_id_base);412	}413 414	fdqring_id = K3_RINGACC_RING_ID_ANY;415	for (i = 0; i < rx_cfg.flow_id_num; i++) {416		struct k3_ring_cfg rxring_cfg = {417			.elm_size = K3_RINGACC_RING_ELSIZE_8,418			.mode = K3_RINGACC_RING_MODE_RING,419			.flags = 0,420		};421		struct k3_ring_cfg fdqring_cfg = {422			.elm_size = K3_RINGACC_RING_ELSIZE_8,423			.flags = K3_RINGACC_RING_SHARED,424		};425		struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = {426			.rx_cfg = rxring_cfg,427			.rxfdq_cfg = fdqring_cfg,428			.ring_rxq_id = K3_RINGACC_RING_ID_ANY,429			.src_tag_lo_sel =430				K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG,431		};432 433		rx_flow_cfg.ring_rxfdq0_id = fdqring_id;434		rx_flow_cfg.rx_cfg.size = max_desc_num;435		rx_flow_cfg.rxfdq_cfg.size = max_desc_num;436		rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode;437 438		ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,439						i, &rx_flow_cfg);440		if (ret) {441			netdev_err(ndev, "Failed to init rx flow%d %d\n",442				   i, ret);443			goto fail;444		}445		if (!i)446			fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn,447								     i);448		ret = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i);449		if (ret < 0) {450			netdev_err(ndev, "Failed to get rx dma irq");451			goto fail;452		}453		rx_chn->irq[i] = ret;454	}455 456	return 0;457 458fail:459	prueth_cleanup_rx_chns(emac, rx_chn, max_rflows);460	return ret;461}462EXPORT_SYMBOL_GPL(prueth_init_rx_chns);463 464int prueth_dma_rx_push(struct prueth_emac *emac,465		       struct sk_buff *skb,466		       struct prueth_rx_chn *rx_chn)467{468	struct net_device *ndev = emac->ndev;469	struct cppi5_host_desc_t *desc_rx;470	u32 pkt_len = skb_tailroom(skb);471	dma_addr_t desc_dma;472	dma_addr_t buf_dma;473	void **swdata;474 475	desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool);476	if (!desc_rx) {477		netdev_err(ndev, "rx push: failed to allocate descriptor\n");478		return -ENOMEM;479	}480	desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx);481 482	buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE);483	if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) {484		k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);485		netdev_err(ndev, "rx push: failed to map rx pkt buffer\n");486		return -EINVAL;487	}488 489	cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT,490			 PRUETH_NAV_PS_DATA_SIZE);491	k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma);492	cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb));493 494	swdata = cppi5_hdesc_get_swdata(desc_rx);495	*swdata = skb;496 497	return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0,498					desc_rx, desc_dma);499}500EXPORT_SYMBOL_GPL(prueth_dma_rx_push);501 502u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns)503{504	u32 iepcount_lo, iepcount_hi, hi_rollover_count;505	u64 ns;506 507	iepcount_lo = lo & GENMASK(19, 0);508	iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20;509	hi_rollover_count = hi >> 11;510 511	ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw);512	ns = ns * cycle_time_ns + iepcount_lo;513 514	return ns;515}516EXPORT_SYMBOL_GPL(icssg_ts_to_ns);517 518void emac_rx_timestamp(struct prueth_emac *emac,519		       struct sk_buff *skb, u32 *psdata)520{521	struct skb_shared_hwtstamps *ssh;522	u64 ns;523 524	if (emac->is_sr1) {525		ns = (u64)psdata[1] << 32 | psdata[0];526	} else {527		u32 hi_sw = readl(emac->prueth->shram.va +528				  TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);529		ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0],530				    IEP_DEFAULT_CYCLE_TIME_NS);531	}532 533	ssh = skb_hwtstamps(skb);534	memset(ssh, 0, sizeof(*ssh));535	ssh->hwtstamp = ns_to_ktime(ns);536}537 538static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)539{540	struct prueth_rx_chn *rx_chn = &emac->rx_chns;541	u32 buf_dma_len, pkt_len, port_id = 0;542	struct net_device *ndev = emac->ndev;543	struct cppi5_host_desc_t *desc_rx;544	struct sk_buff *skb, *new_skb;545	dma_addr_t desc_dma, buf_dma;546	void **swdata;547	u32 *psdata;548	int ret;549 550	ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma);551	if (ret) {552		if (ret != -ENODATA)553			netdev_err(ndev, "rx pop: failed: %d\n", ret);554		return ret;555	}556 557	if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */558		return 0;559 560	desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);561 562	swdata = cppi5_hdesc_get_swdata(desc_rx);563	skb = *swdata;564 565	psdata = cppi5_hdesc_get_psdata(desc_rx);566	/* RX HW timestamp */567	if (emac->rx_ts_enabled)568		emac_rx_timestamp(emac, skb, psdata);569 570	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);571	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);572	pkt_len = cppi5_hdesc_get_pktlen(desc_rx);573	/* firmware adds 4 CRC bytes, strip them */574	pkt_len -= 4;575	cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);576 577	dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);578	k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);579 580	skb->dev = ndev;581	new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE);582	/* if allocation fails we drop the packet but push the583	 * descriptor back to the ring with old skb to prevent a stall584	 */585	if (!new_skb) {586		ndev->stats.rx_dropped++;587		new_skb = skb;588	} else {589		/* send the filled skb up the n/w stack */590		skb_put(skb, pkt_len);591		if (emac->prueth->is_switch_mode)592			skb->offload_fwd_mark = emac->offload_fwd_mark;593		skb->protocol = eth_type_trans(skb, ndev);594		napi_gro_receive(&emac->napi_rx, skb);595		ndev->stats.rx_bytes += pkt_len;596		ndev->stats.rx_packets++;597	}598 599	/* queue another RX DMA */600	ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns);601	if (WARN_ON(ret < 0)) {602		dev_kfree_skb_any(new_skb);603		ndev->stats.rx_errors++;604		ndev->stats.rx_dropped++;605	}606 607	return ret;608}609 610static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma)611{612	struct prueth_rx_chn *rx_chn = data;613	struct cppi5_host_desc_t *desc_rx;614	struct sk_buff *skb;615	dma_addr_t buf_dma;616	u32 buf_dma_len;617	void **swdata;618 619	desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);620	swdata = cppi5_hdesc_get_swdata(desc_rx);621	skb = *swdata;622	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);623	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);624 625	dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len,626			 DMA_FROM_DEVICE);627	k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);628 629	dev_kfree_skb_any(skb);630}631 632static int prueth_tx_ts_cookie_get(struct prueth_emac *emac)633{634	int i;635 636	/* search and get the next free slot */637	for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {638		if (!emac->tx_ts_skb[i]) {639			emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */640			return i;641		}642	}643 644	return -EBUSY;645}646 647/**648 * icssg_ndo_start_xmit - EMAC Transmit function649 * @skb: SKB pointer650 * @ndev: EMAC network adapter651 *652 * Called by the system to transmit a packet  - we queue the packet in653 * EMAC hardware transmit queue654 * Doesn't wait for completion we'll check for TX completion in655 * emac_tx_complete_packets().656 *657 * Return: enum netdev_tx658 */659enum netdev_tx icssg_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)660{661	struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc;662	struct prueth_emac *emac = netdev_priv(ndev);663	struct prueth *prueth = emac->prueth;664	struct netdev_queue *netif_txq;665	struct prueth_tx_chn *tx_chn;666	dma_addr_t desc_dma, buf_dma;667	u32 pkt_len, dst_tag_id;668	int i, ret = 0, q_idx;669	bool in_tx_ts = 0;670	int tx_ts_cookie;671	void **swdata;672	u32 *epib;673 674	pkt_len = skb_headlen(skb);675	q_idx = skb_get_queue_mapping(skb);676 677	tx_chn = &emac->tx_chns[q_idx];678	netif_txq = netdev_get_tx_queue(ndev, q_idx);679 680	/* Map the linear buffer */681	buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE);682	if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {683		netdev_err(ndev, "tx: failed to map skb buffer\n");684		ret = NETDEV_TX_OK;685		goto drop_free_skb;686	}687 688	first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);689	if (!first_desc) {690		netdev_dbg(ndev, "tx: failed to allocate descriptor\n");691		dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE);692		goto drop_stop_q_busy;693	}694 695	cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT,696			 PRUETH_NAV_PS_DATA_SIZE);697	cppi5_hdesc_set_pkttype(first_desc, 0);698	epib = first_desc->epib;699	epib[0] = 0;700	epib[1] = 0;701	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&702	    emac->tx_ts_enabled) {703		tx_ts_cookie = prueth_tx_ts_cookie_get(emac);704		if (tx_ts_cookie >= 0) {705			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;706			/* Request TX timestamp */707			epib[0] = (u32)tx_ts_cookie;708			epib[1] = 0x80000000;	/* TX TS request */709			emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb);710			in_tx_ts = 1;711		}712	}713 714	/* set dst tag to indicate internal qid at the firmware which is at715	 * bit8..bit15. bit0..bit7 indicates port num for directed716	 * packets in case of switch mode operation and port num 0717	 * for undirected packets in case of HSR offload mode718	 */719	dst_tag_id = emac->port_id | (q_idx << 8);720 721	if (prueth->is_hsr_offload_mode &&722	    (ndev->features & NETIF_F_HW_HSR_DUP))723		dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG;724 725	if (prueth->is_hsr_offload_mode &&726	    (ndev->features & NETIF_F_HW_HSR_TAG_INS))727		epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS;728 729	cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id);730	k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);731	cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len);732	swdata = cppi5_hdesc_get_swdata(first_desc);733	*swdata = skb;734 735	/* Handle the case where skb is fragmented in pages */736	cur_desc = first_desc;737	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {738		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];739		u32 frag_size = skb_frag_size(frag);740 741		next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);742		if (!next_desc) {743			netdev_err(ndev,744				   "tx: failed to allocate frag. descriptor\n");745			goto free_desc_stop_q_busy_cleanup_tx_ts;746		}747 748		buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size,749					   DMA_TO_DEVICE);750		if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {751			netdev_err(ndev, "tx: Failed to map skb page\n");752			k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);753			ret = NETDEV_TX_OK;754			goto cleanup_tx_ts;755		}756 757		cppi5_hdesc_reset_hbdesc(next_desc);758		k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);759		cppi5_hdesc_attach_buf(next_desc,760				       buf_dma, frag_size, buf_dma, frag_size);761 762		desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool,763						      next_desc);764		k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma);765		cppi5_hdesc_link_hbdesc(cur_desc, desc_dma);766 767		pkt_len += frag_size;768		cur_desc = next_desc;769	}770	WARN_ON_ONCE(pkt_len != skb->len);771 772	/* report bql before sending packet */773	netdev_tx_sent_queue(netif_txq, pkt_len);774 775	cppi5_hdesc_set_pktlen(first_desc, pkt_len);776	desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc);777	/* cppi5_desc_dump(first_desc, 64); */778 779	skb_tx_timestamp(skb);  /* SW timestamp if SKBTX_IN_PROGRESS not set */780	ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);781	if (ret) {782		netdev_err(ndev, "tx: push failed: %d\n", ret);783		goto drop_free_descs;784	}785 786	if (in_tx_ts)787		atomic_inc(&emac->tx_ts_pending);788 789	if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) {790		netif_tx_stop_queue(netif_txq);791		/* Barrier, so that stop_queue visible to other cpus */792		smp_mb__after_atomic();793 794		if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=795		    MAX_SKB_FRAGS)796			netif_tx_wake_queue(netif_txq);797	}798 799	return NETDEV_TX_OK;800 801cleanup_tx_ts:802	if (in_tx_ts) {803		dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);804		emac->tx_ts_skb[tx_ts_cookie] = NULL;805	}806 807drop_free_descs:808	prueth_xmit_free(tx_chn, first_desc);809 810drop_free_skb:811	dev_kfree_skb_any(skb);812 813	/* error */814	ndev->stats.tx_dropped++;815	netdev_err(ndev, "tx: error: %d\n", ret);816 817	return ret;818 819free_desc_stop_q_busy_cleanup_tx_ts:820	if (in_tx_ts) {821		dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);822		emac->tx_ts_skb[tx_ts_cookie] = NULL;823	}824	prueth_xmit_free(tx_chn, first_desc);825 826drop_stop_q_busy:827	netif_tx_stop_queue(netif_txq);828	return NETDEV_TX_BUSY;829}830EXPORT_SYMBOL_GPL(icssg_ndo_start_xmit);831 832static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma)833{834	struct prueth_tx_chn *tx_chn = data;835	struct cppi5_host_desc_t *desc_tx;836	struct sk_buff *skb;837	void **swdata;838 839	desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);840	swdata = cppi5_hdesc_get_swdata(desc_tx);841	skb = *(swdata);842	prueth_xmit_free(tx_chn, desc_tx);843 844	dev_kfree_skb_any(skb);845}846 847irqreturn_t prueth_rx_irq(int irq, void *dev_id)848{849	struct prueth_emac *emac = dev_id;850 851	disable_irq_nosync(irq);852	napi_schedule(&emac->napi_rx);853 854	return IRQ_HANDLED;855}856EXPORT_SYMBOL_GPL(prueth_rx_irq);857 858void prueth_emac_stop(struct prueth_emac *emac)859{860	struct prueth *prueth = emac->prueth;861	int slice;862 863	switch (emac->port_id) {864	case PRUETH_PORT_MII0:865		slice = ICSS_SLICE0;866		break;867	case PRUETH_PORT_MII1:868		slice = ICSS_SLICE1;869		break;870	default:871		netdev_err(emac->ndev, "invalid port\n");872		return;873	}874 875	emac->fw_running = 0;876	if (!emac->is_sr1)877		rproc_shutdown(prueth->txpru[slice]);878	rproc_shutdown(prueth->rtu[slice]);879	rproc_shutdown(prueth->pru[slice]);880}881EXPORT_SYMBOL_GPL(prueth_emac_stop);882 883void prueth_cleanup_tx_ts(struct prueth_emac *emac)884{885	int i;886 887	for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {888		if (emac->tx_ts_skb[i]) {889			dev_kfree_skb_any(emac->tx_ts_skb[i]);890			emac->tx_ts_skb[i] = NULL;891		}892	}893}894EXPORT_SYMBOL_GPL(prueth_cleanup_tx_ts);895 896int icssg_napi_rx_poll(struct napi_struct *napi_rx, int budget)897{898	struct prueth_emac *emac = prueth_napi_to_emac(napi_rx);899	int rx_flow = emac->is_sr1 ?900		PRUETH_RX_FLOW_DATA_SR1 : PRUETH_RX_FLOW_DATA;901	int flow = emac->is_sr1 ?902		PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS;903	int num_rx = 0;904	int cur_budget;905	int ret;906 907	while (flow--) {908		cur_budget = budget - num_rx;909 910		while (cur_budget--) {911			ret = emac_rx_packet(emac, flow);912			if (ret)913				break;914			num_rx++;915		}916 917		if (num_rx >= budget)918			break;919	}920 921	if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) {922		if (unlikely(emac->rx_pace_timeout_ns)) {923			hrtimer_start(&emac->rx_hrtimer,924				      ns_to_ktime(emac->rx_pace_timeout_ns),925				      HRTIMER_MODE_REL_PINNED);926		} else {927			enable_irq(emac->rx_chns.irq[rx_flow]);928		}929	}930 931	return num_rx;932}933EXPORT_SYMBOL_GPL(icssg_napi_rx_poll);934 935int prueth_prepare_rx_chan(struct prueth_emac *emac,936			   struct prueth_rx_chn *chn,937			   int buf_size)938{939	struct sk_buff *skb;940	int i, ret;941 942	for (i = 0; i < chn->descs_num; i++) {943		skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL);944		if (!skb)945			return -ENOMEM;946 947		ret = prueth_dma_rx_push(emac, skb, chn);948		if (ret < 0) {949			netdev_err(emac->ndev,950				   "cannot submit skb for rx chan %s ret %d\n",951				   chn->name, ret);952			kfree_skb(skb);953			return ret;954		}955	}956 957	return 0;958}959EXPORT_SYMBOL_GPL(prueth_prepare_rx_chan);960 961void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num,962			  bool free_skb)963{964	int i;965 966	for (i = 0; i < ch_num; i++) {967		if (free_skb)968			k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn,969						  &emac->tx_chns[i],970						  prueth_tx_cleanup);971		k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn);972	}973}974EXPORT_SYMBOL_GPL(prueth_reset_tx_chan);975 976void prueth_reset_rx_chan(struct prueth_rx_chn *chn,977			  int num_flows, bool disable)978{979	int i;980 981	for (i = 0; i < num_flows; i++)982		k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,983					  prueth_rx_cleanup, !!i);984	if (disable)985		k3_udma_glue_disable_rx_chn(chn->rx_chn);986}987EXPORT_SYMBOL_GPL(prueth_reset_rx_chan);988 989void icssg_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)990{991	ndev->stats.tx_errors++;992}993EXPORT_SYMBOL_GPL(icssg_ndo_tx_timeout);994 995static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr)996{997	struct prueth_emac *emac = netdev_priv(ndev);998	struct hwtstamp_config config;999 1000	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))1001		return -EFAULT;1002 1003	switch (config.tx_type) {1004	case HWTSTAMP_TX_OFF:1005		emac->tx_ts_enabled = 0;1006		break;1007	case HWTSTAMP_TX_ON:1008		emac->tx_ts_enabled = 1;1009		break;1010	default:1011		return -ERANGE;1012	}1013 1014	switch (config.rx_filter) {1015	case HWTSTAMP_FILTER_NONE:1016		emac->rx_ts_enabled = 0;1017		break;1018	case HWTSTAMP_FILTER_ALL:1019	case HWTSTAMP_FILTER_SOME:1020	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:1021	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:1022	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:1023	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:1024	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:1025	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:1026	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:1027	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:1028	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:1029	case HWTSTAMP_FILTER_PTP_V2_EVENT:1030	case HWTSTAMP_FILTER_PTP_V2_SYNC:1031	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:1032	case HWTSTAMP_FILTER_NTP_ALL:1033		emac->rx_ts_enabled = 1;1034		config.rx_filter = HWTSTAMP_FILTER_ALL;1035		break;1036	default:1037		return -ERANGE;1038	}1039 1040	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?1041		-EFAULT : 0;1042}1043 1044static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr)1045{1046	struct prueth_emac *emac = netdev_priv(ndev);1047	struct hwtstamp_config config;1048 1049	config.flags = 0;1050	config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;1051	config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;1052 1053	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?1054			    -EFAULT : 0;1055}1056 1057int icssg_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)1058{1059	switch (cmd) {1060	case SIOCGHWTSTAMP:1061		return emac_get_ts_config(ndev, ifr);1062	case SIOCSHWTSTAMP:1063		return emac_set_ts_config(ndev, ifr);1064	default:1065		break;1066	}1067 1068	return phy_do_ioctl(ndev, ifr, cmd);1069}1070EXPORT_SYMBOL_GPL(icssg_ndo_ioctl);1071 1072void icssg_ndo_get_stats64(struct net_device *ndev,1073			   struct rtnl_link_stats64 *stats)1074{1075	struct prueth_emac *emac = netdev_priv(ndev);1076 1077	emac_update_hardware_stats(emac);1078 1079	stats->rx_packets     = emac_get_stat_by_name(emac, "rx_packets");1080	stats->rx_bytes       = emac_get_stat_by_name(emac, "rx_bytes");1081	stats->tx_packets     = emac_get_stat_by_name(emac, "tx_packets");1082	stats->tx_bytes       = emac_get_stat_by_name(emac, "tx_bytes");1083	stats->rx_crc_errors  = emac_get_stat_by_name(emac, "rx_crc_errors");1084	stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");1085	stats->multicast      = emac_get_stat_by_name(emac, "rx_multicast_frames");1086 1087	stats->rx_errors  = ndev->stats.rx_errors;1088	stats->rx_dropped = ndev->stats.rx_dropped;1089	stats->tx_errors  = ndev->stats.tx_errors;1090	stats->tx_dropped = ndev->stats.tx_dropped;1091}1092EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64);1093 1094int icssg_ndo_get_phys_port_name(struct net_device *ndev, char *name,1095				 size_t len)1096{1097	struct prueth_emac *emac = netdev_priv(ndev);1098	int ret;1099 1100	ret = snprintf(name, len, "p%d", emac->port_id);1101	if (ret >= len)1102		return -EINVAL;1103 1104	return 0;1105}1106EXPORT_SYMBOL_GPL(icssg_ndo_get_phys_port_name);1107 1108/* get emac_port corresponding to eth_node name */1109int prueth_node_port(struct device_node *eth_node)1110{1111	u32 port_id;1112	int ret;1113 1114	ret = of_property_read_u32(eth_node, "reg", &port_id);1115	if (ret)1116		return ret;1117 1118	if (port_id == 0)1119		return PRUETH_PORT_MII0;1120	else if (port_id == 1)1121		return PRUETH_PORT_MII1;1122	else1123		return PRUETH_PORT_INVALID;1124}1125EXPORT_SYMBOL_GPL(prueth_node_port);1126 1127/* get MAC instance corresponding to eth_node name */1128int prueth_node_mac(struct device_node *eth_node)1129{1130	u32 port_id;1131	int ret;1132 1133	ret = of_property_read_u32(eth_node, "reg", &port_id);1134	if (ret)1135		return ret;1136 1137	if (port_id == 0)1138		return PRUETH_MAC0;1139	else if (port_id == 1)1140		return PRUETH_MAC1;1141	else1142		return PRUETH_MAC_INVALID;1143}1144EXPORT_SYMBOL_GPL(prueth_node_mac);1145 1146void prueth_netdev_exit(struct prueth *prueth,1147			struct device_node *eth_node)1148{1149	struct prueth_emac *emac;1150	enum prueth_mac mac;1151 1152	mac = prueth_node_mac(eth_node);1153	if (mac == PRUETH_MAC_INVALID)1154		return;1155 1156	emac = prueth->emac[mac];1157	if (!emac)1158		return;1159 1160	if (of_phy_is_fixed_link(emac->phy_node))1161		of_phy_deregister_fixed_link(emac->phy_node);1162 1163	netif_napi_del(&emac->napi_rx);1164 1165	pruss_release_mem_region(prueth->pruss, &emac->dram);1166	destroy_workqueue(emac->cmd_wq);1167	free_netdev(emac->ndev);1168	prueth->emac[mac] = NULL;1169}1170EXPORT_SYMBOL_GPL(prueth_netdev_exit);1171 1172int prueth_get_cores(struct prueth *prueth, int slice, bool is_sr1)1173{1174	struct device *dev = prueth->dev;1175	enum pruss_pru_id pruss_id;1176	struct device_node *np;1177	int idx = -1, ret;1178 1179	np = dev->of_node;1180 1181	switch (slice) {1182	case ICSS_SLICE0:1183		idx = 0;1184		break;1185	case ICSS_SLICE1:1186		idx = is_sr1 ? 2 : 3;1187		break;1188	default:1189		return -EINVAL;1190	}1191 1192	prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id);1193	if (IS_ERR(prueth->pru[slice])) {1194		ret = PTR_ERR(prueth->pru[slice]);1195		prueth->pru[slice] = NULL;1196		return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice);1197	}1198	prueth->pru_id[slice] = pruss_id;1199 1200	idx++;1201	prueth->rtu[slice] = pru_rproc_get(np, idx, NULL);1202	if (IS_ERR(prueth->rtu[slice])) {1203		ret = PTR_ERR(prueth->rtu[slice]);1204		prueth->rtu[slice] = NULL;1205		return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice);1206	}1207 1208	if (is_sr1)1209		return 0;1210 1211	idx++;1212	prueth->txpru[slice] = pru_rproc_get(np, idx, NULL);1213	if (IS_ERR(prueth->txpru[slice])) {1214		ret = PTR_ERR(prueth->txpru[slice]);1215		prueth->txpru[slice] = NULL;1216		return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice);1217	}1218 1219	return 0;1220}1221EXPORT_SYMBOL_GPL(prueth_get_cores);1222 1223void prueth_put_cores(struct prueth *prueth, int slice)1224{1225	if (prueth->txpru[slice])1226		pru_rproc_put(prueth->txpru[slice]);1227 1228	if (prueth->rtu[slice])1229		pru_rproc_put(prueth->rtu[slice]);1230 1231	if (prueth->pru[slice])1232		pru_rproc_put(prueth->pru[slice]);1233}1234EXPORT_SYMBOL_GPL(prueth_put_cores);1235 1236#ifdef CONFIG_PM_SLEEP1237static int prueth_suspend(struct device *dev)1238{1239	struct prueth *prueth = dev_get_drvdata(dev);1240	struct net_device *ndev;1241	int i, ret;1242 1243	for (i = 0; i < PRUETH_NUM_MACS; i++) {1244		ndev = prueth->registered_netdevs[i];1245 1246		if (!ndev)1247			continue;1248 1249		if (netif_running(ndev)) {1250			netif_device_detach(ndev);1251			ret = ndev->netdev_ops->ndo_stop(ndev);1252			if (ret < 0) {1253				netdev_err(ndev, "failed to stop: %d", ret);1254				return ret;1255			}1256		}1257	}1258 1259	return 0;1260}1261 1262static int prueth_resume(struct device *dev)1263{1264	struct prueth *prueth = dev_get_drvdata(dev);1265	struct net_device *ndev;1266	int i, ret;1267 1268	for (i = 0; i < PRUETH_NUM_MACS; i++) {1269		ndev = prueth->registered_netdevs[i];1270 1271		if (!ndev)1272			continue;1273 1274		if (netif_running(ndev)) {1275			ret = ndev->netdev_ops->ndo_open(ndev);1276			if (ret < 0) {1277				netdev_err(ndev, "failed to start: %d", ret);1278				return ret;1279			}1280			netif_device_attach(ndev);1281		}1282	}1283 1284	return 0;1285}1286#endif /* CONFIG_PM_SLEEP */1287 1288const struct dev_pm_ops prueth_dev_pm_ops = {1289	SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume)1290};1291EXPORT_SYMBOL_GPL(prueth_dev_pm_ops);1292 1293MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");1294MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");1295MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver Common Module");1296MODULE_LICENSE("GPL");1297