#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
-#include <linux/ioport.h> /* for request_region */
#include <linux/uio.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
#include <linux/atm_zatm.h>
#include <linux/capability.h>
#include <linux/bitops.h>
+#include <linux/wait.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/string.h>
* - OAM
*/
+#define ZATM_COPPER 1
+
#if 0
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else
EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >>
uPD98401_AAL5_ES_SHIFT,error);
skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb;
- do_gettimeofday(&skb->stamp);
+ __net_timestamp(skb);
#if 0
printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1],
#if 0
printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
#endif
- size = error ? 0 : ntohs(((u16 *) skb->data)[cells*
+ size = error ? 0 : ntohs(((__be16 *) skb->data)[cells*
ATM_CELL_PAYLOAD/sizeof(u16)-3]);
EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size);
chan = (here[3] & uPD98401_AAL5_CHAN) >>
uPD98401_AAL5_CHAN_SHIFT;
if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) {
+ int pos;
vcc = zatm_dev->rx_map[chan];
- if (skb == zatm_dev->last_free[ZATM_VCC(vcc)->pool])
- zatm_dev->last_free[ZATM_VCC(vcc)->pool] = NULL;
- skb_unlink(skb);
+ pos = ZATM_VCC(vcc)->pool;
+ if (skb == zatm_dev->last_free[pos])
+ zatm_dev->last_free[pos] = NULL;
+ skb_unlink(skb, zatm_dev->pool + pos);
}
else {
printk(KERN_ERR DEV_LABEL "(itf %d): RX indication "
u32 *put;
int i;
- dsc = (u32 *) kmalloc(uPD98401_TXPD_SIZE*2+
- uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC);
+ dsc = kmalloc(uPD98401_TXPD_SIZE * 2 +
+ uPD98401_TXBD_SIZE * ATM_SKB(skb)->iovcnt, GFP_ATOMIC);
if (!dsc) {
- if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb_irq(skb);
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb_irq(skb);
return -EAGAIN;
}
/* @@@ should check alignment */
(ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ?
uPD98401_CLPM_1 : uPD98401_CLPM_0));
dsc[1] = 0;
- dsc[2] = ATM_SKB(skb)->iovcnt*uPD98401_TXBD_SIZE;
+ dsc[2] = ATM_SKB(skb)->iovcnt * uPD98401_TXBD_SIZE;
dsc[3] = virt_to_bus(put);
for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) {
*put++ = ((struct iovec *) skb->data)[i].iov_len;
struct zatm_vcc *zatm_vcc;
unsigned long flags;
int chan;
-struct sk_buff *skb;
-int once = 1;
zatm_vcc = ZATM_VCC(vcc);
zatm_dev = ZATM_DEV(vcc->dev);
chan = zatm_vcc->tx_chan;
if (!chan) return;
DPRINTK("close_tx\n");
- while (skb_peek(&zatm_vcc->backlog)) {
-if (once) {
-printk("waiting for backlog to drain ...\n");
-event_dump();
-once = 0;
-}
- sleep_on(&zatm_vcc->tx_wait);
+ if (skb_peek(&zatm_vcc->backlog)) {
+ printk("waiting for backlog to drain ...\n");
+ event_dump();
+ wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->backlog));
}
-once = 1;
- while ((skb = skb_peek(&zatm_vcc->tx_queue))) {
-if (once) {
-printk("waiting for TX queue to drain ... %p\n",skb);
-event_dump();
-once = 0;
-}
- DPRINTK("waiting for TX queue to drain ... %p\n",skb);
- sleep_on(&zatm_vcc->tx_wait);
+ if (skb_peek(&zatm_vcc->tx_queue)) {
+ printk("waiting for TX queue to drain ...\n");
+ event_dump();
+ wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->tx_queue));
}
spin_lock_irqsave(&zatm_dev->lock, flags);
#if 0
zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
dealloc_shaper(vcc->dev,zatm_vcc->shaper);
}
- if (zatm_vcc->ring) kfree(zatm_vcc->ring);
+ kfree(zatm_vcc->ring);
}
/*----------------------------- (E)EPROM access -----------------------------*/
-static void __init eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
+static void __devinit eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
unsigned short cmd)
{
int error;
}
-static unsigned long __init eprom_get(struct zatm_dev *zatm_dev,
+static unsigned long __devinit eprom_get(struct zatm_dev *zatm_dev,
unsigned short cmd)
{
unsigned int value;
}
-static void __init eprom_put_bits(struct zatm_dev *zatm_dev,
+static void __devinit eprom_put_bits(struct zatm_dev *zatm_dev,
unsigned long data,int bits,unsigned short cmd)
{
unsigned long value;
}
-static void __init eprom_get_byte(struct zatm_dev *zatm_dev,
+static void __devinit eprom_get_byte(struct zatm_dev *zatm_dev,
unsigned char *byte,unsigned short cmd)
{
int i;
}
-static unsigned char __init eprom_try_esi(struct atm_dev *dev,
+static unsigned char __devinit eprom_try_esi(struct atm_dev *dev,
unsigned short cmd,int offset,int swap)
{
unsigned char buf[ZEPROM_SIZE];
}
-static void __init eprom_get_esi(struct atm_dev *dev)
+static void __devinit eprom_get_esi(struct atm_dev *dev)
{
if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return;
(void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0);
static int __init zatm_start(struct atm_dev *dev)
{
- struct zatm_dev *zatm_dev;
+ struct zatm_dev *zatm_dev = ZATM_DEV(dev);
+ struct pci_dev *pdev = zatm_dev->pci_dev;
unsigned long curr;
int pools,vccs,rx;
- int error,i,ld;
+ int error, i, ld;
DPRINTK("zatm_start\n");
- zatm_dev = ZATM_DEV(dev);
zatm_dev->rx_map = zatm_dev->tx_map = NULL;
- for (i = 0; i < NR_MBX; i++)
- zatm_dev->mbx_start[i] = 0;
- if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) {
- printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
- dev->number,zatm_dev->irq);
- return -EAGAIN;
+ for (i = 0; i < NR_MBX; i++)
+ zatm_dev->mbx_start[i] = 0;
+ error = request_irq(zatm_dev->irq, zatm_int, SA_SHIRQ, DEV_LABEL, dev);
+ if (error < 0) {
+ printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
+ dev->number,zatm_dev->irq);
+ goto done;
}
- request_region(zatm_dev->base,uPD98401_PORTS,DEV_LABEL);
/* define memory regions */
pools = NR_POOLS;
if (NR_SHAPERS*SHAPER_SIZE > pools*POOL_SIZE)
"%ld VCs\n",dev->number,NR_SHAPERS,pools,rx,
(zatm_dev->mem-curr*4)/VC_SIZE);
/* create mailboxes */
- for (i = 0; i < NR_MBX; i++)
- if (mbx_entries[i]) {
- unsigned long here;
-
- here = (unsigned long) kmalloc(2*MBX_SIZE(i),
- GFP_KERNEL);
- if (!here) {
- error = -ENOMEM;
- goto out;
- }
- if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */
- here = (here & ~0xffffUL)+0x10000;
- zatm_dev->mbx_start[i] = here;
- if ((here^virt_to_bus((void *) here)) & 0xffff) {
- printk(KERN_ERR DEV_LABEL "(itf %d): system "
- "bus incompatible with driver\n",
- dev->number);
- error = -ENODEV;
- goto out;
- }
- DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i));
- zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff;
- zout(virt_to_bus((void *) here) >> 16,MSH(i));
- zout(virt_to_bus((void *) here),MSL(i));
- zout((here+MBX_SIZE(i)) & 0xffff,MBA(i));
- zout(here & 0xffff,MTA(i));
- zout(here & 0xffff,MWA(i));
+ for (i = 0; i < NR_MBX; i++) {
+ void *mbx;
+ dma_addr_t mbx_dma;
+
+ if (!mbx_entries[i])
+ continue;
+ mbx = pci_alloc_consistent(pdev, 2*MBX_SIZE(i), &mbx_dma);
+ if (!mbx) {
+ error = -ENOMEM;
+ goto out;
}
+ /*
+ * Alignment provided by pci_alloc_consistent() isn't enough
+ * for this device.
+ */
+ if (((unsigned long)mbx ^ mbx_dma) & 0xffff) {
+ printk(KERN_ERR DEV_LABEL "(itf %d): system "
+ "bus incompatible with driver\n", dev->number);
+ pci_free_consistent(pdev, 2*MBX_SIZE(i), mbx, mbx_dma);
+ error = -ENODEV;
+ goto out;
+ }
+ DPRINTK("mbx@0x%08lx-0x%08lx\n", mbx, mbx + MBX_SIZE(i));
+ zatm_dev->mbx_start[i] = (unsigned long)mbx;
+ zatm_dev->mbx_dma[i] = mbx_dma;
+ zatm_dev->mbx_end[i] = (zatm_dev->mbx_start[i] + MBX_SIZE(i)) &
+ 0xffff;
+ zout(mbx_dma >> 16, MSH(i));
+ zout(mbx_dma, MSL(i));
+ zout(zatm_dev->mbx_end[i], MBA(i));
+ zout((unsigned long)mbx & 0xffff, MTA(i));
+ zout((unsigned long)mbx & 0xffff, MWA(i));
+ }
error = start_tx(dev);
- if (error) goto out;
+ if (error)
+ goto out;
error = start_rx(dev);
- if (error) goto out;
+ if (error)
+ goto out_tx;
error = dev->phy->start(dev);
- if (error) goto out;
+ if (error)
+ goto out_rx;
zout(0xffffffff,IMR); /* enable interrupts */
/* enable TX & RX */
zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR);
- return 0;
- out:
- for (i = 0; i < NR_MBX; i++)
- if (zatm_dev->mbx_start[i] != 0)
- kfree((void *) zatm_dev->mbx_start[i]);
- if (zatm_dev->rx_map != NULL)
- kfree(zatm_dev->rx_map);
- if (zatm_dev->tx_map != NULL)
- kfree(zatm_dev->tx_map);
- free_irq(zatm_dev->irq, dev);
+done:
return error;
+
+out_rx:
+ kfree(zatm_dev->rx_map);
+out_tx:
+ kfree(zatm_dev->tx_map);
+out:
+ while (i-- > 0) {
+ pci_free_consistent(pdev, 2*MBX_SIZE(i),
+ (void *)zatm_dev->mbx_start[i],
+ zatm_dev->mbx_dma[i]);
+ }
+ free_irq(zatm_dev->irq, dev);
+ goto done;
}
}
-static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
+static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
{
struct zatm_dev *zatm_dev;
unsigned long flags;
int pool;
if (get_user(pool,
- &((struct zatm_pool_req *) arg)->pool_num))
+ &((struct zatm_pool_req __user *) arg)->pool_num))
return -EFAULT;
if (pool < 0 || pool > ZATM_LAST_POOL)
return -EINVAL;
}
spin_unlock_irqrestore(&zatm_dev->lock, flags);
return copy_to_user(
- &((struct zatm_pool_req *) arg)->info,
+ &((struct zatm_pool_req __user *) arg)->info,
&info,sizeof(info)) ? -EFAULT : 0;
}
case ZATM_SETPOOL:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (get_user(pool,
- &((struct zatm_pool_req *) arg)->pool_num))
+ &((struct zatm_pool_req __user *) arg)->pool_num))
return -EFAULT;
if (pool < 0 || pool > ZATM_LAST_POOL)
return -EINVAL;
if (copy_from_user(&info,
- &((struct zatm_pool_req *) arg)->info,
+ &((struct zatm_pool_req __user *) arg)->info,
sizeof(info))) return -EFAULT;
if (!info.low_water)
info.low_water = zatm_dev->
static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname,
- void *optval,int optlen)
+ void __user *optval,int optlen)
{
return -EINVAL;
}
static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname,
- void *optval,int optlen)
+ void __user *optval,int optlen)
{
return -EINVAL;
}
.change_qos = zatm_change_qos,
};
-static int __init zatm_module_init(void)
+static int __devinit zatm_init_one(struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
{
struct atm_dev *dev;
struct zatm_dev *zatm_dev;
- int devs,type;
-
- zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev),
- GFP_KERNEL);
- if (!zatm_dev) return -ENOMEM;
- devs = 0;
- for (type = 0; type < 2; type++) {
- struct pci_dev *pci_dev;
-
- pci_dev = NULL;
- while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
- PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
- pci_dev))) {
- if (pci_enable_device(pci_dev)) break;
- dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
- if (!dev) break;
- zatm_dev->pci_dev = pci_dev;
- dev->dev_data = zatm_dev;
- zatm_dev->copper = type;
- if (zatm_init(dev) || zatm_start(dev)) {
- atm_dev_deregister(dev);
- break;
- }
- zatm_dev->more = zatm_boards;
- zatm_boards = dev;
- devs++;
- zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct
- zatm_dev),GFP_KERNEL);
- if (!zatm_dev) {
- printk(KERN_EMERG "zatm.c: memory shortage\n");
- goto out;
- }
- }
+ int ret = -ENOMEM;
+
+ zatm_dev = (struct zatm_dev *) kmalloc(sizeof(*zatm_dev), GFP_KERNEL);
+ if (!zatm_dev) {
+ printk(KERN_EMERG "%s: memory shortage\n", DEV_LABEL);
+ goto out;
}
+
+ dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ if (!dev)
+ goto out_free;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret < 0)
+ goto out_deregister;
+
+ ret = pci_request_regions(pci_dev, DEV_LABEL);
+ if (ret < 0)
+ goto out_disable;
+
+ zatm_dev->pci_dev = pci_dev;
+ dev->dev_data = zatm_dev;
+ zatm_dev->copper = (int)ent->driver_data;
+ if ((ret = zatm_init(dev)) || (ret = zatm_start(dev)))
+ goto out_release;
+
+ pci_set_drvdata(pci_dev, dev);
+ zatm_dev->more = zatm_boards;
+ zatm_boards = dev;
+ ret = 0;
out:
+ return ret;
+
+out_release:
+ pci_release_regions(pci_dev);
+out_disable:
+ pci_disable_device(pci_dev);
+out_deregister:
+ atm_dev_deregister(dev);
+out_free:
kfree(zatm_dev);
-
- return 0;
+ goto out;
}
+
MODULE_LICENSE("GPL");
-module_init(zatm_module_init);
+static struct pci_device_id zatm_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1221,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, ZATM_COPPER },
+ { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1225,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, zatm_pci_tbl);
+
+static struct pci_driver zatm_driver = {
+ .name = DEV_LABEL,
+ .id_table = zatm_pci_tbl,
+ .probe = zatm_init_one,
+};
+
+static int __init zatm_init_module(void)
+{
+ return pci_register_driver(&zatm_driver);
+}
+
+module_init(zatm_init_module);
/* module_exit not defined so not unloadable */