1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */ 3 4 #include <linux/rhashtable.h> 5 6 #include "prestera.h" 7 #include "prestera_hw.h" 8 #include "prestera_router_hw.h" 9 #include "prestera_acl.h" 10 11 /* +--+ 12 * +------->|vr| 13 * | +--+ 14 * | 15 * +-+-------+ 16 * |rif_entry| 17 * +---------+ 18 * Rif is 19 * used as 20 * entry point 21 * for vr in hw 22 */ 23 24 int prestera_router_hw_init(struct prestera_switch *sw) 25 { 26 INIT_LIST_HEAD(&sw->router->vr_list); 27 INIT_LIST_HEAD(&sw->router->rif_entry_list); 28 29 return 0; 30 } 31 32 static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw, 33 u32 tb_id) 34 { 35 struct prestera_vr *vr; 36 37 list_for_each_entry(vr, &sw->router->vr_list, router_node) { 38 if (vr->tb_id == tb_id) 39 return vr; 40 } 41 42 return NULL; 43 } 44 45 static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw, 46 u32 tb_id, 47 struct netlink_ext_ack *extack) 48 { 49 struct prestera_vr *vr; 50 u16 hw_vr_id; 51 int err; 52 53 err = prestera_hw_vr_create(sw, &hw_vr_id); 54 if (err) 55 return ERR_PTR(-ENOMEM); 56 57 vr = kzalloc(sizeof(*vr), GFP_KERNEL); 58 if (!vr) { 59 err = -ENOMEM; 60 goto err_alloc_vr; 61 } 62 63 vr->tb_id = tb_id; 64 vr->hw_vr_id = hw_vr_id; 65 66 list_add(&vr->router_node, &sw->router->vr_list); 67 68 return vr; 69 70 err_alloc_vr: 71 prestera_hw_vr_delete(sw, hw_vr_id); 72 kfree(vr); 73 return ERR_PTR(err); 74 } 75 76 static void __prestera_vr_destroy(struct prestera_switch *sw, 77 struct prestera_vr *vr) 78 { 79 prestera_hw_vr_delete(sw, vr->hw_vr_id); 80 list_del(&vr->router_node); 81 kfree(vr); 82 } 83 84 static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id, 85 struct netlink_ext_ack *extack) 86 { 87 struct prestera_vr *vr; 88 89 vr = __prestera_vr_find(sw, tb_id); 90 if (!vr) 91 vr = __prestera_vr_create(sw, tb_id, extack); 92 if (IS_ERR(vr)) 93 return ERR_CAST(vr); 94 95 return vr; 96 } 97 98 static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr) 99 { 100 if (!vr->ref_cnt) 101 __prestera_vr_destroy(sw, vr); 102 } 103 104 /* iface is overhead struct. vr_id also can be removed. */ 105 static int 106 __prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in, 107 struct prestera_rif_entry_key *out) 108 { 109 memset(out, 0, sizeof(*out)); 110 111 switch (in->iface.type) { 112 case PRESTERA_IF_PORT_E: 113 out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num; 114 out->iface.dev_port.port_num = in->iface.dev_port.port_num; 115 break; 116 case PRESTERA_IF_LAG_E: 117 out->iface.lag_id = in->iface.lag_id; 118 break; 119 case PRESTERA_IF_VID_E: 120 out->iface.vlan_id = in->iface.vlan_id; 121 break; 122 default: 123 pr_err("Unsupported iface type"); 124 return -EINVAL; 125 } 126 127 out->iface.type = in->iface.type; 128 return 0; 129 } 130 131 struct prestera_rif_entry * 132 prestera_rif_entry_find(const struct prestera_switch *sw, 133 const struct prestera_rif_entry_key *k) 134 { 135 struct prestera_rif_entry *rif_entry; 136 struct prestera_rif_entry_key lk; /* lookup key */ 137 138 if (__prestera_rif_entry_key_copy(k, &lk)) 139 return NULL; 140 141 list_for_each_entry(rif_entry, &sw->router->rif_entry_list, 142 router_node) { 143 if (!memcmp(k, &rif_entry->key, sizeof(*k))) 144 return rif_entry; 145 } 146 147 return NULL; 148 } 149 150 void prestera_rif_entry_destroy(struct prestera_switch *sw, 151 struct prestera_rif_entry *e) 152 { 153 struct prestera_iface iface; 154 155 list_del(&e->router_node); 156 157 memcpy(&iface, &e->key.iface, sizeof(iface)); 158 iface.vr_id = e->vr->hw_vr_id; 159 prestera_hw_rif_delete(sw, e->hw_id, &iface); 160 161 e->vr->ref_cnt--; 162 prestera_vr_put(sw, e->vr); 163 kfree(e); 164 } 165 166 struct prestera_rif_entry * 167 prestera_rif_entry_create(struct prestera_switch *sw, 168 struct prestera_rif_entry_key *k, 169 u32 tb_id, const unsigned char *addr) 170 { 171 int err; 172 struct prestera_rif_entry *e; 173 struct prestera_iface iface; 174 175 e = kzalloc(sizeof(*e), GFP_KERNEL); 176 if (!e) 177 goto err_kzalloc; 178 179 if (__prestera_rif_entry_key_copy(k, &e->key)) 180 goto err_key_copy; 181 182 e->vr = prestera_vr_get(sw, tb_id, NULL); 183 if (IS_ERR(e->vr)) 184 goto err_vr_get; 185 186 e->vr->ref_cnt++; 187 memcpy(&e->addr, addr, sizeof(e->addr)); 188 189 /* HW */ 190 memcpy(&iface, &e->key.iface, sizeof(iface)); 191 iface.vr_id = e->vr->hw_vr_id; 192 err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id); 193 if (err) 194 goto err_hw_create; 195 196 list_add(&e->router_node, &sw->router->rif_entry_list); 197 198 return e; 199 200 err_hw_create: 201 e->vr->ref_cnt--; 202 prestera_vr_put(sw, e->vr); 203 err_vr_get: 204 err_key_copy: 205 kfree(e); 206 err_kzalloc: 207 return NULL; 208 } 209