diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /net/atm/atm_misc.c | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'net/atm/atm_misc.c')
-rw-r--r-- | net/atm/atm_misc.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c new file mode 100644 index 000000000..2a3a891b8 --- /dev/null +++ b/net/atm/atm_misc.c @@ -0,0 +1,143 @@ +/* net/atm/atm_misc.c - Various functions for use by ATM drivers */ + +/* Written 1995-1999 by Werner Almesberger, EPFL ICA */ + + +#include <linux/module.h> +#include <linux/atm.h> +#include <linux/atmdev.h> +#include <linux/skbuff.h> +#include <asm/atomic.h> +#include <asm/errno.h> + +#include "tunable.h" + + +int atm_charge(struct atm_vcc *vcc,int truesize) +{ + atm_force_charge(vcc,truesize); + if (atomic_read(&vcc->rx_inuse) <= vcc->rx_quota) return 1; + atm_return(vcc,truesize); + vcc->stats->rx_drop++; + return 0; +} + + +struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, + int gfp_flags) +{ + int guess = atm_guess_pdu2truesize(pdu_size); + + atm_force_charge(vcc,guess); + if (atomic_read(&vcc->rx_inuse) <= vcc->rx_quota) { + struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags); + + if (skb) { + atomic_add(skb->truesize-guess,&vcc->rx_inuse); + return skb; + } + } + atm_return(vcc,guess); + vcc->stats->rx_drop++; + return NULL; +} + + +static int check_ci(struct atm_vcc *vcc,short vpi,int vci) +{ + struct atm_vcc *walk; + + for (walk = vcc->dev->vccs; walk; walk = walk->next) + if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi && + walk->vci == vci && ((walk->qos.txtp.traffic_class != + ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || + (walk->qos.rxtp.traffic_class != ATM_NONE && + vcc->qos.rxtp.traffic_class != ATM_NONE))) + return -EADDRINUSE; + /* allow VCCs with same VPI/VCI iff they don't collide on + TX/RX (but we may refuse such sharing for other reasons, + e.g. if protocol requires to have both channels) */ + return 0; +} + + +int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) +{ + static short p = 0; /* poor man's per-device cache */ + static int c = 0; + short old_p; + int old_c; + + if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) + return check_ci(vcc,*vpi,*vci); + /* last scan may have left values out of bounds for current device */ + if (*vpi != ATM_VPI_ANY) p = *vpi; + else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; + if (*vci != ATM_VCI_ANY) c = *vci; + else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits) + c = ATM_NOT_RSV_VCI; + old_p = p; + old_c = c; + do { + if (!check_ci(vcc,p,c)) { + *vpi = p; + *vci = c; + return 0; + } + if (*vci == ATM_VCI_ANY) { + c++; + if (c >= 1 << vcc->dev->ci_range.vci_bits) + c = ATM_NOT_RSV_VCI; + } + if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) && + *vpi == ATM_VPI_ANY) { + p++; + if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; + } + } + while (old_p != p || old_c != c); + return -EADDRINUSE; +} + + +/* + * atm_pcr_goal returns the positive PCR if it should be rounded up, the + * negative PCR if it should be rounded down, and zero if the maximum available + * bandwidth should be used. + * + * The rules are as follows (* = maximum, - = absent (0), x = value "x", + * (x+ = x or next value above x, x- = x or next value below): + * + * min max pcr result min max pcr result + * - - - * (UBR only) x - - x+ + * - - * * x - * * + * - - z z- x - z z- + * - * - * x * - x+ + * - * * * x * * * + * - * z z- x * z z- + * - y - y- x y - x+ + * - y * y- x y * y- + * - y z z- x y z z- + * + * All non-error cases can be converted with the following simple set of rules: + * + * if pcr == z then z- + * else if min == x && pcr == - then x+ + * else if max == y then y- + * else * + */ + + +int atm_pcr_goal(struct atm_trafprm *tp) +{ + if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr; + if (tp->min_pcr && !tp->pcr) return tp->min_pcr; + if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr; + return 0; +} + + +EXPORT_SYMBOL(atm_charge); +EXPORT_SYMBOL(atm_alloc_charge); +EXPORT_SYMBOL(atm_find_ci); +EXPORT_SYMBOL(atm_pcr_goal); |