patch-2.4.21 linux-2.4.21/drivers/atm/iphase.c
Next file: linux-2.4.21/drivers/atm/iphase.h
Previous file: linux-2.4.21/drivers/atm/idt77252.c
Back to the patch index
Back to the overall index
- Lines: 743
- Date:
2003-06-13 07:51:32.000000000 -0700
- Orig file:
linux-2.4.20/drivers/atm/iphase.c
- Orig date:
2002-11-28 15:53:12.000000000 -0800
diff -urN linux-2.4.20/drivers/atm/iphase.c linux-2.4.21/drivers/atm/iphase.c
@@ -1192,7 +1192,8 @@
/* Build the DLE structure */
wr_ptr = iadev->rx_dle_q.write;
- wr_ptr->sys_pkt_addr = virt_to_bus(skb->data);
+ wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+ len, PCI_DMA_FROMDEVICE);
wr_ptr->local_pkt_addr = buf_addr;
wr_ptr->bytes = len; /* We don't know this do we ?? */
wr_ptr->mode = DMA_INT_ENABLE;
@@ -1311,6 +1312,9 @@
struct cpcs_trailer *trailer;
u_short length;
struct ia_vcc *ia_vcc;
+
+ pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr,
+ len, PCI_DMA_FROMDEVICE);
/* no VCC related housekeeping done as yet. lets see */
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
@@ -1430,7 +1434,7 @@
IADEV *iadev;
struct rx_buf_desc *buf_desc_ptr;
unsigned long rx_pkt_start = 0;
- u32 *odle_addr, *dle_addr;
+ void *dle_addr;
struct abr_vc_table *abr_vc_table;
u16 *vc_table;
u16 *reass_table;
@@ -1441,25 +1445,14 @@
iadev = INPH_IA_DEV(dev);
// spin_lock_init(&iadev->rx_lock);
- /* I need to initialize the DLEs somewhere. Lets see what I
- need to do for this, hmmm...
- - allocate memory for 256 DLEs. make sure that it starts
- on a 4k byte address boundary. Program the start address
- in Receive List address register. ..... to do for TX also
- To make sure that it is a 4k byte boundary - allocate 8k and find
- 4k byte boundary within.
- ( (addr + (4k-1)) & ~(4k-1) )
- */
- /* allocate 8k bytes */
- odle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);
- if (!odle_addr)
- {
- printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
- return -ENOMEM;
- }
- /* find 4k byte boundary within the 8k allocated */
- dle_addr = (u32*)( ((u32)odle_addr+(4096-1)) & ~(4096-1) );
+ /* Allocate 4k bytes - more aligned than needed (4k boundary) */
+ dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+ &iadev->rx_dle_dma);
+ if (!dle_addr) {
+ printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+ goto err_out;
+ }
iadev->rx_dle_q.start = (struct dle*)dle_addr;
iadev->rx_dle_q.read = iadev->rx_dle_q.start;
iadev->rx_dle_q.write = iadev->rx_dle_q.start;
@@ -1468,7 +1461,8 @@
DLE that can be used. */
/* write the upper 20 bits of the start address to rx list address register */
- writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_RX_LIST_ADDR);
+ writel(iadev->rx_dle_dma & 0xfffff000,
+ iadev->dma + IPHASE5575_RX_LIST_ADDR);
IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n",
(u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR),
*(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR));
@@ -1642,8 +1636,7 @@
{
printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
dev->number);
- kfree(odle_addr);
- return -ENOMEM;
+ goto err_free_dle;
}
memset(iadev->rx_open, 0, 4*iadev->num_vc);
iadev->rxing = 1;
@@ -1651,6 +1644,12 @@
/* Mode Register */
writew(R_ONLINE, iadev->reass_reg+MODE_REG);
return 0;
+
+err_free_dle:
+ pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+ iadev->rx_dle_dma);
+err_out:
+ return -ENOMEM;
}
@@ -1715,6 +1714,12 @@
/* free the DMAed skb */
skb = skb_dequeue(&iadev->tx_dma_q);
if (!skb) break;
+
+ /* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */
+ if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) {
+ pci_unmap_single(iadev->pci, dle->sys_pkt_addr, skb->len,
+ PCI_DMA_TODEVICE);
+ }
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("tx_dle_intr: vcc is null\n");
@@ -1884,7 +1889,7 @@
return -EINVAL;
}
if (vcc->qos.txtp.max_pcr > iadev->LineRate) {
- IF_CBR(printk("PCR is not availble\n");)
+ IF_CBR(printk("PCR is not available\n");)
return -1;
}
vc->type = CBR;
@@ -1894,7 +1899,7 @@
}
}
else
- printk("iadev: Non UBR, ABR and CBR traffic not supportedn");
+ printk("iadev: Non UBR, ABR and CBR traffic not supported\n");
iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE;
IF_EVENT(printk("ia open_tx returning \n");)
@@ -1907,7 +1912,7 @@
IADEV *iadev;
struct tx_buf_desc *buf_desc_ptr;
unsigned int tx_pkt_start;
- u32 *dle_addr;
+ void *dle_addr;
int i;
u_short tcq_st_adr;
u_short *tcq_start;
@@ -1923,24 +1928,22 @@
IF_INIT(printk("Tx MASK REG: 0x%0x\n",
readw(iadev->seg_reg+SEG_MASK_REG));)
- /*---------- Initializing Transmit DLEs ----------*/
- /* allocating 8k memory for transmit DLEs */
- dle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);
- if (!dle_addr)
- {
- printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n");
- return -ENOMEM;
- }
-
- /* find 4k byte boundary within the 8k allocated */
- dle_addr = (u32*)(((u32)dle_addr+(4096-1)) & ~(4096-1));
+
+ /* Allocate 4k (boundary aligned) bytes */
+ dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+ &iadev->tx_dle_dma);
+ if (!dle_addr) {
+ printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+ goto err_out;
+ }
iadev->tx_dle_q.start = (struct dle*)dle_addr;
iadev->tx_dle_q.read = iadev->tx_dle_q.start;
iadev->tx_dle_q.write = iadev->tx_dle_q.start;
iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES);
/* write the upper 20 bits of the start address to tx list address register */
- writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_TX_LIST_ADDR);
+ writel(iadev->tx_dle_dma & 0xfffff000,
+ iadev->dma + IPHASE5575_TX_LIST_ADDR);
writew(0xffff, iadev->seg_reg+SEG_MASK_REG);
writew(0, iadev->seg_reg+MODE_REG_0);
writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG);
@@ -1984,23 +1987,28 @@
buf_desc_ptr++;
tx_pkt_start += iadev->tx_buf_sz;
}
- iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(caddr_t), GFP_KERNEL);
+ iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(struct cpcs_trailer_desc), GFP_KERNEL);
if (!iadev->tx_buf) {
printk(KERN_ERR DEV_LABEL " couldn't get mem\n");
- return -EAGAIN;
+ goto err_free_dle;
}
for (i= 0; i< iadev->num_tx_desc; i++)
{
+ struct cpcs_trailer *cpcs;
- iadev->tx_buf[i] = kmalloc(sizeof(struct cpcs_trailer),
- GFP_KERNEL|GFP_DMA);
- if(!iadev->tx_buf[i]) {
+ cpcs = kmalloc(sizeof(*cpcs), GFP_KERNEL|GFP_DMA);
+ if(!cpcs) {
printk(KERN_ERR DEV_LABEL " couldn't get freepage\n");
- return -EAGAIN;
+ goto err_free_tx_bufs;
}
+ iadev->tx_buf[i].cpcs = cpcs;
+ iadev->tx_buf[i].dma_addr = pci_map_single(iadev->pci,
+ cpcs, sizeof(*cpcs), PCI_DMA_TODEVICE);
}
iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
sizeof(struct desc_tbl_t), GFP_KERNEL);
+ if(!iadev->desc_tbl)
+ goto err_free_all_tx_bufs;
/* Communication Queues base address */
i = TX_COMP_Q * iadev->memSize;
@@ -2128,7 +2136,7 @@
iadev->testTable = kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL);
if (!iadev->testTable) {
printk("Get freepage failed\n");
- return -EAGAIN;
+ goto err_free_desc_tbl;
}
for(i=0; i<iadev->num_vc; i++)
{
@@ -2137,7 +2145,7 @@
iadev->testTable[i] = kmalloc(sizeof(struct testTable_t),
GFP_KERNEL);
if (!iadev->testTable[i])
- return -ENOMEM;
+ goto err_free_test_tables;
iadev->testTable[i]->lastTime = 0;
iadev->testTable[i]->fract = 0;
iadev->testTable[i]->vc_status = VC_UBR;
@@ -2193,7 +2201,30 @@
iadev->tx_pkt_cnt = 0;
iadev->rate_limit = iadev->LineRate / 3;
- return 0;
+ return 0;
+
+err_free_test_tables:
+ while (--i >= 0)
+ kfree(iadev->testTable[i]);
+ kfree(iadev->testTable);
+err_free_desc_tbl:
+ kfree(iadev->desc_tbl);
+err_free_all_tx_bufs:
+ i = iadev->num_tx_desc;
+err_free_tx_bufs:
+ while (--i >= 0) {
+ struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+ pci_unmap_single(iadev->pci, desc->dma_addr,
+ sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+ kfree(desc->cpcs);
+ }
+ kfree(iadev->tx_buf);
+err_free_dle:
+ pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+ iadev->tx_dle_dma);
+err_out:
+ return -ENOMEM;
}
static void ia_int(int irq, void *dev_id, struct pt_regs *regs)
@@ -2455,6 +2486,33 @@
return readl(INPH_IA_DEV(dev)->phy+addr);
}
+static void ia_free_tx(IADEV *iadev)
+{
+ int i;
+
+ kfree(iadev->desc_tbl);
+ for (i = 0; i < iadev->num_vc; i++)
+ kfree(iadev->testTable[i]);
+ kfree(iadev->testTable);
+ for (i = 0; i < iadev->num_tx_desc; i++) {
+ struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+ pci_unmap_single(iadev->pci, desc->dma_addr,
+ sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+ kfree(desc->cpcs);
+ }
+ kfree(iadev->tx_buf);
+ pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+ iadev->tx_dle_dma);
+}
+
+static void ia_free_rx(IADEV *iadev)
+{
+ kfree(iadev->rx_open);
+ pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+ iadev->rx_dle_dma);
+}
+
#if LINUX_VERSION_CODE >= 0x20312
static int __init ia_start(struct atm_dev *dev)
#else
@@ -2462,7 +2520,7 @@
#endif
{
IADEV *iadev;
- int error = 1;
+ int error;
unsigned char phy;
u32 ctrl_reg;
IF_EVENT(printk(">ia_start\n");)
@@ -2470,7 +2528,8 @@
if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) {
printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
dev->number, iadev->irq);
- return -EAGAIN;
+ error = -EAGAIN;
+ goto err_out;
}
/* @@@ should release IRQ on error */
/* enabling memory + master */
@@ -2480,8 +2539,8 @@
{
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+"
"master (0x%x)\n",dev->number, error);
- free_irq(iadev->irq, dev);
- return -EIO;
+ error = -EIO;
+ goto err_free_irq;
}
udelay(10);
@@ -2515,15 +2574,11 @@
ia_hw_type(iadev);
error = tx_init(dev);
- if (error) {
- free_irq(iadev->irq, dev);
- return error;
- }
+ if (error)
+ goto err_free_irq;
error = rx_init(dev);
- if (error) {
- free_irq(iadev->irq, dev);
- return error;
- }
+ if (error)
+ goto err_free_tx;
ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG);
writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG);
@@ -2538,33 +2593,36 @@
if (iadev->phy_type & FE_25MBIT_PHY) {
ia_mb25_init(iadev);
- return 0;
- }
- if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
+ } else if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
ia_suni_pm7345_init(iadev);
- return 0;
- }
-
- error = suni_init(dev);
- if (error) {
- free_irq(iadev->irq, dev);
- return error;
- }
-
- /* Enable interrupt on loss of signal SUNI_RSOP_CIE 0x10
- SUNI_RSOP_CIE_LOSE - 0x04
- */
- ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10);
+ } else {
+ error = suni_init(dev);
+ if (error)
+ goto err_free_rx;
+ /*
+ * Enable interrupt on loss of signal
+ * SUNI_RSOP_CIE - 0x10
+ * SUNI_RSOP_CIE_LOSE - 0x04
+ */
+ ia_phy_put(dev, ia_phy_get(dev, 0x10) | 0x04, 0x10);
#ifndef MODULE
- error = dev->phy->start(dev);
- if (error) {
- free_irq(iadev->irq, dev);
- return error;
- }
+ error = dev->phy->start(dev);
+ if (error)
+ goto err_free_rx;
#endif
- /* Get iadev->carrier_detect status */
- IaFrontEndIntr(iadev);
- return 0;
+ /* Get iadev->carrier_detect status */
+ IaFrontEndIntr(iadev);
+ }
+ return 0;
+
+err_free_rx:
+ ia_free_rx(iadev);
+err_free_tx:
+ ia_free_tx(iadev);
+err_free_irq:
+ free_irq(iadev->irq, dev);
+err_out:
+ return error;
}
static void ia_close(struct atm_vcc *vcc)
@@ -2873,10 +2931,10 @@
struct tx_buf_desc *buf_desc_ptr;
int desc;
int comp_code;
- unsigned int addr;
- int total_len, pad, last;
+ int total_len;
struct cpcs_trailer *trailer;
struct ia_vcc *iavcc;
+
iadev = INPH_IA_DEV(vcc->dev);
iavcc = INPH_IA_VCC(vcc);
if (!iavcc->txing) {
@@ -2897,12 +2955,18 @@
return 0;
}
if ((u32)skb->data & 3) {
- printk("Misaligned SKB\n");
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
- dev_kfree_skb_any(skb);
- return 0;
+ /* The copy will end up aligned */
+ struct sk_buff *newskb = skb_copy(skb, GFP_ATOMIC);
+ if(newskb == NULL)
+ {
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+ kfree(skb);
+ skb = newskb;
}
/* Get a descriptor number from our free descriptor queue
We get the descr number from the TCQ now, since I am using
@@ -2955,19 +3019,13 @@
/* Figure out the exact length of the packet and padding required to
make it aligned on a 48 byte boundary. */
total_len = skb->len + sizeof(struct cpcs_trailer);
- last = total_len - (total_len/48)*48;
- pad = 48 - last;
- total_len = pad + total_len;
- IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);)
+ total_len = ((total_len + 47) / 48) * 48;
+ IF_TX(printk("ia packet len:%d padding:%d\n", total_len, total_len - skb->len);)
/* Put the packet in a tx buffer */
- if (!iadev->tx_buf[desc-1])
- printk("couldn't get free page\n");
-
+ trailer = iadev->tx_buf[desc-1].cpcs;
IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n",
(u32)skb, (u32)skb->data, skb->len, desc);)
- addr = virt_to_bus(skb->data);
- trailer = (struct cpcs_trailer*)iadev->tx_buf[desc-1];
trailer->control = 0;
/*big endian*/
trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8);
@@ -2983,6 +3041,7 @@
buf_desc_ptr = (struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE);
buf_desc_ptr += desc; /* points to the corresponding entry */
buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT;
+ /* Huh ? p.115 of users guide describes this as a read-only register */
writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG);
buf_desc_ptr->vc_index = vcc->vci;
buf_desc_ptr->bytes = total_len;
@@ -2993,7 +3052,8 @@
/* Build the DLE structure */
wr_ptr = iadev->tx_dle_q.write;
memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));
- wr_ptr->sys_pkt_addr = addr;
+ wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) |
buf_desc_ptr->buf_start_lo;
/* wr_ptr->bytes = swap(total_len); didn't seem to affect ?? */
@@ -3011,7 +3071,7 @@
wr_ptr = iadev->tx_dle_q.start;
/* Build trailer dle */
- wr_ptr->sys_pkt_addr = virt_to_bus(iadev->tx_buf[desc-1]);
+ wr_ptr->sys_pkt_addr = iadev->tx_buf[desc-1].dma_addr;
wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) |
buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer);
@@ -3163,135 +3223,130 @@
};
-#if LINUX_VERSION_CODE >= 0x20312
-int __init ia_detect(void)
-#else
-__initfunc(int ia_detect(void))
-#endif
+static int __devinit ia_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct atm_dev *dev;
IADEV *iadev;
unsigned long flags;
- int index = 0;
- struct pci_dev *prev_dev;
- if (!pci_present()) {
- printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n");
- return 0;
- }
+ int ret;
+
iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);
- if (!iadev) return -ENOMEM;
- memset((char*)iadev, 0, sizeof(*iadev));
- prev_dev = NULL;
- while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE,
- PCI_DEVICE_ID_IPHASE_5575, prev_dev))) {
- IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
- iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn),
- PCI_FUNC(iadev->pci->devfn));)
- if (pci_enable_device(iadev->pci)) break;
- dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
- if (!dev) break;
- IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n",
- dev->number);)
- INPH_IA_DEV(dev) = iadev;
- // TODO: multi_board using ia_boards logic in cleanup_module
- ia_dev[index] = iadev;
- _ia_dev[index] = dev;
- IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n",
- (u32)dev, iadev->LineRate);)
- iadev_count++;
- spin_lock_init(&iadev->misc_lock);
- spin_lock_irqsave(&iadev->misc_lock, flags);
- if (ia_init(dev) || ia_start(dev)) {
- atm_dev_deregister(dev);
- IF_INIT(printk("IA register failed!\n");)
- ia_dev[index] = NULL;
- _ia_dev[index] = NULL;
- iadev_count--;
- spin_unlock_irqrestore(&iadev->misc_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&iadev->misc_lock, flags);
- IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
- prev_dev = iadev->pci;
- iadev->next_board = ia_boards;
- ia_boards = dev;
- iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);
- if (!iadev) break;
- memset((char*)iadev, 0, sizeof(*iadev));
- index++;
- dev = NULL;
- }
- return index;
-}
-
+ if (!iadev) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+ memset(iadev, 0, sizeof(*iadev));
+ iadev->pci = pdev;
-#ifdef MODULE
-
-int init_module(void)
-{
- IF_EVENT(printk(">ia init_module\n");)
- if (!ia_detect()) {
- printk(KERN_ERR DEV_LABEL ": no adapter found\n");
- return -ENXIO;
- }
- ia_timer.expires = jiffies + 3*HZ;
- add_timer(&ia_timer);
-
- return 0;
-}
-
-
-void cleanup_module(void)
-{
- struct atm_dev *dev;
- IADEV *iadev;
- unsigned short command;
- int i, j= 0;
-
- IF_EVENT(printk(">ia cleanup_module\n");)
- if (MOD_IN_USE)
- printk("ia: module in use\n");
- del_timer(&ia_timer);
- while(ia_dev[j])
- {
- dev = ia_boards;
- iadev = INPH_IA_DEV(dev);
- ia_boards = iadev->next_board;
-
- /* disable interrupt of lost signal */
- ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10);
- udelay(1);
-
- /* De-register device */
- atm_dev_deregister(dev);
- IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
- for (i= 0; i< iadev->num_tx_desc; i++)
- kfree(iadev->tx_buf[i]);
- kfree(iadev->tx_buf);
- /* Disable memory mapping and busmastering */
- if (pci_read_config_word(iadev->pci,
- PCI_COMMAND, &command) != 0)
- {
- printk("ia: can't read PCI_COMMAND.\n");
- }
- command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
- if (pci_write_config_word(iadev->pci,
- PCI_COMMAND, command) != 0)
- {
- printk("ia: can't write PCI_COMMAND.\n");
- }
- free_irq(iadev->irq, dev);
- iounmap((void *) iadev->base);
- kfree(iadev);
- j++;
- }
- /* and voila whatever we tried seems to work. I don't know if it will
- fix suni errors though. Really doubt that. */
- for (i = 0; i<8; i++) {
- ia_dev[i] = NULL;
- _ia_dev[i] = NULL;
- }
-}
+ IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
+ pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));)
+ if (pci_enable_device(pdev)) {
+ ret = -ENODEV;
+ goto err_out_free_iadev;
+ }
+ dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err_out_disable_dev;
+ }
+ INPH_IA_DEV(dev) = iadev;
+ IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);)
+ IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev,
+ iadev->LineRate);)
+
+ ia_dev[iadev_count] = iadev;
+ _ia_dev[iadev_count] = dev;
+ iadev_count++;
+ spin_lock_init(&iadev->misc_lock);
+ /* First fixes first. I don't want to think about this now. */
+ spin_lock_irqsave(&iadev->misc_lock, flags);
+ if (ia_init(dev) || ia_start(dev)) {
+ IF_INIT(printk("IA register failed!\n");)
+ iadev_count--;
+ ia_dev[iadev_count] = NULL;
+ _ia_dev[iadev_count] = NULL;
+ spin_unlock_irqrestore(&iadev->misc_lock, flags);
+ ret = -EINVAL;
+ goto err_out_deregister_dev;
+ }
+ spin_unlock_irqrestore(&iadev->misc_lock, flags);
+ IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
-#endif
+ iadev->next_board = ia_boards;
+ ia_boards = dev;
+
+ pci_set_drvdata(pdev, dev);
+
+ return 0;
+
+err_out_deregister_dev:
+ atm_dev_deregister(dev);
+err_out_disable_dev:
+ pci_disable_device(pdev);
+err_out_free_iadev:
+ kfree(iadev);
+err_out:
+ return ret;
+}
+
+static void __devexit ia_remove_one(struct pci_dev *pdev)
+{
+ struct atm_dev *dev = pci_get_drvdata(pdev);
+ IADEV *iadev = INPH_IA_DEV(dev);
+
+ ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10);
+ udelay(1);
+
+ /* De-register device */
+ free_irq(iadev->irq, dev);
+ iadev_count--;
+ ia_dev[iadev_count] = NULL;
+ _ia_dev[iadev_count] = NULL;
+ atm_dev_deregister(dev);
+ IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
+
+ iounmap((void *) iadev->base);
+ pci_disable_device(pdev);
+
+ ia_free_rx(iadev);
+ ia_free_tx(iadev);
+
+ kfree(iadev);
+}
+
+static struct pci_device_id ia_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_IPHASE, 0x0008, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_IPHASE, 0x0009, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0,}
+};
+MODULE_DEVICE_TABLE(pci, ia_pci_tbl);
+
+static struct pci_driver ia_driver = {
+ .name = DEV_LABEL,
+ .id_table = ia_pci_tbl,
+ .probe = ia_init_one,
+ .remove = __devexit_p(ia_remove_one),
+};
+
+static int __init ia_init_module(void)
+{
+ int ret;
+
+ ret = pci_module_init(&ia_driver);
+ if (ret >= 0) {
+ ia_timer.expires = jiffies + 3*HZ;
+ add_timer(&ia_timer);
+ }
+ return ret;
+}
+
+static void __exit ia_cleanup_module(void)
+{
+ pci_unregister_driver(&ia_driver);
+
+ del_timer(&ia_timer);
+}
+module_init(ia_init_module);
+module_exit(ia_cleanup_module);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)