in ambassador.c [998:1209]
static int amb_open (struct atm_vcc * atm_vcc)
{
int error;
struct atm_qos * qos;
struct atm_trafprm * txtp;
struct atm_trafprm * rxtp;
u16 tx_rate_bits = -1; // hush gcc
u16 tx_vc_bits = -1; // hush gcc
u16 tx_frame_bits = -1; // hush gcc
amb_dev * dev = AMB_DEV(atm_vcc->dev);
amb_vcc * vcc;
unsigned char pool = -1; // hush gcc
short vpi = atm_vcc->vpi;
int vci = atm_vcc->vci;
PRINTD (DBG_FLOW|DBG_VCC, "amb_open %x %x", vpi, vci);
#ifdef ATM_VPI_UNSPEC
// UNSPEC is deprecated, remove this code eventually
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) {
PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)");
return -EINVAL;
}
#endif
if (!(0 <= vpi && vpi < (1<<NUM_VPI_BITS) &&
0 <= vci && vci < (1<<NUM_VCI_BITS))) {
PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci);
return -EINVAL;
}
qos = &atm_vcc->qos;
if (qos->aal != ATM_AAL5) {
PRINTD (DBG_QOS, "AAL not supported");
return -EINVAL;
}
// traffic parameters
PRINTD (DBG_QOS, "TX:");
txtp = &qos->txtp;
if (txtp->traffic_class != ATM_NONE) {
switch (txtp->traffic_class) {
case ATM_UBR: {
// we take "the PCR" as a rate-cap
int pcr = atm_pcr_goal (txtp);
if (!pcr) {
// no rate cap
tx_rate_bits = 0;
tx_vc_bits = TX_UBR;
tx_frame_bits = TX_FRAME_NOTCAP;
} else {
rounding r;
if (pcr < 0) {
r = round_down;
pcr = -pcr;
} else {
r = round_up;
}
error = make_rate (pcr, r, &tx_rate_bits, NULL);
if (error)
return error;
tx_vc_bits = TX_UBR_CAPPED;
tx_frame_bits = TX_FRAME_CAPPED;
}
break;
}
#if 0
case ATM_ABR: {
pcr = atm_pcr_goal (txtp);
PRINTD (DBG_QOS, "pcr goal = %d", pcr);
break;
}
#endif
default: {
// PRINTD (DBG_QOS, "request for non-UBR/ABR denied");
PRINTD (DBG_QOS, "request for non-UBR denied");
return -EINVAL;
}
}
PRINTD (DBG_QOS, "tx_rate_bits=%hx, tx_vc_bits=%hx",
tx_rate_bits, tx_vc_bits);
}
PRINTD (DBG_QOS, "RX:");
rxtp = &qos->rxtp;
if (rxtp->traffic_class == ATM_NONE) {
// do nothing
} else {
// choose an RX pool (arranged in increasing size)
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
if ((unsigned int) rxtp->max_sdu <= dev->rxq[pool].buffer_size) {
PRINTD (DBG_VCC|DBG_QOS|DBG_POOL, "chose pool %hu (max_sdu %u <= %u)",
pool, rxtp->max_sdu, dev->rxq[pool].buffer_size);
break;
}
if (pool == NUM_RX_POOLS) {
PRINTD (DBG_WARN|DBG_VCC|DBG_QOS|DBG_POOL,
"no pool suitable for VC (RX max_sdu %d is too large)",
rxtp->max_sdu);
return -EINVAL;
}
switch (rxtp->traffic_class) {
case ATM_UBR: {
break;
}
#if 0
case ATM_ABR: {
pcr = atm_pcr_goal (rxtp);
PRINTD (DBG_QOS, "pcr goal = %d", pcr);
break;
}
#endif
default: {
// PRINTD (DBG_QOS, "request for non-UBR/ABR denied");
PRINTD (DBG_QOS, "request for non-UBR denied");
return -EINVAL;
}
}
}
// get space for our vcc stuff
vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
if (!vcc) {
PRINTK (KERN_ERR, "out of memory!");
return -ENOMEM;
}
atm_vcc->dev_data = (void *) vcc;
// no failures beyond this point
// we are not really "immediately before allocating the connection
// identifier in hardware", but it will just have to do!
set_bit(ATM_VF_ADDR,&atm_vcc->flags);
if (txtp->traffic_class != ATM_NONE) {
command cmd;
vcc->tx_frame_bits = tx_frame_bits;
mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer on the channel already, just modify rate...
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
cmd.args.modify_rate.vc = cpu_to_be32 (vci); // vpi 0
cmd.args.modify_rate.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT);
while (command_do (dev, &cmd))
schedule();
// ... and TX flags, preserving the RX pool
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0
cmd.args.modify_flags.flags = cpu_to_be32
( (AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT)
| (tx_vc_bits << SRB_FLAGS_SHIFT) );
while (command_do (dev, &cmd))
schedule();
} else {
// no RXer on the channel, just open (with pool zero)
cmd.request = cpu_to_be32 (SRB_OPEN_VC);
cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0
cmd.args.open.flags = cpu_to_be32 (tx_vc_bits << SRB_FLAGS_SHIFT);
cmd.args.open.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT);
while (command_do (dev, &cmd))
schedule();
}
dev->txer[vci].tx_present = 1;
mutex_unlock(&dev->vcc_sf);
}
if (rxtp->traffic_class != ATM_NONE) {
command cmd;
vcc->rx_info.pool = pool;
mutex_lock(&dev->vcc_sf);
/* grow RX buffer pool */
if (!dev->rxq[pool].buffers_wanted)
dev->rxq[pool].buffers_wanted = rx_lats;
dev->rxq[pool].buffers_wanted += 1;
fill_rx_pool (dev, pool, GFP_KERNEL);
if (dev->txer[vci].tx_present) {
// TXer on the channel already
// switch (from pool zero) to this pool, preserving the TX bits
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0
cmd.args.modify_flags.flags = cpu_to_be32
( (pool << SRB_POOL_SHIFT)
| (dev->txer[vci].tx_vc_bits << SRB_FLAGS_SHIFT) );
} else {
// no TXer on the channel, open the VC (with no rate info)
cmd.request = cpu_to_be32 (SRB_OPEN_VC);
cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0
cmd.args.open.flags = cpu_to_be32 (pool << SRB_POOL_SHIFT);
cmd.args.open.rate = cpu_to_be32 (0);
}
while (command_do (dev, &cmd))
schedule();
// this link allows RX frames through
dev->rxer[vci] = atm_vcc;
mutex_unlock(&dev->vcc_sf);
}
// indicate readiness
set_bit(ATM_VF_READY,&atm_vcc->flags);
return 0;
}