in nicstar.c [2480:2690]
static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg)
{
ns_dev *card;
pool_levels pl;
long btype;
unsigned long flags;
card = dev->dev_data;
switch (cmd) {
case NS_GETPSTAT:
if (get_user
(pl.buftype, &((pool_levels __user *) arg)->buftype))
return -EFAULT;
switch (pl.buftype) {
case NS_BUFTYPE_SMALL:
pl.count =
ns_stat_sfbqc_get(readl(card->membase + STAT));
pl.level.min = card->sbnr.min;
pl.level.init = card->sbnr.init;
pl.level.max = card->sbnr.max;
break;
case NS_BUFTYPE_LARGE:
pl.count =
ns_stat_lfbqc_get(readl(card->membase + STAT));
pl.level.min = card->lbnr.min;
pl.level.init = card->lbnr.init;
pl.level.max = card->lbnr.max;
break;
case NS_BUFTYPE_HUGE:
pl.count = card->hbpool.count;
pl.level.min = card->hbnr.min;
pl.level.init = card->hbnr.init;
pl.level.max = card->hbnr.max;
break;
case NS_BUFTYPE_IOVEC:
pl.count = card->iovpool.count;
pl.level.min = card->iovnr.min;
pl.level.init = card->iovnr.init;
pl.level.max = card->iovnr.max;
break;
default:
return -ENOIOCTLCMD;
}
if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
return (sizeof(pl));
else
return -EFAULT;
case NS_SETBUFLEV:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
return -EFAULT;
if (pl.level.min >= pl.level.init
|| pl.level.init >= pl.level.max)
return -EINVAL;
if (pl.level.min == 0)
return -EINVAL;
switch (pl.buftype) {
case NS_BUFTYPE_SMALL:
if (pl.level.max > TOP_SB)
return -EINVAL;
card->sbnr.min = pl.level.min;
card->sbnr.init = pl.level.init;
card->sbnr.max = pl.level.max;
break;
case NS_BUFTYPE_LARGE:
if (pl.level.max > TOP_LB)
return -EINVAL;
card->lbnr.min = pl.level.min;
card->lbnr.init = pl.level.init;
card->lbnr.max = pl.level.max;
break;
case NS_BUFTYPE_HUGE:
if (pl.level.max > TOP_HB)
return -EINVAL;
card->hbnr.min = pl.level.min;
card->hbnr.init = pl.level.init;
card->hbnr.max = pl.level.max;
break;
case NS_BUFTYPE_IOVEC:
if (pl.level.max > TOP_IOVB)
return -EINVAL;
card->iovnr.min = pl.level.min;
card->iovnr.init = pl.level.init;
card->iovnr.max = pl.level.max;
break;
default:
return -EINVAL;
}
return 0;
case NS_ADJBUFLEV:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
btype = (long)arg; /* a long is the same size as a pointer or bigger */
switch (btype) {
case NS_BUFTYPE_SMALL:
while (card->sbfqc < card->sbnr.init) {
struct sk_buff *sb;
sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
if (sb == NULL)
return -ENOMEM;
NS_PRV_BUFTYPE(sb) = BUF_SM;
skb_queue_tail(&card->sbpool.queue, sb);
skb_reserve(sb, NS_AAL0_HEADER);
push_rxbufs(card, sb);
}
break;
case NS_BUFTYPE_LARGE:
while (card->lbfqc < card->lbnr.init) {
struct sk_buff *lb;
lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
if (lb == NULL)
return -ENOMEM;
NS_PRV_BUFTYPE(lb) = BUF_LG;
skb_queue_tail(&card->lbpool.queue, lb);
skb_reserve(lb, NS_SMBUFSIZE);
push_rxbufs(card, lb);
}
break;
case NS_BUFTYPE_HUGE:
while (card->hbpool.count > card->hbnr.init) {
struct sk_buff *hb;
spin_lock_irqsave(&card->int_lock, flags);
hb = skb_dequeue(&card->hbpool.queue);
card->hbpool.count--;
spin_unlock_irqrestore(&card->int_lock, flags);
if (hb == NULL)
printk
("nicstar%d: huge buffer count inconsistent.\n",
card->index);
else
dev_kfree_skb_any(hb);
}
while (card->hbpool.count < card->hbnr.init) {
struct sk_buff *hb;
hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
if (hb == NULL)
return -ENOMEM;
NS_PRV_BUFTYPE(hb) = BUF_NONE;
spin_lock_irqsave(&card->int_lock, flags);
skb_queue_tail(&card->hbpool.queue, hb);
card->hbpool.count++;
spin_unlock_irqrestore(&card->int_lock, flags);
}
break;
case NS_BUFTYPE_IOVEC:
while (card->iovpool.count > card->iovnr.init) {
struct sk_buff *iovb;
spin_lock_irqsave(&card->int_lock, flags);
iovb = skb_dequeue(&card->iovpool.queue);
card->iovpool.count--;
spin_unlock_irqrestore(&card->int_lock, flags);
if (iovb == NULL)
printk
("nicstar%d: iovec buffer count inconsistent.\n",
card->index);
else
dev_kfree_skb_any(iovb);
}
while (card->iovpool.count < card->iovnr.init) {
struct sk_buff *iovb;
iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
if (iovb == NULL)
return -ENOMEM;
NS_PRV_BUFTYPE(iovb) = BUF_NONE;
spin_lock_irqsave(&card->int_lock, flags);
skb_queue_tail(&card->iovpool.queue, iovb);
card->iovpool.count++;
spin_unlock_irqrestore(&card->int_lock, flags);
}
break;
default:
return -EINVAL;
}
return 0;
default:
if (dev->phy && dev->phy->ioctl) {
return dev->phy->ioctl(dev, cmd, arg);
} else {
printk("nicstar%d: %s == NULL \n", card->index,
dev->phy ? "dev->phy->ioctl" : "dev->phy");
return -ENOIOCTLCMD;
}
}
}