summaryrefslogtreecommitdiffstats
path: root/drivers/atm/eni.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/atm/eni.c')
-rw-r--r--drivers/atm/eni.c125
1 files changed, 75 insertions, 50 deletions
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 1904b7e71..081fcdfed 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -156,7 +156,8 @@ static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0,
static struct atm_dev *eni_boards = NULL;
-static u32 *zeroes = NULL; /* aligned "magic" zeroes */
+static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */
+static dma_addr_t zeroes;
/* Read/write registers on card */
#define eni_in(r) readl(eni_dev->reg+(r)*4)
@@ -349,18 +350,21 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
struct eni_vcc *eni_vcc;
u32 dma_rd,dma_wr;
u32 dma[RX_DMA_BUF*2];
- unsigned long paddr,here;
+ dma_addr_t paddr;
+ unsigned long here;
int i,j;
eni_dev = ENI_DEV(vcc->dev);
eni_vcc = ENI_VCC(vcc);
paddr = 0; /* GCC, shut up */
if (skb) {
- paddr = (unsigned long) skb->data;
+ paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
+ PCI_DMA_FROMDEVICE);
+ ENI_PRV_PADDR(skb) = paddr;
if (paddr & 3)
printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has "
"mis-aligned RX data (0x%lx)\n",vcc->dev->number,
- vcc->vci,paddr);
+ vcc->vci,(unsigned long) paddr);
ENI_PRV_SIZE(skb) = size+skip;
/* PDU plus descriptor */
ATM_SKB(skb)->vcc = vcc;
@@ -390,7 +394,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (init > words) init = words;
dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |
(vcc->vci << MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += init << 2;
words -= init;
}
@@ -399,7 +403,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_16W | ((words >> 4) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~15) << 2;
words &= 15;
}
@@ -409,7 +413,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_8W | ((words >> 3) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~7) << 2;
words &= 7;
}
@@ -419,7 +423,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_4W | ((words >> 2) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~3) << 2;
words &= 3;
}
@@ -429,7 +433,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_2W | ((words >> 1) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~1) << 2;
words &= 1;
}
@@ -437,7 +441,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (words) {
dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT)
| (vcc->vci << MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
}
}
if (size != eff) {
@@ -447,8 +451,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
}
if (!j || j > 2*RX_DMA_BUF) {
printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n");
- if (skb) kfree_skb(skb);
- return -1;
+ goto trouble;
}
dma[j-2] |= MID_DMA_END;
j = j >> 1;
@@ -461,8 +464,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */
printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n",
vcc->dev->number);
- if (skb) kfree_skb(skb);
- return -1;
+ goto trouble;
}
for (i = 0; i < j; i++) {
writel(dma[i*2],eni_dev->rx_dma+dma_wr*8);
@@ -472,12 +474,19 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (skb) {
ENI_PRV_POS(skb) = eni_vcc->descr+size+1;
skb_queue_tail(&eni_dev->rx_queue,skb);
-eni_vcc->last = skb;
+ eni_vcc->last = skb;
rx_enqueued++;
}
eni_vcc->descr = here;
eni_out(dma_wr,MID_DMA_WR_RX);
return 0;
+
+trouble:
+ if (paddr)
+ pci_unmap_single(eni_dev->pci_dev,paddr,skb->len,
+ PCI_DMA_FROMDEVICE);
+ if (skb) dev_kfree_skb_irq(skb);
+ return -1;
}
@@ -747,7 +756,9 @@ rx_dequeued++;
}
eni_vcc->rxing--;
eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1);
- if (!skb->len) kfree_skb(skb);
+ pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
+ PCI_DMA_TODEVICE);
+ if (!skb->len) dev_kfree_skb_irq(skb);
else {
EVENT("pushing (len=%ld)\n",skb->len,0);
if (vcc->qos.aal == ATM_AAL0)
@@ -902,13 +913,13 @@ static int start_rx(struct atm_dev *dev)
enum enq_res { enq_ok,enq_next,enq_jam };
-static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
+static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr,
u32 size)
{
u32 init,words;
- DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size);
- EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size);
+ DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size);
+ EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size);
#if 0 /* don't complain anymore */
if (paddr & 3)
printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr);
@@ -918,10 +929,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
if (paddr & 3) {
init = 4-(paddr & 3);
if (init > size || size < 7) init = size;
- DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size);
+ DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",
+ (unsigned long) paddr,init,size);
dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += init;
size -= init;
}
@@ -930,10 +942,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
if (words && (paddr & 31)) {
init = 8-((paddr & 31) >> 2);
if (init > words) init = words;
- DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words);
+ DPRINTK("put_dma: %lx DMA: %d/%d words\n",
+ (unsigned long) paddr,init,words);
dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += init << 2;
words -= init;
}
@@ -943,18 +956,18 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~15) << 2;
words &= 15;
}
#endif
#ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */
if (words & ~7) {
- DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3,
- words);
+ DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",
+ (unsigned long) paddr,words >> 3,words);
dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~7) << 2;
words &= 7;
}
@@ -965,7 +978,7 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~3) << 2;
words &= 3;
}
@@ -976,23 +989,25 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~1) << 2;
words &= 1;
}
#endif
if (words) {
- DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words);
+ DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr,
+ words);
dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += words << 2;
}
if (size) {
- DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size);
+ DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr,
+ size);
dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
}
}
@@ -1003,6 +1018,7 @@ static enum enq_res do_tx(struct sk_buff *skb)
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
struct eni_tx *tx;
+ dma_addr_t paddr;
u32 dma_rd,dma_wr;
u32 size; /* in words */
int aal5,dma_size,i,j;
@@ -1079,6 +1095,9 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
vcc->dev->number);
return enq_jam;
}
+ paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
+ PCI_DMA_TODEVICE);
+ ENI_PRV_PADDR(skb) = paddr;
/* prepare DMA queue entries */
j = 0;
eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) <<
@@ -1086,21 +1105,17 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
MID_DT_JK;
j++;
if (!ATM_SKB(skb)->iovcnt)
- if (aal5)
- put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) skb->data,skb->len);
- else put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) skb->data+4,skb->len-4);
+ if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len);
+ else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4);
else {
-DPRINTK("doing direct send\n");
+DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
for (i = 0; i < ATM_SKB(skb)->iovcnt; i++)
put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
((struct iovec *) skb->data)[i].iov_base,
((struct iovec *) skb->data)[i].iov_len);
}
if (skb->len & 3)
- put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) zeroes,4-(skb->len & 3));
+ put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));
/* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */
eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) <<
MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |
@@ -1188,8 +1203,10 @@ static void dequeue_tx(struct atm_dev *dev)
break;
}
ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb);
+ pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
+ PCI_DMA_TODEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_irq(skb);
vcc->stats->tx++;
wake_up(&eni_dev->tx_wait);
dma_complete++;
@@ -1670,7 +1687,7 @@ static int __init eni_init(struct atm_dev *dev)
(eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory "
"(0x%02x)\n",dev->number,error);
- return error;
+ return -EIO;
}
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,",
dev->number,revision,real_base,eni_dev->irq);
@@ -2020,7 +2037,6 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!skb) {
printk(KERN_CRIT "!skb in eni_send ?\n");
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
return -EINVAL;
}
if (vcc->qos.aal == ATM_AAL0) {
@@ -2195,7 +2211,14 @@ int __init eni_detect(void)
struct atm_dev *dev;
struct eni_dev *eni_dev;
int devs,type;
+ struct sk_buff *skb;
+ DPRINTK("eni_detect\n");
+ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
+ printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
+ sizeof(skb->cb),sizeof(struct eni_skb_prv));
+ return 0;
+ }
eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),
GFP_KERNEL);
if (!eni_dev) return -ENOMEM;
@@ -2208,8 +2231,9 @@ int __init eni_detect(void)
PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA,
pci_dev))) {
if (!devs) {
- zeroes = kmalloc(4,GFP_KERNEL);
- if (!zeroes) {
+ cpu_zeroes = pci_alloc_consistent(pci_dev,
+ ENI_ZEROES_SIZE,&zeroes);
+ if (!cpu_zeroes) {
kfree(eni_dev);
return -ENOMEM;
}
@@ -2231,11 +2255,12 @@ int __init eni_detect(void)
if (!eni_dev) break;
}
}
- kfree(eni_dev);
- if (!devs && zeroes) {
- kfree(zeroes);
- zeroes = NULL;
+ if (!devs && cpu_zeroes) {
+ pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,
+ cpu_zeroes,zeroes);
+ cpu_zeroes = NULL;
}
+ kfree(eni_dev);
return devs;
}