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 ---