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 void prestera_router_hw_fini(struct prestera_switch *sw) 33 { 34 WARN_ON(!list_empty(&sw->router->vr_list)); 35 WARN_ON(!list_empty(&sw->router->rif_entry_list)); 36 } 37 38 static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw, 39 u32 tb_id) 40 { 41 struct prestera_vr *vr; 42 43 list_for_each_entry(vr, &sw->router->vr_list, router_node) { 44 if (vr->tb_id == tb_id) 45 return vr; 46 } 47 48 return NULL; 49 } 50 51 static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw, 52 u32 tb_id, 53 struct netlink_ext_ack *extack) 54 { 55 struct prestera_vr *vr; 56 int err; 57 58 vr = kzalloc(sizeof(*vr), GFP_KERNEL); 59 if (!vr) { 60 err = -ENOMEM; 61 goto err_alloc_vr; 62 } 63 64 vr->tb_id = tb_id; 65 66 err = prestera_hw_vr_create(sw, &vr->hw_vr_id); 67 if (err) 68 goto err_hw_create; 69 70 list_add(&vr->router_node, &sw->router->vr_list); 71 72 return vr; 73 74 err_hw_create: 75 kfree(vr); 76 err_alloc_vr: 77 return ERR_PTR(err); 78 } 79 80 static void __prestera_vr_destroy(struct prestera_switch *sw, 81 struct prestera_vr *vr) 82 { 83 list_del(&vr->router_node); 84 prestera_hw_vr_delete(sw, vr->hw_vr_id); 85 kfree(vr); 86 } 87 88 static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id, 89 struct netlink_ext_ack *extack) 90 { 91 struct prestera_vr *vr; 92 93 vr = __prestera_vr_find(sw, tb_id); 94 if (vr) { 95 refcount_inc(&vr->refcount); 96 } else { 97 vr = __prestera_vr_create(sw, tb_id, extack); 98 if (IS_ERR(vr)) 99 return ERR_CAST(vr); 100 101 refcount_set(&vr->refcount, 1); 102 } 103 104 return vr; 105 } 106 107 static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr) 108 { 109 if (refcount_dec_and_test(&vr->refcount)) 110 __prestera_vr_destroy(sw, vr); 111 } 112 113 /* iface is overhead struct. vr_id also can be removed. */ 114 static int 115 __prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in, 116 struct prestera_rif_entry_key *out) 117 { 118 memset(out, 0, sizeof(*out)); 119 120 switch (in->iface.type) { 121 case PRESTERA_IF_PORT_E: 122 out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num; 123 out->iface.dev_port.port_num = in->iface.dev_port.port_num; 124 break; 125 case PRESTERA_IF_LAG_E: 126 out->iface.lag_id = in->iface.lag_id; 127 break; 128 case PRESTERA_IF_VID_E: 129 out->iface.vlan_id = in->iface.vlan_id; 130 break; 131 default: 132 WARN(1, "Unsupported iface type"); 133 return -EINVAL; 134 } 135 136 out->iface.type = in->iface.type; 137 return 0; 138 } 139 140 struct prestera_rif_entry * 141 prestera_rif_entry_find(const struct prestera_switch *sw, 142 const struct prestera_rif_entry_key *k) 143 { 144 struct prestera_rif_entry *rif_entry; 145 struct prestera_rif_entry_key lk; /* lookup key */ 146 147 if (__prestera_rif_entry_key_copy(k, &lk)) 148 return NULL; 149 150 list_for_each_entry(rif_entry, &sw->router->rif_entry_list, 151 router_node) { 152 if (!memcmp(k, &rif_entry->key, sizeof(*k))) 153 return rif_entry; 154 } 155 156 return NULL; 157 } 158 159 void prestera_rif_entry_destroy(struct prestera_switch *sw, 160 struct prestera_rif_entry *e) 161 { 162 struct prestera_iface iface; 163 164 list_del(&e->router_node); 165 166 memcpy(&iface, &e->key.iface, sizeof(iface)); 167 iface.vr_id = e->vr->hw_vr_id; 168 prestera_hw_rif_delete(sw, e->hw_id, &iface); 169 170 prestera_vr_put(sw, e->vr); 171 kfree(e); 172 } 173 174 struct prestera_rif_entry * 175 prestera_rif_entry_create(struct prestera_switch *sw, 176 struct prestera_rif_entry_key *k, 177 u32 tb_id, const unsigned char *addr) 178 { 179 int err; 180 struct prestera_rif_entry *e; 181 struct prestera_iface iface; 182 183 e = kzalloc(sizeof(*e), GFP_KERNEL); 184 if (!e) 185 goto err_kzalloc; 186 187 if (__prestera_rif_entry_key_copy(k, &e->key)) 188 goto err_key_copy; 189 190 e->vr = prestera_vr_get(sw, tb_id, NULL); 191 if (IS_ERR(e->vr)) 192 goto err_vr_get; 193 194 memcpy(&e->addr, addr, sizeof(e->addr)); 195 196 /* HW */ 197 memcpy(&iface, &e->key.iface, sizeof(iface)); 198 iface.vr_id = e->vr->hw_vr_id; 199 err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id); 200 if (err) 201 goto err_hw_create; 202 203 list_add(&e->router_node, &sw->router->rif_entry_list); 204 205 return e; 206 207 err_hw_create: 208 prestera_vr_put(sw, e->vr); 209 err_vr_get: 210 err_key_copy: 211 kfree(e); 212 err_kzalloc: 213 return NULL; 214 } 215