import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / net / atm / atm_misc.c
1 /* net/atm/atm_misc.c - Various functions for use by ATM drivers */
2
3 /* Written 1995-2000 by Werner Almesberger, EPFL ICA */
4
5
6 #include <linux/module.h>
7 #include <linux/atm.h>
8 #include <linux/atmdev.h>
9 #include <linux/skbuff.h>
10 #include <linux/sonet.h>
11 #include <linux/bitops.h>
12 #include <asm/atomic.h>
13 #include <asm/errno.h>
14
15
16 int atm_charge(struct atm_vcc *vcc,int truesize)
17 {
18         atm_force_charge(vcc,truesize);
19         if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) return 1;
20         atm_return(vcc,truesize);
21         atomic_inc(&vcc->stats->rx_drop);
22         return 0;
23 }
24
25
26 struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
27     int gfp_flags)
28 {
29         int guess = atm_guess_pdu2truesize(pdu_size);
30
31         atm_force_charge(vcc,guess);
32         if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) {
33                 struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
34
35                 if (skb) {
36                         atomic_add(skb->truesize-guess,&vcc->sk->rmem_alloc);
37                         return skb;
38                 }
39         }
40         atm_return(vcc,guess);
41         atomic_inc(&vcc->stats->rx_drop);
42         return NULL;
43 }
44
45
46 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
47 {
48         struct sock *s;
49         struct atm_vcc *walk;
50
51         for (s = vcc_sklist; s; s = s->next) {
52                 walk = s->protinfo.af_atm;
53                 if (walk->dev != vcc->dev)
54                         continue;
55                 if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
56                     walk->vci == vci && ((walk->qos.txtp.traffic_class !=
57                     ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
58                     (walk->qos.rxtp.traffic_class != ATM_NONE &&
59                     vcc->qos.rxtp.traffic_class != ATM_NONE)))
60                         return -EADDRINUSE;
61         }
62                 /* allow VCCs with same VPI/VCI iff they don't collide on
63                    TX/RX (but we may refuse such sharing for other reasons,
64                    e.g. if protocol requires to have both channels) */
65         return 0;
66 }
67
68
69 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
70 {
71         static short p = 0; /* poor man's per-device cache */
72         static int c = 0;
73         short old_p;
74         int old_c;
75         int err;
76
77         read_lock(&vcc_sklist_lock);
78         if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
79                 err = check_ci(vcc,*vpi,*vci);
80                 read_unlock(&vcc_sklist_lock);
81                 return err;
82         }
83         /* last scan may have left values out of bounds for current device */
84         if (*vpi != ATM_VPI_ANY) p = *vpi;
85         else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
86         if (*vci != ATM_VCI_ANY) c = *vci;
87         else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
88                         c = ATM_NOT_RSV_VCI;
89         old_p = p;
90         old_c = c;
91         do {
92                 if (!check_ci(vcc,p,c)) {
93                         *vpi = p;
94                         *vci = c;
95                         read_unlock(&vcc_sklist_lock);
96                         return 0;
97                 }
98                 if (*vci == ATM_VCI_ANY) {
99                         c++;
100                         if (c >= 1 << vcc->dev->ci_range.vci_bits)
101                                 c = ATM_NOT_RSV_VCI;
102                 }
103                 if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
104                     *vpi == ATM_VPI_ANY) {
105                         p++;
106                         if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
107                 }
108         }
109         while (old_p != p || old_c != c);
110         read_unlock(&vcc_sklist_lock);
111         return -EADDRINUSE;
112 }
113
114
115 /*
116  * atm_pcr_goal returns the positive PCR if it should be rounded up, the
117  * negative PCR if it should be rounded down, and zero if the maximum available
118  * bandwidth should be used.
119  *
120  * The rules are as follows (* = maximum, - = absent (0), x = value "x",
121  * (x+ = x or next value above x, x- = x or next value below):
122  *
123  *      min max pcr     result          min max pcr     result
124  *      -   -   -       * (UBR only)    x   -   -       x+
125  *      -   -   *       *               x   -   *       *
126  *      -   -   z       z-              x   -   z       z-
127  *      -   *   -       *               x   *   -       x+
128  *      -   *   *       *               x   *   *       *
129  *      -   *   z       z-              x   *   z       z-
130  *      -   y   -       y-              x   y   -       x+
131  *      -   y   *       y-              x   y   *       y-
132  *      -   y   z       z-              x   y   z       z-
133  *
134  * All non-error cases can be converted with the following simple set of rules:
135  *
136  *   if pcr == z then z-
137  *   else if min == x && pcr == - then x+
138  *     else if max == y then y-
139  *       else *
140  */
141
142
143 int atm_pcr_goal(struct atm_trafprm *tp)
144 {
145         if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr;
146         if (tp->min_pcr && !tp->pcr) return tp->min_pcr;
147         if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr;
148         return 0;
149 }
150
151
152 void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
153 {
154 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
155         __SONET_ITEMS
156 #undef __HANDLE_ITEM
157 }
158
159
160 void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
161 {
162 #define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
163         __SONET_ITEMS
164 #undef __HANDLE_ITEM
165 }
166
167
168 EXPORT_SYMBOL(atm_charge);
169 EXPORT_SYMBOL(atm_alloc_charge);
170 EXPORT_SYMBOL(atm_find_ci);
171 EXPORT_SYMBOL(atm_pcr_goal);
172 EXPORT_SYMBOL(sonet_copy_stats);
173 EXPORT_SYMBOL(sonet_subtract_stats);