ncsi-manage.c (30596ec32e2cd141d73ee8701386887def9e98c0) | ncsi-manage.c (062b3e1b6d4f2a33c1d0fd7ae9b4550da5cf7e4b) |
---|---|
1/* 2 * Copyright Gavin Shan, IBM Corporation 2016. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ --- 13 unchanged lines hidden (view full) --- 22 23#include "internal.h" 24#include "ncsi-pkt.h" 25#include "ncsi-netlink.h" 26 27LIST_HEAD(ncsi_dev_list); 28DEFINE_SPINLOCK(ncsi_dev_lock); 29 | 1/* 2 * Copyright Gavin Shan, IBM Corporation 2016. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ --- 13 unchanged lines hidden (view full) --- 22 23#include "internal.h" 24#include "ncsi-pkt.h" 25#include "ncsi-netlink.h" 26 27LIST_HEAD(ncsi_dev_list); 28DEFINE_SPINLOCK(ncsi_dev_lock); 29 |
30static inline int ncsi_filter_size(int table) 31{ 32 int sizes[] = { 2, 6, 6, 6 }; 33 34 BUILD_BUG_ON(ARRAY_SIZE(sizes) != NCSI_FILTER_MAX); 35 if (table < NCSI_FILTER_BASE || table >= NCSI_FILTER_MAX) 36 return -EINVAL; 37 38 return sizes[table]; 39} 40 41u32 *ncsi_get_filter(struct ncsi_channel *nc, int table, int index) 42{ 43 struct ncsi_channel_filter *ncf; 44 int size; 45 46 ncf = nc->filters[table]; 47 if (!ncf) 48 return NULL; 49 50 size = ncsi_filter_size(table); 51 if (size < 0) 52 return NULL; 53 54 return ncf->data + size * index; 55} 56 57/* Find the first active filter in a filter table that matches the given 58 * data parameter. If data is NULL, this returns the first active filter. 59 */ 60int ncsi_find_filter(struct ncsi_channel *nc, int table, void *data) 61{ 62 struct ncsi_channel_filter *ncf; 63 void *bitmap; 64 int index, size; 65 unsigned long flags; 66 67 ncf = nc->filters[table]; 68 if (!ncf) 69 return -ENXIO; 70 71 size = ncsi_filter_size(table); 72 if (size < 0) 73 return size; 74 75 spin_lock_irqsave(&nc->lock, flags); 76 bitmap = (void *)&ncf->bitmap; 77 index = -1; 78 while ((index = find_next_bit(bitmap, ncf->total, index + 1)) 79 < ncf->total) { 80 if (!data || !memcmp(ncf->data + size * index, data, size)) { 81 spin_unlock_irqrestore(&nc->lock, flags); 82 return index; 83 } 84 } 85 spin_unlock_irqrestore(&nc->lock, flags); 86 87 return -ENOENT; 88} 89 90int ncsi_add_filter(struct ncsi_channel *nc, int table, void *data) 91{ 92 struct ncsi_channel_filter *ncf; 93 int index, size; 94 void *bitmap; 95 unsigned long flags; 96 97 size = ncsi_filter_size(table); 98 if (size < 0) 99 return size; 100 101 index = ncsi_find_filter(nc, table, data); 102 if (index >= 0) 103 return index; 104 105 ncf = nc->filters[table]; 106 if (!ncf) 107 return -ENODEV; 108 109 spin_lock_irqsave(&nc->lock, flags); 110 bitmap = (void *)&ncf->bitmap; 111 do { 112 index = find_next_zero_bit(bitmap, ncf->total, 0); 113 if (index >= ncf->total) { 114 spin_unlock_irqrestore(&nc->lock, flags); 115 return -ENOSPC; 116 } 117 } while (test_and_set_bit(index, bitmap)); 118 119 memcpy(ncf->data + size * index, data, size); 120 spin_unlock_irqrestore(&nc->lock, flags); 121 122 return index; 123} 124 125int ncsi_remove_filter(struct ncsi_channel *nc, int table, int index) 126{ 127 struct ncsi_channel_filter *ncf; 128 int size; 129 void *bitmap; 130 unsigned long flags; 131 132 size = ncsi_filter_size(table); 133 if (size < 0) 134 return size; 135 136 ncf = nc->filters[table]; 137 if (!ncf || index >= ncf->total) 138 return -ENODEV; 139 140 spin_lock_irqsave(&nc->lock, flags); 141 bitmap = (void *)&ncf->bitmap; 142 if (test_and_clear_bit(index, bitmap)) 143 memset(ncf->data + size * index, 0, size); 144 spin_unlock_irqrestore(&nc->lock, flags); 145 146 return 0; 147} 148 | |
149static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down) 150{ 151 struct ncsi_dev *nd = &ndp->ndev; 152 struct ncsi_package *np; 153 struct ncsi_channel *nc; 154 unsigned long flags; 155 156 nd->state = ncsi_dev_state_functional; --- 177 unchanged lines hidden (view full) --- 334 spin_unlock_irqrestore(&np->lock, flags); 335 336 return nc; 337} 338 339static void ncsi_remove_channel(struct ncsi_channel *nc) 340{ 341 struct ncsi_package *np = nc->package; | 30static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down) 31{ 32 struct ncsi_dev *nd = &ndp->ndev; 33 struct ncsi_package *np; 34 struct ncsi_channel *nc; 35 unsigned long flags; 36 37 nd->state = ncsi_dev_state_functional; --- 177 unchanged lines hidden (view full) --- 215 spin_unlock_irqrestore(&np->lock, flags); 216 217 return nc; 218} 219 220static void ncsi_remove_channel(struct ncsi_channel *nc) 221{ 222 struct ncsi_package *np = nc->package; |
342 struct ncsi_channel_filter *ncf; | |
343 unsigned long flags; | 223 unsigned long flags; |
344 int i; | |
345 | 224 |
346 /* Release filters */ | |
347 spin_lock_irqsave(&nc->lock, flags); | 225 spin_lock_irqsave(&nc->lock, flags); |
348 for (i = 0; i < NCSI_FILTER_MAX; i++) { 349 ncf = nc->filters[i]; 350 if (!ncf) 351 continue; | |
352 | 226 |
353 nc->filters[i] = NULL; 354 kfree(ncf); 355 } | 227 /* Release filters */ 228 kfree(nc->mac_filter.addrs); 229 kfree(nc->vlan_filter.vids); |
356 357 nc->state = NCSI_CHANNEL_INACTIVE; 358 spin_unlock_irqrestore(&nc->lock, flags); 359 ncsi_stop_channel_monitor(nc); 360 361 /* Remove and free channel */ 362 spin_lock_irqsave(&np->lock, flags); 363 list_del_rcu(&nc->node); --- 301 unchanged lines hidden (view full) --- 665} 666 667/* Check the VLAN filter bitmap for a set filter, and construct a 668 * "Set VLAN Filter - Disable" packet if found. 669 */ 670static int clear_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 671 struct ncsi_cmd_arg *nca) 672{ | 230 231 nc->state = NCSI_CHANNEL_INACTIVE; 232 spin_unlock_irqrestore(&nc->lock, flags); 233 ncsi_stop_channel_monitor(nc); 234 235 /* Remove and free channel */ 236 spin_lock_irqsave(&np->lock, flags); 237 list_del_rcu(&nc->node); --- 301 unchanged lines hidden (view full) --- 539} 540 541/* Check the VLAN filter bitmap for a set filter, and construct a 542 * "Set VLAN Filter - Disable" packet if found. 543 */ 544static int clear_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 545 struct ncsi_cmd_arg *nca) 546{ |
547 struct ncsi_channel_vlan_filter *ncf; 548 unsigned long flags; 549 void *bitmap; |
|
673 int index; | 550 int index; |
674 u32 *data; | |
675 u16 vid; 676 | 551 u16 vid; 552 |
677 index = ncsi_find_filter(nc, NCSI_FILTER_VLAN, NULL); 678 if (index < 0) { 679 /* Filter table empty */ | 553 ncf = &nc->vlan_filter; 554 bitmap = &ncf->bitmap; 555 556 spin_lock_irqsave(&nc->lock, flags); 557 index = find_next_bit(bitmap, ncf->n_vids, 0); 558 if (index >= ncf->n_vids) { 559 spin_unlock_irqrestore(&nc->lock, flags); |
680 return -1; 681 } | 560 return -1; 561 } |
562 vid = ncf->vids[index]; |
|
682 | 563 |
683 data = ncsi_get_filter(nc, NCSI_FILTER_VLAN, index); 684 if (!data) { 685 netdev_err(ndp->ndev.dev, 686 "NCSI: failed to retrieve filter %d\n", index); 687 /* Set the VLAN id to 0 - this will still disable the entry in 688 * the filter table, but we won't know what it was. 689 */ 690 vid = 0; 691 } else { 692 vid = *(u16 *)data; 693 } | 564 clear_bit(index, bitmap); 565 ncf->vids[index] = 0; 566 spin_unlock_irqrestore(&nc->lock, flags); |
694 | 567 |
695 netdev_printk(KERN_DEBUG, ndp->ndev.dev, 696 "NCSI: removed vlan tag %u at index %d\n", 697 vid, index + 1); 698 ncsi_remove_filter(nc, NCSI_FILTER_VLAN, index); 699 | |
700 nca->type = NCSI_PKT_CMD_SVF; 701 nca->words[1] = vid; 702 /* HW filter index starts at 1 */ 703 nca->bytes[6] = index + 1; 704 nca->bytes[7] = 0x00; 705 return 0; 706} 707 708/* Find an outstanding VLAN tag and constuct a "Set VLAN Filter - Enable" 709 * packet. 710 */ 711static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 712 struct ncsi_cmd_arg *nca) 713{ | 568 nca->type = NCSI_PKT_CMD_SVF; 569 nca->words[1] = vid; 570 /* HW filter index starts at 1 */ 571 nca->bytes[6] = index + 1; 572 nca->bytes[7] = 0x00; 573 return 0; 574} 575 576/* Find an outstanding VLAN tag and constuct a "Set VLAN Filter - Enable" 577 * packet. 578 */ 579static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 580 struct ncsi_cmd_arg *nca) 581{ |
582 struct ncsi_channel_vlan_filter *ncf; |
|
714 struct vlan_vid *vlan = NULL; | 583 struct vlan_vid *vlan = NULL; |
715 int index = 0; | 584 unsigned long flags; 585 int i, index; 586 void *bitmap; 587 u16 vid; |
716 | 588 |
589 if (list_empty(&ndp->vlan_vids)) 590 return -1; 591 592 ncf = &nc->vlan_filter; 593 bitmap = &ncf->bitmap; 594 595 spin_lock_irqsave(&nc->lock, flags); 596 597 rcu_read_lock(); |
|
717 list_for_each_entry_rcu(vlan, &ndp->vlan_vids, list) { | 598 list_for_each_entry_rcu(vlan, &ndp->vlan_vids, list) { |
718 index = ncsi_find_filter(nc, NCSI_FILTER_VLAN, &vlan->vid); 719 if (index < 0) { 720 /* New tag to add */ 721 netdev_printk(KERN_DEBUG, ndp->ndev.dev, 722 "NCSI: new vlan id to set: %u\n", 723 vlan->vid); | 599 vid = vlan->vid; 600 for (i = 0; i < ncf->n_vids; i++) 601 if (ncf->vids[i] == vid) { 602 vid = 0; 603 break; 604 } 605 if (vid) |
724 break; | 606 break; |
725 } 726 netdev_printk(KERN_DEBUG, ndp->ndev.dev, 727 "vid %u already at filter pos %d\n", 728 vlan->vid, index); | |
729 } | 607 } |
608 rcu_read_unlock(); |
|
730 | 609 |
731 if (!vlan || index >= 0) { 732 netdev_printk(KERN_DEBUG, ndp->ndev.dev, 733 "no vlan ids left to set\n"); | 610 if (!vid) { 611 /* No VLAN ID is not set */ 612 spin_unlock_irqrestore(&nc->lock, flags); |
734 return -1; 735 } 736 | 613 return -1; 614 } 615 |
737 index = ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan->vid); 738 if (index < 0) { | 616 index = find_next_zero_bit(bitmap, ncf->n_vids, 0); 617 if (index < 0 || index >= ncf->n_vids) { |
739 netdev_err(ndp->ndev.dev, | 618 netdev_err(ndp->ndev.dev, |
740 "Failed to add new VLAN tag, error %d\n", index); 741 if (index == -ENOSPC) 742 netdev_err(ndp->ndev.dev, 743 "Channel %u already has all VLAN filters set\n", 744 nc->id); | 619 "Channel %u already has all VLAN filters set\n", 620 nc->id); 621 spin_unlock_irqrestore(&nc->lock, flags); |
745 return -1; 746 } 747 | 622 return -1; 623 } 624 |
748 netdev_printk(KERN_DEBUG, ndp->ndev.dev, 749 "NCSI: set vid %u in packet, index %u\n", 750 vlan->vid, index + 1); | 625 ncf->vids[index] = vid; 626 set_bit(index, bitmap); 627 spin_unlock_irqrestore(&nc->lock, flags); 628 |
751 nca->type = NCSI_PKT_CMD_SVF; | 629 nca->type = NCSI_PKT_CMD_SVF; |
752 nca->words[1] = vlan->vid; | 630 nca->words[1] = vid; |
753 /* HW filter index starts at 1 */ 754 nca->bytes[6] = index + 1; 755 nca->bytes[7] = 0x01; 756 757 return 0; 758} 759 760static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) --- 940 unchanged lines hidden --- | 631 /* HW filter index starts at 1 */ 632 nca->bytes[6] = index + 1; 633 nca->bytes[7] = 0x01; 634 635 return 0; 636} 637 638static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) --- 940 unchanged lines hidden --- |