in eni.c [1285:1370]
static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp,
int set_rsv,int set_shp)
{
struct eni_dev *eni_dev = ENI_DEV(vcc->dev);
struct eni_vcc *eni_vcc = ENI_VCC(vcc);
struct eni_tx *tx;
unsigned long size;
void __iomem *mem;
int rate,ubr,unlimited,new_tx;
int pre,res,order;
int error;
rate = atm_pcr_goal(txtp);
ubr = txtp->traffic_class == ATM_UBR;
unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR ||
rate >= ATM_OC3_PCR);
if (!unlimited) {
size = txtp->max_sdu*eni_dev->tx_mult/100;
if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <=
MID_MAX_BUF_SIZE)
size = MID_MAX_BUF_SIZE;
}
else {
if (eni_dev->ubr) {
eni_vcc->tx = eni_dev->ubr;
txtp->pcr = ATM_OC3_PCR;
return 0;
}
size = UBR_BUFFER;
}
new_tx = !eni_vcc->tx;
mem = NULL; /* for gcc */
if (!new_tx) tx = eni_vcc->tx;
else {
mem = eni_alloc_mem(eni_dev,&size);
if (!mem) return -ENOBUFS;
tx = alloc_tx(eni_dev,unlimited);
if (!tx) {
eni_free_mem(eni_dev,mem,size);
return -EBUSY;
}
DPRINTK("got chan %d\n",tx->index);
tx->reserved = tx->shaping = 0;
tx->send = mem;
tx->words = size >> 2;
skb_queue_head_init(&tx->backlog);
for (order = 0; size > (1 << (order+10)); order++);
eni_out((order << MID_SIZE_SHIFT) |
((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)),
MID_TX_PLACE(tx->index));
tx->tx_pos = eni_in(MID_TX_DESCRSTART(tx->index)) &
MID_DESCR_START;
}
error = comp_tx(eni_dev,&rate,tx->reserved,&pre,&res,unlimited);
if (!error && txtp->min_pcr > rate) error = -EINVAL;
if (!error && txtp->max_pcr && txtp->max_pcr != ATM_MAX_PCR &&
txtp->max_pcr < rate) error = -EINVAL;
if (!error && !ubr && rate > eni_dev->tx_bw+tx->reserved)
error = -EINVAL;
if (!error && set_rsv && !set_shp && rate < tx->shaping)
error = -EINVAL;
if (!error && !set_rsv && rate > tx->reserved && !ubr)
error = -EINVAL;
if (error) {
if (new_tx) {
tx->send = NULL;
eni_free_mem(eni_dev,mem,size);
}
return error;
}
txtp->pcr = rate;
if (set_rsv && !ubr) {
eni_dev->tx_bw += tx->reserved;
tx->reserved = rate;
eni_dev->tx_bw -= rate;
}
if (set_shp || (unlimited && new_tx)) {
if (unlimited && new_tx) eni_dev->ubr = tx;
tx->prescaler = pre;
tx->resolution = res;
tx->shaping = rate;
}
if (set_shp) eni_vcc->tx = tx;
DPRINTK("rsv %d shp %d\n",tx->reserved,tx->shaping);
return 0;
}