in nicstar.c [1232:1412]
static int ns_open(struct atm_vcc *vcc)
{
ns_dev *card;
vc_map *vc;
unsigned long tmpl, modl;
int tcr, tcra; /* target cell rate, and absolute value */
int n = 0; /* Number of entries in the TST. Initialized to remove
the compiler warning. */
u32 u32d[4];
int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler
warning. How I wish compilers were clever enough to
tell which variables can truly be used
uninitialized... */
int inuse; /* tx or rx vc already in use by another vcc */
short vpi = vcc->vpi;
int vci = vcc->vci;
card = (ns_dev *) vcc->dev->dev_data;
PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi,
vci);
if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
PRINTK("nicstar%d: unsupported AAL.\n", card->index);
return -EINVAL;
}
vc = &(card->vcmap[vpi << card->vcibits | vci]);
vcc->dev_data = vc;
inuse = 0;
if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
inuse = 1;
if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
inuse += 2;
if (inuse) {
printk("nicstar%d: %s vci already in use.\n", card->index,
inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
return -EINVAL;
}
set_bit(ATM_VF_ADDR, &vcc->flags);
/* NOTE: You are not allowed to modify an open connection's QOS. To change
that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
needed to do that. */
if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
scq_info *scq;
set_bit(ATM_VF_PARTIAL, &vcc->flags);
if (vcc->qos.txtp.traffic_class == ATM_CBR) {
/* Check requested cell rate and availability of SCD */
if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0
&& vcc->qos.txtp.min_pcr == 0) {
PRINTK
("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
card->index);
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -EINVAL;
}
tcr = atm_pcr_goal(&(vcc->qos.txtp));
tcra = tcr >= 0 ? tcr : -tcr;
PRINTK("nicstar%d: target cell rate = %d.\n",
card->index, vcc->qos.txtp.max_pcr);
tmpl =
(unsigned long)tcra *(unsigned long)
NS_TST_NUM_ENTRIES;
modl = tmpl % card->max_pcr;
n = (int)(tmpl / card->max_pcr);
if (tcr > 0) {
if (modl > 0)
n++;
} else if (tcr == 0) {
if ((n =
(card->tst_free_entries -
NS_TST_RESERVED)) <= 0) {
PRINTK
("nicstar%d: no CBR bandwidth free.\n",
card->index);
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -EINVAL;
}
}
if (n == 0) {
printk
("nicstar%d: selected bandwidth < granularity.\n",
card->index);
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -EINVAL;
}
if (n > (card->tst_free_entries - NS_TST_RESERVED)) {
PRINTK
("nicstar%d: not enough free CBR bandwidth.\n",
card->index);
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -EINVAL;
} else
card->tst_free_entries -= n;
XPRINTK("nicstar%d: writing %d tst entries.\n",
card->index, n);
for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) {
if (card->scd2vc[frscdi] == NULL) {
card->scd2vc[frscdi] = vc;
break;
}
}
if (frscdi == NS_FRSCD_NUM) {
PRINTK
("nicstar%d: no SCD available for CBR channel.\n",
card->index);
card->tst_free_entries += n;
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -EBUSY;
}
vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd);
if (scq == NULL) {
PRINTK("nicstar%d: can't get fixed rate SCQ.\n",
card->index);
card->scd2vc[frscdi] = NULL;
card->tst_free_entries += n;
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
return -ENOMEM;
}
vc->scq = scq;
u32d[0] = scq_virt_to_bus(scq, scq->base);
u32d[1] = (u32) 0x00000000;
u32d[2] = (u32) 0xffffffff;
u32d[3] = (u32) 0x00000000;
ns_write_sram(card, vc->cbr_scd, u32d, 4);
fill_tst(card, n, vc);
} else if (vcc->qos.txtp.traffic_class == ATM_UBR) {
vc->cbr_scd = 0x00000000;
vc->scq = card->scq0;
}
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
vc->tx = 1;
vc->tx_vcc = vcc;
vc->tbd_count = 0;
}
if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
u32 status;
vc->rx = 1;
vc->rx_vcc = vcc;
vc->rx_iov = NULL;
/* Open the connection in hardware */
if (vcc->qos.aal == ATM_AAL5)
status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
else /* vcc->qos.aal == ATM_AAL0 */
status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
#ifdef RCQ_SUPPORT
status |= NS_RCTE_RAWCELLINTEN;
#endif /* RCQ_SUPPORT */
ns_write_sram(card,
NS_RCT +
(vpi << card->vcibits | vci) *
NS_RCT_ENTRY_SIZE, &status, 1);
}
}
set_bit(ATM_VF_READY, &vcc->flags);
return 0;
}