1128d5874SRoger Quadros // SPDX-License-Identifier: GPL-2.0
2128d5874SRoger Quadros
3128d5874SRoger Quadros /* Texas Instruments ICSSG Ethernet Driver
4128d5874SRoger Quadros *
5128d5874SRoger Quadros * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
6128d5874SRoger Quadros *
7128d5874SRoger Quadros */
8128d5874SRoger Quadros
9128d5874SRoger Quadros #include <linux/bitops.h>
10128d5874SRoger Quadros #include <linux/clk.h>
11c1e10d5dSMD Danish Anwar #include <linux/delay.h>
12128d5874SRoger Quadros #include <linux/dma-mapping.h>
13128d5874SRoger Quadros #include <linux/dma/ti-cppi5.h>
14128d5874SRoger Quadros #include <linux/etherdevice.h>
15128d5874SRoger Quadros #include <linux/genalloc.h>
16128d5874SRoger Quadros #include <linux/if_vlan.h>
17128d5874SRoger Quadros #include <linux/interrupt.h>
18*c67ce71dSMeghana Malladi #include <linux/io-64-nonatomic-hi-lo.h>
19128d5874SRoger Quadros #include <linux/kernel.h>
20128d5874SRoger Quadros #include <linux/mfd/syscon.h>
21128d5874SRoger Quadros #include <linux/module.h>
22128d5874SRoger Quadros #include <linux/of.h>
23128d5874SRoger Quadros #include <linux/of_irq.h>
24128d5874SRoger Quadros #include <linux/of_mdio.h>
25128d5874SRoger Quadros #include <linux/of_net.h>
26128d5874SRoger Quadros #include <linux/of_platform.h>
27128d5874SRoger Quadros #include <linux/phy.h>
28128d5874SRoger Quadros #include <linux/remoteproc/pruss.h>
29128d5874SRoger Quadros #include <linux/regmap.h>
30128d5874SRoger Quadros #include <linux/remoteproc.h>
31128d5874SRoger Quadros
32128d5874SRoger Quadros #include "icssg_prueth.h"
33128d5874SRoger Quadros #include "icssg_mii_rt.h"
34128d5874SRoger Quadros #include "../k3-cppi-desc-pool.h"
35128d5874SRoger Quadros
36128d5874SRoger Quadros #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"
37128d5874SRoger Quadros
38128d5874SRoger Quadros /* Netif debug messages possible */
39128d5874SRoger Quadros #define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \
40128d5874SRoger Quadros NETIF_MSG_PROBE | \
41128d5874SRoger Quadros NETIF_MSG_LINK | \
42128d5874SRoger Quadros NETIF_MSG_TIMER | \
43128d5874SRoger Quadros NETIF_MSG_IFDOWN | \
44128d5874SRoger Quadros NETIF_MSG_IFUP | \
45128d5874SRoger Quadros NETIF_MSG_RX_ERR | \
46128d5874SRoger Quadros NETIF_MSG_TX_ERR | \
47128d5874SRoger Quadros NETIF_MSG_TX_QUEUED | \
48128d5874SRoger Quadros NETIF_MSG_INTR | \
49128d5874SRoger Quadros NETIF_MSG_TX_DONE | \
50128d5874SRoger Quadros NETIF_MSG_RX_STATUS | \
51128d5874SRoger Quadros NETIF_MSG_PKTDATA | \
52128d5874SRoger Quadros NETIF_MSG_HW | \
53128d5874SRoger Quadros NETIF_MSG_WOL)
54128d5874SRoger Quadros
55128d5874SRoger Quadros #define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)
56128d5874SRoger Quadros
57128d5874SRoger Quadros /* CTRLMMR_ICSSG_RGMII_CTRL register bits */
58128d5874SRoger Quadros #define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
59128d5874SRoger Quadros
60186734c1SRoger Quadros #define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */
61186734c1SRoger Quadros
prueth_cleanup_rx_chns(struct prueth_emac * emac,struct prueth_rx_chn * rx_chn,int max_rflows)62128d5874SRoger Quadros static void prueth_cleanup_rx_chns(struct prueth_emac *emac,
63128d5874SRoger Quadros struct prueth_rx_chn *rx_chn,
64128d5874SRoger Quadros int max_rflows)
65128d5874SRoger Quadros {
66128d5874SRoger Quadros if (rx_chn->desc_pool)
67128d5874SRoger Quadros k3_cppi_desc_pool_destroy(rx_chn->desc_pool);
68128d5874SRoger Quadros
69128d5874SRoger Quadros if (rx_chn->rx_chn)
70128d5874SRoger Quadros k3_udma_glue_release_rx_chn(rx_chn->rx_chn);
71128d5874SRoger Quadros }
72128d5874SRoger Quadros
prueth_cleanup_tx_chns(struct prueth_emac * emac)73128d5874SRoger Quadros static void prueth_cleanup_tx_chns(struct prueth_emac *emac)
74128d5874SRoger Quadros {
75128d5874SRoger Quadros int i;
76128d5874SRoger Quadros
77128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++) {
78128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
79128d5874SRoger Quadros
80128d5874SRoger Quadros if (tx_chn->desc_pool)
81128d5874SRoger Quadros k3_cppi_desc_pool_destroy(tx_chn->desc_pool);
82128d5874SRoger Quadros
83128d5874SRoger Quadros if (tx_chn->tx_chn)
84128d5874SRoger Quadros k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
85128d5874SRoger Quadros
86128d5874SRoger Quadros /* Assume prueth_cleanup_tx_chns() is called at the
87128d5874SRoger Quadros * end after all channel resources are freed
88128d5874SRoger Quadros */
89128d5874SRoger Quadros memset(tx_chn, 0, sizeof(*tx_chn));
90128d5874SRoger Quadros }
91128d5874SRoger Quadros }
92128d5874SRoger Quadros
prueth_ndev_del_tx_napi(struct prueth_emac * emac,int num)93128d5874SRoger Quadros static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num)
94128d5874SRoger Quadros {
95128d5874SRoger Quadros int i;
96128d5874SRoger Quadros
97128d5874SRoger Quadros for (i = 0; i < num; i++) {
98128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
99128d5874SRoger Quadros
100128d5874SRoger Quadros if (tx_chn->irq)
101128d5874SRoger Quadros free_irq(tx_chn->irq, tx_chn);
102128d5874SRoger Quadros netif_napi_del(&tx_chn->napi_tx);
103128d5874SRoger Quadros }
104128d5874SRoger Quadros }
105128d5874SRoger Quadros
prueth_xmit_free(struct prueth_tx_chn * tx_chn,struct cppi5_host_desc_t * desc)106128d5874SRoger Quadros static void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
107128d5874SRoger Quadros struct cppi5_host_desc_t *desc)
108128d5874SRoger Quadros {
109128d5874SRoger Quadros struct cppi5_host_desc_t *first_desc, *next_desc;
110128d5874SRoger Quadros dma_addr_t buf_dma, next_desc_dma;
111128d5874SRoger Quadros u32 buf_dma_len;
112128d5874SRoger Quadros
113128d5874SRoger Quadros first_desc = desc;
114128d5874SRoger Quadros next_desc = first_desc;
115128d5874SRoger Quadros
116128d5874SRoger Quadros cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
117128d5874SRoger Quadros k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
118128d5874SRoger Quadros
119128d5874SRoger Quadros dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len,
120128d5874SRoger Quadros DMA_TO_DEVICE);
121128d5874SRoger Quadros
122128d5874SRoger Quadros next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);
123128d5874SRoger Quadros k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
124128d5874SRoger Quadros while (next_desc_dma) {
125128d5874SRoger Quadros next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
126128d5874SRoger Quadros next_desc_dma);
127128d5874SRoger Quadros cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);
128128d5874SRoger Quadros k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
129128d5874SRoger Quadros
130128d5874SRoger Quadros dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,
131128d5874SRoger Quadros DMA_TO_DEVICE);
132128d5874SRoger Quadros
133128d5874SRoger Quadros next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);
134128d5874SRoger Quadros k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
135128d5874SRoger Quadros
136128d5874SRoger Quadros k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
137128d5874SRoger Quadros }
138128d5874SRoger Quadros
139128d5874SRoger Quadros k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
140128d5874SRoger Quadros }
141128d5874SRoger Quadros
emac_tx_complete_packets(struct prueth_emac * emac,int chn,int budget)142128d5874SRoger Quadros static int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
143128d5874SRoger Quadros int budget)
144128d5874SRoger Quadros {
145128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
146128d5874SRoger Quadros struct cppi5_host_desc_t *desc_tx;
147128d5874SRoger Quadros struct netdev_queue *netif_txq;
148128d5874SRoger Quadros struct prueth_tx_chn *tx_chn;
149128d5874SRoger Quadros unsigned int total_bytes = 0;
150128d5874SRoger Quadros struct sk_buff *skb;
151128d5874SRoger Quadros dma_addr_t desc_dma;
152128d5874SRoger Quadros int res, num_tx = 0;
153128d5874SRoger Quadros void **swdata;
154128d5874SRoger Quadros
155128d5874SRoger Quadros tx_chn = &emac->tx_chns[chn];
156128d5874SRoger Quadros
157128d5874SRoger Quadros while (true) {
158128d5874SRoger Quadros res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);
159128d5874SRoger Quadros if (res == -ENODATA)
160128d5874SRoger Quadros break;
161128d5874SRoger Quadros
162128d5874SRoger Quadros /* teardown completion */
163128d5874SRoger Quadros if (cppi5_desc_is_tdcm(desc_dma)) {
164128d5874SRoger Quadros if (atomic_dec_and_test(&emac->tdown_cnt))
165128d5874SRoger Quadros complete(&emac->tdown_complete);
166128d5874SRoger Quadros break;
167128d5874SRoger Quadros }
168128d5874SRoger Quadros
169128d5874SRoger Quadros desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
170128d5874SRoger Quadros desc_dma);
171128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(desc_tx);
172128d5874SRoger Quadros
173128d5874SRoger Quadros skb = *(swdata);
174128d5874SRoger Quadros prueth_xmit_free(tx_chn, desc_tx);
175128d5874SRoger Quadros
176128d5874SRoger Quadros ndev = skb->dev;
177128d5874SRoger Quadros ndev->stats.tx_packets++;
178128d5874SRoger Quadros ndev->stats.tx_bytes += skb->len;
179128d5874SRoger Quadros total_bytes += skb->len;
180128d5874SRoger Quadros napi_consume_skb(skb, budget);
181128d5874SRoger Quadros num_tx++;
182128d5874SRoger Quadros }
183128d5874SRoger Quadros
184128d5874SRoger Quadros if (!num_tx)
185128d5874SRoger Quadros return 0;
186128d5874SRoger Quadros
187128d5874SRoger Quadros netif_txq = netdev_get_tx_queue(ndev, chn);
188128d5874SRoger Quadros netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
189128d5874SRoger Quadros
190128d5874SRoger Quadros if (netif_tx_queue_stopped(netif_txq)) {
191128d5874SRoger Quadros /* If the TX queue was stopped, wake it now
192128d5874SRoger Quadros * if we have enough room.
193128d5874SRoger Quadros */
194128d5874SRoger Quadros __netif_tx_lock(netif_txq, smp_processor_id());
195128d5874SRoger Quadros if (netif_running(ndev) &&
196128d5874SRoger Quadros (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
197128d5874SRoger Quadros MAX_SKB_FRAGS))
198128d5874SRoger Quadros netif_tx_wake_queue(netif_txq);
199128d5874SRoger Quadros __netif_tx_unlock(netif_txq);
200128d5874SRoger Quadros }
201128d5874SRoger Quadros
202128d5874SRoger Quadros return num_tx;
203128d5874SRoger Quadros }
204128d5874SRoger Quadros
emac_napi_tx_poll(struct napi_struct * napi_tx,int budget)205128d5874SRoger Quadros static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget)
206128d5874SRoger Quadros {
207128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx);
208128d5874SRoger Quadros struct prueth_emac *emac = tx_chn->emac;
209128d5874SRoger Quadros int num_tx_packets;
210128d5874SRoger Quadros
211128d5874SRoger Quadros num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget);
212128d5874SRoger Quadros
213128d5874SRoger Quadros if (num_tx_packets >= budget)
214128d5874SRoger Quadros return budget;
215128d5874SRoger Quadros
216128d5874SRoger Quadros if (napi_complete_done(napi_tx, num_tx_packets))
217128d5874SRoger Quadros enable_irq(tx_chn->irq);
218128d5874SRoger Quadros
219128d5874SRoger Quadros return num_tx_packets;
220128d5874SRoger Quadros }
221128d5874SRoger Quadros
prueth_tx_irq(int irq,void * dev_id)222128d5874SRoger Quadros static irqreturn_t prueth_tx_irq(int irq, void *dev_id)
223128d5874SRoger Quadros {
224128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = dev_id;
225128d5874SRoger Quadros
226128d5874SRoger Quadros disable_irq_nosync(irq);
227128d5874SRoger Quadros napi_schedule(&tx_chn->napi_tx);
228128d5874SRoger Quadros
229128d5874SRoger Quadros return IRQ_HANDLED;
230128d5874SRoger Quadros }
231128d5874SRoger Quadros
prueth_ndev_add_tx_napi(struct prueth_emac * emac)232128d5874SRoger Quadros static int prueth_ndev_add_tx_napi(struct prueth_emac *emac)
233128d5874SRoger Quadros {
234128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
235128d5874SRoger Quadros int i, ret;
236128d5874SRoger Quadros
237128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++) {
238128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
239128d5874SRoger Quadros
240128d5874SRoger Quadros netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll);
241128d5874SRoger Quadros ret = request_irq(tx_chn->irq, prueth_tx_irq,
242128d5874SRoger Quadros IRQF_TRIGGER_HIGH, tx_chn->name,
243128d5874SRoger Quadros tx_chn);
244128d5874SRoger Quadros if (ret) {
245128d5874SRoger Quadros netif_napi_del(&tx_chn->napi_tx);
246128d5874SRoger Quadros dev_err(prueth->dev, "unable to request TX IRQ %d\n",
247128d5874SRoger Quadros tx_chn->irq);
248128d5874SRoger Quadros goto fail;
249128d5874SRoger Quadros }
250128d5874SRoger Quadros }
251128d5874SRoger Quadros
252128d5874SRoger Quadros return 0;
253128d5874SRoger Quadros fail:
254128d5874SRoger Quadros prueth_ndev_del_tx_napi(emac, i);
255128d5874SRoger Quadros return ret;
256128d5874SRoger Quadros }
257128d5874SRoger Quadros
prueth_init_tx_chns(struct prueth_emac * emac)258128d5874SRoger Quadros static int prueth_init_tx_chns(struct prueth_emac *emac)
259128d5874SRoger Quadros {
260128d5874SRoger Quadros static const struct k3_ring_cfg ring_cfg = {
261128d5874SRoger Quadros .elm_size = K3_RINGACC_RING_ELSIZE_8,
262128d5874SRoger Quadros .mode = K3_RINGACC_RING_MODE_RING,
263128d5874SRoger Quadros .flags = 0,
264128d5874SRoger Quadros .size = PRUETH_MAX_TX_DESC,
265128d5874SRoger Quadros };
266128d5874SRoger Quadros struct k3_udma_glue_tx_channel_cfg tx_cfg;
267128d5874SRoger Quadros struct device *dev = emac->prueth->dev;
268128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
269128d5874SRoger Quadros int ret, slice, i;
270128d5874SRoger Quadros u32 hdesc_size;
271128d5874SRoger Quadros
272128d5874SRoger Quadros slice = prueth_emac_slice(emac);
273128d5874SRoger Quadros if (slice < 0)
274128d5874SRoger Quadros return slice;
275128d5874SRoger Quadros
276128d5874SRoger Quadros init_completion(&emac->tdown_complete);
277128d5874SRoger Quadros
278128d5874SRoger Quadros hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
279128d5874SRoger Quadros PRUETH_NAV_SW_DATA_SIZE);
280128d5874SRoger Quadros memset(&tx_cfg, 0, sizeof(tx_cfg));
281128d5874SRoger Quadros tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
282128d5874SRoger Quadros tx_cfg.tx_cfg = ring_cfg;
283128d5874SRoger Quadros tx_cfg.txcq_cfg = ring_cfg;
284128d5874SRoger Quadros
285128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++) {
286128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
287128d5874SRoger Quadros
288128d5874SRoger Quadros /* To differentiate channels for SLICE0 vs SLICE1 */
289128d5874SRoger Quadros snprintf(tx_chn->name, sizeof(tx_chn->name),
290128d5874SRoger Quadros "tx%d-%d", slice, i);
291128d5874SRoger Quadros
292128d5874SRoger Quadros tx_chn->emac = emac;
293128d5874SRoger Quadros tx_chn->id = i;
294128d5874SRoger Quadros tx_chn->descs_num = PRUETH_MAX_TX_DESC;
295128d5874SRoger Quadros
296128d5874SRoger Quadros tx_chn->tx_chn =
297128d5874SRoger Quadros k3_udma_glue_request_tx_chn(dev, tx_chn->name,
298128d5874SRoger Quadros &tx_cfg);
299128d5874SRoger Quadros if (IS_ERR(tx_chn->tx_chn)) {
300128d5874SRoger Quadros ret = PTR_ERR(tx_chn->tx_chn);
301128d5874SRoger Quadros tx_chn->tx_chn = NULL;
302128d5874SRoger Quadros netdev_err(ndev,
303128d5874SRoger Quadros "Failed to request tx dma ch: %d\n", ret);
304128d5874SRoger Quadros goto fail;
305128d5874SRoger Quadros }
306128d5874SRoger Quadros
307128d5874SRoger Quadros tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn);
308128d5874SRoger Quadros tx_chn->desc_pool =
309128d5874SRoger Quadros k3_cppi_desc_pool_create_name(tx_chn->dma_dev,
310128d5874SRoger Quadros tx_chn->descs_num,
311128d5874SRoger Quadros hdesc_size,
312128d5874SRoger Quadros tx_chn->name);
313128d5874SRoger Quadros if (IS_ERR(tx_chn->desc_pool)) {
314128d5874SRoger Quadros ret = PTR_ERR(tx_chn->desc_pool);
315128d5874SRoger Quadros tx_chn->desc_pool = NULL;
316128d5874SRoger Quadros netdev_err(ndev, "Failed to create tx pool: %d\n", ret);
317128d5874SRoger Quadros goto fail;
318128d5874SRoger Quadros }
319128d5874SRoger Quadros
320a325f174SDan Carpenter ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
321f9a1d321SDan Carpenter if (ret < 0) {
322128d5874SRoger Quadros netdev_err(ndev, "failed to get tx irq\n");
323128d5874SRoger Quadros goto fail;
324128d5874SRoger Quadros }
325a325f174SDan Carpenter tx_chn->irq = ret;
326128d5874SRoger Quadros
327128d5874SRoger Quadros snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d",
328128d5874SRoger Quadros dev_name(dev), tx_chn->id);
329128d5874SRoger Quadros }
330128d5874SRoger Quadros
331128d5874SRoger Quadros return 0;
332128d5874SRoger Quadros
333128d5874SRoger Quadros fail:
334128d5874SRoger Quadros prueth_cleanup_tx_chns(emac);
335128d5874SRoger Quadros return ret;
336128d5874SRoger Quadros }
337128d5874SRoger Quadros
prueth_init_rx_chns(struct prueth_emac * emac,struct prueth_rx_chn * rx_chn,char * name,u32 max_rflows,u32 max_desc_num)338128d5874SRoger Quadros static int prueth_init_rx_chns(struct prueth_emac *emac,
339128d5874SRoger Quadros struct prueth_rx_chn *rx_chn,
340128d5874SRoger Quadros char *name, u32 max_rflows,
341128d5874SRoger Quadros u32 max_desc_num)
342128d5874SRoger Quadros {
343128d5874SRoger Quadros struct k3_udma_glue_rx_channel_cfg rx_cfg;
344128d5874SRoger Quadros struct device *dev = emac->prueth->dev;
345128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
346128d5874SRoger Quadros u32 fdqring_id, hdesc_size;
347128d5874SRoger Quadros int i, ret = 0, slice;
348128d5874SRoger Quadros
349128d5874SRoger Quadros slice = prueth_emac_slice(emac);
350128d5874SRoger Quadros if (slice < 0)
351128d5874SRoger Quadros return slice;
352128d5874SRoger Quadros
353128d5874SRoger Quadros /* To differentiate channels for SLICE0 vs SLICE1 */
354128d5874SRoger Quadros snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice);
355128d5874SRoger Quadros
356128d5874SRoger Quadros hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
357128d5874SRoger Quadros PRUETH_NAV_SW_DATA_SIZE);
358128d5874SRoger Quadros memset(&rx_cfg, 0, sizeof(rx_cfg));
359128d5874SRoger Quadros rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
360128d5874SRoger Quadros rx_cfg.flow_id_num = max_rflows;
361128d5874SRoger Quadros rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */
362128d5874SRoger Quadros
363128d5874SRoger Quadros /* init all flows */
364128d5874SRoger Quadros rx_chn->dev = dev;
365128d5874SRoger Quadros rx_chn->descs_num = max_desc_num;
366128d5874SRoger Quadros
367128d5874SRoger Quadros rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name,
368128d5874SRoger Quadros &rx_cfg);
369128d5874SRoger Quadros if (IS_ERR(rx_chn->rx_chn)) {
370128d5874SRoger Quadros ret = PTR_ERR(rx_chn->rx_chn);
371128d5874SRoger Quadros rx_chn->rx_chn = NULL;
372128d5874SRoger Quadros netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret);
373128d5874SRoger Quadros goto fail;
374128d5874SRoger Quadros }
375128d5874SRoger Quadros
376128d5874SRoger Quadros rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn);
377128d5874SRoger Quadros rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev,
378128d5874SRoger Quadros rx_chn->descs_num,
379128d5874SRoger Quadros hdesc_size,
380128d5874SRoger Quadros rx_chn->name);
381128d5874SRoger Quadros if (IS_ERR(rx_chn->desc_pool)) {
382128d5874SRoger Quadros ret = PTR_ERR(rx_chn->desc_pool);
383128d5874SRoger Quadros rx_chn->desc_pool = NULL;
384128d5874SRoger Quadros netdev_err(ndev, "Failed to create rx pool: %d\n", ret);
385128d5874SRoger Quadros goto fail;
386128d5874SRoger Quadros }
387128d5874SRoger Quadros
388128d5874SRoger Quadros emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn);
389128d5874SRoger Quadros netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base);
390128d5874SRoger Quadros
391128d5874SRoger Quadros fdqring_id = K3_RINGACC_RING_ID_ANY;
392128d5874SRoger Quadros for (i = 0; i < rx_cfg.flow_id_num; i++) {
393128d5874SRoger Quadros struct k3_ring_cfg rxring_cfg = {
394128d5874SRoger Quadros .elm_size = K3_RINGACC_RING_ELSIZE_8,
395128d5874SRoger Quadros .mode = K3_RINGACC_RING_MODE_RING,
396128d5874SRoger Quadros .flags = 0,
397128d5874SRoger Quadros };
398128d5874SRoger Quadros struct k3_ring_cfg fdqring_cfg = {
399128d5874SRoger Quadros .elm_size = K3_RINGACC_RING_ELSIZE_8,
400128d5874SRoger Quadros .flags = K3_RINGACC_RING_SHARED,
401128d5874SRoger Quadros };
402128d5874SRoger Quadros struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = {
403128d5874SRoger Quadros .rx_cfg = rxring_cfg,
404128d5874SRoger Quadros .rxfdq_cfg = fdqring_cfg,
405128d5874SRoger Quadros .ring_rxq_id = K3_RINGACC_RING_ID_ANY,
406128d5874SRoger Quadros .src_tag_lo_sel =
407128d5874SRoger Quadros K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG,
408128d5874SRoger Quadros };
409128d5874SRoger Quadros
410128d5874SRoger Quadros rx_flow_cfg.ring_rxfdq0_id = fdqring_id;
411128d5874SRoger Quadros rx_flow_cfg.rx_cfg.size = max_desc_num;
412128d5874SRoger Quadros rx_flow_cfg.rxfdq_cfg.size = max_desc_num;
413128d5874SRoger Quadros rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode;
414128d5874SRoger Quadros
415128d5874SRoger Quadros ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
416128d5874SRoger Quadros i, &rx_flow_cfg);
417128d5874SRoger Quadros if (ret) {
418128d5874SRoger Quadros netdev_err(ndev, "Failed to init rx flow%d %d\n",
419128d5874SRoger Quadros i, ret);
420128d5874SRoger Quadros goto fail;
421128d5874SRoger Quadros }
422128d5874SRoger Quadros if (!i)
423128d5874SRoger Quadros fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn,
424128d5874SRoger Quadros i);
42594b00cd6SDan Carpenter ret = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i);
42694b00cd6SDan Carpenter if (ret <= 0) {
42794b00cd6SDan Carpenter if (!ret)
42894b00cd6SDan Carpenter ret = -ENXIO;
429128d5874SRoger Quadros netdev_err(ndev, "Failed to get rx dma irq");
430128d5874SRoger Quadros goto fail;
431128d5874SRoger Quadros }
43294b00cd6SDan Carpenter rx_chn->irq[i] = ret;
433128d5874SRoger Quadros }
434128d5874SRoger Quadros
435128d5874SRoger Quadros return 0;
436128d5874SRoger Quadros
437128d5874SRoger Quadros fail:
438128d5874SRoger Quadros prueth_cleanup_rx_chns(emac, rx_chn, max_rflows);
439128d5874SRoger Quadros return ret;
440128d5874SRoger Quadros }
441128d5874SRoger Quadros
prueth_dma_rx_push(struct prueth_emac * emac,struct sk_buff * skb,struct prueth_rx_chn * rx_chn)442128d5874SRoger Quadros static int prueth_dma_rx_push(struct prueth_emac *emac,
443128d5874SRoger Quadros struct sk_buff *skb,
444128d5874SRoger Quadros struct prueth_rx_chn *rx_chn)
445128d5874SRoger Quadros {
446128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
447128d5874SRoger Quadros struct cppi5_host_desc_t *desc_rx;
448128d5874SRoger Quadros u32 pkt_len = skb_tailroom(skb);
449128d5874SRoger Quadros dma_addr_t desc_dma;
450128d5874SRoger Quadros dma_addr_t buf_dma;
451128d5874SRoger Quadros void **swdata;
452128d5874SRoger Quadros
453128d5874SRoger Quadros desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool);
454128d5874SRoger Quadros if (!desc_rx) {
455128d5874SRoger Quadros netdev_err(ndev, "rx push: failed to allocate descriptor\n");
456128d5874SRoger Quadros return -ENOMEM;
457128d5874SRoger Quadros }
458128d5874SRoger Quadros desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx);
459128d5874SRoger Quadros
460128d5874SRoger Quadros buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE);
461128d5874SRoger Quadros if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) {
462128d5874SRoger Quadros k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
463128d5874SRoger Quadros netdev_err(ndev, "rx push: failed to map rx pkt buffer\n");
464128d5874SRoger Quadros return -EINVAL;
465128d5874SRoger Quadros }
466128d5874SRoger Quadros
467128d5874SRoger Quadros cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT,
468128d5874SRoger Quadros PRUETH_NAV_PS_DATA_SIZE);
469128d5874SRoger Quadros k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma);
470128d5874SRoger Quadros cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb));
471128d5874SRoger Quadros
472128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(desc_rx);
473128d5874SRoger Quadros *swdata = skb;
474128d5874SRoger Quadros
475128d5874SRoger Quadros return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0,
476128d5874SRoger Quadros desc_rx, desc_dma);
477128d5874SRoger Quadros }
478128d5874SRoger Quadros
icssg_ts_to_ns(u32 hi_sw,u32 hi,u32 lo,u32 cycle_time_ns)479186734c1SRoger Quadros static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns)
480186734c1SRoger Quadros {
481186734c1SRoger Quadros u32 iepcount_lo, iepcount_hi, hi_rollover_count;
482186734c1SRoger Quadros u64 ns;
483186734c1SRoger Quadros
484186734c1SRoger Quadros iepcount_lo = lo & GENMASK(19, 0);
485186734c1SRoger Quadros iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20;
486186734c1SRoger Quadros hi_rollover_count = hi >> 11;
487186734c1SRoger Quadros
488186734c1SRoger Quadros ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw);
489186734c1SRoger Quadros ns = ns * cycle_time_ns + iepcount_lo;
490186734c1SRoger Quadros
491186734c1SRoger Quadros return ns;
492186734c1SRoger Quadros }
493186734c1SRoger Quadros
emac_rx_timestamp(struct prueth_emac * emac,struct sk_buff * skb,u32 * psdata)494186734c1SRoger Quadros static void emac_rx_timestamp(struct prueth_emac *emac,
495186734c1SRoger Quadros struct sk_buff *skb, u32 *psdata)
496186734c1SRoger Quadros {
497186734c1SRoger Quadros struct skb_shared_hwtstamps *ssh;
498186734c1SRoger Quadros u64 ns;
499186734c1SRoger Quadros
500186734c1SRoger Quadros u32 hi_sw = readl(emac->prueth->shram.va +
501186734c1SRoger Quadros TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
502186734c1SRoger Quadros ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0],
503186734c1SRoger Quadros IEP_DEFAULT_CYCLE_TIME_NS);
504186734c1SRoger Quadros
505186734c1SRoger Quadros ssh = skb_hwtstamps(skb);
506186734c1SRoger Quadros memset(ssh, 0, sizeof(*ssh));
507186734c1SRoger Quadros ssh->hwtstamp = ns_to_ktime(ns);
508186734c1SRoger Quadros }
509186734c1SRoger Quadros
emac_rx_packet(struct prueth_emac * emac,u32 flow_id)510128d5874SRoger Quadros static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
511128d5874SRoger Quadros {
512128d5874SRoger Quadros struct prueth_rx_chn *rx_chn = &emac->rx_chns;
513128d5874SRoger Quadros u32 buf_dma_len, pkt_len, port_id = 0;
514128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
515128d5874SRoger Quadros struct cppi5_host_desc_t *desc_rx;
516128d5874SRoger Quadros struct sk_buff *skb, *new_skb;
517128d5874SRoger Quadros dma_addr_t desc_dma, buf_dma;
518128d5874SRoger Quadros void **swdata;
519186734c1SRoger Quadros u32 *psdata;
520128d5874SRoger Quadros int ret;
521128d5874SRoger Quadros
522128d5874SRoger Quadros ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma);
523128d5874SRoger Quadros if (ret) {
524128d5874SRoger Quadros if (ret != -ENODATA)
525128d5874SRoger Quadros netdev_err(ndev, "rx pop: failed: %d\n", ret);
526128d5874SRoger Quadros return ret;
527128d5874SRoger Quadros }
528128d5874SRoger Quadros
529128d5874SRoger Quadros if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */
530128d5874SRoger Quadros return 0;
531128d5874SRoger Quadros
532128d5874SRoger Quadros desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
533128d5874SRoger Quadros
534128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(desc_rx);
535128d5874SRoger Quadros skb = *swdata;
536128d5874SRoger Quadros
537186734c1SRoger Quadros psdata = cppi5_hdesc_get_psdata(desc_rx);
538186734c1SRoger Quadros /* RX HW timestamp */
539186734c1SRoger Quadros if (emac->rx_ts_enabled)
540186734c1SRoger Quadros emac_rx_timestamp(emac, skb, psdata);
541186734c1SRoger Quadros
542128d5874SRoger Quadros cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
543128d5874SRoger Quadros k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
544128d5874SRoger Quadros pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
545128d5874SRoger Quadros /* firmware adds 4 CRC bytes, strip them */
546128d5874SRoger Quadros pkt_len -= 4;
547128d5874SRoger Quadros cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
548128d5874SRoger Quadros
549128d5874SRoger Quadros dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
550128d5874SRoger Quadros k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
551128d5874SRoger Quadros
552128d5874SRoger Quadros skb->dev = ndev;
553128d5874SRoger Quadros new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE);
554128d5874SRoger Quadros /* if allocation fails we drop the packet but push the
555128d5874SRoger Quadros * descriptor back to the ring with old skb to prevent a stall
556128d5874SRoger Quadros */
557128d5874SRoger Quadros if (!new_skb) {
558128d5874SRoger Quadros ndev->stats.rx_dropped++;
559128d5874SRoger Quadros new_skb = skb;
560128d5874SRoger Quadros } else {
561128d5874SRoger Quadros /* send the filled skb up the n/w stack */
562128d5874SRoger Quadros skb_put(skb, pkt_len);
563128d5874SRoger Quadros skb->protocol = eth_type_trans(skb, ndev);
564128d5874SRoger Quadros napi_gro_receive(&emac->napi_rx, skb);
565128d5874SRoger Quadros ndev->stats.rx_bytes += pkt_len;
566128d5874SRoger Quadros ndev->stats.rx_packets++;
567128d5874SRoger Quadros }
568128d5874SRoger Quadros
569128d5874SRoger Quadros /* queue another RX DMA */
570128d5874SRoger Quadros ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns);
571128d5874SRoger Quadros if (WARN_ON(ret < 0)) {
572128d5874SRoger Quadros dev_kfree_skb_any(new_skb);
573128d5874SRoger Quadros ndev->stats.rx_errors++;
574128d5874SRoger Quadros ndev->stats.rx_dropped++;
575128d5874SRoger Quadros }
576128d5874SRoger Quadros
577128d5874SRoger Quadros return ret;
578128d5874SRoger Quadros }
579128d5874SRoger Quadros
prueth_rx_cleanup(void * data,dma_addr_t desc_dma)580128d5874SRoger Quadros static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma)
581128d5874SRoger Quadros {
582128d5874SRoger Quadros struct prueth_rx_chn *rx_chn = data;
583128d5874SRoger Quadros struct cppi5_host_desc_t *desc_rx;
584128d5874SRoger Quadros struct sk_buff *skb;
585128d5874SRoger Quadros dma_addr_t buf_dma;
586128d5874SRoger Quadros u32 buf_dma_len;
587128d5874SRoger Quadros void **swdata;
588128d5874SRoger Quadros
589128d5874SRoger Quadros desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
590128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(desc_rx);
591128d5874SRoger Quadros skb = *swdata;
592128d5874SRoger Quadros cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
593128d5874SRoger Quadros k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
594128d5874SRoger Quadros
595128d5874SRoger Quadros dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len,
596128d5874SRoger Quadros DMA_FROM_DEVICE);
597128d5874SRoger Quadros k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
598128d5874SRoger Quadros
599128d5874SRoger Quadros dev_kfree_skb_any(skb);
600128d5874SRoger Quadros }
601128d5874SRoger Quadros
emac_get_tx_ts(struct prueth_emac * emac,struct emac_tx_ts_response * rsp)602186734c1SRoger Quadros static int emac_get_tx_ts(struct prueth_emac *emac,
603186734c1SRoger Quadros struct emac_tx_ts_response *rsp)
604186734c1SRoger Quadros {
605186734c1SRoger Quadros struct prueth *prueth = emac->prueth;
606186734c1SRoger Quadros int slice = prueth_emac_slice(emac);
607186734c1SRoger Quadros int addr;
608186734c1SRoger Quadros
609186734c1SRoger Quadros addr = icssg_queue_pop(prueth, slice == 0 ?
610186734c1SRoger Quadros ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1);
611186734c1SRoger Quadros if (addr < 0)
612186734c1SRoger Quadros return addr;
613186734c1SRoger Quadros
614186734c1SRoger Quadros memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
615186734c1SRoger Quadros /* return buffer back for to pool */
616186734c1SRoger Quadros icssg_queue_push(prueth, slice == 0 ?
617186734c1SRoger Quadros ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr);
618186734c1SRoger Quadros
619186734c1SRoger Quadros return 0;
620186734c1SRoger Quadros }
621186734c1SRoger Quadros
tx_ts_work(struct prueth_emac * emac)622186734c1SRoger Quadros static void tx_ts_work(struct prueth_emac *emac)
623186734c1SRoger Quadros {
624186734c1SRoger Quadros struct skb_shared_hwtstamps ssh;
625186734c1SRoger Quadros struct emac_tx_ts_response tsr;
626186734c1SRoger Quadros struct sk_buff *skb;
627186734c1SRoger Quadros int ret = 0;
628186734c1SRoger Quadros u32 hi_sw;
629186734c1SRoger Quadros u64 ns;
630186734c1SRoger Quadros
631186734c1SRoger Quadros /* There may be more than one pending requests */
632186734c1SRoger Quadros while (1) {
633186734c1SRoger Quadros ret = emac_get_tx_ts(emac, &tsr);
634186734c1SRoger Quadros if (ret) /* nothing more */
635186734c1SRoger Quadros break;
636186734c1SRoger Quadros
637186734c1SRoger Quadros if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS ||
638186734c1SRoger Quadros !emac->tx_ts_skb[tsr.cookie]) {
639186734c1SRoger Quadros netdev_err(emac->ndev, "Invalid TX TS cookie 0x%x\n",
640186734c1SRoger Quadros tsr.cookie);
641186734c1SRoger Quadros break;
642186734c1SRoger Quadros }
643186734c1SRoger Quadros
644186734c1SRoger Quadros skb = emac->tx_ts_skb[tsr.cookie];
645186734c1SRoger Quadros emac->tx_ts_skb[tsr.cookie] = NULL; /* free slot */
646186734c1SRoger Quadros if (!skb) {
647186734c1SRoger Quadros netdev_err(emac->ndev, "Driver Bug! got NULL skb\n");
648186734c1SRoger Quadros break;
649186734c1SRoger Quadros }
650186734c1SRoger Quadros
651186734c1SRoger Quadros hi_sw = readl(emac->prueth->shram.va +
652186734c1SRoger Quadros TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
653186734c1SRoger Quadros ns = icssg_ts_to_ns(hi_sw, tsr.hi_ts, tsr.lo_ts,
654186734c1SRoger Quadros IEP_DEFAULT_CYCLE_TIME_NS);
655186734c1SRoger Quadros
656186734c1SRoger Quadros memset(&ssh, 0, sizeof(ssh));
657186734c1SRoger Quadros ssh.hwtstamp = ns_to_ktime(ns);
658186734c1SRoger Quadros
659186734c1SRoger Quadros skb_tstamp_tx(skb, &ssh);
660186734c1SRoger Quadros dev_consume_skb_any(skb);
661186734c1SRoger Quadros
662186734c1SRoger Quadros if (atomic_dec_and_test(&emac->tx_ts_pending)) /* no more? */
663186734c1SRoger Quadros break;
664186734c1SRoger Quadros }
665186734c1SRoger Quadros }
666186734c1SRoger Quadros
prueth_tx_ts_cookie_get(struct prueth_emac * emac)667186734c1SRoger Quadros static int prueth_tx_ts_cookie_get(struct prueth_emac *emac)
668186734c1SRoger Quadros {
669186734c1SRoger Quadros int i;
670186734c1SRoger Quadros
671186734c1SRoger Quadros /* search and get the next free slot */
672186734c1SRoger Quadros for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
673186734c1SRoger Quadros if (!emac->tx_ts_skb[i]) {
674186734c1SRoger Quadros emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */
675186734c1SRoger Quadros return i;
676186734c1SRoger Quadros }
677186734c1SRoger Quadros }
678186734c1SRoger Quadros
679186734c1SRoger Quadros return -EBUSY;
680186734c1SRoger Quadros }
681186734c1SRoger Quadros
682128d5874SRoger Quadros /**
683128d5874SRoger Quadros * emac_ndo_start_xmit - EMAC Transmit function
684128d5874SRoger Quadros * @skb: SKB pointer
685128d5874SRoger Quadros * @ndev: EMAC network adapter
686128d5874SRoger Quadros *
687128d5874SRoger Quadros * Called by the system to transmit a packet - we queue the packet in
688128d5874SRoger Quadros * EMAC hardware transmit queue
689128d5874SRoger Quadros * Doesn't wait for completion we'll check for TX completion in
690128d5874SRoger Quadros * emac_tx_complete_packets().
691128d5874SRoger Quadros *
692128d5874SRoger Quadros * Return: enum netdev_tx
693128d5874SRoger Quadros */
emac_ndo_start_xmit(struct sk_buff * skb,struct net_device * ndev)694128d5874SRoger Quadros static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
695128d5874SRoger Quadros {
696128d5874SRoger Quadros struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc;
697128d5874SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
698128d5874SRoger Quadros struct netdev_queue *netif_txq;
699128d5874SRoger Quadros struct prueth_tx_chn *tx_chn;
700128d5874SRoger Quadros dma_addr_t desc_dma, buf_dma;
701128d5874SRoger Quadros int i, ret = 0, q_idx;
702186734c1SRoger Quadros bool in_tx_ts = 0;
703186734c1SRoger Quadros int tx_ts_cookie;
704128d5874SRoger Quadros void **swdata;
705128d5874SRoger Quadros u32 pkt_len;
706128d5874SRoger Quadros u32 *epib;
707128d5874SRoger Quadros
708128d5874SRoger Quadros pkt_len = skb_headlen(skb);
709128d5874SRoger Quadros q_idx = skb_get_queue_mapping(skb);
710128d5874SRoger Quadros
711128d5874SRoger Quadros tx_chn = &emac->tx_chns[q_idx];
712128d5874SRoger Quadros netif_txq = netdev_get_tx_queue(ndev, q_idx);
713128d5874SRoger Quadros
714128d5874SRoger Quadros /* Map the linear buffer */
715128d5874SRoger Quadros buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE);
716128d5874SRoger Quadros if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
717128d5874SRoger Quadros netdev_err(ndev, "tx: failed to map skb buffer\n");
718128d5874SRoger Quadros ret = NETDEV_TX_OK;
719128d5874SRoger Quadros goto drop_free_skb;
720128d5874SRoger Quadros }
721128d5874SRoger Quadros
722128d5874SRoger Quadros first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
723128d5874SRoger Quadros if (!first_desc) {
724128d5874SRoger Quadros netdev_dbg(ndev, "tx: failed to allocate descriptor\n");
725128d5874SRoger Quadros dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE);
726128d5874SRoger Quadros goto drop_stop_q_busy;
727128d5874SRoger Quadros }
728128d5874SRoger Quadros
729128d5874SRoger Quadros cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT,
730128d5874SRoger Quadros PRUETH_NAV_PS_DATA_SIZE);
731128d5874SRoger Quadros cppi5_hdesc_set_pkttype(first_desc, 0);
732128d5874SRoger Quadros epib = first_desc->epib;
733128d5874SRoger Quadros epib[0] = 0;
734128d5874SRoger Quadros epib[1] = 0;
735186734c1SRoger Quadros if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
736186734c1SRoger Quadros emac->tx_ts_enabled) {
737186734c1SRoger Quadros tx_ts_cookie = prueth_tx_ts_cookie_get(emac);
738186734c1SRoger Quadros if (tx_ts_cookie >= 0) {
739186734c1SRoger Quadros skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
740186734c1SRoger Quadros /* Request TX timestamp */
741186734c1SRoger Quadros epib[0] = (u32)tx_ts_cookie;
742186734c1SRoger Quadros epib[1] = 0x80000000; /* TX TS request */
743186734c1SRoger Quadros emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb);
744186734c1SRoger Quadros in_tx_ts = 1;
745186734c1SRoger Quadros }
746186734c1SRoger Quadros }
747128d5874SRoger Quadros
748128d5874SRoger Quadros /* set dst tag to indicate internal qid at the firmware which is at
749128d5874SRoger Quadros * bit8..bit15. bit0..bit7 indicates port num for directed
750128d5874SRoger Quadros * packets in case of switch mode operation
751128d5874SRoger Quadros */
752128d5874SRoger Quadros cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8)));
753128d5874SRoger Quadros k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
754128d5874SRoger Quadros cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len);
755128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(first_desc);
756128d5874SRoger Quadros *swdata = skb;
757128d5874SRoger Quadros
758128d5874SRoger Quadros /* Handle the case where skb is fragmented in pages */
759128d5874SRoger Quadros cur_desc = first_desc;
760128d5874SRoger Quadros for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
761128d5874SRoger Quadros skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
762128d5874SRoger Quadros u32 frag_size = skb_frag_size(frag);
763128d5874SRoger Quadros
764128d5874SRoger Quadros next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
765128d5874SRoger Quadros if (!next_desc) {
766128d5874SRoger Quadros netdev_err(ndev,
767128d5874SRoger Quadros "tx: failed to allocate frag. descriptor\n");
768186734c1SRoger Quadros goto free_desc_stop_q_busy_cleanup_tx_ts;
769128d5874SRoger Quadros }
770128d5874SRoger Quadros
771128d5874SRoger Quadros buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size,
772128d5874SRoger Quadros DMA_TO_DEVICE);
773128d5874SRoger Quadros if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
774128d5874SRoger Quadros netdev_err(ndev, "tx: Failed to map skb page\n");
775128d5874SRoger Quadros k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
776128d5874SRoger Quadros ret = NETDEV_TX_OK;
777186734c1SRoger Quadros goto cleanup_tx_ts;
778128d5874SRoger Quadros }
779128d5874SRoger Quadros
780128d5874SRoger Quadros cppi5_hdesc_reset_hbdesc(next_desc);
781128d5874SRoger Quadros k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
782128d5874SRoger Quadros cppi5_hdesc_attach_buf(next_desc,
783128d5874SRoger Quadros buf_dma, frag_size, buf_dma, frag_size);
784128d5874SRoger Quadros
785128d5874SRoger Quadros desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool,
786128d5874SRoger Quadros next_desc);
787128d5874SRoger Quadros k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma);
788128d5874SRoger Quadros cppi5_hdesc_link_hbdesc(cur_desc, desc_dma);
789128d5874SRoger Quadros
790128d5874SRoger Quadros pkt_len += frag_size;
791128d5874SRoger Quadros cur_desc = next_desc;
792128d5874SRoger Quadros }
793128d5874SRoger Quadros WARN_ON_ONCE(pkt_len != skb->len);
794128d5874SRoger Quadros
795128d5874SRoger Quadros /* report bql before sending packet */
796128d5874SRoger Quadros netdev_tx_sent_queue(netif_txq, pkt_len);
797128d5874SRoger Quadros
798128d5874SRoger Quadros cppi5_hdesc_set_pktlen(first_desc, pkt_len);
799128d5874SRoger Quadros desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc);
800128d5874SRoger Quadros /* cppi5_desc_dump(first_desc, 64); */
801128d5874SRoger Quadros
802128d5874SRoger Quadros skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */
803128d5874SRoger Quadros ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
804128d5874SRoger Quadros if (ret) {
805128d5874SRoger Quadros netdev_err(ndev, "tx: push failed: %d\n", ret);
806128d5874SRoger Quadros goto drop_free_descs;
807128d5874SRoger Quadros }
808128d5874SRoger Quadros
809186734c1SRoger Quadros if (in_tx_ts)
810186734c1SRoger Quadros atomic_inc(&emac->tx_ts_pending);
811186734c1SRoger Quadros
812128d5874SRoger Quadros if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) {
813128d5874SRoger Quadros netif_tx_stop_queue(netif_txq);
814128d5874SRoger Quadros /* Barrier, so that stop_queue visible to other cpus */
815128d5874SRoger Quadros smp_mb__after_atomic();
816128d5874SRoger Quadros
817128d5874SRoger Quadros if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
818128d5874SRoger Quadros MAX_SKB_FRAGS)
819128d5874SRoger Quadros netif_tx_wake_queue(netif_txq);
820128d5874SRoger Quadros }
821128d5874SRoger Quadros
822128d5874SRoger Quadros return NETDEV_TX_OK;
823128d5874SRoger Quadros
824186734c1SRoger Quadros cleanup_tx_ts:
825186734c1SRoger Quadros if (in_tx_ts) {
826186734c1SRoger Quadros dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
827186734c1SRoger Quadros emac->tx_ts_skb[tx_ts_cookie] = NULL;
828186734c1SRoger Quadros }
829186734c1SRoger Quadros
830128d5874SRoger Quadros drop_free_descs:
831128d5874SRoger Quadros prueth_xmit_free(tx_chn, first_desc);
832128d5874SRoger Quadros
833128d5874SRoger Quadros drop_free_skb:
834128d5874SRoger Quadros dev_kfree_skb_any(skb);
835128d5874SRoger Quadros
836128d5874SRoger Quadros /* error */
837128d5874SRoger Quadros ndev->stats.tx_dropped++;
838128d5874SRoger Quadros netdev_err(ndev, "tx: error: %d\n", ret);
839128d5874SRoger Quadros
840128d5874SRoger Quadros return ret;
841128d5874SRoger Quadros
842186734c1SRoger Quadros free_desc_stop_q_busy_cleanup_tx_ts:
843186734c1SRoger Quadros if (in_tx_ts) {
844186734c1SRoger Quadros dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
845186734c1SRoger Quadros emac->tx_ts_skb[tx_ts_cookie] = NULL;
846186734c1SRoger Quadros }
847128d5874SRoger Quadros prueth_xmit_free(tx_chn, first_desc);
848128d5874SRoger Quadros
849128d5874SRoger Quadros drop_stop_q_busy:
850128d5874SRoger Quadros netif_tx_stop_queue(netif_txq);
851128d5874SRoger Quadros return NETDEV_TX_BUSY;
852128d5874SRoger Quadros }
853128d5874SRoger Quadros
prueth_tx_cleanup(void * data,dma_addr_t desc_dma)854128d5874SRoger Quadros static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma)
855128d5874SRoger Quadros {
856128d5874SRoger Quadros struct prueth_tx_chn *tx_chn = data;
857128d5874SRoger Quadros struct cppi5_host_desc_t *desc_tx;
858128d5874SRoger Quadros struct sk_buff *skb;
859128d5874SRoger Quadros void **swdata;
860128d5874SRoger Quadros
861128d5874SRoger Quadros desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);
862128d5874SRoger Quadros swdata = cppi5_hdesc_get_swdata(desc_tx);
863128d5874SRoger Quadros skb = *(swdata);
864128d5874SRoger Quadros prueth_xmit_free(tx_chn, desc_tx);
865128d5874SRoger Quadros
866128d5874SRoger Quadros dev_kfree_skb_any(skb);
867128d5874SRoger Quadros }
868128d5874SRoger Quadros
prueth_tx_ts_irq(int irq,void * dev_id)869186734c1SRoger Quadros static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)
870186734c1SRoger Quadros {
871186734c1SRoger Quadros struct prueth_emac *emac = dev_id;
872186734c1SRoger Quadros
873186734c1SRoger Quadros /* currently only TX timestamp is being returned */
874186734c1SRoger Quadros tx_ts_work(emac);
875186734c1SRoger Quadros
876186734c1SRoger Quadros return IRQ_HANDLED;
877186734c1SRoger Quadros }
878186734c1SRoger Quadros
prueth_rx_irq(int irq,void * dev_id)879128d5874SRoger Quadros static irqreturn_t prueth_rx_irq(int irq, void *dev_id)
880128d5874SRoger Quadros {
881128d5874SRoger Quadros struct prueth_emac *emac = dev_id;
882128d5874SRoger Quadros
883128d5874SRoger Quadros disable_irq_nosync(irq);
884128d5874SRoger Quadros napi_schedule(&emac->napi_rx);
885128d5874SRoger Quadros
886128d5874SRoger Quadros return IRQ_HANDLED;
887128d5874SRoger Quadros }
888128d5874SRoger Quadros
889128d5874SRoger Quadros struct icssg_firmwares {
890128d5874SRoger Quadros char *pru;
891128d5874SRoger Quadros char *rtu;
892128d5874SRoger Quadros char *txpru;
893128d5874SRoger Quadros };
894128d5874SRoger Quadros
895128d5874SRoger Quadros static struct icssg_firmwares icssg_emac_firmwares[] = {
896128d5874SRoger Quadros {
897128d5874SRoger Quadros .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
898128d5874SRoger Quadros .rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
899128d5874SRoger Quadros .txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
900128d5874SRoger Quadros },
901128d5874SRoger Quadros {
902128d5874SRoger Quadros .pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
903128d5874SRoger Quadros .rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
904128d5874SRoger Quadros .txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
905128d5874SRoger Quadros }
906128d5874SRoger Quadros };
907128d5874SRoger Quadros
prueth_emac_start(struct prueth * prueth,struct prueth_emac * emac)908128d5874SRoger Quadros static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
909128d5874SRoger Quadros {
910128d5874SRoger Quadros struct icssg_firmwares *firmwares;
911128d5874SRoger Quadros struct device *dev = prueth->dev;
912128d5874SRoger Quadros int slice, ret;
913128d5874SRoger Quadros
914128d5874SRoger Quadros firmwares = icssg_emac_firmwares;
915128d5874SRoger Quadros
916128d5874SRoger Quadros slice = prueth_emac_slice(emac);
917128d5874SRoger Quadros if (slice < 0) {
918128d5874SRoger Quadros netdev_err(emac->ndev, "invalid port\n");
919128d5874SRoger Quadros return -EINVAL;
920128d5874SRoger Quadros }
921128d5874SRoger Quadros
922128d5874SRoger Quadros ret = icssg_config(prueth, emac, slice);
923128d5874SRoger Quadros if (ret)
924128d5874SRoger Quadros return ret;
925128d5874SRoger Quadros
926128d5874SRoger Quadros ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru);
927128d5874SRoger Quadros ret = rproc_boot(prueth->pru[slice]);
928128d5874SRoger Quadros if (ret) {
929128d5874SRoger Quadros dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
930128d5874SRoger Quadros return -EINVAL;
931128d5874SRoger Quadros }
932128d5874SRoger Quadros
933128d5874SRoger Quadros ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu);
934128d5874SRoger Quadros ret = rproc_boot(prueth->rtu[slice]);
935128d5874SRoger Quadros if (ret) {
936128d5874SRoger Quadros dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
937128d5874SRoger Quadros goto halt_pru;
938128d5874SRoger Quadros }
939128d5874SRoger Quadros
940128d5874SRoger Quadros ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru);
941128d5874SRoger Quadros ret = rproc_boot(prueth->txpru[slice]);
942128d5874SRoger Quadros if (ret) {
943128d5874SRoger Quadros dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);
944128d5874SRoger Quadros goto halt_rtu;
945128d5874SRoger Quadros }
946128d5874SRoger Quadros
947128d5874SRoger Quadros emac->fw_running = 1;
948128d5874SRoger Quadros return 0;
949128d5874SRoger Quadros
950128d5874SRoger Quadros halt_rtu:
951128d5874SRoger Quadros rproc_shutdown(prueth->rtu[slice]);
952128d5874SRoger Quadros
953128d5874SRoger Quadros halt_pru:
954128d5874SRoger Quadros rproc_shutdown(prueth->pru[slice]);
955128d5874SRoger Quadros
956128d5874SRoger Quadros return ret;
957128d5874SRoger Quadros }
958128d5874SRoger Quadros
prueth_emac_stop(struct prueth_emac * emac)959128d5874SRoger Quadros static void prueth_emac_stop(struct prueth_emac *emac)
960128d5874SRoger Quadros {
961128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
962128d5874SRoger Quadros int slice;
963128d5874SRoger Quadros
964128d5874SRoger Quadros switch (emac->port_id) {
965128d5874SRoger Quadros case PRUETH_PORT_MII0:
966128d5874SRoger Quadros slice = ICSS_SLICE0;
967128d5874SRoger Quadros break;
968128d5874SRoger Quadros case PRUETH_PORT_MII1:
969128d5874SRoger Quadros slice = ICSS_SLICE1;
970128d5874SRoger Quadros break;
971128d5874SRoger Quadros default:
972128d5874SRoger Quadros netdev_err(emac->ndev, "invalid port\n");
973128d5874SRoger Quadros return;
974128d5874SRoger Quadros }
975128d5874SRoger Quadros
976128d5874SRoger Quadros emac->fw_running = 0;
977128d5874SRoger Quadros rproc_shutdown(prueth->txpru[slice]);
978128d5874SRoger Quadros rproc_shutdown(prueth->rtu[slice]);
979128d5874SRoger Quadros rproc_shutdown(prueth->pru[slice]);
980128d5874SRoger Quadros }
981128d5874SRoger Quadros
prueth_cleanup_tx_ts(struct prueth_emac * emac)982186734c1SRoger Quadros static void prueth_cleanup_tx_ts(struct prueth_emac *emac)
983186734c1SRoger Quadros {
984186734c1SRoger Quadros int i;
985186734c1SRoger Quadros
986186734c1SRoger Quadros for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
987186734c1SRoger Quadros if (emac->tx_ts_skb[i]) {
988186734c1SRoger Quadros dev_kfree_skb_any(emac->tx_ts_skb[i]);
989186734c1SRoger Quadros emac->tx_ts_skb[i] = NULL;
990186734c1SRoger Quadros }
991186734c1SRoger Quadros }
992186734c1SRoger Quadros }
993186734c1SRoger Quadros
994128d5874SRoger Quadros /* called back by PHY layer if there is change in link state of hw port*/
emac_adjust_link(struct net_device * ndev)995128d5874SRoger Quadros static void emac_adjust_link(struct net_device *ndev)
996128d5874SRoger Quadros {
997128d5874SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
998128d5874SRoger Quadros struct phy_device *phydev = ndev->phydev;
999128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
1000128d5874SRoger Quadros bool new_state = false;
1001128d5874SRoger Quadros unsigned long flags;
1002128d5874SRoger Quadros
1003128d5874SRoger Quadros if (phydev->link) {
1004128d5874SRoger Quadros /* check the mode of operation - full/half duplex */
1005128d5874SRoger Quadros if (phydev->duplex != emac->duplex) {
1006128d5874SRoger Quadros new_state = true;
1007128d5874SRoger Quadros emac->duplex = phydev->duplex;
1008128d5874SRoger Quadros }
1009128d5874SRoger Quadros if (phydev->speed != emac->speed) {
1010128d5874SRoger Quadros new_state = true;
1011128d5874SRoger Quadros emac->speed = phydev->speed;
1012128d5874SRoger Quadros }
1013128d5874SRoger Quadros if (!emac->link) {
1014128d5874SRoger Quadros new_state = true;
1015128d5874SRoger Quadros emac->link = 1;
1016128d5874SRoger Quadros }
1017128d5874SRoger Quadros } else if (emac->link) {
1018128d5874SRoger Quadros new_state = true;
1019128d5874SRoger Quadros emac->link = 0;
1020128d5874SRoger Quadros
1021128d5874SRoger Quadros /* f/w should support 100 & 1000 */
1022128d5874SRoger Quadros emac->speed = SPEED_1000;
1023128d5874SRoger Quadros
1024128d5874SRoger Quadros /* half duplex may not be supported by f/w */
1025128d5874SRoger Quadros emac->duplex = DUPLEX_FULL;
1026128d5874SRoger Quadros }
1027128d5874SRoger Quadros
1028128d5874SRoger Quadros if (new_state) {
1029128d5874SRoger Quadros phy_print_status(phydev);
1030128d5874SRoger Quadros
1031128d5874SRoger Quadros /* update RGMII and MII configuration based on PHY negotiated
1032128d5874SRoger Quadros * values
1033128d5874SRoger Quadros */
1034128d5874SRoger Quadros if (emac->link) {
1035128d5874SRoger Quadros /* Set the RGMII cfg for gig en and full duplex */
1036128d5874SRoger Quadros icssg_update_rgmii_cfg(prueth->miig_rt, emac);
1037128d5874SRoger Quadros
1038128d5874SRoger Quadros /* update the Tx IPG based on 100M/1G speed */
1039128d5874SRoger Quadros spin_lock_irqsave(&emac->lock, flags);
1040128d5874SRoger Quadros icssg_config_ipg(emac);
1041128d5874SRoger Quadros spin_unlock_irqrestore(&emac->lock, flags);
1042128d5874SRoger Quadros icssg_config_set_speed(emac);
1043128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD);
1044128d5874SRoger Quadros
1045128d5874SRoger Quadros } else {
1046128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
1047128d5874SRoger Quadros }
1048128d5874SRoger Quadros }
1049128d5874SRoger Quadros
1050128d5874SRoger Quadros if (emac->link) {
1051128d5874SRoger Quadros /* reactivate the transmit queue */
1052128d5874SRoger Quadros netif_tx_wake_all_queues(ndev);
1053128d5874SRoger Quadros } else {
1054128d5874SRoger Quadros netif_tx_stop_all_queues(ndev);
1055186734c1SRoger Quadros prueth_cleanup_tx_ts(emac);
1056128d5874SRoger Quadros }
1057128d5874SRoger Quadros }
1058128d5874SRoger Quadros
emac_napi_rx_poll(struct napi_struct * napi_rx,int budget)1059128d5874SRoger Quadros static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget)
1060128d5874SRoger Quadros {
1061128d5874SRoger Quadros struct prueth_emac *emac = prueth_napi_to_emac(napi_rx);
1062128d5874SRoger Quadros int rx_flow = PRUETH_RX_FLOW_DATA;
1063128d5874SRoger Quadros int flow = PRUETH_MAX_RX_FLOWS;
1064128d5874SRoger Quadros int num_rx = 0;
1065128d5874SRoger Quadros int cur_budget;
1066128d5874SRoger Quadros int ret;
1067128d5874SRoger Quadros
1068128d5874SRoger Quadros while (flow--) {
1069128d5874SRoger Quadros cur_budget = budget - num_rx;
1070128d5874SRoger Quadros
1071128d5874SRoger Quadros while (cur_budget--) {
1072128d5874SRoger Quadros ret = emac_rx_packet(emac, flow);
1073128d5874SRoger Quadros if (ret)
1074128d5874SRoger Quadros break;
1075128d5874SRoger Quadros num_rx++;
1076128d5874SRoger Quadros }
1077128d5874SRoger Quadros
1078128d5874SRoger Quadros if (num_rx >= budget)
1079128d5874SRoger Quadros break;
1080128d5874SRoger Quadros }
1081128d5874SRoger Quadros
1082128d5874SRoger Quadros if (num_rx < budget && napi_complete_done(napi_rx, num_rx))
1083128d5874SRoger Quadros enable_irq(emac->rx_chns.irq[rx_flow]);
1084128d5874SRoger Quadros
1085128d5874SRoger Quadros return num_rx;
1086128d5874SRoger Quadros }
1087128d5874SRoger Quadros
prueth_prepare_rx_chan(struct prueth_emac * emac,struct prueth_rx_chn * chn,int buf_size)1088128d5874SRoger Quadros static int prueth_prepare_rx_chan(struct prueth_emac *emac,
1089128d5874SRoger Quadros struct prueth_rx_chn *chn,
1090128d5874SRoger Quadros int buf_size)
1091128d5874SRoger Quadros {
1092128d5874SRoger Quadros struct sk_buff *skb;
1093128d5874SRoger Quadros int i, ret;
1094128d5874SRoger Quadros
1095128d5874SRoger Quadros for (i = 0; i < chn->descs_num; i++) {
1096128d5874SRoger Quadros skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL);
1097128d5874SRoger Quadros if (!skb)
1098128d5874SRoger Quadros return -ENOMEM;
1099128d5874SRoger Quadros
1100128d5874SRoger Quadros ret = prueth_dma_rx_push(emac, skb, chn);
1101128d5874SRoger Quadros if (ret < 0) {
1102128d5874SRoger Quadros netdev_err(emac->ndev,
1103128d5874SRoger Quadros "cannot submit skb for rx chan %s ret %d\n",
1104128d5874SRoger Quadros chn->name, ret);
1105128d5874SRoger Quadros kfree_skb(skb);
1106128d5874SRoger Quadros return ret;
1107128d5874SRoger Quadros }
1108128d5874SRoger Quadros }
1109128d5874SRoger Quadros
1110128d5874SRoger Quadros return 0;
1111128d5874SRoger Quadros }
1112128d5874SRoger Quadros
prueth_reset_tx_chan(struct prueth_emac * emac,int ch_num,bool free_skb)1113128d5874SRoger Quadros static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num,
1114128d5874SRoger Quadros bool free_skb)
1115128d5874SRoger Quadros {
1116128d5874SRoger Quadros int i;
1117128d5874SRoger Quadros
1118128d5874SRoger Quadros for (i = 0; i < ch_num; i++) {
1119128d5874SRoger Quadros if (free_skb)
1120128d5874SRoger Quadros k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn,
1121128d5874SRoger Quadros &emac->tx_chns[i],
1122128d5874SRoger Quadros prueth_tx_cleanup);
1123128d5874SRoger Quadros k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn);
1124128d5874SRoger Quadros }
1125128d5874SRoger Quadros }
1126128d5874SRoger Quadros
prueth_reset_rx_chan(struct prueth_rx_chn * chn,int num_flows,bool disable)1127128d5874SRoger Quadros static void prueth_reset_rx_chan(struct prueth_rx_chn *chn,
1128128d5874SRoger Quadros int num_flows, bool disable)
1129128d5874SRoger Quadros {
1130128d5874SRoger Quadros int i;
1131128d5874SRoger Quadros
1132128d5874SRoger Quadros for (i = 0; i < num_flows; i++)
1133128d5874SRoger Quadros k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,
1134128d5874SRoger Quadros prueth_rx_cleanup, !!i);
1135128d5874SRoger Quadros if (disable)
1136128d5874SRoger Quadros k3_udma_glue_disable_rx_chn(chn->rx_chn);
1137128d5874SRoger Quadros }
1138128d5874SRoger Quadros
emac_phy_connect(struct prueth_emac * emac)1139128d5874SRoger Quadros static int emac_phy_connect(struct prueth_emac *emac)
1140128d5874SRoger Quadros {
1141128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
1142128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
1143128d5874SRoger Quadros /* connect PHY */
1144128d5874SRoger Quadros ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node,
1145128d5874SRoger Quadros &emac_adjust_link, 0,
1146128d5874SRoger Quadros emac->phy_if);
1147128d5874SRoger Quadros if (!ndev->phydev) {
1148128d5874SRoger Quadros dev_err(prueth->dev, "couldn't connect to phy %s\n",
1149128d5874SRoger Quadros emac->phy_node->full_name);
1150128d5874SRoger Quadros return -ENODEV;
1151128d5874SRoger Quadros }
1152128d5874SRoger Quadros
1153128d5874SRoger Quadros /* remove unsupported modes */
1154128d5874SRoger Quadros phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
1155128d5874SRoger Quadros phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
1156128d5874SRoger Quadros phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
1157128d5874SRoger Quadros phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
1158128d5874SRoger Quadros phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
1159128d5874SRoger Quadros
1160128d5874SRoger Quadros if (emac->phy_if == PHY_INTERFACE_MODE_MII)
1161128d5874SRoger Quadros phy_set_max_speed(ndev->phydev, SPEED_100);
1162128d5874SRoger Quadros
1163128d5874SRoger Quadros return 0;
1164128d5874SRoger Quadros }
1165128d5874SRoger Quadros
prueth_iep_gettime(void * clockops_data,struct ptp_system_timestamp * sts)1166186734c1SRoger Quadros static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts)
1167186734c1SRoger Quadros {
1168186734c1SRoger Quadros u32 hi_rollover_count, hi_rollover_count_r;
1169186734c1SRoger Quadros struct prueth_emac *emac = clockops_data;
1170186734c1SRoger Quadros struct prueth *prueth = emac->prueth;
1171186734c1SRoger Quadros void __iomem *fw_hi_r_count_addr;
1172186734c1SRoger Quadros void __iomem *fw_count_hi_addr;
1173186734c1SRoger Quadros u32 iepcount_hi, iepcount_hi_r;
1174186734c1SRoger Quadros unsigned long flags;
1175186734c1SRoger Quadros u32 iepcount_lo;
1176186734c1SRoger Quadros u64 ts = 0;
1177186734c1SRoger Quadros
1178186734c1SRoger Quadros fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET;
1179186734c1SRoger Quadros fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET;
1180186734c1SRoger Quadros
1181186734c1SRoger Quadros local_irq_save(flags);
1182186734c1SRoger Quadros do {
1183186734c1SRoger Quadros iepcount_hi = icss_iep_get_count_hi(emac->iep);
1184186734c1SRoger Quadros iepcount_hi += readl(fw_count_hi_addr);
1185186734c1SRoger Quadros hi_rollover_count = readl(fw_hi_r_count_addr);
1186186734c1SRoger Quadros ptp_read_system_prets(sts);
1187186734c1SRoger Quadros iepcount_lo = icss_iep_get_count_low(emac->iep);
1188186734c1SRoger Quadros ptp_read_system_postts(sts);
1189186734c1SRoger Quadros
1190186734c1SRoger Quadros iepcount_hi_r = icss_iep_get_count_hi(emac->iep);
1191186734c1SRoger Quadros iepcount_hi_r += readl(fw_count_hi_addr);
1192186734c1SRoger Quadros hi_rollover_count_r = readl(fw_hi_r_count_addr);
1193186734c1SRoger Quadros } while ((iepcount_hi_r != iepcount_hi) ||
1194186734c1SRoger Quadros (hi_rollover_count != hi_rollover_count_r));
1195186734c1SRoger Quadros local_irq_restore(flags);
1196186734c1SRoger Quadros
1197186734c1SRoger Quadros ts = ((u64)hi_rollover_count) << 23 | iepcount_hi;
1198186734c1SRoger Quadros ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo;
1199186734c1SRoger Quadros
1200186734c1SRoger Quadros return ts;
1201186734c1SRoger Quadros }
1202186734c1SRoger Quadros
prueth_iep_settime(void * clockops_data,u64 ns)1203186734c1SRoger Quadros static void prueth_iep_settime(void *clockops_data, u64 ns)
1204186734c1SRoger Quadros {
1205186734c1SRoger Quadros struct icssg_setclock_desc __iomem *sc_descp;
1206186734c1SRoger Quadros struct prueth_emac *emac = clockops_data;
1207186734c1SRoger Quadros struct icssg_setclock_desc sc_desc;
1208186734c1SRoger Quadros u64 cyclecount;
1209186734c1SRoger Quadros u32 cycletime;
1210186734c1SRoger Quadros int timeout;
1211186734c1SRoger Quadros
1212186734c1SRoger Quadros if (!emac->fw_running)
1213186734c1SRoger Quadros return;
1214186734c1SRoger Quadros
1215186734c1SRoger Quadros sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET;
1216186734c1SRoger Quadros
1217186734c1SRoger Quadros cycletime = IEP_DEFAULT_CYCLE_TIME_NS;
1218186734c1SRoger Quadros cyclecount = ns / cycletime;
1219186734c1SRoger Quadros
1220186734c1SRoger Quadros memset(&sc_desc, 0, sizeof(sc_desc));
1221186734c1SRoger Quadros sc_desc.margin = cycletime - 1000;
1222186734c1SRoger Quadros sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0);
1223186734c1SRoger Quadros sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32;
1224186734c1SRoger Quadros sc_desc.iepcount_set = ns % cycletime;
1225186734c1SRoger Quadros sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4
1226186734c1SRoger Quadros
1227186734c1SRoger Quadros memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc));
1228186734c1SRoger Quadros
1229186734c1SRoger Quadros writeb(1, &sc_descp->request);
1230186734c1SRoger Quadros
1231186734c1SRoger Quadros timeout = 5; /* fw should take 2-3 ms */
1232186734c1SRoger Quadros while (timeout--) {
1233186734c1SRoger Quadros if (readb(&sc_descp->acknowledgment))
1234186734c1SRoger Quadros return;
1235186734c1SRoger Quadros
1236186734c1SRoger Quadros usleep_range(500, 1000);
1237186734c1SRoger Quadros }
1238186734c1SRoger Quadros
1239186734c1SRoger Quadros dev_err(emac->prueth->dev, "settime timeout\n");
1240186734c1SRoger Quadros }
1241186734c1SRoger Quadros
prueth_perout_enable(void * clockops_data,struct ptp_perout_request * req,int on,u64 * cmp)1242186734c1SRoger Quadros static int prueth_perout_enable(void *clockops_data,
1243186734c1SRoger Quadros struct ptp_perout_request *req, int on,
1244186734c1SRoger Quadros u64 *cmp)
1245186734c1SRoger Quadros {
1246186734c1SRoger Quadros struct prueth_emac *emac = clockops_data;
1247186734c1SRoger Quadros u32 reduction_factor = 0, offset = 0;
1248186734c1SRoger Quadros struct timespec64 ts;
1249*c67ce71dSMeghana Malladi u64 current_cycle;
1250*c67ce71dSMeghana Malladi u64 start_offset;
1251186734c1SRoger Quadros u64 ns_period;
1252186734c1SRoger Quadros
1253186734c1SRoger Quadros if (!on)
1254186734c1SRoger Quadros return 0;
1255186734c1SRoger Quadros
1256186734c1SRoger Quadros /* Any firmware specific stuff for PPS/PEROUT handling */
1257186734c1SRoger Quadros ts.tv_sec = req->period.sec;
1258186734c1SRoger Quadros ts.tv_nsec = req->period.nsec;
1259186734c1SRoger Quadros ns_period = timespec64_to_ns(&ts);
1260186734c1SRoger Quadros
1261186734c1SRoger Quadros /* f/w doesn't support period less than cycle time */
1262186734c1SRoger Quadros if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS)
1263186734c1SRoger Quadros return -ENXIO;
1264186734c1SRoger Quadros
1265186734c1SRoger Quadros reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS;
1266186734c1SRoger Quadros offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS;
1267186734c1SRoger Quadros
1268186734c1SRoger Quadros /* f/w requires at least 1uS within a cycle so CMP
1269186734c1SRoger Quadros * can trigger after SYNC is enabled
1270186734c1SRoger Quadros */
1271186734c1SRoger Quadros if (offset < 5 * NSEC_PER_USEC)
1272186734c1SRoger Quadros offset = 5 * NSEC_PER_USEC;
1273186734c1SRoger Quadros
1274186734c1SRoger Quadros /* if offset is close to cycle time then we will miss
1275186734c1SRoger Quadros * the CMP event for last tick when IEP rolls over.
1276186734c1SRoger Quadros * In normal mode, IEP tick is 4ns.
1277186734c1SRoger Quadros * In slow compensation it could be 0ns or 8ns at
1278186734c1SRoger Quadros * every slow compensation cycle.
1279186734c1SRoger Quadros */
1280186734c1SRoger Quadros if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8)
1281186734c1SRoger Quadros offset = IEP_DEFAULT_CYCLE_TIME_NS - 8;
1282186734c1SRoger Quadros
1283186734c1SRoger Quadros /* we're in shadow mode so need to set upper 32-bits */
1284186734c1SRoger Quadros *cmp = (u64)offset << 32;
1285186734c1SRoger Quadros
1286186734c1SRoger Quadros writel(reduction_factor, emac->prueth->shram.va +
1287186734c1SRoger Quadros TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);
1288186734c1SRoger Quadros
1289*c67ce71dSMeghana Malladi current_cycle = icssg_read_time(emac->prueth->shram.va +
1290*c67ce71dSMeghana Malladi TIMESYNC_FW_WC_CYCLECOUNT_OFFSET);
1291*c67ce71dSMeghana Malladi
1292*c67ce71dSMeghana Malladi /* Rounding of current_cycle count to next second */
1293*c67ce71dSMeghana Malladi start_offset = roundup(current_cycle, MSEC_PER_SEC);
1294*c67ce71dSMeghana Malladi
1295*c67ce71dSMeghana Malladi hi_lo_writeq(start_offset, emac->prueth->shram.va +
1296186734c1SRoger Quadros TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
1297186734c1SRoger Quadros
1298186734c1SRoger Quadros return 0;
1299186734c1SRoger Quadros }
1300186734c1SRoger Quadros
1301186734c1SRoger Quadros const struct icss_iep_clockops prueth_iep_clockops = {
1302186734c1SRoger Quadros .settime = prueth_iep_settime,
1303186734c1SRoger Quadros .gettime = prueth_iep_gettime,
1304186734c1SRoger Quadros .perout_enable = prueth_perout_enable,
1305186734c1SRoger Quadros };
1306186734c1SRoger Quadros
1307128d5874SRoger Quadros /**
1308128d5874SRoger Quadros * emac_ndo_open - EMAC device open
1309128d5874SRoger Quadros * @ndev: network adapter device
1310128d5874SRoger Quadros *
1311128d5874SRoger Quadros * Called when system wants to start the interface.
1312128d5874SRoger Quadros *
1313128d5874SRoger Quadros * Return: 0 for a successful open, or appropriate error code
1314128d5874SRoger Quadros */
emac_ndo_open(struct net_device * ndev)1315128d5874SRoger Quadros static int emac_ndo_open(struct net_device *ndev)
1316128d5874SRoger Quadros {
1317128d5874SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
1318128d5874SRoger Quadros int ret, i, num_data_chn = emac->tx_ch_num;
1319128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
1320128d5874SRoger Quadros int slice = prueth_emac_slice(emac);
1321128d5874SRoger Quadros struct device *dev = prueth->dev;
1322128d5874SRoger Quadros int max_rx_flows;
1323128d5874SRoger Quadros int rx_flow;
1324128d5874SRoger Quadros
1325128d5874SRoger Quadros /* clear SMEM and MSMC settings for all slices */
1326128d5874SRoger Quadros if (!prueth->emacs_initialized) {
1327128d5874SRoger Quadros memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
1328128d5874SRoger Quadros memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
1329128d5874SRoger Quadros }
1330128d5874SRoger Quadros
1331128d5874SRoger Quadros /* set h/w MAC as user might have re-configured */
1332128d5874SRoger Quadros ether_addr_copy(emac->mac_addr, ndev->dev_addr);
1333128d5874SRoger Quadros
1334128d5874SRoger Quadros icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
1335128d5874SRoger Quadros icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
1336128d5874SRoger Quadros
1337128d5874SRoger Quadros icssg_class_default(prueth->miig_rt, slice, 0);
1338128d5874SRoger Quadros
1339128d5874SRoger Quadros /* Notify the stack of the actual queue counts. */
1340128d5874SRoger Quadros ret = netif_set_real_num_tx_queues(ndev, num_data_chn);
1341128d5874SRoger Quadros if (ret) {
1342128d5874SRoger Quadros dev_err(dev, "cannot set real number of tx queues\n");
1343128d5874SRoger Quadros return ret;
1344128d5874SRoger Quadros }
1345128d5874SRoger Quadros
1346128d5874SRoger Quadros init_completion(&emac->cmd_complete);
1347128d5874SRoger Quadros ret = prueth_init_tx_chns(emac);
1348128d5874SRoger Quadros if (ret) {
1349128d5874SRoger Quadros dev_err(dev, "failed to init tx channel: %d\n", ret);
1350128d5874SRoger Quadros return ret;
1351128d5874SRoger Quadros }
1352128d5874SRoger Quadros
1353128d5874SRoger Quadros max_rx_flows = PRUETH_MAX_RX_FLOWS;
1354128d5874SRoger Quadros ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx",
1355128d5874SRoger Quadros max_rx_flows, PRUETH_MAX_RX_DESC);
1356128d5874SRoger Quadros if (ret) {
1357128d5874SRoger Quadros dev_err(dev, "failed to init rx channel: %d\n", ret);
1358128d5874SRoger Quadros goto cleanup_tx;
1359128d5874SRoger Quadros }
1360128d5874SRoger Quadros
1361128d5874SRoger Quadros ret = prueth_ndev_add_tx_napi(emac);
1362128d5874SRoger Quadros if (ret)
1363128d5874SRoger Quadros goto cleanup_rx;
1364128d5874SRoger Quadros
1365128d5874SRoger Quadros /* we use only the highest priority flow for now i.e. @irq[3] */
1366128d5874SRoger Quadros rx_flow = PRUETH_RX_FLOW_DATA;
1367128d5874SRoger Quadros ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq,
1368128d5874SRoger Quadros IRQF_TRIGGER_HIGH, dev_name(dev), emac);
1369128d5874SRoger Quadros if (ret) {
1370128d5874SRoger Quadros dev_err(dev, "unable to request RX IRQ\n");
1371128d5874SRoger Quadros goto cleanup_napi;
1372128d5874SRoger Quadros }
1373128d5874SRoger Quadros
1374128d5874SRoger Quadros /* reset and start PRU firmware */
1375128d5874SRoger Quadros ret = prueth_emac_start(prueth, emac);
1376128d5874SRoger Quadros if (ret)
1377128d5874SRoger Quadros goto free_rx_irq;
1378128d5874SRoger Quadros
1379128d5874SRoger Quadros icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);
1380128d5874SRoger Quadros
1381186734c1SRoger Quadros if (!prueth->emacs_initialized) {
1382186734c1SRoger Quadros ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
1383186734c1SRoger Quadros emac, IEP_DEFAULT_CYCLE_TIME_NS);
1384186734c1SRoger Quadros }
1385186734c1SRoger Quadros
1386186734c1SRoger Quadros ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq,
1387186734c1SRoger Quadros IRQF_ONESHOT, dev_name(dev), emac);
1388186734c1SRoger Quadros if (ret)
1389186734c1SRoger Quadros goto stop;
1390186734c1SRoger Quadros
1391128d5874SRoger Quadros /* Prepare RX */
1392128d5874SRoger Quadros ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE);
1393128d5874SRoger Quadros if (ret)
1394186734c1SRoger Quadros goto free_tx_ts_irq;
1395128d5874SRoger Quadros
1396128d5874SRoger Quadros ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn);
1397128d5874SRoger Quadros if (ret)
1398128d5874SRoger Quadros goto reset_rx_chn;
1399128d5874SRoger Quadros
1400128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++) {
1401128d5874SRoger Quadros ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn);
1402128d5874SRoger Quadros if (ret)
1403128d5874SRoger Quadros goto reset_tx_chan;
1404128d5874SRoger Quadros }
1405128d5874SRoger Quadros
1406128d5874SRoger Quadros /* Enable NAPI in Tx and Rx direction */
1407128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++)
1408128d5874SRoger Quadros napi_enable(&emac->tx_chns[i].napi_tx);
1409128d5874SRoger Quadros napi_enable(&emac->napi_rx);
1410128d5874SRoger Quadros
1411128d5874SRoger Quadros /* start PHY */
1412128d5874SRoger Quadros phy_start(ndev->phydev);
1413128d5874SRoger Quadros
1414128d5874SRoger Quadros prueth->emacs_initialized++;
1415128d5874SRoger Quadros
1416c1e10d5dSMD Danish Anwar queue_work(system_long_wq, &emac->stats_work.work);
1417c1e10d5dSMD Danish Anwar
1418128d5874SRoger Quadros return 0;
1419128d5874SRoger Quadros
1420128d5874SRoger Quadros reset_tx_chan:
1421128d5874SRoger Quadros /* Since interface is not yet up, there is wouldn't be
1422128d5874SRoger Quadros * any SKB for completion. So set false to free_skb
1423128d5874SRoger Quadros */
1424128d5874SRoger Quadros prueth_reset_tx_chan(emac, i, false);
1425128d5874SRoger Quadros reset_rx_chn:
1426128d5874SRoger Quadros prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false);
1427186734c1SRoger Quadros free_tx_ts_irq:
1428186734c1SRoger Quadros free_irq(emac->tx_ts_irq, emac);
1429128d5874SRoger Quadros stop:
1430128d5874SRoger Quadros prueth_emac_stop(emac);
1431128d5874SRoger Quadros free_rx_irq:
1432128d5874SRoger Quadros free_irq(emac->rx_chns.irq[rx_flow], emac);
1433128d5874SRoger Quadros cleanup_napi:
1434128d5874SRoger Quadros prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
1435128d5874SRoger Quadros cleanup_rx:
1436128d5874SRoger Quadros prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
1437128d5874SRoger Quadros cleanup_tx:
1438128d5874SRoger Quadros prueth_cleanup_tx_chns(emac);
1439128d5874SRoger Quadros
1440128d5874SRoger Quadros return ret;
1441128d5874SRoger Quadros }
1442128d5874SRoger Quadros
1443128d5874SRoger Quadros /**
1444128d5874SRoger Quadros * emac_ndo_stop - EMAC device stop
1445128d5874SRoger Quadros * @ndev: network adapter device
1446128d5874SRoger Quadros *
1447128d5874SRoger Quadros * Called when system wants to stop or down the interface.
1448128d5874SRoger Quadros *
1449128d5874SRoger Quadros * Return: Always 0 (Success)
1450128d5874SRoger Quadros */
emac_ndo_stop(struct net_device * ndev)1451128d5874SRoger Quadros static int emac_ndo_stop(struct net_device *ndev)
1452128d5874SRoger Quadros {
1453128d5874SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
1454128d5874SRoger Quadros struct prueth *prueth = emac->prueth;
1455128d5874SRoger Quadros int rx_flow = PRUETH_RX_FLOW_DATA;
1456128d5874SRoger Quadros int max_rx_flows;
1457128d5874SRoger Quadros int ret, i;
1458128d5874SRoger Quadros
1459128d5874SRoger Quadros /* inform the upper layers. */
1460128d5874SRoger Quadros netif_tx_stop_all_queues(ndev);
1461128d5874SRoger Quadros
1462128d5874SRoger Quadros /* block packets from wire */
1463128d5874SRoger Quadros if (ndev->phydev)
1464128d5874SRoger Quadros phy_stop(ndev->phydev);
1465128d5874SRoger Quadros
1466128d5874SRoger Quadros icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac));
1467128d5874SRoger Quadros
1468128d5874SRoger Quadros atomic_set(&emac->tdown_cnt, emac->tx_ch_num);
1469128d5874SRoger Quadros /* ensure new tdown_cnt value is visible */
1470128d5874SRoger Quadros smp_mb__after_atomic();
1471128d5874SRoger Quadros /* tear down and disable UDMA channels */
1472128d5874SRoger Quadros reinit_completion(&emac->tdown_complete);
1473128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++)
1474128d5874SRoger Quadros k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false);
1475128d5874SRoger Quadros
1476128d5874SRoger Quadros ret = wait_for_completion_timeout(&emac->tdown_complete,
1477128d5874SRoger Quadros msecs_to_jiffies(1000));
1478128d5874SRoger Quadros if (!ret)
1479128d5874SRoger Quadros netdev_err(ndev, "tx teardown timeout\n");
1480128d5874SRoger Quadros
1481128d5874SRoger Quadros prueth_reset_tx_chan(emac, emac->tx_ch_num, true);
1482128d5874SRoger Quadros for (i = 0; i < emac->tx_ch_num; i++)
1483128d5874SRoger Quadros napi_disable(&emac->tx_chns[i].napi_tx);
1484128d5874SRoger Quadros
1485128d5874SRoger Quadros max_rx_flows = PRUETH_MAX_RX_FLOWS;
1486128d5874SRoger Quadros k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true);
1487128d5874SRoger Quadros
1488128d5874SRoger Quadros prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true);
1489128d5874SRoger Quadros
1490128d5874SRoger Quadros napi_disable(&emac->napi_rx);
1491128d5874SRoger Quadros
1492128d5874SRoger Quadros cancel_work_sync(&emac->rx_mode_work);
1493128d5874SRoger Quadros
1494c1e10d5dSMD Danish Anwar /* Destroying the queued work in ndo_stop() */
1495c1e10d5dSMD Danish Anwar cancel_delayed_work_sync(&emac->stats_work);
1496c1e10d5dSMD Danish Anwar
1497128d5874SRoger Quadros /* stop PRUs */
1498128d5874SRoger Quadros prueth_emac_stop(emac);
1499128d5874SRoger Quadros
1500186734c1SRoger Quadros if (prueth->emacs_initialized == 1)
1501186734c1SRoger Quadros icss_iep_exit(emac->iep);
1502186734c1SRoger Quadros
1503186734c1SRoger Quadros /* stop PRUs */
1504186734c1SRoger Quadros prueth_emac_stop(emac);
1505186734c1SRoger Quadros
1506186734c1SRoger Quadros free_irq(emac->tx_ts_irq, emac);
1507186734c1SRoger Quadros
1508128d5874SRoger Quadros free_irq(emac->rx_chns.irq[rx_flow], emac);
1509128d5874SRoger Quadros prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
1510128d5874SRoger Quadros prueth_cleanup_tx_chns(emac);
1511128d5874SRoger Quadros
1512128d5874SRoger Quadros prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
1513128d5874SRoger Quadros prueth_cleanup_tx_chns(emac);
1514128d5874SRoger Quadros
1515128d5874SRoger Quadros prueth->emacs_initialized--;
1516128d5874SRoger Quadros
1517128d5874SRoger Quadros return 0;
1518128d5874SRoger Quadros }
1519128d5874SRoger Quadros
emac_ndo_tx_timeout(struct net_device * ndev,unsigned int txqueue)1520128d5874SRoger Quadros static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)
1521128d5874SRoger Quadros {
1522128d5874SRoger Quadros ndev->stats.tx_errors++;
1523128d5874SRoger Quadros }
1524128d5874SRoger Quadros
emac_ndo_set_rx_mode_work(struct work_struct * work)1525128d5874SRoger Quadros static void emac_ndo_set_rx_mode_work(struct work_struct *work)
1526128d5874SRoger Quadros {
1527128d5874SRoger Quadros struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work);
1528128d5874SRoger Quadros struct net_device *ndev = emac->ndev;
1529128d5874SRoger Quadros bool promisc, allmulti;
1530128d5874SRoger Quadros
1531128d5874SRoger Quadros if (!netif_running(ndev))
1532128d5874SRoger Quadros return;
1533128d5874SRoger Quadros
1534128d5874SRoger Quadros promisc = ndev->flags & IFF_PROMISC;
1535128d5874SRoger Quadros allmulti = ndev->flags & IFF_ALLMULTI;
1536128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_DISABLE);
1537128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_DISABLE);
1538128d5874SRoger Quadros
1539128d5874SRoger Quadros if (promisc) {
1540128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_ENABLE);
1541128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1542128d5874SRoger Quadros return;
1543128d5874SRoger Quadros }
1544128d5874SRoger Quadros
1545128d5874SRoger Quadros if (allmulti) {
1546128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1547128d5874SRoger Quadros return;
1548128d5874SRoger Quadros }
1549128d5874SRoger Quadros
1550128d5874SRoger Quadros if (!netdev_mc_empty(ndev)) {
1551128d5874SRoger Quadros emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1552128d5874SRoger Quadros return;
1553128d5874SRoger Quadros }
1554128d5874SRoger Quadros }
1555128d5874SRoger Quadros
1556128d5874SRoger Quadros /**
1557128d5874SRoger Quadros * emac_ndo_set_rx_mode - EMAC set receive mode function
1558128d5874SRoger Quadros * @ndev: The EMAC network adapter
1559128d5874SRoger Quadros *
1560128d5874SRoger Quadros * Called when system wants to set the receive mode of the device.
1561128d5874SRoger Quadros *
1562128d5874SRoger Quadros */
emac_ndo_set_rx_mode(struct net_device * ndev)1563128d5874SRoger Quadros static void emac_ndo_set_rx_mode(struct net_device *ndev)
1564128d5874SRoger Quadros {
1565128d5874SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
1566128d5874SRoger Quadros
1567128d5874SRoger Quadros queue_work(emac->cmd_wq, &emac->rx_mode_work);
1568128d5874SRoger Quadros }
1569128d5874SRoger Quadros
emac_set_ts_config(struct net_device * ndev,struct ifreq * ifr)1570186734c1SRoger Quadros static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr)
1571186734c1SRoger Quadros {
1572186734c1SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
1573186734c1SRoger Quadros struct hwtstamp_config config;
1574186734c1SRoger Quadros
1575186734c1SRoger Quadros if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
1576186734c1SRoger Quadros return -EFAULT;
1577186734c1SRoger Quadros
1578186734c1SRoger Quadros switch (config.tx_type) {
1579186734c1SRoger Quadros case HWTSTAMP_TX_OFF:
1580186734c1SRoger Quadros emac->tx_ts_enabled = 0;
1581186734c1SRoger Quadros break;
1582186734c1SRoger Quadros case HWTSTAMP_TX_ON:
1583186734c1SRoger Quadros emac->tx_ts_enabled = 1;
1584186734c1SRoger Quadros break;
1585186734c1SRoger Quadros default:
1586186734c1SRoger Quadros return -ERANGE;
1587186734c1SRoger Quadros }
1588186734c1SRoger Quadros
1589186734c1SRoger Quadros switch (config.rx_filter) {
1590186734c1SRoger Quadros case HWTSTAMP_FILTER_NONE:
1591186734c1SRoger Quadros emac->rx_ts_enabled = 0;
1592186734c1SRoger Quadros break;
1593186734c1SRoger Quadros case HWTSTAMP_FILTER_ALL:
1594186734c1SRoger Quadros case HWTSTAMP_FILTER_SOME:
1595186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
1596186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
1597186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
1598186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
1599186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
1600186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
1601186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
1602186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
1603186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
1604186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_EVENT:
1605186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_SYNC:
1606186734c1SRoger Quadros case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
1607186734c1SRoger Quadros case HWTSTAMP_FILTER_NTP_ALL:
1608186734c1SRoger Quadros emac->rx_ts_enabled = 1;
1609186734c1SRoger Quadros config.rx_filter = HWTSTAMP_FILTER_ALL;
1610186734c1SRoger Quadros break;
1611186734c1SRoger Quadros default:
1612186734c1SRoger Quadros return -ERANGE;
1613186734c1SRoger Quadros }
1614186734c1SRoger Quadros
1615186734c1SRoger Quadros return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1616186734c1SRoger Quadros -EFAULT : 0;
1617186734c1SRoger Quadros }
1618186734c1SRoger Quadros
emac_get_ts_config(struct net_device * ndev,struct ifreq * ifr)1619186734c1SRoger Quadros static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr)
1620186734c1SRoger Quadros {
1621186734c1SRoger Quadros struct prueth_emac *emac = netdev_priv(ndev);
1622186734c1SRoger Quadros struct hwtstamp_config config;
1623186734c1SRoger Quadros
1624186734c1SRoger Quadros config.flags = 0;
1625186734c1SRoger Quadros config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
1626186734c1SRoger Quadros config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
1627186734c1SRoger Quadros
1628186734c1SRoger Quadros return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1629186734c1SRoger Quadros -EFAULT : 0;
1630186734c1SRoger Quadros }
1631186734c1SRoger Quadros
emac_ndo_ioctl(struct net_device * ndev,struct ifreq * ifr,int cmd)1632128d5874SRoger Quadros static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
1633128d5874SRoger Quadros {
1634186734c1SRoger Quadros switch (cmd) {
1635186734c1SRoger Quadros case SIOCGHWTSTAMP:
1636186734c1SRoger Quadros return emac_get_ts_config(ndev, ifr);
1637186734c1SRoger Quadros case SIOCSHWTSTAMP:
1638186734c1SRoger Quadros return emac_set_ts_config(ndev, ifr);
1639186734c1SRoger Quadros default:
1640186734c1SRoger Quadros break;
1641186734c1SRoger Quadros }
1642186734c1SRoger Quadros
1643128d5874SRoger Quadros return phy_do_ioctl(ndev, ifr, cmd);
1644128d5874SRoger Quadros }
1645128d5874SRoger Quadros
emac_ndo_get_stats64(struct net_device * ndev,struct rtnl_link_stats64 * stats)1646c2f67d19SMD Danish Anwar static void emac_ndo_get_stats64(struct net_device *ndev,
1647c2f67d19SMD Danish Anwar struct rtnl_link_stats64 *stats)
1648c2f67d19SMD Danish Anwar {
1649c2f67d19SMD Danish Anwar struct prueth_emac *emac = netdev_priv(ndev);
1650c2f67d19SMD Danish Anwar
1651c2f67d19SMD Danish Anwar emac_update_hardware_stats(emac);
1652c2f67d19SMD Danish Anwar
1653c2f67d19SMD Danish Anwar stats->rx_packets = emac_get_stat_by_name(emac, "rx_packets");
1654c2f67d19SMD Danish Anwar stats->rx_bytes = emac_get_stat_by_name(emac, "rx_bytes");
1655c2f67d19SMD Danish Anwar stats->tx_packets = emac_get_stat_by_name(emac, "tx_packets");
1656c2f67d19SMD Danish Anwar stats->tx_bytes = emac_get_stat_by_name(emac, "tx_bytes");
1657c2f67d19SMD Danish Anwar stats->rx_crc_errors = emac_get_stat_by_name(emac, "rx_crc_errors");
1658c2f67d19SMD Danish Anwar stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");
1659c2f67d19SMD Danish Anwar stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames");
1660c2f67d19SMD Danish Anwar
1661c2f67d19SMD Danish Anwar stats->rx_errors = ndev->stats.rx_errors;
1662c2f67d19SMD Danish Anwar stats->rx_dropped = ndev->stats.rx_dropped;
1663c2f67d19SMD Danish Anwar stats->tx_errors = ndev->stats.tx_errors;
1664c2f67d19SMD Danish Anwar stats->tx_dropped = ndev->stats.tx_dropped;
1665c2f67d19SMD Danish Anwar }
1666c2f67d19SMD Danish Anwar
1667128d5874SRoger Quadros static const struct net_device_ops emac_netdev_ops = {
1668128d5874SRoger Quadros .ndo_open = emac_ndo_open,
1669128d5874SRoger Quadros .ndo_stop = emac_ndo_stop,
1670128d5874SRoger Quadros .ndo_start_xmit = emac_ndo_start_xmit,
1671128d5874SRoger Quadros .ndo_set_mac_address = eth_mac_addr,
1672128d5874SRoger Quadros .ndo_validate_addr = eth_validate_addr,
1673128d5874SRoger Quadros .ndo_tx_timeout = emac_ndo_tx_timeout,
1674128d5874SRoger Quadros .ndo_set_rx_mode = emac_ndo_set_rx_mode,
1675128d5874SRoger Quadros .ndo_eth_ioctl = emac_ndo_ioctl,
1676c2f67d19SMD Danish Anwar .ndo_get_stats64 = emac_ndo_get_stats64,
1677128d5874SRoger Quadros };
1678128d5874SRoger Quadros
1679128d5874SRoger Quadros /* get emac_port corresponding to eth_node name */
prueth_node_port(struct device_node * eth_node)1680128d5874SRoger Quadros static int prueth_node_port(struct device_node *eth_node)
1681128d5874SRoger Quadros {
1682128d5874SRoger Quadros u32 port_id;
1683128d5874SRoger Quadros int ret;
1684128d5874SRoger Quadros
1685128d5874SRoger Quadros ret = of_property_read_u32(eth_node, "reg", &port_id);
1686128d5874SRoger Quadros if (ret)
1687128d5874SRoger Quadros return ret;
1688128d5874SRoger Quadros
1689128d5874SRoger Quadros if (port_id == 0)
1690128d5874SRoger Quadros return PRUETH_PORT_MII0;
1691128d5874SRoger Quadros else if (port_id == 1)
1692128d5874SRoger Quadros return PRUETH_PORT_MII1;
1693128d5874SRoger Quadros else
1694128d5874SRoger Quadros return PRUETH_PORT_INVALID;
1695128d5874SRoger Quadros }
1696128d5874SRoger Quadros
1697128d5874SRoger Quadros /* get MAC instance corresponding to eth_node name */
prueth_node_mac(struct device_node * eth_node)1698128d5874SRoger Quadros static int prueth_node_mac(struct device_node *eth_node)
1699128d5874SRoger Quadros {
1700128d5874SRoger Quadros u32 port_id;
1701128d5874SRoger Quadros int ret;
1702128d5874SRoger Quadros
1703128d5874SRoger Quadros ret = of_property_read_u32(eth_node, "reg", &port_id);
1704128d5874SRoger Quadros if (ret)
1705128d5874SRoger Quadros return ret;
1706128d5874SRoger Quadros
1707128d5874SRoger Quadros if (port_id == 0)
1708128d5874SRoger Quadros return PRUETH_MAC0;
1709128d5874SRoger Quadros else if (port_id == 1)
1710128d5874SRoger Quadros return PRUETH_MAC1;
1711128d5874SRoger Quadros else
1712128d5874SRoger Quadros return PRUETH_MAC_INVALID;
1713128d5874SRoger Quadros }
1714128d5874SRoger Quadros
prueth_netdev_init(struct prueth * prueth,struct device_node * eth_node)1715128d5874SRoger Quadros static int prueth_netdev_init(struct prueth *prueth,
1716128d5874SRoger Quadros struct device_node *eth_node)
1717128d5874SRoger Quadros {
1718128d5874SRoger Quadros int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES;
1719128d5874SRoger Quadros struct prueth_emac *emac;
1720128d5874SRoger Quadros struct net_device *ndev;
1721128d5874SRoger Quadros enum prueth_port port;
1722186734c1SRoger Quadros const char *irq_name;
1723128d5874SRoger Quadros enum prueth_mac mac;
1724128d5874SRoger Quadros
1725128d5874SRoger Quadros port = prueth_node_port(eth_node);
1726128d5874SRoger Quadros if (port == PRUETH_PORT_INVALID)
1727128d5874SRoger Quadros return -EINVAL;
1728128d5874SRoger Quadros
1729128d5874SRoger Quadros mac = prueth_node_mac(eth_node);
1730128d5874SRoger Quadros if (mac == PRUETH_MAC_INVALID)
1731128d5874SRoger Quadros return -EINVAL;
1732128d5874SRoger Quadros
1733128d5874SRoger Quadros ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn);
1734128d5874SRoger Quadros if (!ndev)
1735128d5874SRoger Quadros return -ENOMEM;
1736128d5874SRoger Quadros
1737128d5874SRoger Quadros emac = netdev_priv(ndev);
1738128d5874SRoger Quadros emac->prueth = prueth;
1739128d5874SRoger Quadros emac->ndev = ndev;
1740128d5874SRoger Quadros emac->port_id = port;
1741128d5874SRoger Quadros emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq");
1742128d5874SRoger Quadros if (!emac->cmd_wq) {
1743128d5874SRoger Quadros ret = -ENOMEM;
1744128d5874SRoger Quadros goto free_ndev;
1745128d5874SRoger Quadros }
1746128d5874SRoger Quadros INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work);
1747128d5874SRoger Quadros
1748c1e10d5dSMD Danish Anwar INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler);
1749c1e10d5dSMD Danish Anwar
1750128d5874SRoger Quadros ret = pruss_request_mem_region(prueth->pruss,
1751128d5874SRoger Quadros port == PRUETH_PORT_MII0 ?
1752128d5874SRoger Quadros PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,
1753128d5874SRoger Quadros &emac->dram);
1754128d5874SRoger Quadros if (ret) {
1755128d5874SRoger Quadros dev_err(prueth->dev, "unable to get DRAM: %d\n", ret);
1756128d5874SRoger Quadros ret = -ENOMEM;
1757128d5874SRoger Quadros goto free_wq;
1758128d5874SRoger Quadros }
1759128d5874SRoger Quadros
1760128d5874SRoger Quadros emac->tx_ch_num = 1;
1761128d5874SRoger Quadros
1762186734c1SRoger Quadros irq_name = "tx_ts0";
1763186734c1SRoger Quadros if (emac->port_id == PRUETH_PORT_MII1)
1764186734c1SRoger Quadros irq_name = "tx_ts1";
1765186734c1SRoger Quadros emac->tx_ts_irq = platform_get_irq_byname_optional(prueth->pdev, irq_name);
1766186734c1SRoger Quadros if (emac->tx_ts_irq < 0) {
1767186734c1SRoger Quadros ret = dev_err_probe(prueth->dev, emac->tx_ts_irq, "could not get tx_ts_irq\n");
1768186734c1SRoger Quadros goto free;
1769186734c1SRoger Quadros }
1770186734c1SRoger Quadros
1771128d5874SRoger Quadros SET_NETDEV_DEV(ndev, prueth->dev);
1772128d5874SRoger Quadros spin_lock_init(&emac->lock);
1773128d5874SRoger Quadros mutex_init(&emac->cmd_lock);
1774128d5874SRoger Quadros
1775128d5874SRoger Quadros emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0);
1776128d5874SRoger Quadros if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) {
1777128d5874SRoger Quadros dev_err(prueth->dev, "couldn't find phy-handle\n");
1778128d5874SRoger Quadros ret = -ENODEV;
1779128d5874SRoger Quadros goto free;
1780128d5874SRoger Quadros } else if (of_phy_is_fixed_link(eth_node)) {
1781128d5874SRoger Quadros ret = of_phy_register_fixed_link(eth_node);
1782128d5874SRoger Quadros if (ret) {
1783128d5874SRoger Quadros ret = dev_err_probe(prueth->dev, ret,
1784128d5874SRoger Quadros "failed to register fixed-link phy\n");
1785128d5874SRoger Quadros goto free;
1786128d5874SRoger Quadros }
1787128d5874SRoger Quadros
1788128d5874SRoger Quadros emac->phy_node = eth_node;
1789128d5874SRoger Quadros }
1790128d5874SRoger Quadros
1791128d5874SRoger Quadros ret = of_get_phy_mode(eth_node, &emac->phy_if);
1792128d5874SRoger Quadros if (ret) {
1793128d5874SRoger Quadros dev_err(prueth->dev, "could not get phy-mode property\n");
1794128d5874SRoger Quadros goto free;
1795128d5874SRoger Quadros }
1796128d5874SRoger Quadros
1797128d5874SRoger Quadros if (emac->phy_if != PHY_INTERFACE_MODE_MII &&
1798128d5874SRoger Quadros !phy_interface_mode_is_rgmii(emac->phy_if)) {
1799128d5874SRoger Quadros dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if));
1800128d5874SRoger Quadros ret = -EINVAL;
1801128d5874SRoger Quadros goto free;
1802128d5874SRoger Quadros }
1803128d5874SRoger Quadros
1804128d5874SRoger Quadros /* AM65 SR2.0 has TX Internal delay always enabled by hardware
1805128d5874SRoger Quadros * and it is not possible to disable TX Internal delay. The below
1806128d5874SRoger Quadros * switch case block describes how we handle different phy modes
1807128d5874SRoger Quadros * based on hardware restriction.
1808128d5874SRoger Quadros */
1809128d5874SRoger Quadros switch (emac->phy_if) {
1810128d5874SRoger Quadros case PHY_INTERFACE_MODE_RGMII_ID:
1811128d5874SRoger Quadros emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID;
1812128d5874SRoger Quadros break;
1813128d5874SRoger Quadros case PHY_INTERFACE_MODE_RGMII_TXID:
1814128d5874SRoger Quadros emac->phy_if = PHY_INTERFACE_MODE_RGMII;
1815128d5874SRoger Quadros break;
1816128d5874SRoger Quadros case PHY_INTERFACE_MODE_RGMII:
1817128d5874SRoger Quadros case PHY_INTERFACE_MODE_RGMII_RXID:
1818128d5874SRoger Quadros dev_err(prueth->dev, "RGMII mode without TX delay is not supported");
1819128d5874SRoger Quadros ret = -EINVAL;
1820128d5874SRoger Quadros goto free;
1821128d5874SRoger Quadros default:
1822128d5874SRoger Quadros break;
1823128d5874SRoger Quadros }
1824128d5874SRoger Quadros
1825128d5874SRoger Quadros /* get mac address from DT and set private and netdev addr */
1826128d5874SRoger Quadros ret = of_get_ethdev_address(eth_node, ndev);
1827128d5874SRoger Quadros if (!is_valid_ether_addr(ndev->dev_addr)) {
1828128d5874SRoger Quadros eth_hw_addr_random(ndev);
1829128d5874SRoger Quadros dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
1830128d5874SRoger Quadros port, ndev->dev_addr);
1831128d5874SRoger Quadros }
1832128d5874SRoger Quadros ether_addr_copy(emac->mac_addr, ndev->dev_addr);
1833128d5874SRoger Quadros
1834128d5874SRoger Quadros ndev->min_mtu = PRUETH_MIN_PKT_SIZE;
1835128d5874SRoger Quadros ndev->max_mtu = PRUETH_MAX_MTU;
1836128d5874SRoger Quadros ndev->netdev_ops = &emac_netdev_ops;
18378fb86b0dSMD Danish Anwar ndev->ethtool_ops = &icssg_ethtool_ops;
1838128d5874SRoger Quadros ndev->hw_features = NETIF_F_SG;
1839128d5874SRoger Quadros ndev->features = ndev->hw_features;
1840128d5874SRoger Quadros
1841128d5874SRoger Quadros netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll);
1842128d5874SRoger Quadros prueth->emac[mac] = emac;
1843128d5874SRoger Quadros
1844128d5874SRoger Quadros return 0;
1845128d5874SRoger Quadros
1846128d5874SRoger Quadros free:
1847128d5874SRoger Quadros pruss_release_mem_region(prueth->pruss, &emac->dram);
1848128d5874SRoger Quadros free_wq:
1849128d5874SRoger Quadros destroy_workqueue(emac->cmd_wq);
1850128d5874SRoger Quadros free_ndev:
1851128d5874SRoger Quadros emac->ndev = NULL;
1852128d5874SRoger Quadros prueth->emac[mac] = NULL;
1853128d5874SRoger Quadros free_netdev(ndev);
1854128d5874SRoger Quadros
1855128d5874SRoger Quadros return ret;
1856128d5874SRoger Quadros }
1857128d5874SRoger Quadros
prueth_netdev_exit(struct prueth * prueth,struct device_node * eth_node)1858128d5874SRoger Quadros static void prueth_netdev_exit(struct prueth *prueth,
1859128d5874SRoger Quadros struct device_node *eth_node)
1860128d5874SRoger Quadros {
1861128d5874SRoger Quadros struct prueth_emac *emac;
1862128d5874SRoger Quadros enum prueth_mac mac;
1863128d5874SRoger Quadros
1864128d5874SRoger Quadros mac = prueth_node_mac(eth_node);
1865128d5874SRoger Quadros if (mac == PRUETH_MAC_INVALID)
1866128d5874SRoger Quadros return;
1867128d5874SRoger Quadros
1868128d5874SRoger Quadros emac = prueth->emac[mac];
1869128d5874SRoger Quadros if (!emac)
1870128d5874SRoger Quadros return;
1871128d5874SRoger Quadros
1872128d5874SRoger Quadros if (of_phy_is_fixed_link(emac->phy_node))
1873128d5874SRoger Quadros of_phy_deregister_fixed_link(emac->phy_node);
1874128d5874SRoger Quadros
1875128d5874SRoger Quadros netif_napi_del(&emac->napi_rx);
1876128d5874SRoger Quadros
1877128d5874SRoger Quadros pruss_release_mem_region(prueth->pruss, &emac->dram);
1878128d5874SRoger Quadros destroy_workqueue(emac->cmd_wq);
1879128d5874SRoger Quadros free_netdev(emac->ndev);
1880128d5874SRoger Quadros prueth->emac[mac] = NULL;
1881128d5874SRoger Quadros }
1882128d5874SRoger Quadros
prueth_get_cores(struct prueth * prueth,int slice)1883128d5874SRoger Quadros static int prueth_get_cores(struct prueth *prueth, int slice)
1884128d5874SRoger Quadros {
1885128d5874SRoger Quadros struct device *dev = prueth->dev;
1886128d5874SRoger Quadros enum pruss_pru_id pruss_id;
1887128d5874SRoger Quadros struct device_node *np;
1888128d5874SRoger Quadros int idx = -1, ret;
1889128d5874SRoger Quadros
1890128d5874SRoger Quadros np = dev->of_node;
1891128d5874SRoger Quadros
1892128d5874SRoger Quadros switch (slice) {
1893128d5874SRoger Quadros case ICSS_SLICE0:
1894128d5874SRoger Quadros idx = 0;
1895128d5874SRoger Quadros break;
1896128d5874SRoger Quadros case ICSS_SLICE1:
1897128d5874SRoger Quadros idx = 3;
1898128d5874SRoger Quadros break;
1899128d5874SRoger Quadros default:
1900128d5874SRoger Quadros return -EINVAL;
1901128d5874SRoger Quadros }
1902128d5874SRoger Quadros
1903128d5874SRoger Quadros prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id);
1904128d5874SRoger Quadros if (IS_ERR(prueth->pru[slice])) {
1905128d5874SRoger Quadros ret = PTR_ERR(prueth->pru[slice]);
1906128d5874SRoger Quadros prueth->pru[slice] = NULL;
1907128d5874SRoger Quadros return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice);
1908128d5874SRoger Quadros }
1909128d5874SRoger Quadros prueth->pru_id[slice] = pruss_id;
1910128d5874SRoger Quadros
1911128d5874SRoger Quadros idx++;
1912128d5874SRoger Quadros prueth->rtu[slice] = pru_rproc_get(np, idx, NULL);
1913128d5874SRoger Quadros if (IS_ERR(prueth->rtu[slice])) {
1914128d5874SRoger Quadros ret = PTR_ERR(prueth->rtu[slice]);
1915128d5874SRoger Quadros prueth->rtu[slice] = NULL;
1916128d5874SRoger Quadros return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice);
1917128d5874SRoger Quadros }
1918128d5874SRoger Quadros
1919128d5874SRoger Quadros idx++;
1920128d5874SRoger Quadros prueth->txpru[slice] = pru_rproc_get(np, idx, NULL);
1921128d5874SRoger Quadros if (IS_ERR(prueth->txpru[slice])) {
1922128d5874SRoger Quadros ret = PTR_ERR(prueth->txpru[slice]);
1923128d5874SRoger Quadros prueth->txpru[slice] = NULL;
1924128d5874SRoger Quadros return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice);
1925128d5874SRoger Quadros }
1926128d5874SRoger Quadros
1927128d5874SRoger Quadros return 0;
1928128d5874SRoger Quadros }
1929128d5874SRoger Quadros
prueth_put_cores(struct prueth * prueth,int slice)1930128d5874SRoger Quadros static void prueth_put_cores(struct prueth *prueth, int slice)
1931128d5874SRoger Quadros {
1932128d5874SRoger Quadros if (prueth->txpru[slice])
1933128d5874SRoger Quadros pru_rproc_put(prueth->txpru[slice]);
1934128d5874SRoger Quadros
1935128d5874SRoger Quadros if (prueth->rtu[slice])
1936128d5874SRoger Quadros pru_rproc_put(prueth->rtu[slice]);
1937128d5874SRoger Quadros
1938128d5874SRoger Quadros if (prueth->pru[slice])
1939128d5874SRoger Quadros pru_rproc_put(prueth->pru[slice]);
1940128d5874SRoger Quadros }
1941128d5874SRoger Quadros
1942128d5874SRoger Quadros static const struct of_device_id prueth_dt_match[];
1943128d5874SRoger Quadros
prueth_probe(struct platform_device * pdev)1944128d5874SRoger Quadros static int prueth_probe(struct platform_device *pdev)
1945128d5874SRoger Quadros {
1946128d5874SRoger Quadros struct device_node *eth_node, *eth_ports_node;
1947128d5874SRoger Quadros struct device_node *eth0_node = NULL;
1948128d5874SRoger Quadros struct device_node *eth1_node = NULL;
1949128d5874SRoger Quadros struct genpool_data_align gp_data = {
1950128d5874SRoger Quadros .align = SZ_64K,
1951128d5874SRoger Quadros };
1952128d5874SRoger Quadros const struct of_device_id *match;
1953128d5874SRoger Quadros struct device *dev = &pdev->dev;
1954128d5874SRoger Quadros struct device_node *np;
1955128d5874SRoger Quadros struct prueth *prueth;
1956128d5874SRoger Quadros struct pruss *pruss;
1957128d5874SRoger Quadros u32 msmc_ram_size;
1958128d5874SRoger Quadros int i, ret;
1959128d5874SRoger Quadros
1960128d5874SRoger Quadros np = dev->of_node;
1961128d5874SRoger Quadros
1962128d5874SRoger Quadros match = of_match_device(prueth_dt_match, dev);
1963128d5874SRoger Quadros if (!match)
1964128d5874SRoger Quadros return -ENODEV;
1965128d5874SRoger Quadros
1966128d5874SRoger Quadros prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
1967128d5874SRoger Quadros if (!prueth)
1968128d5874SRoger Quadros return -ENOMEM;
1969128d5874SRoger Quadros
1970128d5874SRoger Quadros dev_set_drvdata(dev, prueth);
1971128d5874SRoger Quadros prueth->pdev = pdev;
1972128d5874SRoger Quadros prueth->pdata = *(const struct prueth_pdata *)match->data;
1973128d5874SRoger Quadros
1974128d5874SRoger Quadros prueth->dev = dev;
1975128d5874SRoger Quadros eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
1976128d5874SRoger Quadros if (!eth_ports_node)
1977128d5874SRoger Quadros return -ENOENT;
1978128d5874SRoger Quadros
1979128d5874SRoger Quadros for_each_child_of_node(eth_ports_node, eth_node) {
1980128d5874SRoger Quadros u32 reg;
1981128d5874SRoger Quadros
1982128d5874SRoger Quadros if (strcmp(eth_node->name, "port"))
1983128d5874SRoger Quadros continue;
1984128d5874SRoger Quadros ret = of_property_read_u32(eth_node, "reg", ®);
1985128d5874SRoger Quadros if (ret < 0) {
1986128d5874SRoger Quadros dev_err(dev, "%pOF error reading port_id %d\n",
1987128d5874SRoger Quadros eth_node, ret);
1988128d5874SRoger Quadros }
1989128d5874SRoger Quadros
1990128d5874SRoger Quadros of_node_get(eth_node);
1991128d5874SRoger Quadros
1992128d5874SRoger Quadros if (reg == 0) {
1993128d5874SRoger Quadros eth0_node = eth_node;
1994128d5874SRoger Quadros if (!of_device_is_available(eth0_node)) {
1995128d5874SRoger Quadros of_node_put(eth0_node);
1996128d5874SRoger Quadros eth0_node = NULL;
1997128d5874SRoger Quadros }
1998128d5874SRoger Quadros } else if (reg == 1) {
1999128d5874SRoger Quadros eth1_node = eth_node;
2000128d5874SRoger Quadros if (!of_device_is_available(eth1_node)) {
2001128d5874SRoger Quadros of_node_put(eth1_node);
2002128d5874SRoger Quadros eth1_node = NULL;
2003128d5874SRoger Quadros }
2004128d5874SRoger Quadros } else {
2005128d5874SRoger Quadros dev_err(dev, "port reg should be 0 or 1\n");
2006128d5874SRoger Quadros }
2007128d5874SRoger Quadros }
2008128d5874SRoger Quadros
2009128d5874SRoger Quadros of_node_put(eth_ports_node);
2010128d5874SRoger Quadros
2011128d5874SRoger Quadros /* At least one node must be present and available else we fail */
2012128d5874SRoger Quadros if (!eth0_node && !eth1_node) {
2013128d5874SRoger Quadros dev_err(dev, "neither port0 nor port1 node available\n");
2014128d5874SRoger Quadros return -ENODEV;
2015128d5874SRoger Quadros }
2016128d5874SRoger Quadros
2017128d5874SRoger Quadros if (eth0_node == eth1_node) {
2018128d5874SRoger Quadros dev_err(dev, "port0 and port1 can't have same reg\n");
2019128d5874SRoger Quadros of_node_put(eth0_node);
2020128d5874SRoger Quadros return -ENODEV;
2021128d5874SRoger Quadros }
2022128d5874SRoger Quadros
2023128d5874SRoger Quadros prueth->eth_node[PRUETH_MAC0] = eth0_node;
2024128d5874SRoger Quadros prueth->eth_node[PRUETH_MAC1] = eth1_node;
2025128d5874SRoger Quadros
2026128d5874SRoger Quadros prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt");
2027128d5874SRoger Quadros if (IS_ERR(prueth->miig_rt)) {
2028128d5874SRoger Quadros dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n");
2029128d5874SRoger Quadros return -ENODEV;
2030128d5874SRoger Quadros }
2031128d5874SRoger Quadros
2032128d5874SRoger Quadros prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");
2033128d5874SRoger Quadros if (IS_ERR(prueth->mii_rt)) {
2034128d5874SRoger Quadros dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n");
2035128d5874SRoger Quadros return -ENODEV;
2036128d5874SRoger Quadros }
2037128d5874SRoger Quadros
2038128d5874SRoger Quadros if (eth0_node) {
2039128d5874SRoger Quadros ret = prueth_get_cores(prueth, ICSS_SLICE0);
2040128d5874SRoger Quadros if (ret)
2041128d5874SRoger Quadros goto put_cores;
2042128d5874SRoger Quadros }
2043128d5874SRoger Quadros
2044128d5874SRoger Quadros if (eth1_node) {
2045128d5874SRoger Quadros ret = prueth_get_cores(prueth, ICSS_SLICE1);
2046128d5874SRoger Quadros if (ret)
2047128d5874SRoger Quadros goto put_cores;
2048128d5874SRoger Quadros }
2049128d5874SRoger Quadros
2050128d5874SRoger Quadros pruss = pruss_get(eth0_node ?
2051128d5874SRoger Quadros prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]);
2052128d5874SRoger Quadros if (IS_ERR(pruss)) {
2053128d5874SRoger Quadros ret = PTR_ERR(pruss);
2054128d5874SRoger Quadros dev_err(dev, "unable to get pruss handle\n");
2055128d5874SRoger Quadros goto put_cores;
2056128d5874SRoger Quadros }
2057128d5874SRoger Quadros
2058128d5874SRoger Quadros prueth->pruss = pruss;
2059128d5874SRoger Quadros
2060128d5874SRoger Quadros ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2,
2061128d5874SRoger Quadros &prueth->shram);
2062128d5874SRoger Quadros if (ret) {
2063128d5874SRoger Quadros dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret);
2064920114bfSJan Kiszka goto put_pruss;
2065128d5874SRoger Quadros }
2066128d5874SRoger Quadros
2067128d5874SRoger Quadros prueth->sram_pool = of_gen_pool_get(np, "sram", 0);
2068128d5874SRoger Quadros if (!prueth->sram_pool) {
2069128d5874SRoger Quadros dev_err(dev, "unable to get SRAM pool\n");
2070128d5874SRoger Quadros ret = -ENODEV;
2071128d5874SRoger Quadros
2072128d5874SRoger Quadros goto put_mem;
2073128d5874SRoger Quadros }
2074128d5874SRoger Quadros
2075128d5874SRoger Quadros msmc_ram_size = MSMC_RAM_SIZE;
2076128d5874SRoger Quadros
2077128d5874SRoger Quadros /* NOTE: FW bug needs buffer base to be 64KB aligned */
2078128d5874SRoger Quadros prueth->msmcram.va =
2079128d5874SRoger Quadros (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool,
2080128d5874SRoger Quadros msmc_ram_size,
2081128d5874SRoger Quadros gen_pool_first_fit_align,
2082128d5874SRoger Quadros &gp_data);
2083128d5874SRoger Quadros
2084128d5874SRoger Quadros if (!prueth->msmcram.va) {
2085128d5874SRoger Quadros ret = -ENOMEM;
2086128d5874SRoger Quadros dev_err(dev, "unable to allocate MSMC resource\n");
2087128d5874SRoger Quadros goto put_mem;
2088128d5874SRoger Quadros }
2089128d5874SRoger Quadros prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool,
2090128d5874SRoger Quadros (unsigned long)prueth->msmcram.va);
2091128d5874SRoger Quadros prueth->msmcram.size = msmc_ram_size;
2092128d5874SRoger Quadros memset_io(prueth->msmcram.va, 0, msmc_ram_size);
2093128d5874SRoger Quadros dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa,
2094128d5874SRoger Quadros prueth->msmcram.va, prueth->msmcram.size);
2095128d5874SRoger Quadros
2096186734c1SRoger Quadros prueth->iep0 = icss_iep_get_idx(np, 0);
2097186734c1SRoger Quadros if (IS_ERR(prueth->iep0)) {
2098186734c1SRoger Quadros ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n");
2099186734c1SRoger Quadros prueth->iep0 = NULL;
2100186734c1SRoger Quadros goto free_pool;
2101186734c1SRoger Quadros }
2102186734c1SRoger Quadros
2103443a2367SGrygorii Strashko prueth->iep1 = icss_iep_get_idx(np, 1);
2104443a2367SGrygorii Strashko if (IS_ERR(prueth->iep1)) {
2105443a2367SGrygorii Strashko ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n");
210670151949SJan Kiszka goto put_iep0;
2107443a2367SGrygorii Strashko }
2108443a2367SGrygorii Strashko
2109443a2367SGrygorii Strashko if (prueth->pdata.quirk_10m_link_issue) {
2110443a2367SGrygorii Strashko /* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX
2111443a2367SGrygorii Strashko * traffic.
2112443a2367SGrygorii Strashko */
2113443a2367SGrygorii Strashko icss_iep_init_fw(prueth->iep1);
2114443a2367SGrygorii Strashko }
2115443a2367SGrygorii Strashko
2116128d5874SRoger Quadros /* setup netdev interfaces */
2117128d5874SRoger Quadros if (eth0_node) {
2118128d5874SRoger Quadros ret = prueth_netdev_init(prueth, eth0_node);
2119128d5874SRoger Quadros if (ret) {
2120128d5874SRoger Quadros dev_err_probe(dev, ret, "netdev init %s failed\n",
2121128d5874SRoger Quadros eth0_node->name);
2122443a2367SGrygorii Strashko goto exit_iep;
2123128d5874SRoger Quadros }
2124186734c1SRoger Quadros prueth->emac[PRUETH_MAC0]->iep = prueth->iep0;
2125128d5874SRoger Quadros }
2126128d5874SRoger Quadros
2127128d5874SRoger Quadros if (eth1_node) {
2128128d5874SRoger Quadros ret = prueth_netdev_init(prueth, eth1_node);
2129128d5874SRoger Quadros if (ret) {
2130128d5874SRoger Quadros dev_err_probe(dev, ret, "netdev init %s failed\n",
2131128d5874SRoger Quadros eth1_node->name);
2132128d5874SRoger Quadros goto netdev_exit;
2133128d5874SRoger Quadros }
2134186734c1SRoger Quadros
2135186734c1SRoger Quadros prueth->emac[PRUETH_MAC1]->iep = prueth->iep0;
2136128d5874SRoger Quadros }
2137128d5874SRoger Quadros
2138128d5874SRoger Quadros /* register the network devices */
2139128d5874SRoger Quadros if (eth0_node) {
2140128d5874SRoger Quadros ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);
2141128d5874SRoger Quadros if (ret) {
2142128d5874SRoger Quadros dev_err(dev, "can't register netdev for port MII0");
2143128d5874SRoger Quadros goto netdev_exit;
2144128d5874SRoger Quadros }
2145128d5874SRoger Quadros
2146128d5874SRoger Quadros prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev;
2147128d5874SRoger Quadros
21485cd17f0eSRomain Gantois ret = emac_phy_connect(prueth->emac[PRUETH_MAC0]);
21495cd17f0eSRomain Gantois if (ret) {
21505cd17f0eSRomain Gantois dev_err(dev,
21515cd17f0eSRomain Gantois "can't connect to MII0 PHY, error -%d", ret);
21525cd17f0eSRomain Gantois goto netdev_unregister;
21535cd17f0eSRomain Gantois }
2154128d5874SRoger Quadros phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev);
2155128d5874SRoger Quadros }
2156128d5874SRoger Quadros
2157128d5874SRoger Quadros if (eth1_node) {
2158128d5874SRoger Quadros ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);
2159128d5874SRoger Quadros if (ret) {
2160128d5874SRoger Quadros dev_err(dev, "can't register netdev for port MII1");
2161128d5874SRoger Quadros goto netdev_unregister;
2162128d5874SRoger Quadros }
2163128d5874SRoger Quadros
2164128d5874SRoger Quadros prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev;
21655cd17f0eSRomain Gantois ret = emac_phy_connect(prueth->emac[PRUETH_MAC1]);
21665cd17f0eSRomain Gantois if (ret) {
21675cd17f0eSRomain Gantois dev_err(dev,
21685cd17f0eSRomain Gantois "can't connect to MII1 PHY, error %d", ret);
21695cd17f0eSRomain Gantois goto netdev_unregister;
21705cd17f0eSRomain Gantois }
2171128d5874SRoger Quadros phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);
2172128d5874SRoger Quadros }
2173128d5874SRoger Quadros
2174128d5874SRoger Quadros dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
2175128d5874SRoger Quadros (!eth0_node || !eth1_node) ? "single" : "dual");
2176128d5874SRoger Quadros
2177128d5874SRoger Quadros if (eth1_node)
2178128d5874SRoger Quadros of_node_put(eth1_node);
2179128d5874SRoger Quadros if (eth0_node)
2180128d5874SRoger Quadros of_node_put(eth0_node);
2181128d5874SRoger Quadros return 0;
2182128d5874SRoger Quadros
2183128d5874SRoger Quadros netdev_unregister:
2184128d5874SRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) {
2185128d5874SRoger Quadros if (!prueth->registered_netdevs[i])
2186128d5874SRoger Quadros continue;
2187128d5874SRoger Quadros if (prueth->emac[i]->ndev->phydev) {
2188128d5874SRoger Quadros phy_disconnect(prueth->emac[i]->ndev->phydev);
2189128d5874SRoger Quadros prueth->emac[i]->ndev->phydev = NULL;
2190128d5874SRoger Quadros }
2191128d5874SRoger Quadros unregister_netdev(prueth->registered_netdevs[i]);
2192128d5874SRoger Quadros }
2193128d5874SRoger Quadros
2194128d5874SRoger Quadros netdev_exit:
2195128d5874SRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) {
2196128d5874SRoger Quadros eth_node = prueth->eth_node[i];
2197128d5874SRoger Quadros if (!eth_node)
2198128d5874SRoger Quadros continue;
2199128d5874SRoger Quadros
2200128d5874SRoger Quadros prueth_netdev_exit(prueth, eth_node);
2201128d5874SRoger Quadros }
2202128d5874SRoger Quadros
2203443a2367SGrygorii Strashko exit_iep:
2204443a2367SGrygorii Strashko if (prueth->pdata.quirk_10m_link_issue)
2205443a2367SGrygorii Strashko icss_iep_exit_fw(prueth->iep1);
220670151949SJan Kiszka icss_iep_put(prueth->iep1);
220770151949SJan Kiszka
220870151949SJan Kiszka put_iep0:
220970151949SJan Kiszka icss_iep_put(prueth->iep0);
221070151949SJan Kiszka prueth->iep0 = NULL;
221170151949SJan Kiszka prueth->iep1 = NULL;
2212443a2367SGrygorii Strashko
2213186734c1SRoger Quadros free_pool:
2214128d5874SRoger Quadros gen_pool_free(prueth->sram_pool,
2215128d5874SRoger Quadros (unsigned long)prueth->msmcram.va, msmc_ram_size);
2216128d5874SRoger Quadros
2217128d5874SRoger Quadros put_mem:
2218128d5874SRoger Quadros pruss_release_mem_region(prueth->pruss, &prueth->shram);
2219920114bfSJan Kiszka
2220920114bfSJan Kiszka put_pruss:
2221128d5874SRoger Quadros pruss_put(prueth->pruss);
2222128d5874SRoger Quadros
2223128d5874SRoger Quadros put_cores:
2224128d5874SRoger Quadros if (eth1_node) {
2225128d5874SRoger Quadros prueth_put_cores(prueth, ICSS_SLICE1);
2226128d5874SRoger Quadros of_node_put(eth1_node);
2227128d5874SRoger Quadros }
2228128d5874SRoger Quadros
2229128d5874SRoger Quadros if (eth0_node) {
2230128d5874SRoger Quadros prueth_put_cores(prueth, ICSS_SLICE0);
2231128d5874SRoger Quadros of_node_put(eth0_node);
2232128d5874SRoger Quadros }
2233128d5874SRoger Quadros
2234128d5874SRoger Quadros return ret;
2235128d5874SRoger Quadros }
2236128d5874SRoger Quadros
prueth_remove(struct platform_device * pdev)2237128d5874SRoger Quadros static void prueth_remove(struct platform_device *pdev)
2238128d5874SRoger Quadros {
2239128d5874SRoger Quadros struct prueth *prueth = platform_get_drvdata(pdev);
2240128d5874SRoger Quadros struct device_node *eth_node;
2241128d5874SRoger Quadros int i;
2242128d5874SRoger Quadros
2243128d5874SRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) {
2244128d5874SRoger Quadros if (!prueth->registered_netdevs[i])
2245128d5874SRoger Quadros continue;
2246128d5874SRoger Quadros phy_stop(prueth->emac[i]->ndev->phydev);
2247128d5874SRoger Quadros phy_disconnect(prueth->emac[i]->ndev->phydev);
2248128d5874SRoger Quadros prueth->emac[i]->ndev->phydev = NULL;
2249128d5874SRoger Quadros unregister_netdev(prueth->registered_netdevs[i]);
2250128d5874SRoger Quadros }
2251128d5874SRoger Quadros
2252128d5874SRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) {
2253128d5874SRoger Quadros eth_node = prueth->eth_node[i];
2254128d5874SRoger Quadros if (!eth_node)
2255128d5874SRoger Quadros continue;
2256128d5874SRoger Quadros
2257128d5874SRoger Quadros prueth_netdev_exit(prueth, eth_node);
2258128d5874SRoger Quadros }
2259128d5874SRoger Quadros
2260443a2367SGrygorii Strashko if (prueth->pdata.quirk_10m_link_issue)
2261443a2367SGrygorii Strashko icss_iep_exit_fw(prueth->iep1);
2262443a2367SGrygorii Strashko
2263443a2367SGrygorii Strashko icss_iep_put(prueth->iep1);
2264186734c1SRoger Quadros icss_iep_put(prueth->iep0);
2265186734c1SRoger Quadros
2266128d5874SRoger Quadros gen_pool_free(prueth->sram_pool,
2267128d5874SRoger Quadros (unsigned long)prueth->msmcram.va,
2268128d5874SRoger Quadros MSMC_RAM_SIZE);
2269128d5874SRoger Quadros
2270128d5874SRoger Quadros pruss_release_mem_region(prueth->pruss, &prueth->shram);
2271128d5874SRoger Quadros
2272128d5874SRoger Quadros pruss_put(prueth->pruss);
2273128d5874SRoger Quadros
2274128d5874SRoger Quadros if (prueth->eth_node[PRUETH_MAC1])
2275128d5874SRoger Quadros prueth_put_cores(prueth, ICSS_SLICE1);
2276128d5874SRoger Quadros
2277128d5874SRoger Quadros if (prueth->eth_node[PRUETH_MAC0])
2278128d5874SRoger Quadros prueth_put_cores(prueth, ICSS_SLICE0);
2279128d5874SRoger Quadros }
2280128d5874SRoger Quadros
2281a46750a1SMD Danish Anwar #ifdef CONFIG_PM_SLEEP
prueth_suspend(struct device * dev)2282a46750a1SMD Danish Anwar static int prueth_suspend(struct device *dev)
2283a46750a1SMD Danish Anwar {
2284a46750a1SMD Danish Anwar struct prueth *prueth = dev_get_drvdata(dev);
2285a46750a1SMD Danish Anwar struct net_device *ndev;
2286a46750a1SMD Danish Anwar int i, ret;
2287a46750a1SMD Danish Anwar
2288a46750a1SMD Danish Anwar for (i = 0; i < PRUETH_NUM_MACS; i++) {
2289a46750a1SMD Danish Anwar ndev = prueth->registered_netdevs[i];
2290a46750a1SMD Danish Anwar
2291a46750a1SMD Danish Anwar if (!ndev)
2292a46750a1SMD Danish Anwar continue;
2293a46750a1SMD Danish Anwar
2294a46750a1SMD Danish Anwar if (netif_running(ndev)) {
2295a46750a1SMD Danish Anwar netif_device_detach(ndev);
2296a46750a1SMD Danish Anwar ret = emac_ndo_stop(ndev);
2297a46750a1SMD Danish Anwar if (ret < 0) {
2298a46750a1SMD Danish Anwar netdev_err(ndev, "failed to stop: %d", ret);
2299a46750a1SMD Danish Anwar return ret;
2300a46750a1SMD Danish Anwar }
2301a46750a1SMD Danish Anwar }
2302a46750a1SMD Danish Anwar }
2303a46750a1SMD Danish Anwar
2304a46750a1SMD Danish Anwar return 0;
2305a46750a1SMD Danish Anwar }
2306a46750a1SMD Danish Anwar
prueth_resume(struct device * dev)2307a46750a1SMD Danish Anwar static int prueth_resume(struct device *dev)
2308a46750a1SMD Danish Anwar {
2309a46750a1SMD Danish Anwar struct prueth *prueth = dev_get_drvdata(dev);
2310a46750a1SMD Danish Anwar struct net_device *ndev;
2311a46750a1SMD Danish Anwar int i, ret;
2312a46750a1SMD Danish Anwar
2313a46750a1SMD Danish Anwar for (i = 0; i < PRUETH_NUM_MACS; i++) {
2314a46750a1SMD Danish Anwar ndev = prueth->registered_netdevs[i];
2315a46750a1SMD Danish Anwar
2316a46750a1SMD Danish Anwar if (!ndev)
2317a46750a1SMD Danish Anwar continue;
2318a46750a1SMD Danish Anwar
2319a46750a1SMD Danish Anwar if (netif_running(ndev)) {
2320a46750a1SMD Danish Anwar ret = emac_ndo_open(ndev);
2321a46750a1SMD Danish Anwar if (ret < 0) {
2322a46750a1SMD Danish Anwar netdev_err(ndev, "failed to start: %d", ret);
2323a46750a1SMD Danish Anwar return ret;
2324a46750a1SMD Danish Anwar }
2325a46750a1SMD Danish Anwar netif_device_attach(ndev);
2326a46750a1SMD Danish Anwar }
2327a46750a1SMD Danish Anwar }
2328a46750a1SMD Danish Anwar
2329a46750a1SMD Danish Anwar return 0;
2330a46750a1SMD Danish Anwar }
2331a46750a1SMD Danish Anwar #endif /* CONFIG_PM_SLEEP */
2332a46750a1SMD Danish Anwar
2333a46750a1SMD Danish Anwar static const struct dev_pm_ops prueth_dev_pm_ops = {
2334a46750a1SMD Danish Anwar SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume)
2335a46750a1SMD Danish Anwar };
2336a46750a1SMD Danish Anwar
2337128d5874SRoger Quadros static const struct prueth_pdata am654_icssg_pdata = {
2338128d5874SRoger Quadros .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
2339128d5874SRoger Quadros .quirk_10m_link_issue = 1,
2340128d5874SRoger Quadros };
2341128d5874SRoger Quadros
2342128d5874SRoger Quadros static const struct of_device_id prueth_dt_match[] = {
2343128d5874SRoger Quadros { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata },
2344128d5874SRoger Quadros { /* sentinel */ }
2345128d5874SRoger Quadros };
2346128d5874SRoger Quadros MODULE_DEVICE_TABLE(of, prueth_dt_match);
2347128d5874SRoger Quadros
2348128d5874SRoger Quadros static struct platform_driver prueth_driver = {
2349128d5874SRoger Quadros .probe = prueth_probe,
2350128d5874SRoger Quadros .remove_new = prueth_remove,
2351128d5874SRoger Quadros .driver = {
2352128d5874SRoger Quadros .name = "icssg-prueth",
2353128d5874SRoger Quadros .of_match_table = prueth_dt_match,
2354a46750a1SMD Danish Anwar .pm = &prueth_dev_pm_ops,
2355128d5874SRoger Quadros },
2356128d5874SRoger Quadros };
2357128d5874SRoger Quadros module_platform_driver(prueth_driver);
2358128d5874SRoger Quadros
2359128d5874SRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
2360128d5874SRoger Quadros MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");
2361128d5874SRoger Quadros MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver");
2362128d5874SRoger Quadros MODULE_LICENSE("GPL");
2363