cleanup
[linux-2.4.21-pre4.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->rx_inuse) <= 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->rx_inuse) <= 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->rx_inuse);
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 atm_vcc *walk;
49
50         for (walk = vcc->dev->vccs; walk; walk = walk->next)
51                 if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
52                     walk->vci == vci && ((walk->qos.txtp.traffic_class !=
53                     ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
54                     (walk->qos.rxtp.traffic_class != ATM_NONE &&
55                     vcc->qos.rxtp.traffic_class != ATM_NONE)))
56                         return -EADDRINUSE;
57                 /* allow VCCs with same VPI/VCI iff they don't collide on
58                    TX/RX (but we may refuse such sharing for other reasons,
59                    e.g. if protocol requires to have both channels) */
60         return 0;
61 }
62
63
64 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
65 {
66         static short p = 0; /* poor man's per-device cache */
67         static int c = 0;
68         short old_p;
69         int old_c;
70
71         if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY)
72                 return check_ci(vcc,*vpi,*vci);
73         /* last scan may have left values out of bounds for current device */
74         if (*vpi != ATM_VPI_ANY) p = *vpi;
75         else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
76         if (*vci != ATM_VCI_ANY) c = *vci;
77         else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
78                         c = ATM_NOT_RSV_VCI;
79         old_p = p;
80         old_c = c;
81         do {
82                 if (!check_ci(vcc,p,c)) {
83                         *vpi = p;
84                         *vci = c;
85                         return 0;
86                 }
87                 if (*vci == ATM_VCI_ANY) {
88                         c++;
89                         if (c >= 1 << vcc->dev->ci_range.vci_bits)
90                                 c = ATM_NOT_RSV_VCI;
91                 }
92                 if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
93                     *vpi == ATM_VPI_ANY) {
94                         p++;
95                         if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
96                 }
97         }
98         while (old_p != p || old_c != c);
99         return -EADDRINUSE;
100 }
101
102
103 /*
104  * atm_pcr_goal returns the positive PCR if it should be rounded up, the
105  * negative PCR if it should be rounded down, and zero if the maximum available
106  * bandwidth should be used.
107  *
108  * The rules are as follows (* = maximum, - = absent (0), x = value "x",
109  * (x+ = x or next value above x, x- = x or next value below):
110  *
111  *      min max pcr     result          min max pcr     result
112  *      -   -   -       * (UBR only)    x   -   -       x+
113  *      -   -   *       *               x   -   *       *
114  *      -   -   z       z-              x   -   z       z-
115  *      -   *   -       *               x   *   -       x+
116  *      -   *   *       *               x   *   *       *
117  *      -   *   z       z-              x   *   z       z-
118  *      -   y   -       y-              x   y   -       x+
119  *      -   y   *       y-              x   y   *       y-
120  *      -   y   z       z-              x   y   z       z-
121  *
122  * All non-error cases can be converted with the following simple set of rules:
123  *
124  *   if pcr == z then z-
125  *   else if min == x && pcr == - then x+
126  *     else if max == y then y-
127  *       else *
128  */
129
130
131 int atm_pcr_goal(struct atm_trafprm *tp)
132 {
133         if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr;
134         if (tp->min_pcr && !tp->pcr) return tp->min_pcr;
135         if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr;
136         return 0;
137 }
138
139
140 void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
141 {
142 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
143         __SONET_ITEMS
144 #undef __HANDLE_ITEM
145 }
146
147
148 void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
149 {
150 #define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
151         __SONET_ITEMS
152 #undef __HANDLE_ITEM
153 }
154
155
156 EXPORT_SYMBOL(atm_charge);
157 EXPORT_SYMBOL(atm_alloc_charge);
158 EXPORT_SYMBOL(atm_find_ci);
159 EXPORT_SYMBOL(atm_pcr_goal);
160 EXPORT_SYMBOL(sonet_copy_stats);
161 EXPORT_SYMBOL(sonet_subtract_stats);