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