162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* net/atm/atm_misc.c - Various functions for use by ATM drivers */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL ICA */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/atm.h> 862306a36Sopenharmony_ci#include <linux/atmdev.h> 962306a36Sopenharmony_ci#include <linux/skbuff.h> 1062306a36Sopenharmony_ci#include <linux/sonet.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/atomic.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciint atm_charge(struct atm_vcc *vcc, int truesize) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci atm_force_charge(vcc, truesize); 1862306a36Sopenharmony_ci if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf) 1962306a36Sopenharmony_ci return 1; 2062306a36Sopenharmony_ci atm_return(vcc, truesize); 2162306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 2262306a36Sopenharmony_ci return 0; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ciEXPORT_SYMBOL(atm_charge); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size, 2762306a36Sopenharmony_ci gfp_t gfp_flags) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct sock *sk = sk_atm(vcc); 3062306a36Sopenharmony_ci int guess = SKB_TRUESIZE(pdu_size); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci atm_force_charge(vcc, guess); 3362306a36Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { 3462306a36Sopenharmony_ci struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (skb) { 3762306a36Sopenharmony_ci atomic_add(skb->truesize-guess, 3862306a36Sopenharmony_ci &sk->sk_rmem_alloc); 3962306a36Sopenharmony_ci return skb; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci atm_return(vcc, guess); 4362306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 4462306a36Sopenharmony_ci return NULL; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ciEXPORT_SYMBOL(atm_alloc_charge); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * atm_pcr_goal returns the positive PCR if it should be rounded up, the 5162306a36Sopenharmony_ci * negative PCR if it should be rounded down, and zero if the maximum available 5262306a36Sopenharmony_ci * bandwidth should be used. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * The rules are as follows (* = maximum, - = absent (0), x = value "x", 5562306a36Sopenharmony_ci * (x+ = x or next value above x, x- = x or next value below): 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * min max pcr result min max pcr result 5862306a36Sopenharmony_ci * - - - * (UBR only) x - - x+ 5962306a36Sopenharmony_ci * - - * * x - * * 6062306a36Sopenharmony_ci * - - z z- x - z z- 6162306a36Sopenharmony_ci * - * - * x * - x+ 6262306a36Sopenharmony_ci * - * * * x * * * 6362306a36Sopenharmony_ci * - * z z- x * z z- 6462306a36Sopenharmony_ci * - y - y- x y - x+ 6562306a36Sopenharmony_ci * - y * y- x y * y- 6662306a36Sopenharmony_ci * - y z z- x y z z- 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * All non-error cases can be converted with the following simple set of rules: 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * if pcr == z then z- 7162306a36Sopenharmony_ci * else if min == x && pcr == - then x+ 7262306a36Sopenharmony_ci * else if max == y then y- 7362306a36Sopenharmony_ci * else * 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint atm_pcr_goal(const struct atm_trafprm *tp) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci if (tp->pcr && tp->pcr != ATM_MAX_PCR) 7962306a36Sopenharmony_ci return -tp->pcr; 8062306a36Sopenharmony_ci if (tp->min_pcr && !tp->pcr) 8162306a36Sopenharmony_ci return tp->min_pcr; 8262306a36Sopenharmony_ci if (tp->max_pcr != ATM_MAX_PCR) 8362306a36Sopenharmony_ci return -tp->max_pcr; 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ciEXPORT_SYMBOL(atm_pcr_goal); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid sonet_copy_stats(struct k_sonet_stats *from, struct sonet_stats *to) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) 9162306a36Sopenharmony_ci __SONET_ITEMS 9262306a36Sopenharmony_ci#undef __HANDLE_ITEM 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ciEXPORT_SYMBOL(sonet_copy_stats); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid sonet_subtract_stats(struct k_sonet_stats *from, struct sonet_stats *to) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) 9962306a36Sopenharmony_ci __SONET_ITEMS 10062306a36Sopenharmony_ci#undef __HANDLE_ITEM 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ciEXPORT_SYMBOL(sonet_subtract_stats); 103