1d8931847SRahul Lakkireddy /* 2d8931847SRahul Lakkireddy * This file is part of the Chelsio T4 Ethernet driver for Linux. 3d8931847SRahul Lakkireddy * 4d8931847SRahul Lakkireddy * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 5d8931847SRahul Lakkireddy * 6d8931847SRahul Lakkireddy * This software is available to you under a choice of one of two 7d8931847SRahul Lakkireddy * licenses. You may choose to be licensed under the terms of the GNU 8d8931847SRahul Lakkireddy * General Public License (GPL) Version 2, available from the file 9d8931847SRahul Lakkireddy * COPYING in the main directory of this source tree, or the 10d8931847SRahul Lakkireddy * OpenIB.org BSD license below: 11d8931847SRahul Lakkireddy * 12d8931847SRahul Lakkireddy * Redistribution and use in source and binary forms, with or 13d8931847SRahul Lakkireddy * without modification, are permitted provided that the following 14d8931847SRahul Lakkireddy * conditions are met: 15d8931847SRahul Lakkireddy * 16d8931847SRahul Lakkireddy * - Redistributions of source code must retain the above 17d8931847SRahul Lakkireddy * copyright notice, this list of conditions and the following 18d8931847SRahul Lakkireddy * disclaimer. 19d8931847SRahul Lakkireddy * 20d8931847SRahul Lakkireddy * - Redistributions in binary form must reproduce the above 21d8931847SRahul Lakkireddy * copyright notice, this list of conditions and the following 22d8931847SRahul Lakkireddy * disclaimer in the documentation and/or other materials 23d8931847SRahul Lakkireddy * provided with the distribution. 24d8931847SRahul Lakkireddy * 25d8931847SRahul Lakkireddy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26d8931847SRahul Lakkireddy * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27d8931847SRahul Lakkireddy * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28d8931847SRahul Lakkireddy * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29d8931847SRahul Lakkireddy * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30d8931847SRahul Lakkireddy * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31d8931847SRahul Lakkireddy * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32d8931847SRahul Lakkireddy * SOFTWARE. 33d8931847SRahul Lakkireddy */ 34d8931847SRahul Lakkireddy 35d8931847SRahul Lakkireddy #include "cxgb4.h" 36d8931847SRahul Lakkireddy #include "cxgb4_tc_u32_parse.h" 37d8931847SRahul Lakkireddy #include "cxgb4_tc_u32.h" 38d8931847SRahul Lakkireddy 39d8931847SRahul Lakkireddy /* Fill ch_filter_specification with parsed match value/mask pair. */ 40d8931847SRahul Lakkireddy static int fill_match_fields(struct adapter *adap, 41d8931847SRahul Lakkireddy struct ch_filter_specification *fs, 42d8931847SRahul Lakkireddy struct tc_cls_u32_offload *cls, 43d8931847SRahul Lakkireddy const struct cxgb4_match_field *entry, 44d8931847SRahul Lakkireddy bool next_header) 45d8931847SRahul Lakkireddy { 46d8931847SRahul Lakkireddy unsigned int i, j; 47d8931847SRahul Lakkireddy u32 val, mask; 48d8931847SRahul Lakkireddy int off, err; 49d8931847SRahul Lakkireddy bool found; 50d8931847SRahul Lakkireddy 51d8931847SRahul Lakkireddy for (i = 0; i < cls->knode.sel->nkeys; i++) { 52d8931847SRahul Lakkireddy off = cls->knode.sel->keys[i].off; 53d8931847SRahul Lakkireddy val = cls->knode.sel->keys[i].val; 54d8931847SRahul Lakkireddy mask = cls->knode.sel->keys[i].mask; 55d8931847SRahul Lakkireddy 56d8931847SRahul Lakkireddy if (next_header) { 57d8931847SRahul Lakkireddy /* For next headers, parse only keys with offmask */ 58d8931847SRahul Lakkireddy if (!cls->knode.sel->keys[i].offmask) 59d8931847SRahul Lakkireddy continue; 60d8931847SRahul Lakkireddy } else { 61d8931847SRahul Lakkireddy /* For the remaining, parse only keys without offmask */ 62d8931847SRahul Lakkireddy if (cls->knode.sel->keys[i].offmask) 63d8931847SRahul Lakkireddy continue; 64d8931847SRahul Lakkireddy } 65d8931847SRahul Lakkireddy 66d8931847SRahul Lakkireddy found = false; 67d8931847SRahul Lakkireddy 68d8931847SRahul Lakkireddy for (j = 0; entry[j].val; j++) { 69d8931847SRahul Lakkireddy if (off == entry[j].off) { 70d8931847SRahul Lakkireddy found = true; 71d8931847SRahul Lakkireddy err = entry[j].val(fs, val, mask); 72d8931847SRahul Lakkireddy if (err) 73d8931847SRahul Lakkireddy return err; 74d8931847SRahul Lakkireddy break; 75d8931847SRahul Lakkireddy } 76d8931847SRahul Lakkireddy } 77d8931847SRahul Lakkireddy 78d8931847SRahul Lakkireddy if (!found) 79d8931847SRahul Lakkireddy return -EINVAL; 80d8931847SRahul Lakkireddy } 81d8931847SRahul Lakkireddy 82d8931847SRahul Lakkireddy return 0; 83d8931847SRahul Lakkireddy } 84d8931847SRahul Lakkireddy 85d8931847SRahul Lakkireddy int cxgb4_config_knode(struct net_device *dev, __be16 protocol, 86d8931847SRahul Lakkireddy struct tc_cls_u32_offload *cls) 87d8931847SRahul Lakkireddy { 88d8931847SRahul Lakkireddy const struct cxgb4_match_field *start, *link_start = NULL; 89d8931847SRahul Lakkireddy struct adapter *adapter = netdev2adap(dev); 90d8931847SRahul Lakkireddy struct ch_filter_specification fs; 91d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *t; 92d8931847SRahul Lakkireddy struct cxgb4_link *link; 93d8931847SRahul Lakkireddy unsigned int filter_id; 94d8931847SRahul Lakkireddy u32 uhtid, link_uhtid; 95d8931847SRahul Lakkireddy bool is_ipv6 = false; 96d8931847SRahul Lakkireddy int ret; 97d8931847SRahul Lakkireddy 98d8931847SRahul Lakkireddy if (!can_tc_u32_offload(dev)) 99d8931847SRahul Lakkireddy return -EOPNOTSUPP; 100d8931847SRahul Lakkireddy 101d8931847SRahul Lakkireddy if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6)) 102d8931847SRahul Lakkireddy return -EOPNOTSUPP; 103d8931847SRahul Lakkireddy 104d8931847SRahul Lakkireddy /* Fetch the location to insert the filter. */ 105d8931847SRahul Lakkireddy filter_id = cls->knode.handle & 0xFFFFF; 106d8931847SRahul Lakkireddy 107d8931847SRahul Lakkireddy if (filter_id > adapter->tids.nftids) { 108d8931847SRahul Lakkireddy dev_err(adapter->pdev_dev, 109d8931847SRahul Lakkireddy "Location %d out of range for insertion. Max: %d\n", 110d8931847SRahul Lakkireddy filter_id, adapter->tids.nftids); 111d8931847SRahul Lakkireddy return -ERANGE; 112d8931847SRahul Lakkireddy } 113d8931847SRahul Lakkireddy 114d8931847SRahul Lakkireddy t = adapter->tc_u32; 115d8931847SRahul Lakkireddy uhtid = TC_U32_USERHTID(cls->knode.handle); 116d8931847SRahul Lakkireddy link_uhtid = TC_U32_USERHTID(cls->knode.link_handle); 117d8931847SRahul Lakkireddy 118d8931847SRahul Lakkireddy /* Ensure that uhtid is either root u32 (i.e. 0x800) 119d8931847SRahul Lakkireddy * or a a valid linked bucket. 120d8931847SRahul Lakkireddy */ 121d8931847SRahul Lakkireddy if (uhtid != 0x800 && uhtid >= t->size) 122d8931847SRahul Lakkireddy return -EINVAL; 123d8931847SRahul Lakkireddy 124d8931847SRahul Lakkireddy /* Ensure link handle uhtid is sane, if specified. */ 125d8931847SRahul Lakkireddy if (link_uhtid >= t->size) 126d8931847SRahul Lakkireddy return -EINVAL; 127d8931847SRahul Lakkireddy 128d8931847SRahul Lakkireddy memset(&fs, 0, sizeof(fs)); 129d8931847SRahul Lakkireddy 130d8931847SRahul Lakkireddy if (protocol == htons(ETH_P_IPV6)) { 131d8931847SRahul Lakkireddy start = cxgb4_ipv6_fields; 132d8931847SRahul Lakkireddy is_ipv6 = true; 133d8931847SRahul Lakkireddy } else { 134d8931847SRahul Lakkireddy start = cxgb4_ipv4_fields; 135d8931847SRahul Lakkireddy is_ipv6 = false; 136d8931847SRahul Lakkireddy } 137d8931847SRahul Lakkireddy 138d8931847SRahul Lakkireddy if (uhtid != 0x800) { 139d8931847SRahul Lakkireddy /* Link must exist from root node before insertion. */ 140d8931847SRahul Lakkireddy if (!t->table[uhtid - 1].link_handle) 141d8931847SRahul Lakkireddy return -EINVAL; 142d8931847SRahul Lakkireddy 143d8931847SRahul Lakkireddy /* Link must have a valid supported next header. */ 144d8931847SRahul Lakkireddy link_start = t->table[uhtid - 1].match_field; 145d8931847SRahul Lakkireddy if (!link_start) 146d8931847SRahul Lakkireddy return -EINVAL; 147d8931847SRahul Lakkireddy } 148d8931847SRahul Lakkireddy 149d8931847SRahul Lakkireddy /* Parse links and record them for subsequent jumps to valid 150d8931847SRahul Lakkireddy * next headers. 151d8931847SRahul Lakkireddy */ 152d8931847SRahul Lakkireddy if (link_uhtid) { 153d8931847SRahul Lakkireddy const struct cxgb4_next_header *next; 154d8931847SRahul Lakkireddy bool found = false; 155d8931847SRahul Lakkireddy unsigned int i, j; 156d8931847SRahul Lakkireddy u32 val, mask; 157d8931847SRahul Lakkireddy int off; 158d8931847SRahul Lakkireddy 159d8931847SRahul Lakkireddy if (t->table[link_uhtid - 1].link_handle) { 160d8931847SRahul Lakkireddy dev_err(adapter->pdev_dev, 161d8931847SRahul Lakkireddy "Link handle exists for: 0x%x\n", 162d8931847SRahul Lakkireddy link_uhtid); 163d8931847SRahul Lakkireddy return -EINVAL; 164d8931847SRahul Lakkireddy } 165d8931847SRahul Lakkireddy 166d8931847SRahul Lakkireddy next = is_ipv6 ? cxgb4_ipv6_jumps : cxgb4_ipv4_jumps; 167d8931847SRahul Lakkireddy 168d8931847SRahul Lakkireddy /* Try to find matches that allow jumps to next header. */ 169d8931847SRahul Lakkireddy for (i = 0; next[i].jump; i++) { 170d8931847SRahul Lakkireddy if (next[i].offoff != cls->knode.sel->offoff || 171d8931847SRahul Lakkireddy next[i].shift != cls->knode.sel->offshift || 172d8931847SRahul Lakkireddy next[i].mask != cls->knode.sel->offmask || 173d8931847SRahul Lakkireddy next[i].offset != cls->knode.sel->off) 174d8931847SRahul Lakkireddy continue; 175d8931847SRahul Lakkireddy 176d8931847SRahul Lakkireddy /* Found a possible candidate. Find a key that 177d8931847SRahul Lakkireddy * matches the corresponding offset, value, and 178d8931847SRahul Lakkireddy * mask to jump to next header. 179d8931847SRahul Lakkireddy */ 180d8931847SRahul Lakkireddy for (j = 0; j < cls->knode.sel->nkeys; j++) { 181d8931847SRahul Lakkireddy off = cls->knode.sel->keys[j].off; 182d8931847SRahul Lakkireddy val = cls->knode.sel->keys[j].val; 183d8931847SRahul Lakkireddy mask = cls->knode.sel->keys[j].mask; 184d8931847SRahul Lakkireddy 185d8931847SRahul Lakkireddy if (next[i].match_off == off && 186d8931847SRahul Lakkireddy next[i].match_val == val && 187d8931847SRahul Lakkireddy next[i].match_mask == mask) { 188d8931847SRahul Lakkireddy found = true; 189d8931847SRahul Lakkireddy break; 190d8931847SRahul Lakkireddy } 191d8931847SRahul Lakkireddy } 192d8931847SRahul Lakkireddy 193d8931847SRahul Lakkireddy if (!found) 194d8931847SRahul Lakkireddy continue; /* Try next candidate. */ 195d8931847SRahul Lakkireddy 196d8931847SRahul Lakkireddy /* Candidate to jump to next header found. 197d8931847SRahul Lakkireddy * Translate all keys to internal specification 198d8931847SRahul Lakkireddy * and store them in jump table. This spec is copied 199d8931847SRahul Lakkireddy * later to set the actual filters. 200d8931847SRahul Lakkireddy */ 201d8931847SRahul Lakkireddy ret = fill_match_fields(adapter, &fs, cls, 202d8931847SRahul Lakkireddy start, false); 203d8931847SRahul Lakkireddy if (ret) 204d8931847SRahul Lakkireddy goto out; 205d8931847SRahul Lakkireddy 206d8931847SRahul Lakkireddy link = &t->table[link_uhtid - 1]; 207d8931847SRahul Lakkireddy link->match_field = next[i].jump; 208d8931847SRahul Lakkireddy link->link_handle = cls->knode.handle; 209d8931847SRahul Lakkireddy memcpy(&link->fs, &fs, sizeof(fs)); 210d8931847SRahul Lakkireddy break; 211d8931847SRahul Lakkireddy } 212d8931847SRahul Lakkireddy 213d8931847SRahul Lakkireddy /* No candidate found to jump to next header. */ 214d8931847SRahul Lakkireddy if (!found) 215d8931847SRahul Lakkireddy return -EINVAL; 216d8931847SRahul Lakkireddy 217d8931847SRahul Lakkireddy return 0; 218d8931847SRahul Lakkireddy } 219d8931847SRahul Lakkireddy 220d8931847SRahul Lakkireddy /* Fill ch_filter_specification match fields to be shipped to hardware. 221d8931847SRahul Lakkireddy * Copy the linked spec (if any) first. And then update the spec as 222d8931847SRahul Lakkireddy * needed. 223d8931847SRahul Lakkireddy */ 224d8931847SRahul Lakkireddy if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) { 225d8931847SRahul Lakkireddy /* Copy linked ch_filter_specification */ 226d8931847SRahul Lakkireddy memcpy(&fs, &t->table[uhtid - 1].fs, sizeof(fs)); 227d8931847SRahul Lakkireddy ret = fill_match_fields(adapter, &fs, cls, 228d8931847SRahul Lakkireddy link_start, true); 229d8931847SRahul Lakkireddy if (ret) 230d8931847SRahul Lakkireddy goto out; 231d8931847SRahul Lakkireddy } 232d8931847SRahul Lakkireddy 233d8931847SRahul Lakkireddy ret = fill_match_fields(adapter, &fs, cls, start, false); 234d8931847SRahul Lakkireddy if (ret) 235d8931847SRahul Lakkireddy goto out; 236d8931847SRahul Lakkireddy 237d8931847SRahul Lakkireddy /* The filter spec has been completely built from the info 238d8931847SRahul Lakkireddy * provided from u32. We now set some default fields in the 239d8931847SRahul Lakkireddy * spec for sanity. 240d8931847SRahul Lakkireddy */ 241d8931847SRahul Lakkireddy 242d8931847SRahul Lakkireddy /* Match only packets coming from the ingress port where this 243d8931847SRahul Lakkireddy * filter will be created. 244d8931847SRahul Lakkireddy */ 245d8931847SRahul Lakkireddy fs.val.iport = netdev2pinfo(dev)->port_id; 246d8931847SRahul Lakkireddy fs.mask.iport = ~0; 247d8931847SRahul Lakkireddy 248d8931847SRahul Lakkireddy /* Enable filter hit counts. */ 249d8931847SRahul Lakkireddy fs.hitcnts = 1; 250d8931847SRahul Lakkireddy 251d8931847SRahul Lakkireddy /* Set type of filter - IPv6 or IPv4 */ 252d8931847SRahul Lakkireddy fs.type = is_ipv6 ? 1 : 0; 253d8931847SRahul Lakkireddy 254d8931847SRahul Lakkireddy /* Set the filter */ 255d8931847SRahul Lakkireddy ret = cxgb4_set_filter(dev, filter_id, &fs); 256d8931847SRahul Lakkireddy if (ret) 257d8931847SRahul Lakkireddy goto out; 258d8931847SRahul Lakkireddy 259d8931847SRahul Lakkireddy /* If this is a linked bucket, then set the corresponding 260d8931847SRahul Lakkireddy * entry in the bitmap to mark it as belonging to this linked 261d8931847SRahul Lakkireddy * bucket. 262d8931847SRahul Lakkireddy */ 263d8931847SRahul Lakkireddy if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) 264d8931847SRahul Lakkireddy set_bit(filter_id, t->table[uhtid - 1].tid_map); 265d8931847SRahul Lakkireddy 266d8931847SRahul Lakkireddy out: 267d8931847SRahul Lakkireddy return ret; 268d8931847SRahul Lakkireddy } 269d8931847SRahul Lakkireddy 270d8931847SRahul Lakkireddy int cxgb4_delete_knode(struct net_device *dev, __be16 protocol, 271d8931847SRahul Lakkireddy struct tc_cls_u32_offload *cls) 272d8931847SRahul Lakkireddy { 273d8931847SRahul Lakkireddy struct adapter *adapter = netdev2adap(dev); 274d8931847SRahul Lakkireddy unsigned int filter_id, max_tids, i, j; 275d8931847SRahul Lakkireddy struct cxgb4_link *link = NULL; 276d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *t; 277d8931847SRahul Lakkireddy u32 handle, uhtid; 278d8931847SRahul Lakkireddy int ret; 279d8931847SRahul Lakkireddy 280d8931847SRahul Lakkireddy if (!can_tc_u32_offload(dev)) 281d8931847SRahul Lakkireddy return -EOPNOTSUPP; 282d8931847SRahul Lakkireddy 283d8931847SRahul Lakkireddy /* Fetch the location to delete the filter. */ 284d8931847SRahul Lakkireddy filter_id = cls->knode.handle & 0xFFFFF; 285d8931847SRahul Lakkireddy 286d8931847SRahul Lakkireddy if (filter_id > adapter->tids.nftids) { 287d8931847SRahul Lakkireddy dev_err(adapter->pdev_dev, 288d8931847SRahul Lakkireddy "Location %d out of range for deletion. Max: %d\n", 289d8931847SRahul Lakkireddy filter_id, adapter->tids.nftids); 290d8931847SRahul Lakkireddy return -ERANGE; 291d8931847SRahul Lakkireddy } 292d8931847SRahul Lakkireddy 293d8931847SRahul Lakkireddy t = adapter->tc_u32; 294d8931847SRahul Lakkireddy handle = cls->knode.handle; 295d8931847SRahul Lakkireddy uhtid = TC_U32_USERHTID(cls->knode.handle); 296d8931847SRahul Lakkireddy 297d8931847SRahul Lakkireddy /* Ensure that uhtid is either root u32 (i.e. 0x800) 298d8931847SRahul Lakkireddy * or a a valid linked bucket. 299d8931847SRahul Lakkireddy */ 300d8931847SRahul Lakkireddy if (uhtid != 0x800 && uhtid >= t->size) 301d8931847SRahul Lakkireddy return -EINVAL; 302d8931847SRahul Lakkireddy 303d8931847SRahul Lakkireddy /* Delete the specified filter */ 304d8931847SRahul Lakkireddy if (uhtid != 0x800) { 305d8931847SRahul Lakkireddy link = &t->table[uhtid - 1]; 306d8931847SRahul Lakkireddy if (!link->link_handle) 307d8931847SRahul Lakkireddy return -EINVAL; 308d8931847SRahul Lakkireddy 309d8931847SRahul Lakkireddy if (!test_bit(filter_id, link->tid_map)) 310d8931847SRahul Lakkireddy return -EINVAL; 311d8931847SRahul Lakkireddy } 312d8931847SRahul Lakkireddy 313d8931847SRahul Lakkireddy ret = cxgb4_del_filter(dev, filter_id); 314d8931847SRahul Lakkireddy if (ret) 315d8931847SRahul Lakkireddy goto out; 316d8931847SRahul Lakkireddy 317d8931847SRahul Lakkireddy if (link) 318d8931847SRahul Lakkireddy clear_bit(filter_id, link->tid_map); 319d8931847SRahul Lakkireddy 320d8931847SRahul Lakkireddy /* If a link is being deleted, then delete all filters 321d8931847SRahul Lakkireddy * associated with the link. 322d8931847SRahul Lakkireddy */ 323d8931847SRahul Lakkireddy max_tids = adapter->tids.nftids; 324d8931847SRahul Lakkireddy for (i = 0; i < t->size; i++) { 325d8931847SRahul Lakkireddy link = &t->table[i]; 326d8931847SRahul Lakkireddy 327d8931847SRahul Lakkireddy if (link->link_handle == handle) { 328d8931847SRahul Lakkireddy for (j = 0; j < max_tids; j++) { 329d8931847SRahul Lakkireddy if (!test_bit(j, link->tid_map)) 330d8931847SRahul Lakkireddy continue; 331d8931847SRahul Lakkireddy 332d8931847SRahul Lakkireddy ret = __cxgb4_del_filter(dev, j, NULL); 333d8931847SRahul Lakkireddy if (ret) 334d8931847SRahul Lakkireddy goto out; 335d8931847SRahul Lakkireddy 336d8931847SRahul Lakkireddy clear_bit(j, link->tid_map); 337d8931847SRahul Lakkireddy } 338d8931847SRahul Lakkireddy 339d8931847SRahul Lakkireddy /* Clear the link state */ 340d8931847SRahul Lakkireddy link->match_field = NULL; 341d8931847SRahul Lakkireddy link->link_handle = 0; 342d8931847SRahul Lakkireddy memset(&link->fs, 0, sizeof(link->fs)); 343d8931847SRahul Lakkireddy break; 344d8931847SRahul Lakkireddy } 345d8931847SRahul Lakkireddy } 346d8931847SRahul Lakkireddy 347d8931847SRahul Lakkireddy out: 348d8931847SRahul Lakkireddy return ret; 349d8931847SRahul Lakkireddy } 350d8931847SRahul Lakkireddy 351d8931847SRahul Lakkireddy void cxgb4_cleanup_tc_u32(struct adapter *adap) 352d8931847SRahul Lakkireddy { 353d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *t; 354d8931847SRahul Lakkireddy unsigned int i; 355d8931847SRahul Lakkireddy 356d8931847SRahul Lakkireddy if (!adap->tc_u32) 357d8931847SRahul Lakkireddy return; 358d8931847SRahul Lakkireddy 359d8931847SRahul Lakkireddy /* Free up all allocated memory. */ 360d8931847SRahul Lakkireddy t = adap->tc_u32; 361d8931847SRahul Lakkireddy for (i = 0; i < t->size; i++) { 362d8931847SRahul Lakkireddy struct cxgb4_link *link = &t->table[i]; 363d8931847SRahul Lakkireddy 364d8931847SRahul Lakkireddy t4_free_mem(link->tid_map); 365d8931847SRahul Lakkireddy } 366d8931847SRahul Lakkireddy t4_free_mem(adap->tc_u32); 367d8931847SRahul Lakkireddy } 368d8931847SRahul Lakkireddy 369d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap, 370d8931847SRahul Lakkireddy unsigned int size) 371d8931847SRahul Lakkireddy { 372d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *t; 373d8931847SRahul Lakkireddy unsigned int i; 374d8931847SRahul Lakkireddy 375d8931847SRahul Lakkireddy if (!size) 376d8931847SRahul Lakkireddy return NULL; 377d8931847SRahul Lakkireddy 378d8931847SRahul Lakkireddy t = t4_alloc_mem(sizeof(*t) + 379d8931847SRahul Lakkireddy (size * sizeof(struct cxgb4_link))); 380d8931847SRahul Lakkireddy if (!t) 381d8931847SRahul Lakkireddy return NULL; 382d8931847SRahul Lakkireddy 383d8931847SRahul Lakkireddy t->size = size; 384d8931847SRahul Lakkireddy 385d8931847SRahul Lakkireddy for (i = 0; i < t->size; i++) { 386d8931847SRahul Lakkireddy struct cxgb4_link *link = &t->table[i]; 387d8931847SRahul Lakkireddy unsigned int bmap_size; 388d8931847SRahul Lakkireddy unsigned int max_tids; 389d8931847SRahul Lakkireddy 390d8931847SRahul Lakkireddy max_tids = adap->tids.nftids; 391d8931847SRahul Lakkireddy bmap_size = BITS_TO_LONGS(max_tids); 392d8931847SRahul Lakkireddy link->tid_map = t4_alloc_mem(sizeof(unsigned long) * bmap_size); 393d8931847SRahul Lakkireddy if (!link->tid_map) 394d8931847SRahul Lakkireddy goto out_no_mem; 395d8931847SRahul Lakkireddy bitmap_zero(link->tid_map, max_tids); 396d8931847SRahul Lakkireddy } 397d8931847SRahul Lakkireddy 398d8931847SRahul Lakkireddy return t; 399d8931847SRahul Lakkireddy 400d8931847SRahul Lakkireddy out_no_mem: 401d8931847SRahul Lakkireddy for (i = 0; i < t->size; i++) { 402d8931847SRahul Lakkireddy struct cxgb4_link *link = &t->table[i]; 403d8931847SRahul Lakkireddy 404d8931847SRahul Lakkireddy if (link->tid_map) 405d8931847SRahul Lakkireddy t4_free_mem(link->tid_map); 406d8931847SRahul Lakkireddy } 407d8931847SRahul Lakkireddy 408d8931847SRahul Lakkireddy if (t) 409d8931847SRahul Lakkireddy t4_free_mem(t); 410d8931847SRahul Lakkireddy 411d8931847SRahul Lakkireddy return NULL; 412d8931847SRahul Lakkireddy } 413