xref: /linux/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
14c8566a1SRoger Quadros // SPDX-License-Identifier: GPL-2.0
24c8566a1SRoger Quadros /* Texas Instruments PRUETH Switch Driver
34c8566a1SRoger Quadros  *
44c8566a1SRoger Quadros  * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
54c8566a1SRoger Quadros  */
64c8566a1SRoger Quadros #include <linux/etherdevice.h>
74c8566a1SRoger Quadros #include <linux/kernel.h>
84c8566a1SRoger Quadros #include <linux/remoteproc.h>
94c8566a1SRoger Quadros #include <net/switchdev.h>
104c8566a1SRoger Quadros #include "icssm_prueth.h"
114c8566a1SRoger Quadros #include "icssm_prueth_switch.h"
124c8566a1SRoger Quadros #include "icssm_prueth_fdb_tbl.h"
134c8566a1SRoger Quadros 
144c8566a1SRoger Quadros #define FDB_IDX_TBL_ENTRY(n) (&prueth->fdb_tbl->index_a->index_tbl_entry[n])
154c8566a1SRoger Quadros 
164c8566a1SRoger Quadros #define FDB_MAC_TBL_ENTRY(n) (&prueth->fdb_tbl->mac_tbl_a->mac_tbl_entry[n])
174c8566a1SRoger Quadros 
184c8566a1SRoger Quadros #define FLAG_IS_STATIC	BIT(0)
194c8566a1SRoger Quadros #define FLAG_ACTIVE	BIT(1)
204c8566a1SRoger Quadros 
21eea65b87SRoger Quadros #define FDB_LEARN  1
22eea65b87SRoger Quadros #define FDB_PURGE  2
23eea65b87SRoger Quadros 
24eea65b87SRoger Quadros struct icssm_prueth_sw_fdb_work {
25eea65b87SRoger Quadros 	netdevice_tracker ndev_tracker;
26eea65b87SRoger Quadros 	struct work_struct work;
27eea65b87SRoger Quadros 	struct prueth_emac *emac;
28eea65b87SRoger Quadros 	u8 addr[ETH_ALEN];
29eea65b87SRoger Quadros 	int event;
30eea65b87SRoger Quadros };
31eea65b87SRoger Quadros 
32eca327aeSRoger Quadros const struct prueth_queue_info sw_queue_infos[][NUM_QUEUES] = {
33eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
34eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
35eca327aeSRoger Quadros 			P0_Q1_BUFFER_OFFSET,
36eca327aeSRoger Quadros 			P0_QUEUE_DESC_OFFSET,
37eca327aeSRoger Quadros 			P0_Q1_BD_OFFSET,
38eca327aeSRoger Quadros 			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
39eca327aeSRoger Quadros 		},
40eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
41eca327aeSRoger Quadros 			P0_Q2_BUFFER_OFFSET,
42eca327aeSRoger Quadros 			P0_QUEUE_DESC_OFFSET + 8,
43eca327aeSRoger Quadros 			P0_Q2_BD_OFFSET,
44eca327aeSRoger Quadros 			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
45eca327aeSRoger Quadros 		},
46eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
47eca327aeSRoger Quadros 			P0_Q3_BUFFER_OFFSET,
48eca327aeSRoger Quadros 			P0_QUEUE_DESC_OFFSET + 16,
49eca327aeSRoger Quadros 			P0_Q3_BD_OFFSET,
50eca327aeSRoger Quadros 			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
51eca327aeSRoger Quadros 		},
52eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
53eca327aeSRoger Quadros 			P0_Q4_BUFFER_OFFSET,
54eca327aeSRoger Quadros 			P0_QUEUE_DESC_OFFSET + 24,
55eca327aeSRoger Quadros 			P0_Q4_BD_OFFSET,
56eca327aeSRoger Quadros 			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
57eca327aeSRoger Quadros 		},
58eca327aeSRoger Quadros 	},
59eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
60eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
61eca327aeSRoger Quadros 			P1_Q1_BUFFER_OFFSET,
62eca327aeSRoger Quadros 			P1_Q1_BUFFER_OFFSET +
63eca327aeSRoger Quadros 				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
64eca327aeSRoger Quadros 			P1_Q1_BD_OFFSET,
65eca327aeSRoger Quadros 			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
66eca327aeSRoger Quadros 		},
67eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
68eca327aeSRoger Quadros 			P1_Q2_BUFFER_OFFSET,
69eca327aeSRoger Quadros 			P1_Q2_BUFFER_OFFSET +
70eca327aeSRoger Quadros 				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
71eca327aeSRoger Quadros 			P1_Q2_BD_OFFSET,
72eca327aeSRoger Quadros 			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
73eca327aeSRoger Quadros 		},
74eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
75eca327aeSRoger Quadros 			P1_Q3_BUFFER_OFFSET,
76eca327aeSRoger Quadros 			P1_Q3_BUFFER_OFFSET +
77eca327aeSRoger Quadros 				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
78eca327aeSRoger Quadros 			P1_Q3_BD_OFFSET,
79eca327aeSRoger Quadros 			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
80eca327aeSRoger Quadros 		},
81eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
82eca327aeSRoger Quadros 			P1_Q4_BUFFER_OFFSET,
83eca327aeSRoger Quadros 			P1_Q4_BUFFER_OFFSET +
84eca327aeSRoger Quadros 				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
85eca327aeSRoger Quadros 			P1_Q4_BD_OFFSET,
86eca327aeSRoger Quadros 			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
87eca327aeSRoger Quadros 		},
88eca327aeSRoger Quadros 	},
89eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
90eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
91eca327aeSRoger Quadros 			P2_Q1_BUFFER_OFFSET,
92eca327aeSRoger Quadros 			P2_Q1_BUFFER_OFFSET +
93eca327aeSRoger Quadros 				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
94eca327aeSRoger Quadros 			P2_Q1_BD_OFFSET,
95eca327aeSRoger Quadros 			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
96eca327aeSRoger Quadros 		},
97eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
98eca327aeSRoger Quadros 			P2_Q2_BUFFER_OFFSET,
99eca327aeSRoger Quadros 			P2_Q2_BUFFER_OFFSET +
100eca327aeSRoger Quadros 				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
101eca327aeSRoger Quadros 			P2_Q2_BD_OFFSET,
102eca327aeSRoger Quadros 			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
103eca327aeSRoger Quadros 		},
104eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
105eca327aeSRoger Quadros 			P2_Q3_BUFFER_OFFSET,
106eca327aeSRoger Quadros 			P2_Q3_BUFFER_OFFSET +
107eca327aeSRoger Quadros 				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
108eca327aeSRoger Quadros 			P2_Q3_BD_OFFSET,
109eca327aeSRoger Quadros 			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
110eca327aeSRoger Quadros 		},
111eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
112eca327aeSRoger Quadros 			P2_Q4_BUFFER_OFFSET,
113eca327aeSRoger Quadros 			P2_Q4_BUFFER_OFFSET +
114eca327aeSRoger Quadros 				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
115eca327aeSRoger Quadros 			P2_Q4_BD_OFFSET,
116eca327aeSRoger Quadros 			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
117eca327aeSRoger Quadros 		},
118eca327aeSRoger Quadros 	},
119eca327aeSRoger Quadros };
120eca327aeSRoger Quadros 
121eca327aeSRoger Quadros static const struct prueth_queue_info rx_queue_infos[][NUM_QUEUES] = {
122eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
123eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
124eca327aeSRoger Quadros 			P0_Q1_BUFFER_OFFSET,
125eca327aeSRoger Quadros 			HOST_QUEUE_DESC_OFFSET,
126eca327aeSRoger Quadros 			P0_Q1_BD_OFFSET,
127eca327aeSRoger Quadros 			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
128eca327aeSRoger Quadros 		},
129eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
130eca327aeSRoger Quadros 			P0_Q2_BUFFER_OFFSET,
131eca327aeSRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 8,
132eca327aeSRoger Quadros 			P0_Q2_BD_OFFSET,
133eca327aeSRoger Quadros 			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
134eca327aeSRoger Quadros 		},
135eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
136eca327aeSRoger Quadros 			P0_Q3_BUFFER_OFFSET,
137eca327aeSRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 16,
138eca327aeSRoger Quadros 			P0_Q3_BD_OFFSET,
139eca327aeSRoger Quadros 			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
140eca327aeSRoger Quadros 		},
141eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
142eca327aeSRoger Quadros 			P0_Q4_BUFFER_OFFSET,
143eca327aeSRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 24,
144eca327aeSRoger Quadros 			P0_Q4_BD_OFFSET,
145eca327aeSRoger Quadros 			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
146eca327aeSRoger Quadros 		},
147eca327aeSRoger Quadros 	},
148eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
149eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
150eca327aeSRoger Quadros 			P1_Q1_BUFFER_OFFSET,
151eca327aeSRoger Quadros 			P1_QUEUE_DESC_OFFSET,
152eca327aeSRoger Quadros 			P1_Q1_BD_OFFSET,
153eca327aeSRoger Quadros 			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
154eca327aeSRoger Quadros 		},
155eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
156eca327aeSRoger Quadros 			P1_Q2_BUFFER_OFFSET,
157eca327aeSRoger Quadros 			P1_QUEUE_DESC_OFFSET + 8,
158eca327aeSRoger Quadros 			P1_Q2_BD_OFFSET,
159eca327aeSRoger Quadros 			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
160eca327aeSRoger Quadros 		},
161eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
162eca327aeSRoger Quadros 			P1_Q3_BUFFER_OFFSET,
163eca327aeSRoger Quadros 			P1_QUEUE_DESC_OFFSET + 16,
164eca327aeSRoger Quadros 			P1_Q3_BD_OFFSET,
165eca327aeSRoger Quadros 			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
166eca327aeSRoger Quadros 		},
167eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
168eca327aeSRoger Quadros 			P1_Q4_BUFFER_OFFSET,
169eca327aeSRoger Quadros 			P1_QUEUE_DESC_OFFSET + 24,
170eca327aeSRoger Quadros 			P1_Q4_BD_OFFSET,
171eca327aeSRoger Quadros 			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
172eca327aeSRoger Quadros 		},
173eca327aeSRoger Quadros 	},
174eca327aeSRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
175eca327aeSRoger Quadros 		[PRUETH_QUEUE1] = {
176eca327aeSRoger Quadros 			P2_Q1_BUFFER_OFFSET,
177eca327aeSRoger Quadros 			P2_QUEUE_DESC_OFFSET,
178eca327aeSRoger Quadros 			P2_Q1_BD_OFFSET,
179eca327aeSRoger Quadros 			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
180eca327aeSRoger Quadros 		},
181eca327aeSRoger Quadros 		[PRUETH_QUEUE2] = {
182eca327aeSRoger Quadros 			P2_Q2_BUFFER_OFFSET,
183eca327aeSRoger Quadros 			P2_QUEUE_DESC_OFFSET + 8,
184eca327aeSRoger Quadros 			P2_Q2_BD_OFFSET,
185eca327aeSRoger Quadros 			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
186eca327aeSRoger Quadros 		},
187eca327aeSRoger Quadros 		[PRUETH_QUEUE3] = {
188eca327aeSRoger Quadros 			P2_Q3_BUFFER_OFFSET,
189eca327aeSRoger Quadros 			P2_QUEUE_DESC_OFFSET + 16,
190eca327aeSRoger Quadros 			P2_Q3_BD_OFFSET,
191eca327aeSRoger Quadros 			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
192eca327aeSRoger Quadros 		},
193eca327aeSRoger Quadros 		[PRUETH_QUEUE4] = {
194eca327aeSRoger Quadros 			P2_Q4_BUFFER_OFFSET,
195eca327aeSRoger Quadros 			P2_QUEUE_DESC_OFFSET + 24,
196eca327aeSRoger Quadros 			P2_Q4_BD_OFFSET,
197eca327aeSRoger Quadros 			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
198eca327aeSRoger Quadros 		},
199eca327aeSRoger Quadros 	},
200eca327aeSRoger Quadros };
201eca327aeSRoger Quadros 
2024c8566a1SRoger Quadros void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
2034c8566a1SRoger Quadros {
2044c8566a1SRoger Quadros 	if (prueth->emac_configured)
2054c8566a1SRoger Quadros 		return;
2064c8566a1SRoger Quadros 
2074c8566a1SRoger Quadros 	kfree(prueth->fdb_tbl);
2084c8566a1SRoger Quadros 	prueth->fdb_tbl = NULL;
2094c8566a1SRoger Quadros }
2104c8566a1SRoger Quadros 
2114c8566a1SRoger Quadros void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth)
2124c8566a1SRoger Quadros {
2134c8566a1SRoger Quadros 	struct fdb_tbl *t = prueth->fdb_tbl;
2144c8566a1SRoger Quadros 	void __iomem *sram_base;
2154c8566a1SRoger Quadros 	u8 val;
2164c8566a1SRoger Quadros 
2174c8566a1SRoger Quadros 	sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
2184c8566a1SRoger Quadros 
2194c8566a1SRoger Quadros 	t->index_a = sram_base + V2_1_FDB_TBL_OFFSET;
2204c8566a1SRoger Quadros 	t->mac_tbl_a = sram_base + FDB_MAC_TBL_OFFSET;
2214c8566a1SRoger Quadros 	t->port1_stp_cfg = sram_base + FDB_PORT1_STP_CFG_OFFSET;
2224c8566a1SRoger Quadros 	t->port2_stp_cfg = sram_base + FDB_PORT2_STP_CFG_OFFSET;
2234c8566a1SRoger Quadros 	t->flood_enable_flags = sram_base + FDB_FLOOD_ENABLE_FLAGS_OFFSET;
2244c8566a1SRoger Quadros 	t->locks = sram_base + FDB_LOCKS_OFFSET;
2254c8566a1SRoger Quadros 
2264c8566a1SRoger Quadros 	val = readb(t->flood_enable_flags);
2274c8566a1SRoger Quadros 	/* host_flood_enable = 1 */
2284c8566a1SRoger Quadros 	val |= BIT(0);
2294c8566a1SRoger Quadros 	/* port1_flood_enable = 1 */
2304c8566a1SRoger Quadros 	val |= BIT(1);
2314c8566a1SRoger Quadros 	/* port2_flood_enable = 1 */
2324c8566a1SRoger Quadros 	val |= BIT(2);
2334c8566a1SRoger Quadros 	writeb(val, t->flood_enable_flags);
2344c8566a1SRoger Quadros 
2354c8566a1SRoger Quadros 	writeb(0, &t->locks->host_lock);
2364c8566a1SRoger Quadros 	t->total_entries = 0;
2374c8566a1SRoger Quadros }
2384c8566a1SRoger Quadros 
2394c8566a1SRoger Quadros static u8 icssm_pru_lock_done(struct fdb_tbl *fdb_tbl)
2404c8566a1SRoger Quadros {
2414c8566a1SRoger Quadros 	return readb(&fdb_tbl->locks->pru_locks);
2424c8566a1SRoger Quadros }
2434c8566a1SRoger Quadros 
2444c8566a1SRoger Quadros static int icssm_prueth_sw_fdb_spin_lock(struct fdb_tbl *fdb_tbl)
2454c8566a1SRoger Quadros {
2464c8566a1SRoger Quadros 	u8 done;
2474c8566a1SRoger Quadros 	int ret;
2484c8566a1SRoger Quadros 
2494c8566a1SRoger Quadros 	/* Take the host lock */
2504c8566a1SRoger Quadros 	writeb(1, &fdb_tbl->locks->host_lock);
2514c8566a1SRoger Quadros 
2524c8566a1SRoger Quadros 	/* Wait for the PRUs to release their locks */
2534c8566a1SRoger Quadros 	ret = read_poll_timeout(icssm_pru_lock_done, done, done == 0,
2544c8566a1SRoger Quadros 				1, 10, false, fdb_tbl);
2554c8566a1SRoger Quadros 	if (ret == -ETIMEDOUT)
2564c8566a1SRoger Quadros 		writeb(0, &fdb_tbl->locks->host_lock);
2574c8566a1SRoger Quadros 
2584c8566a1SRoger Quadros 	return ret;
2594c8566a1SRoger Quadros }
2604c8566a1SRoger Quadros 
2614c8566a1SRoger Quadros static void icssm_prueth_sw_fdb_spin_unlock(struct fdb_tbl *fdb_tbl)
2624c8566a1SRoger Quadros {
2634c8566a1SRoger Quadros 	writeb(0, &fdb_tbl->locks->host_lock);
2644c8566a1SRoger Quadros }
2654c8566a1SRoger Quadros 
2664c8566a1SRoger Quadros static u8 icssm_prueth_sw_fdb_hash(const u8 *mac)
2674c8566a1SRoger Quadros {
2684c8566a1SRoger Quadros 	return (mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5]);
2694c8566a1SRoger Quadros }
2704c8566a1SRoger Quadros 
2714c8566a1SRoger Quadros static int
2724c8566a1SRoger Quadros icssm_prueth_sw_fdb_search(struct fdb_mac_tbl_array __iomem *mac_tbl,
2734c8566a1SRoger Quadros 			   struct fdb_index_tbl_entry __iomem *bucket_info,
2744c8566a1SRoger Quadros 			   const u8 *mac)
2754c8566a1SRoger Quadros {
2764c8566a1SRoger Quadros 	unsigned int bucket_entries, mac_tbl_idx;
2774c8566a1SRoger Quadros 	u8 tmp_mac[ETH_ALEN];
2784c8566a1SRoger Quadros 	int i;
2794c8566a1SRoger Quadros 
2804c8566a1SRoger Quadros 	mac_tbl_idx = readw(&bucket_info->bucket_idx);
2814c8566a1SRoger Quadros 	bucket_entries = readw(&bucket_info->bucket_entries);
2824c8566a1SRoger Quadros 	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
2834c8566a1SRoger Quadros 		memcpy_fromio(tmp_mac, mac_tbl->mac_tbl_entry[mac_tbl_idx].mac,
2844c8566a1SRoger Quadros 			      ETH_ALEN);
2854c8566a1SRoger Quadros 		if (ether_addr_equal(mac, tmp_mac))
2864c8566a1SRoger Quadros 			return mac_tbl_idx;
2874c8566a1SRoger Quadros 	}
2884c8566a1SRoger Quadros 
2894c8566a1SRoger Quadros 	return -ENODATA;
2904c8566a1SRoger Quadros }
2914c8566a1SRoger Quadros 
2924c8566a1SRoger Quadros static int icssm_prueth_sw_fdb_find_open_slot(struct fdb_tbl *fdb_tbl)
2934c8566a1SRoger Quadros {
2944c8566a1SRoger Quadros 	unsigned int i;
2954c8566a1SRoger Quadros 	u8 flags;
2964c8566a1SRoger Quadros 
2974c8566a1SRoger Quadros 	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
2984c8566a1SRoger Quadros 		flags = readb(&fdb_tbl->mac_tbl_a->mac_tbl_entry[i].flags);
2994c8566a1SRoger Quadros 		if (!(flags & FLAG_ACTIVE))
3004c8566a1SRoger Quadros 			break;
3014c8566a1SRoger Quadros 	}
3024c8566a1SRoger Quadros 
3034c8566a1SRoger Quadros 	return i;
3044c8566a1SRoger Quadros }
3054c8566a1SRoger Quadros 
3064c8566a1SRoger Quadros static int
3074c8566a1SRoger Quadros icssm_prueth_sw_find_fdb_insert(struct fdb_tbl *fdb, struct prueth *prueth,
3084c8566a1SRoger Quadros 				struct fdb_index_tbl_entry __iomem *bkt_info,
3094c8566a1SRoger Quadros 				const u8 *mac, const u8 port)
3104c8566a1SRoger Quadros {
3114c8566a1SRoger Quadros 	struct fdb_mac_tbl_array __iomem *mac_tbl = fdb->mac_tbl_a;
3124c8566a1SRoger Quadros 	unsigned int bucket_entries, mac_tbl_idx;
3134c8566a1SRoger Quadros 	struct fdb_mac_tbl_entry __iomem *e;
3144c8566a1SRoger Quadros 	u8 mac_from_hw[ETH_ALEN];
3154c8566a1SRoger Quadros 	s8 cmp;
3164c8566a1SRoger Quadros 	int i;
3174c8566a1SRoger Quadros 
3184c8566a1SRoger Quadros 	mac_tbl_idx = readw(&bkt_info->bucket_idx);
3194c8566a1SRoger Quadros 	bucket_entries = readw(&bkt_info->bucket_entries);
3204c8566a1SRoger Quadros 
3214c8566a1SRoger Quadros 	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
3224c8566a1SRoger Quadros 		e = &mac_tbl->mac_tbl_entry[mac_tbl_idx];
3234c8566a1SRoger Quadros 		memcpy_fromio(mac_from_hw, e->mac, ETH_ALEN);
3244c8566a1SRoger Quadros 		cmp = memcmp(mac, mac_from_hw, ETH_ALEN);
3254c8566a1SRoger Quadros 		if (cmp < 0) {
3264c8566a1SRoger Quadros 			return mac_tbl_idx;
3274c8566a1SRoger Quadros 		} else if (cmp == 0) {
3284c8566a1SRoger Quadros 			if (readb(&e->port) != port) {
3294c8566a1SRoger Quadros 				/* MAC is already in FDB, only port is
3304c8566a1SRoger Quadros 				 * different. So just update the port.
3314c8566a1SRoger Quadros 				 * Note: total_entries and bucket_entries
3324c8566a1SRoger Quadros 				 * remain the same.
3334c8566a1SRoger Quadros 				 */
3344c8566a1SRoger Quadros 				writeb(port, &e->port);
3354c8566a1SRoger Quadros 			}
3364c8566a1SRoger Quadros 
3374c8566a1SRoger Quadros 			/* MAC and port are the same, touch the fdb */
3384c8566a1SRoger Quadros 			writew(0, &e->age);
3394c8566a1SRoger Quadros 			return -EEXIST;
3404c8566a1SRoger Quadros 		}
3414c8566a1SRoger Quadros 	}
3424c8566a1SRoger Quadros 
3434c8566a1SRoger Quadros 	return mac_tbl_idx;
3444c8566a1SRoger Quadros }
3454c8566a1SRoger Quadros 
3464c8566a1SRoger Quadros static int
3474c8566a1SRoger Quadros icssm_prueth_sw_fdb_empty_slot_left(struct fdb_mac_tbl_array __iomem *mac_tbl,
3484c8566a1SRoger Quadros 				    unsigned int mac_tbl_idx)
3494c8566a1SRoger Quadros {
3504c8566a1SRoger Quadros 	u8 flags;
3514c8566a1SRoger Quadros 	int i;
3524c8566a1SRoger Quadros 
3534c8566a1SRoger Quadros 	for (i = mac_tbl_idx - 1; i > -1; i--) {
3544c8566a1SRoger Quadros 		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
3554c8566a1SRoger Quadros 		if (!(flags & FLAG_ACTIVE))
3564c8566a1SRoger Quadros 			break;
3574c8566a1SRoger Quadros 	}
3584c8566a1SRoger Quadros 
3594c8566a1SRoger Quadros 	return i;
3604c8566a1SRoger Quadros }
3614c8566a1SRoger Quadros 
3624c8566a1SRoger Quadros static int
3634c8566a1SRoger Quadros icssm_prueth_sw_fdb_empty_slot_right(struct fdb_mac_tbl_array __iomem *mac_tbl,
3644c8566a1SRoger Quadros 				     unsigned int mac_tbl_idx)
3654c8566a1SRoger Quadros {
3664c8566a1SRoger Quadros 	u8 flags;
3674c8566a1SRoger Quadros 	int i;
3684c8566a1SRoger Quadros 
3694c8566a1SRoger Quadros 	for (i = mac_tbl_idx; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
3704c8566a1SRoger Quadros 		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
3714c8566a1SRoger Quadros 		if (!(flags & FLAG_ACTIVE))
3724c8566a1SRoger Quadros 			return i;
3734c8566a1SRoger Quadros 	}
3744c8566a1SRoger Quadros 
3754c8566a1SRoger Quadros 	return -1;
3764c8566a1SRoger Quadros }
3774c8566a1SRoger Quadros 
3784c8566a1SRoger Quadros static void icssm_prueth_sw_fdb_move_range_left(struct prueth *prueth,
3794c8566a1SRoger Quadros 						u16 left, u16 right)
3804c8566a1SRoger Quadros {
3814c8566a1SRoger Quadros 	struct fdb_mac_tbl_entry entry;
3824c8566a1SRoger Quadros 	u32 sz = 0;
3834c8566a1SRoger Quadros 	u16 i;
3844c8566a1SRoger Quadros 
3854c8566a1SRoger Quadros 	sz = sizeof(struct fdb_mac_tbl_entry);
3864c8566a1SRoger Quadros 	for (i = left; i < right; i++) {
3874c8566a1SRoger Quadros 		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i + 1), sz);
3884c8566a1SRoger Quadros 		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
3894c8566a1SRoger Quadros 	}
3904c8566a1SRoger Quadros }
3914c8566a1SRoger Quadros 
3924c8566a1SRoger Quadros static void icssm_prueth_sw_fdb_move_range_right(struct prueth *prueth,
3934c8566a1SRoger Quadros 						 u16 left, u16 right)
3944c8566a1SRoger Quadros {
3954c8566a1SRoger Quadros 	struct fdb_mac_tbl_entry entry;
3964c8566a1SRoger Quadros 	u32 sz = 0;
3974c8566a1SRoger Quadros 	u16 i;
3984c8566a1SRoger Quadros 
3994c8566a1SRoger Quadros 	sz = sizeof(struct fdb_mac_tbl_entry);
4004c8566a1SRoger Quadros 	for (i = right; i > left; i--) {
4014c8566a1SRoger Quadros 		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i - 1), sz);
4024c8566a1SRoger Quadros 		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
4034c8566a1SRoger Quadros 	}
4044c8566a1SRoger Quadros }
4054c8566a1SRoger Quadros 
4064c8566a1SRoger Quadros static void icssm_prueth_sw_fdb_update_index_tbl(struct prueth *prueth,
4074c8566a1SRoger Quadros 						 u16 left, u16 right)
4084c8566a1SRoger Quadros {
4094c8566a1SRoger Quadros 	unsigned int hash, hash_prev;
4104c8566a1SRoger Quadros 	u8 mac[ETH_ALEN];
4114c8566a1SRoger Quadros 	unsigned int i;
4124c8566a1SRoger Quadros 
4134c8566a1SRoger Quadros 	/* To ensure we don't improperly update the
4144c8566a1SRoger Quadros 	 * bucket index, initialize with an invalid
4154c8566a1SRoger Quadros 	 * hash in case we are in leftmost slot
4164c8566a1SRoger Quadros 	 */
4174c8566a1SRoger Quadros 	hash_prev = 0xff;
4184c8566a1SRoger Quadros 
4194c8566a1SRoger Quadros 	if (left > 0) {
4204c8566a1SRoger Quadros 		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(left - 1)->mac, ETH_ALEN);
4214c8566a1SRoger Quadros 		hash_prev = icssm_prueth_sw_fdb_hash(mac);
4224c8566a1SRoger Quadros 	}
4234c8566a1SRoger Quadros 
4244c8566a1SRoger Quadros 	/* For each moved element, update the bucket index */
4254c8566a1SRoger Quadros 	for (i = left; i <= right; i++) {
4264c8566a1SRoger Quadros 		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac, ETH_ALEN);
4274c8566a1SRoger Quadros 		hash = icssm_prueth_sw_fdb_hash(mac);
4284c8566a1SRoger Quadros 
4294c8566a1SRoger Quadros 		/* Only need to update buckets once */
4304c8566a1SRoger Quadros 		if (hash != hash_prev)
4314c8566a1SRoger Quadros 			writew(i, &FDB_IDX_TBL_ENTRY(hash)->bucket_idx);
4324c8566a1SRoger Quadros 
4334c8566a1SRoger Quadros 		hash_prev = hash;
4344c8566a1SRoger Quadros 	}
4354c8566a1SRoger Quadros }
4364c8566a1SRoger Quadros 
4374c8566a1SRoger Quadros static struct fdb_mac_tbl_entry __iomem *
4384c8566a1SRoger Quadros icssm_prueth_sw_find_free_mac(struct prueth *prueth, struct fdb_index_tbl_entry
4394c8566a1SRoger Quadros 			      __iomem *bucket_info, u8 suggested_mac_tbl_idx,
4404c8566a1SRoger Quadros 			      bool *update_indexes, const u8 *mac)
4414c8566a1SRoger Quadros {
4424c8566a1SRoger Quadros 	s16 empty_slot_idx = 0, left = 0, right = 0;
4434c8566a1SRoger Quadros 	unsigned int mti = suggested_mac_tbl_idx;
4444c8566a1SRoger Quadros 	struct fdb_mac_tbl_array __iomem *mt;
4454c8566a1SRoger Quadros 	struct fdb_tbl *fdb;
4464c8566a1SRoger Quadros 	u8 flags;
4474c8566a1SRoger Quadros 
4484c8566a1SRoger Quadros 	fdb = prueth->fdb_tbl;
4494c8566a1SRoger Quadros 	mt = fdb->mac_tbl_a;
4504c8566a1SRoger Quadros 
4514c8566a1SRoger Quadros 	flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
4524c8566a1SRoger Quadros 	if (!(flags & FLAG_ACTIVE)) {
4534c8566a1SRoger Quadros 		/* Claim the entry */
4544c8566a1SRoger Quadros 		flags |= FLAG_ACTIVE;
4554c8566a1SRoger Quadros 		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
4564c8566a1SRoger Quadros 
4574c8566a1SRoger Quadros 		return FDB_MAC_TBL_ENTRY(mti);
4584c8566a1SRoger Quadros 	}
4594c8566a1SRoger Quadros 
4604c8566a1SRoger Quadros 	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES)
4614c8566a1SRoger Quadros 		return NULL;
4624c8566a1SRoger Quadros 
4634c8566a1SRoger Quadros 	empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_left(mt, mti);
4644c8566a1SRoger Quadros 	if (empty_slot_idx == -1) {
4654c8566a1SRoger Quadros 		/* Nothing available on the left. But table isn't full
4664c8566a1SRoger Quadros 		 * so there must be space to the right,
4674c8566a1SRoger Quadros 		 */
4684c8566a1SRoger Quadros 		empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_right(mt, mti);
4694c8566a1SRoger Quadros 
4704c8566a1SRoger Quadros 		/* Shift right */
4714c8566a1SRoger Quadros 		left = mti;
4724c8566a1SRoger Quadros 		right = empty_slot_idx;
4734c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_move_range_right(prueth, left, right);
4744c8566a1SRoger Quadros 
4754c8566a1SRoger Quadros 		/* Claim the entry */
4764c8566a1SRoger Quadros 		flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
4774c8566a1SRoger Quadros 		flags |= FLAG_ACTIVE;
4784c8566a1SRoger Quadros 		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
4794c8566a1SRoger Quadros 
4804c8566a1SRoger Quadros 		memcpy_toio(FDB_MAC_TBL_ENTRY(mti)->mac, mac, ETH_ALEN);
4814c8566a1SRoger Quadros 
4824c8566a1SRoger Quadros 		/* There is a chance we moved something in a
4834c8566a1SRoger Quadros 		 * different bucket, update index table
4844c8566a1SRoger Quadros 		 */
4854c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
4864c8566a1SRoger Quadros 
4874c8566a1SRoger Quadros 		return FDB_MAC_TBL_ENTRY(mti);
4884c8566a1SRoger Quadros 	}
4894c8566a1SRoger Quadros 
4904c8566a1SRoger Quadros 	if (empty_slot_idx == mti - 1) {
4914c8566a1SRoger Quadros 		/* There is space immediately left of the open slot,
4924c8566a1SRoger Quadros 		 * which means the inserted MAC address
4934c8566a1SRoger Quadros 		 * must be the lowest-valued MAC address in bucket.
4944c8566a1SRoger Quadros 		 * Update bucket pointer accordingly.
4954c8566a1SRoger Quadros 		 */
4964c8566a1SRoger Quadros 		writew(empty_slot_idx, &bucket_info->bucket_idx);
4974c8566a1SRoger Quadros 
4984c8566a1SRoger Quadros 		/* Claim the entry */
4994c8566a1SRoger Quadros 		flags = readb(&FDB_MAC_TBL_ENTRY(empty_slot_idx)->flags);
5004c8566a1SRoger Quadros 		flags |= FLAG_ACTIVE;
5014c8566a1SRoger Quadros 		writeb(flags, &FDB_MAC_TBL_ENTRY(empty_slot_idx)->flags);
5024c8566a1SRoger Quadros 
5034c8566a1SRoger Quadros 		return FDB_MAC_TBL_ENTRY(empty_slot_idx);
5044c8566a1SRoger Quadros 	}
5054c8566a1SRoger Quadros 
5064c8566a1SRoger Quadros 	/* There is empty space to the left, shift MAC table entries left */
5074c8566a1SRoger Quadros 	left = empty_slot_idx;
5084c8566a1SRoger Quadros 	right = mti - 1;
5094c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
5104c8566a1SRoger Quadros 
5114c8566a1SRoger Quadros 	/* Claim the entry */
5124c8566a1SRoger Quadros 	flags = readb(&FDB_MAC_TBL_ENTRY(mti - 1)->flags);
5134c8566a1SRoger Quadros 	flags |= FLAG_ACTIVE;
5144c8566a1SRoger Quadros 	writeb(flags, &FDB_MAC_TBL_ENTRY(mti - 1)->flags);
5154c8566a1SRoger Quadros 
5164c8566a1SRoger Quadros 	memcpy_toio(FDB_MAC_TBL_ENTRY(mti - 1)->mac, mac, ETH_ALEN);
5174c8566a1SRoger Quadros 
5184c8566a1SRoger Quadros 	/* There is a chance we moved something in a
5194c8566a1SRoger Quadros 	 * different bucket, update index table
5204c8566a1SRoger Quadros 	 */
5214c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
5224c8566a1SRoger Quadros 
5234c8566a1SRoger Quadros 	return FDB_MAC_TBL_ENTRY(mti - 1);
5244c8566a1SRoger Quadros }
5254c8566a1SRoger Quadros 
5264c8566a1SRoger Quadros static int icssm_prueth_sw_insert_fdb_entry(struct prueth_emac *emac,
5274c8566a1SRoger Quadros 					    const u8 *mac, u8 is_static)
5284c8566a1SRoger Quadros {
5294c8566a1SRoger Quadros 	struct fdb_index_tbl_entry __iomem *bucket_info;
5304c8566a1SRoger Quadros 	struct fdb_mac_tbl_entry __iomem *mac_info;
5314c8566a1SRoger Quadros 	struct prueth *prueth = emac->prueth;
5324c8566a1SRoger Quadros 	unsigned int hash_val, mac_tbl_idx;
5334c8566a1SRoger Quadros 	struct prueth_emac *other_emac;
5344c8566a1SRoger Quadros 	enum prueth_port other_port_id;
5354c8566a1SRoger Quadros 	int total_fdb_entries;
5364c8566a1SRoger Quadros 	struct fdb_tbl *fdb;
5374c8566a1SRoger Quadros 	u8 flags;
5384c8566a1SRoger Quadros 	s16 ret;
5394c8566a1SRoger Quadros 	int err;
5404c8566a1SRoger Quadros 	u16 val;
5414c8566a1SRoger Quadros 
5424c8566a1SRoger Quadros 	fdb = prueth->fdb_tbl;
5434c8566a1SRoger Quadros 	other_port_id = (emac->port_id == PRUETH_PORT_MII0) ?
5444c8566a1SRoger Quadros 			 PRUETH_PORT_MII1 : PRUETH_PORT_MII0;
5454c8566a1SRoger Quadros 
5464c8566a1SRoger Quadros 	other_emac = prueth->emac[other_port_id - 1];
5474c8566a1SRoger Quadros 	if (!other_emac)
5484c8566a1SRoger Quadros 		return -EINVAL;
5494c8566a1SRoger Quadros 
5504c8566a1SRoger Quadros 	err = icssm_prueth_sw_fdb_spin_lock(fdb);
5514c8566a1SRoger Quadros 	if (err) {
5524c8566a1SRoger Quadros 		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
5534c8566a1SRoger Quadros 		return err;
5544c8566a1SRoger Quadros 	}
5554c8566a1SRoger Quadros 
5564c8566a1SRoger Quadros 	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES) {
5574c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
5584c8566a1SRoger Quadros 		return -ENOMEM;
5594c8566a1SRoger Quadros 	}
5604c8566a1SRoger Quadros 
5614c8566a1SRoger Quadros 	if (ether_addr_equal(mac, emac->mac_addr) ||
5624c8566a1SRoger Quadros 	    (ether_addr_equal(mac, other_emac->mac_addr))) {
5634c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
5644c8566a1SRoger Quadros 		/* Don't insert fdb of own mac addr */
5654c8566a1SRoger Quadros 		return -EINVAL;
5664c8566a1SRoger Quadros 	}
5674c8566a1SRoger Quadros 
5684c8566a1SRoger Quadros 	/* Get the bucket that the mac belongs to */
5694c8566a1SRoger Quadros 	hash_val = icssm_prueth_sw_fdb_hash(mac);
5704c8566a1SRoger Quadros 	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
5714c8566a1SRoger Quadros 
5724c8566a1SRoger Quadros 	if (!readw(&bucket_info->bucket_entries)) {
5734c8566a1SRoger Quadros 		mac_tbl_idx = icssm_prueth_sw_fdb_find_open_slot(fdb);
5744c8566a1SRoger Quadros 		writew(mac_tbl_idx, &bucket_info->bucket_idx);
5754c8566a1SRoger Quadros 	}
5764c8566a1SRoger Quadros 
5774c8566a1SRoger Quadros 	ret = icssm_prueth_sw_find_fdb_insert(fdb, prueth, bucket_info, mac,
5784c8566a1SRoger Quadros 					      emac->port_id - 1);
5794c8566a1SRoger Quadros 	if (ret < 0) {
5804c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
5814c8566a1SRoger Quadros 		/* mac is already in fdb table */
5824c8566a1SRoger Quadros 		return 0;
5834c8566a1SRoger Quadros 	}
5844c8566a1SRoger Quadros 
5854c8566a1SRoger Quadros 	mac_tbl_idx = ret;
5864c8566a1SRoger Quadros 
5874c8566a1SRoger Quadros 	mac_info = icssm_prueth_sw_find_free_mac(prueth, bucket_info,
5884c8566a1SRoger Quadros 						 mac_tbl_idx, NULL,
5894c8566a1SRoger Quadros 						 mac);
5904c8566a1SRoger Quadros 	if (!mac_info) {
5914c8566a1SRoger Quadros 		/* Should not happen */
5924c8566a1SRoger Quadros 		dev_warn(prueth->dev, "OUT of FDB MEM\n");
5934c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
5944c8566a1SRoger Quadros 		return -ENOMEM;
5954c8566a1SRoger Quadros 	}
5964c8566a1SRoger Quadros 
5974c8566a1SRoger Quadros 	memcpy_toio(mac_info->mac, mac, ETH_ALEN);
5984c8566a1SRoger Quadros 	writew(0, &mac_info->age);
5994c8566a1SRoger Quadros 	writeb(emac->port_id - 1, &mac_info->port);
6004c8566a1SRoger Quadros 
6014c8566a1SRoger Quadros 	flags = readb(&mac_info->flags);
6024c8566a1SRoger Quadros 	if (is_static)
6034c8566a1SRoger Quadros 		flags |= FLAG_IS_STATIC;
6044c8566a1SRoger Quadros 	else
6054c8566a1SRoger Quadros 		flags &= ~FLAG_IS_STATIC;
6064c8566a1SRoger Quadros 
6074c8566a1SRoger Quadros 	/* bit 1 - active */
6084c8566a1SRoger Quadros 	flags |= FLAG_ACTIVE;
6094c8566a1SRoger Quadros 	writeb(flags, &mac_info->flags);
6104c8566a1SRoger Quadros 
6114c8566a1SRoger Quadros 	val = readw(&bucket_info->bucket_entries);
6124c8566a1SRoger Quadros 	val++;
6134c8566a1SRoger Quadros 	writew(val, &bucket_info->bucket_entries);
6144c8566a1SRoger Quadros 
6154c8566a1SRoger Quadros 	fdb->total_entries++;
6164c8566a1SRoger Quadros 
6174c8566a1SRoger Quadros 	total_fdb_entries = fdb->total_entries;
6184c8566a1SRoger Quadros 
6194c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_spin_unlock(fdb);
6204c8566a1SRoger Quadros 
6214c8566a1SRoger Quadros 	dev_dbg(prueth->dev, "added fdb: %pM port=%d total_entries=%u\n",
6224c8566a1SRoger Quadros 		mac, emac->port_id, total_fdb_entries);
6234c8566a1SRoger Quadros 
6244c8566a1SRoger Quadros 	return 0;
6254c8566a1SRoger Quadros }
6264c8566a1SRoger Quadros 
6274c8566a1SRoger Quadros static int icssm_prueth_sw_delete_fdb_entry(struct prueth_emac *emac,
6284c8566a1SRoger Quadros 					    const u8 *mac, u8 is_static)
6294c8566a1SRoger Quadros {
6304c8566a1SRoger Quadros 	struct fdb_index_tbl_entry __iomem *bucket_info;
6314c8566a1SRoger Quadros 	struct fdb_mac_tbl_entry __iomem *mac_info;
6324c8566a1SRoger Quadros 	struct fdb_mac_tbl_array __iomem *mt;
6334c8566a1SRoger Quadros 	unsigned int hash_val, mac_tbl_idx;
6344c8566a1SRoger Quadros 	unsigned int idx, entries;
6354c8566a1SRoger Quadros 	struct prueth *prueth;
6364c8566a1SRoger Quadros 	int total_fdb_entries;
6374c8566a1SRoger Quadros 	s16 ret, left, right;
6384c8566a1SRoger Quadros 	struct fdb_tbl *fdb;
6394c8566a1SRoger Quadros 	u8 flags;
6404c8566a1SRoger Quadros 	int err;
6414c8566a1SRoger Quadros 	u16 val;
6424c8566a1SRoger Quadros 
6434c8566a1SRoger Quadros 	prueth = emac->prueth;
6444c8566a1SRoger Quadros 	fdb = prueth->fdb_tbl;
6454c8566a1SRoger Quadros 	mt = fdb->mac_tbl_a;
6464c8566a1SRoger Quadros 
6474c8566a1SRoger Quadros 	err = icssm_prueth_sw_fdb_spin_lock(fdb);
6484c8566a1SRoger Quadros 	if (err) {
6494c8566a1SRoger Quadros 		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
6504c8566a1SRoger Quadros 		return err;
6514c8566a1SRoger Quadros 	}
6524c8566a1SRoger Quadros 
6534c8566a1SRoger Quadros 	if (fdb->total_entries == 0) {
6544c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
6554c8566a1SRoger Quadros 		return 0;
6564c8566a1SRoger Quadros 	}
6574c8566a1SRoger Quadros 
6584c8566a1SRoger Quadros 	/* Get the bucket that the mac belongs to */
6594c8566a1SRoger Quadros 	hash_val = icssm_prueth_sw_fdb_hash(mac);
6604c8566a1SRoger Quadros 	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
6614c8566a1SRoger Quadros 
6624c8566a1SRoger Quadros 	ret = icssm_prueth_sw_fdb_search(mt, bucket_info, mac);
6634c8566a1SRoger Quadros 	if (ret < 0) {
6644c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
6654c8566a1SRoger Quadros 		return ret;
6664c8566a1SRoger Quadros 	}
6674c8566a1SRoger Quadros 
6684c8566a1SRoger Quadros 	mac_tbl_idx = ret;
6694c8566a1SRoger Quadros 	mac_info = FDB_MAC_TBL_ENTRY(mac_tbl_idx);
6704c8566a1SRoger Quadros 
6714c8566a1SRoger Quadros 	/* Shift all elements in bucket to the left. No need to
6724c8566a1SRoger Quadros 	 * update index table since only shifting within bucket.
6734c8566a1SRoger Quadros 	 */
6744c8566a1SRoger Quadros 	left = mac_tbl_idx;
6754c8566a1SRoger Quadros 	idx = readw(&bucket_info->bucket_idx);
6764c8566a1SRoger Quadros 	entries = readw(&bucket_info->bucket_entries);
6774c8566a1SRoger Quadros 	right = idx + entries - 1;
6784c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
6794c8566a1SRoger Quadros 
6804c8566a1SRoger Quadros 	/* Remove end of bucket from table */
6814c8566a1SRoger Quadros 	mac_info = FDB_MAC_TBL_ENTRY(right);
6824c8566a1SRoger Quadros 	flags = readb(&mac_info->flags);
6834c8566a1SRoger Quadros 	/* active = 0 */
6844c8566a1SRoger Quadros 	flags &= ~FLAG_ACTIVE;
6854c8566a1SRoger Quadros 	writeb(flags, &mac_info->flags);
6864c8566a1SRoger Quadros 	val = readw(&bucket_info->bucket_entries);
6874c8566a1SRoger Quadros 	val--;
6884c8566a1SRoger Quadros 	writew(val, &bucket_info->bucket_entries);
6894c8566a1SRoger Quadros 	fdb->total_entries--;
6904c8566a1SRoger Quadros 
6914c8566a1SRoger Quadros 	total_fdb_entries = fdb->total_entries;
6924c8566a1SRoger Quadros 
6934c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_spin_unlock(fdb);
6944c8566a1SRoger Quadros 
6954c8566a1SRoger Quadros 	dev_dbg(prueth->dev, "del fdb: %pM total_entries=%u\n",
6964c8566a1SRoger Quadros 		mac, total_fdb_entries);
6974c8566a1SRoger Quadros 
6984c8566a1SRoger Quadros 	return 0;
6994c8566a1SRoger Quadros }
7004c8566a1SRoger Quadros 
7014c8566a1SRoger Quadros int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac)
7024c8566a1SRoger Quadros {
7034c8566a1SRoger Quadros 	struct fdb_index_tbl_entry __iomem *bucket_info;
7044c8566a1SRoger Quadros 	struct prueth *prueth = emac->prueth;
7054c8566a1SRoger Quadros 	u8 flags, mac[ETH_ALEN];
7064c8566a1SRoger Quadros 	unsigned int hash_val;
7074c8566a1SRoger Quadros 	struct fdb_tbl *fdb;
7084c8566a1SRoger Quadros 	int ret, i;
7094c8566a1SRoger Quadros 	u16 val;
7104c8566a1SRoger Quadros 
7114c8566a1SRoger Quadros 	fdb = prueth->fdb_tbl;
7124c8566a1SRoger Quadros 
7134c8566a1SRoger Quadros 	ret = icssm_prueth_sw_fdb_spin_lock(fdb);
7144c8566a1SRoger Quadros 	if (ret) {
7154c8566a1SRoger Quadros 		dev_err(prueth->dev, "PRU lock timeout %d\n", ret);
7164c8566a1SRoger Quadros 		return ret;
7174c8566a1SRoger Quadros 	}
7184c8566a1SRoger Quadros 
7194c8566a1SRoger Quadros 	if (fdb->total_entries == 0) {
7204c8566a1SRoger Quadros 		icssm_prueth_sw_fdb_spin_unlock(fdb);
7214c8566a1SRoger Quadros 		return 0;
7224c8566a1SRoger Quadros 	}
7234c8566a1SRoger Quadros 
7244c8566a1SRoger Quadros 	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
7254c8566a1SRoger Quadros 		flags = readb(&fdb->mac_tbl_a->mac_tbl_entry[i].flags);
7264c8566a1SRoger Quadros 		if ((flags & FLAG_ACTIVE) && !(flags & FLAG_IS_STATIC)) {
7274c8566a1SRoger Quadros 			/* Get the bucket that the mac belongs to */
7284c8566a1SRoger Quadros 			memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac,
7294c8566a1SRoger Quadros 				      ETH_ALEN);
7304c8566a1SRoger Quadros 			hash_val = icssm_prueth_sw_fdb_hash(mac);
7314c8566a1SRoger Quadros 			bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
7324c8566a1SRoger Quadros 			flags &= ~FLAG_ACTIVE;
7334c8566a1SRoger Quadros 			writeb(flags,
7344c8566a1SRoger Quadros 			       &fdb->mac_tbl_a->mac_tbl_entry[i].flags);
7354c8566a1SRoger Quadros 			val = readw(&bucket_info->bucket_entries);
7364c8566a1SRoger Quadros 			val--;
7374c8566a1SRoger Quadros 			writew(val, &bucket_info->bucket_entries);
7384c8566a1SRoger Quadros 			fdb->total_entries--;
7394c8566a1SRoger Quadros 		}
7404c8566a1SRoger Quadros 	}
7414c8566a1SRoger Quadros 
7424c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_spin_unlock(fdb);
7434c8566a1SRoger Quadros 	return 0;
7444c8566a1SRoger Quadros }
7454c8566a1SRoger Quadros 
7464c8566a1SRoger Quadros int icssm_prueth_sw_init_fdb_table(struct prueth *prueth)
7474c8566a1SRoger Quadros {
7484c8566a1SRoger Quadros 	if (prueth->emac_configured)
7494c8566a1SRoger Quadros 		return 0;
7504c8566a1SRoger Quadros 
751*bf4afc53SLinus Torvalds 	prueth->fdb_tbl = kmalloc_obj(*prueth->fdb_tbl);
7524c8566a1SRoger Quadros 	if (!prueth->fdb_tbl)
7534c8566a1SRoger Quadros 		return -ENOMEM;
7544c8566a1SRoger Quadros 
7554c8566a1SRoger Quadros 	icssm_prueth_sw_fdb_tbl_init(prueth);
7564c8566a1SRoger Quadros 
7574c8566a1SRoger Quadros 	return 0;
7584c8566a1SRoger Quadros }
7594c8566a1SRoger Quadros 
7604c8566a1SRoger Quadros /**
7614c8566a1SRoger Quadros  * icssm_prueth_sw_fdb_add - insert fdb entry
7624c8566a1SRoger Quadros  *
7634c8566a1SRoger Quadros  * @emac: EMAC data structure
7644c8566a1SRoger Quadros  * @fdb: fdb info
7654c8566a1SRoger Quadros  *
7664c8566a1SRoger Quadros  */
7674c8566a1SRoger Quadros void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
7684c8566a1SRoger Quadros 			     struct switchdev_notifier_fdb_info *fdb)
7694c8566a1SRoger Quadros {
7704c8566a1SRoger Quadros 	icssm_prueth_sw_insert_fdb_entry(emac, fdb->addr, 1);
7714c8566a1SRoger Quadros }
7724c8566a1SRoger Quadros 
7734c8566a1SRoger Quadros /**
7744c8566a1SRoger Quadros  * icssm_prueth_sw_fdb_del - delete fdb entry
7754c8566a1SRoger Quadros  *
7764c8566a1SRoger Quadros  * @emac: EMAC data structure
7774c8566a1SRoger Quadros  * @fdb: fdb info
7784c8566a1SRoger Quadros  *
7794c8566a1SRoger Quadros  */
7804c8566a1SRoger Quadros void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
7814c8566a1SRoger Quadros 			     struct switchdev_notifier_fdb_info *fdb)
7824c8566a1SRoger Quadros {
7834c8566a1SRoger Quadros 	icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1);
7844c8566a1SRoger Quadros }
785eea65b87SRoger Quadros 
786eea65b87SRoger Quadros static void icssm_prueth_sw_fdb_work(struct work_struct *work)
787eea65b87SRoger Quadros {
788eea65b87SRoger Quadros 	struct icssm_prueth_sw_fdb_work *fdb_work =
789eea65b87SRoger Quadros 		container_of(work, struct icssm_prueth_sw_fdb_work, work);
790eea65b87SRoger Quadros 	struct prueth_emac *emac = fdb_work->emac;
791eea65b87SRoger Quadros 
792eea65b87SRoger Quadros 	rtnl_lock();
793eea65b87SRoger Quadros 
794eea65b87SRoger Quadros 	/* Interface is not up */
795eea65b87SRoger Quadros 	if (!emac->prueth->fdb_tbl)
796eea65b87SRoger Quadros 		goto free;
797eea65b87SRoger Quadros 
798eea65b87SRoger Quadros 	switch (fdb_work->event) {
799eea65b87SRoger Quadros 	case FDB_LEARN:
800eea65b87SRoger Quadros 		icssm_prueth_sw_insert_fdb_entry(emac, fdb_work->addr, 0);
801eea65b87SRoger Quadros 		break;
802eea65b87SRoger Quadros 	case FDB_PURGE:
803eea65b87SRoger Quadros 		icssm_prueth_sw_do_purge_fdb(emac);
804eea65b87SRoger Quadros 		break;
805eea65b87SRoger Quadros 	default:
806eea65b87SRoger Quadros 		break;
807eea65b87SRoger Quadros 	}
808eea65b87SRoger Quadros 
809eea65b87SRoger Quadros free:
810eea65b87SRoger Quadros 	rtnl_unlock();
811eea65b87SRoger Quadros 	netdev_put(emac->ndev, &fdb_work->ndev_tracker);
812eea65b87SRoger Quadros 	kfree(fdb_work);
813eea65b87SRoger Quadros }
814eea65b87SRoger Quadros 
815eea65b87SRoger Quadros int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac)
816eea65b87SRoger Quadros {
817eea65b87SRoger Quadros 	struct icssm_prueth_sw_fdb_work *fdb_work;
818eea65b87SRoger Quadros 
81969050f8dSKees Cook 	fdb_work = kzalloc_obj(*fdb_work, GFP_ATOMIC);
820eea65b87SRoger Quadros 	if (WARN_ON(!fdb_work))
821eea65b87SRoger Quadros 		return -ENOMEM;
822eea65b87SRoger Quadros 
823eea65b87SRoger Quadros 	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
824eea65b87SRoger Quadros 
825eea65b87SRoger Quadros 	fdb_work->event = FDB_LEARN;
826eea65b87SRoger Quadros 	fdb_work->emac  = emac;
827eea65b87SRoger Quadros 	ether_addr_copy(fdb_work->addr, src_mac);
828eea65b87SRoger Quadros 
829eea65b87SRoger Quadros 	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
830eea65b87SRoger Quadros 	queue_work(system_long_wq, &fdb_work->work);
831eea65b87SRoger Quadros 	return 0;
832eea65b87SRoger Quadros }
833eea65b87SRoger Quadros 
834eea65b87SRoger Quadros int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac)
835eea65b87SRoger Quadros {
836eea65b87SRoger Quadros 	struct icssm_prueth_sw_fdb_work *fdb_work;
837eea65b87SRoger Quadros 
83869050f8dSKees Cook 	fdb_work = kzalloc_obj(*fdb_work, GFP_ATOMIC);
839eea65b87SRoger Quadros 	if (WARN_ON(!fdb_work))
840eea65b87SRoger Quadros 		return -ENOMEM;
841eea65b87SRoger Quadros 
842eea65b87SRoger Quadros 	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
843eea65b87SRoger Quadros 
844eea65b87SRoger Quadros 	fdb_work->event = FDB_PURGE;
845eea65b87SRoger Quadros 	fdb_work->emac  = emac;
846eea65b87SRoger Quadros 
847eea65b87SRoger Quadros 	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
848eea65b87SRoger Quadros 	queue_work(system_long_wq, &fdb_work->work);
849eea65b87SRoger Quadros 	return 0;
850eea65b87SRoger Quadros }
851eca327aeSRoger Quadros 
852eca327aeSRoger Quadros void icssm_prueth_sw_hostconfig(struct prueth *prueth)
853eca327aeSRoger Quadros {
854eca327aeSRoger Quadros 	void __iomem *dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
855eca327aeSRoger Quadros 	void __iomem *dram;
856eca327aeSRoger Quadros 
857eca327aeSRoger Quadros 	/* queue information table */
858eca327aeSRoger Quadros 	dram = dram1_base + P0_Q1_RX_CONTEXT_OFFSET;
859eca327aeSRoger Quadros 	memcpy_toio(dram, sw_queue_infos[PRUETH_PORT_QUEUE_HOST],
860eca327aeSRoger Quadros 		    sizeof(sw_queue_infos[PRUETH_PORT_QUEUE_HOST]));
861eca327aeSRoger Quadros 
862eca327aeSRoger Quadros 	/* buffer descriptor offset table*/
863eca327aeSRoger Quadros 	dram = dram1_base + QUEUE_DESCRIPTOR_OFFSET_ADDR;
864eca327aeSRoger Quadros 	writew(P0_Q1_BD_OFFSET, dram);
865eca327aeSRoger Quadros 	writew(P0_Q2_BD_OFFSET, dram + 2);
866eca327aeSRoger Quadros 	writew(P0_Q3_BD_OFFSET, dram + 4);
867eca327aeSRoger Quadros 	writew(P0_Q4_BD_OFFSET, dram + 6);
868eca327aeSRoger Quadros 
869eca327aeSRoger Quadros 	/* buffer offset table */
870eca327aeSRoger Quadros 	dram = dram1_base + QUEUE_OFFSET_ADDR;
871eca327aeSRoger Quadros 	writew(P0_Q1_BUFFER_OFFSET, dram);
872eca327aeSRoger Quadros 	writew(P0_Q2_BUFFER_OFFSET, dram + 2);
873eca327aeSRoger Quadros 	writew(P0_Q3_BUFFER_OFFSET, dram + 4);
874eca327aeSRoger Quadros 	writew(P0_Q4_BUFFER_OFFSET, dram + 6);
875eca327aeSRoger Quadros 
876eca327aeSRoger Quadros 	/* queue size lookup table */
877eca327aeSRoger Quadros 	dram = dram1_base + QUEUE_SIZE_ADDR;
878eca327aeSRoger Quadros 	writew(HOST_QUEUE_1_SIZE, dram);
879eca327aeSRoger Quadros 	writew(HOST_QUEUE_1_SIZE, dram + 2);
880eca327aeSRoger Quadros 	writew(HOST_QUEUE_1_SIZE, dram + 4);
881eca327aeSRoger Quadros 	writew(HOST_QUEUE_1_SIZE, dram + 6);
882eca327aeSRoger Quadros 
883eca327aeSRoger Quadros 	/* queue table */
884eca327aeSRoger Quadros 	dram = dram1_base + P0_QUEUE_DESC_OFFSET;
885eca327aeSRoger Quadros 	memcpy_toio(dram, queue_descs[PRUETH_PORT_QUEUE_HOST],
886eca327aeSRoger Quadros 		    sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST]));
887eca327aeSRoger Quadros }
888eca327aeSRoger Quadros 
889eca327aeSRoger Quadros static int icssm_prueth_sw_port_config(struct prueth *prueth,
890eca327aeSRoger Quadros 				       enum prueth_port port_id)
891eca327aeSRoger Quadros {
892eca327aeSRoger Quadros 	unsigned int tx_context_ofs_addr, rx_context_ofs, queue_desc_ofs;
893eca327aeSRoger Quadros 	void __iomem *dram, *dram_base, *dram_mac;
894eca327aeSRoger Quadros 	struct prueth_emac *emac;
895eca327aeSRoger Quadros 	void __iomem *dram1_base;
896eca327aeSRoger Quadros 
897eca327aeSRoger Quadros 	dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
898eca327aeSRoger Quadros 	emac = prueth->emac[port_id - 1];
899eca327aeSRoger Quadros 	switch (port_id) {
900eca327aeSRoger Quadros 	case PRUETH_PORT_MII0:
901eca327aeSRoger Quadros 		tx_context_ofs_addr     = TX_CONTEXT_P1_Q1_OFFSET_ADDR;
902eca327aeSRoger Quadros 		rx_context_ofs          = P1_Q1_RX_CONTEXT_OFFSET;
903eca327aeSRoger Quadros 		queue_desc_ofs          = P1_QUEUE_DESC_OFFSET;
904eca327aeSRoger Quadros 
905eca327aeSRoger Quadros 		/* for switch PORT MII0 mac addr is in DRAM0. */
906eca327aeSRoger Quadros 		dram_mac = prueth->mem[PRUETH_MEM_DRAM0].va;
907eca327aeSRoger Quadros 		break;
908eca327aeSRoger Quadros 	case PRUETH_PORT_MII1:
909eca327aeSRoger Quadros 		tx_context_ofs_addr     = TX_CONTEXT_P2_Q1_OFFSET_ADDR;
910eca327aeSRoger Quadros 		rx_context_ofs          = P2_Q1_RX_CONTEXT_OFFSET;
911eca327aeSRoger Quadros 		queue_desc_ofs          = P2_QUEUE_DESC_OFFSET;
912eca327aeSRoger Quadros 
913eca327aeSRoger Quadros 		/* for switch PORT MII1 mac addr is in DRAM1. */
914eca327aeSRoger Quadros 		dram_mac = prueth->mem[PRUETH_MEM_DRAM1].va;
915eca327aeSRoger Quadros 		break;
916eca327aeSRoger Quadros 	default:
917eca327aeSRoger Quadros 		netdev_err(emac->ndev, "invalid port\n");
918eca327aeSRoger Quadros 		return -EINVAL;
919eca327aeSRoger Quadros 	}
920eca327aeSRoger Quadros 
921eca327aeSRoger Quadros 	/* setup mac address */
922eca327aeSRoger Quadros 	memcpy_toio(dram_mac + PORT_MAC_ADDR, emac->mac_addr, 6);
923eca327aeSRoger Quadros 
924eca327aeSRoger Quadros 	/* Remaining switch port configs are in DRAM1 */
925eca327aeSRoger Quadros 	dram_base = prueth->mem[PRUETH_MEM_DRAM1].va;
926eca327aeSRoger Quadros 
927eca327aeSRoger Quadros 	/* queue information table */
928eca327aeSRoger Quadros 	memcpy_toio(dram_base + tx_context_ofs_addr,
929eca327aeSRoger Quadros 		    sw_queue_infos[port_id],
930eca327aeSRoger Quadros 		    sizeof(sw_queue_infos[port_id]));
931eca327aeSRoger Quadros 
932eca327aeSRoger Quadros 	memcpy_toio(dram_base + rx_context_ofs,
933eca327aeSRoger Quadros 		    rx_queue_infos[port_id],
934eca327aeSRoger Quadros 		    sizeof(rx_queue_infos[port_id]));
935eca327aeSRoger Quadros 
936eca327aeSRoger Quadros 	/* buffer descriptor offset table*/
937eca327aeSRoger Quadros 	dram = dram_base + QUEUE_DESCRIPTOR_OFFSET_ADDR +
938eca327aeSRoger Quadros 	       (port_id * NUM_QUEUES * sizeof(u16));
939eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_desc_offset, dram);
940eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_desc_offset,
941eca327aeSRoger Quadros 	       dram + 2);
942eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_desc_offset,
943eca327aeSRoger Quadros 	       dram + 4);
944eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_desc_offset,
945eca327aeSRoger Quadros 	       dram + 6);
946eca327aeSRoger Quadros 
947eca327aeSRoger Quadros 	/* buffer offset table */
948eca327aeSRoger Quadros 	dram = dram_base + QUEUE_OFFSET_ADDR +
949eca327aeSRoger Quadros 	       port_id * NUM_QUEUES * sizeof(u16);
950eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_offset, dram);
951eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_offset,
952eca327aeSRoger Quadros 	       dram + 2);
953eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_offset,
954eca327aeSRoger Quadros 	       dram + 4);
955eca327aeSRoger Quadros 	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_offset,
956eca327aeSRoger Quadros 	       dram + 6);
957eca327aeSRoger Quadros 
958eca327aeSRoger Quadros 	/* queue size lookup table */
959eca327aeSRoger Quadros 	dram = dram_base + QUEUE_SIZE_ADDR +
960eca327aeSRoger Quadros 	       port_id * NUM_QUEUES * sizeof(u16);
961eca327aeSRoger Quadros 	writew(QUEUE_1_SIZE, dram);
962eca327aeSRoger Quadros 	writew(QUEUE_2_SIZE, dram + 2);
963eca327aeSRoger Quadros 	writew(QUEUE_3_SIZE, dram + 4);
964eca327aeSRoger Quadros 	writew(QUEUE_4_SIZE, dram + 6);
965eca327aeSRoger Quadros 
966eca327aeSRoger Quadros 	/* queue table */
967eca327aeSRoger Quadros 	memcpy_toio(dram_base + queue_desc_ofs,
968eca327aeSRoger Quadros 		    &queue_descs[port_id][0],
969eca327aeSRoger Quadros 		    4 * sizeof(queue_descs[port_id][0]));
970eca327aeSRoger Quadros 
971eca327aeSRoger Quadros 	emac->rx_queue_descs = dram1_base + P0_QUEUE_DESC_OFFSET;
972eca327aeSRoger Quadros 	emac->tx_queue_descs = dram1_base +
973eca327aeSRoger Quadros 		rx_queue_infos[port_id][PRUETH_QUEUE1].queue_desc_offset;
974eca327aeSRoger Quadros 
975eca327aeSRoger Quadros 	return 0;
976eca327aeSRoger Quadros }
977eca327aeSRoger Quadros 
978eca327aeSRoger Quadros int icssm_prueth_sw_emac_config(struct prueth_emac *emac)
979eca327aeSRoger Quadros {
980eca327aeSRoger Quadros 	struct prueth *prueth = emac->prueth;
981eca327aeSRoger Quadros 	u32 sharedramaddr, ocmcaddr;
982eca327aeSRoger Quadros 	int ret;
983eca327aeSRoger Quadros 
984eca327aeSRoger Quadros 	/* PRU needs local shared RAM address for C28 */
985eca327aeSRoger Quadros 	sharedramaddr = ICSS_LOCAL_SHARED_RAM;
986eca327aeSRoger Quadros 	/* PRU needs real global OCMC address for C30*/
987eca327aeSRoger Quadros 	ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa;
988eca327aeSRoger Quadros 
989eca327aeSRoger Quadros 	if (prueth->emac_configured & BIT(emac->port_id))
990eca327aeSRoger Quadros 		return 0;
991eca327aeSRoger Quadros 
992eca327aeSRoger Quadros 	ret = icssm_prueth_sw_port_config(prueth, emac->port_id);
993eca327aeSRoger Quadros 	if (ret)
994eca327aeSRoger Quadros 		return ret;
995eca327aeSRoger Quadros 
996eca327aeSRoger Quadros 	if (!prueth->emac_configured) {
997eca327aeSRoger Quadros 		/* Set in constant table C28 of PRUn to ICSS Shared memory */
998eca327aeSRoger Quadros 		pru_rproc_set_ctable(prueth->pru0, PRU_C28, sharedramaddr);
999eca327aeSRoger Quadros 		pru_rproc_set_ctable(prueth->pru1, PRU_C28, sharedramaddr);
1000eca327aeSRoger Quadros 
1001eca327aeSRoger Quadros 		/* Set in constant table C30 of PRUn to OCMC memory */
1002eca327aeSRoger Quadros 		pru_rproc_set_ctable(prueth->pru0, PRU_C30, ocmcaddr);
1003eca327aeSRoger Quadros 		pru_rproc_set_ctable(prueth->pru1, PRU_C30, ocmcaddr);
1004eca327aeSRoger Quadros 	}
1005eca327aeSRoger Quadros 	return 0;
1006eca327aeSRoger Quadros }
1007eca327aeSRoger Quadros 
1008eca327aeSRoger Quadros int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev)
1009eca327aeSRoger Quadros {
1010eca327aeSRoger Quadros 	const struct prueth_firmware *pru_firmwares;
1011eca327aeSRoger Quadros 	const char *fw_name, *fw_name1;
1012eca327aeSRoger Quadros 	int ret;
1013eca327aeSRoger Quadros 
1014eca327aeSRoger Quadros 	if (prueth->emac_configured)
1015eca327aeSRoger Quadros 		return 0;
1016eca327aeSRoger Quadros 
1017eca327aeSRoger Quadros 	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU0];
1018eca327aeSRoger Quadros 	fw_name = pru_firmwares->fw_name[prueth->eth_type];
1019eca327aeSRoger Quadros 	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU1];
1020eca327aeSRoger Quadros 	fw_name1 = pru_firmwares->fw_name[prueth->eth_type];
1021eca327aeSRoger Quadros 
1022eca327aeSRoger Quadros 	ret = rproc_set_firmware(prueth->pru0, fw_name);
1023eca327aeSRoger Quadros 	if (ret) {
1024eca327aeSRoger Quadros 		netdev_err(ndev, "failed to set PRU0 firmware %s: %d\n",
1025eca327aeSRoger Quadros 			   fw_name, ret);
1026eca327aeSRoger Quadros 		return ret;
1027eca327aeSRoger Quadros 	}
1028eca327aeSRoger Quadros 	ret = rproc_boot(prueth->pru0);
1029eca327aeSRoger Quadros 	if (ret) {
1030eca327aeSRoger Quadros 		netdev_err(ndev, "failed to boot PRU0: %d\n", ret);
1031eca327aeSRoger Quadros 		return ret;
1032eca327aeSRoger Quadros 	}
1033eca327aeSRoger Quadros 
1034eca327aeSRoger Quadros 	ret = rproc_set_firmware(prueth->pru1, fw_name1);
1035eca327aeSRoger Quadros 	if (ret) {
1036eca327aeSRoger Quadros 		netdev_err(ndev, "failed to set PRU1 firmware %s: %d\n",
1037eca327aeSRoger Quadros 			   fw_name1, ret);
1038eca327aeSRoger Quadros 		goto rproc0_shutdown;
1039eca327aeSRoger Quadros 	}
1040eca327aeSRoger Quadros 	ret = rproc_boot(prueth->pru1);
1041eca327aeSRoger Quadros 	if (ret) {
1042eca327aeSRoger Quadros 		netdev_err(ndev, "failed to boot PRU1: %d\n", ret);
1043eca327aeSRoger Quadros 		goto rproc0_shutdown;
1044eca327aeSRoger Quadros 	}
1045eca327aeSRoger Quadros 
1046eca327aeSRoger Quadros 	return 0;
1047eca327aeSRoger Quadros 
1048eca327aeSRoger Quadros rproc0_shutdown:
1049eca327aeSRoger Quadros 	rproc_shutdown(prueth->pru0);
1050eca327aeSRoger Quadros 	return ret;
1051eca327aeSRoger Quadros }
1052eca327aeSRoger Quadros 
1053eca327aeSRoger Quadros int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
1054eca327aeSRoger Quadros 				  struct net_device *ndev)
1055eca327aeSRoger Quadros {
1056eca327aeSRoger Quadros 	struct prueth *prueth = emac->prueth;
1057eca327aeSRoger Quadros 
1058eca327aeSRoger Quadros 	if (prueth->emac_configured)
1059eca327aeSRoger Quadros 		return 0;
1060eca327aeSRoger Quadros 
1061eca327aeSRoger Quadros 	rproc_shutdown(prueth->pru0);
1062eca327aeSRoger Quadros 	rproc_shutdown(prueth->pru1);
1063eca327aeSRoger Quadros 
1064eca327aeSRoger Quadros 	return 0;
1065eca327aeSRoger Quadros }
1066