in nicstar.c [1414:1575]
static void ns_close(struct atm_vcc *vcc)
{
vc_map *vc;
ns_dev *card;
u32 data;
int i;
vc = vcc->dev_data;
card = vcc->dev->dev_data;
PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
(int)vcc->vpi, vcc->vci);
clear_bit(ATM_VF_READY, &vcc->flags);
if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
u32 addr;
unsigned long flags;
addr =
NS_RCT +
(vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
spin_lock_irqsave(&card->res_lock, flags);
while (CMD_BUSY(card)) ;
writel(NS_CMD_CLOSE_CONNECTION | addr << 2,
card->membase + CMD);
spin_unlock_irqrestore(&card->res_lock, flags);
vc->rx = 0;
if (vc->rx_iov != NULL) {
struct sk_buff *iovb;
u32 stat;
stat = readl(card->membase + STAT);
card->sbfqc = ns_stat_sfbqc_get(stat);
card->lbfqc = ns_stat_lfbqc_get(stat);
PRINTK
("nicstar%d: closing a VC with pending rx buffers.\n",
card->index);
iovb = vc->rx_iov;
recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
NS_PRV_IOVCNT(iovb));
NS_PRV_IOVCNT(iovb) = 0;
spin_lock_irqsave(&card->int_lock, flags);
recycle_iov_buf(card, iovb);
spin_unlock_irqrestore(&card->int_lock, flags);
vc->rx_iov = NULL;
}
}
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
vc->tx = 0;
}
if (vcc->qos.txtp.traffic_class == ATM_CBR) {
unsigned long flags;
ns_scqe *scqep;
scq_info *scq;
scq = vc->scq;
for (;;) {
spin_lock_irqsave(&scq->lock, flags);
scqep = scq->next;
if (scqep == scq->base)
scqep = scq->last;
else
scqep--;
if (scqep == scq->tail) {
spin_unlock_irqrestore(&scq->lock, flags);
break;
}
/* If the last entry is not a TSR, place one in the SCQ in order to
be able to completely drain it and then close. */
if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) {
ns_scqe tsr;
u32 scdi, scqi;
u32 data;
int index;
tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
scqi = scq->next - scq->base;
tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
tsr.word_3 = 0x00000000;
tsr.word_4 = 0x00000000;
*scq->next = tsr;
index = (int)scqi;
scq->skb[index] = NULL;
if (scq->next == scq->last)
scq->next = scq->base;
else
scq->next++;
data = scq_virt_to_bus(scq, scq->next);
ns_write_sram(card, scq->scd, &data, 1);
}
spin_unlock_irqrestore(&scq->lock, flags);
schedule();
}
/* Free all TST entries */
data = NS_TST_OPCODE_VARIABLE;
for (i = 0; i < NS_TST_NUM_ENTRIES; i++) {
if (card->tste2vc[i] == vc) {
ns_write_sram(card, card->tst_addr + i, &data,
1);
card->tste2vc[i] = NULL;
card->tst_free_entries++;
}
}
card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
free_scq(card, vc->scq, vcc);
}
/* remove all references to vcc before deleting it */
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
unsigned long flags;
scq_info *scq = card->scq0;
spin_lock_irqsave(&scq->lock, flags);
for (i = 0; i < scq->num_entries; i++) {
if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
ATM_SKB(scq->skb[i])->vcc = NULL;
atm_return(vcc, scq->skb[i]->truesize);
PRINTK
("nicstar: deleted pending vcc mapping\n");
}
}
spin_unlock_irqrestore(&scq->lock, flags);
}
vcc->dev_data = NULL;
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
clear_bit(ATM_VF_ADDR, &vcc->flags);
#ifdef RX_DEBUG
{
u32 stat, cfg;
stat = readl(card->membase + STAT);
cfg = readl(card->membase + CFG);
printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg);
printk
("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n",
card->tsq.base, card->tsq.next,
card->tsq.last, readl(card->membase + TSQT));
printk
("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n",
card->rsq.base, card->rsq.next,
card->rsq.last, readl(card->membase + RSQT));
printk("Empty free buffer queue interrupt %s \n",
card->efbie ? "enabled" : "disabled");
printk("SBCNT = %d count = %d LBCNT = %d count = %d \n",
ns_stat_sfbqc_get(stat), card->sbpool.count,
ns_stat_lfbqc_get(stat), card->lbpool.count);
printk("hbpool.count = %d iovpool.count = %d \n",
card->hbpool.count, card->iovpool.count);
}
#endif /* RX_DEBUG */
}