diff options
Diffstat (limited to 'drivers/atm/he.c')
-rw-r--r-- | drivers/atm/he.c | 310 |
1 files changed, 108 insertions, 202 deletions
diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 56c2e99..801e8b6 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -67,6 +67,7 @@ #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> +#include <linux/bitmap.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/byteorder.h> @@ -778,61 +779,39 @@ he_init_cs_block_rcm(struct he_dev *he_dev) static int __devinit he_init_group(struct he_dev *he_dev, int group) { + struct he_buff *heb, *next; + dma_addr_t mapping; int i; - /* small buffer pool */ - he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev, - CONFIG_RBPS_BUFSIZE, 8, 0); - if (he_dev->rbps_pool == NULL) { - hprintk("unable to create rbps pages\n"); + he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); + he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), + G0_RBPS_BS + (group * 32)); + + /* bitmap table */ + he_dev->rbpl_table = kmalloc(BITS_TO_LONGS(RBPL_TABLE_SIZE) + * sizeof(unsigned long), GFP_KERNEL); + if (!he_dev->rbpl_table) { + hprintk("unable to allocate rbpl bitmap table\n"); return -ENOMEM; } + bitmap_zero(he_dev->rbpl_table, RBPL_TABLE_SIZE); - he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, - CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); - if (he_dev->rbps_base == NULL) { - hprintk("failed to alloc rbps_base\n"); - goto out_destroy_rbps_pool; + /* rbpl_virt 64-bit pointers */ + he_dev->rbpl_virt = kmalloc(RBPL_TABLE_SIZE + * sizeof(struct he_buff *), GFP_KERNEL); + if (!he_dev->rbpl_virt) { + hprintk("unable to allocate rbpl virt table\n"); + goto out_free_rbpl_table; } - memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); - he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL); - if (he_dev->rbps_virt == NULL) { - hprintk("failed to alloc rbps_virt\n"); - goto out_free_rbps_base; - } - - for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { - dma_addr_t dma_handle; - void *cpuaddr; - - cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle); - if (cpuaddr == NULL) - goto out_free_rbps_virt; - - he_dev->rbps_virt[i].virt = cpuaddr; - he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF); - he_dev->rbps_base[i].phys = dma_handle; - - } - he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1]; - - he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32)); - he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), - G0_RBPS_T + (group * 32)); - he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4, - G0_RBPS_BS + (group * 32)); - he_writel(he_dev, - RBP_THRESH(CONFIG_RBPS_THRESH) | - RBP_QSIZE(CONFIG_RBPS_SIZE - 1) | - RBP_INT_ENB, - G0_RBPS_QI + (group * 32)); /* large buffer pool */ he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, - CONFIG_RBPL_BUFSIZE, 8, 0); + CONFIG_RBPL_BUFSIZE, 64, 0); if (he_dev->rbpl_pool == NULL) { hprintk("unable to create rbpl pool\n"); - goto out_free_rbps_virt; + goto out_free_rbpl_virt; } he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, @@ -842,30 +821,29 @@ he_init_group(struct he_dev *he_dev, int group) goto out_destroy_rbpl_pool; } memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); - he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); - if (he_dev->rbpl_virt == NULL) { - hprintk("failed to alloc rbpl_virt\n"); - goto out_free_rbpl_base; - } + + INIT_LIST_HEAD(&he_dev->rbpl_outstanding); for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { - dma_addr_t dma_handle; - void *cpuaddr; - cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); - if (cpuaddr == NULL) - goto out_free_rbpl_virt; + heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping); + if (!heb) + goto out_free_rbpl; + heb->mapping = mapping; + list_add(&heb->entry, &he_dev->rbpl_outstanding); - he_dev->rbpl_virt[i].virt = cpuaddr; - he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); - he_dev->rbpl_base[i].phys = dma_handle; + set_bit(i, he_dev->rbpl_table); + he_dev->rbpl_virt[i] = heb; + he_dev->rbpl_hint = i + 1; + he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET; + he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data); } he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T + (group * 32)); - he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4, + he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4, G0_RBPL_BS + (group * 32)); he_writel(he_dev, RBP_THRESH(CONFIG_RBPL_THRESH) | @@ -879,7 +857,7 @@ he_init_group(struct he_dev *he_dev, int group) CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); if (he_dev->rbrq_base == NULL) { hprintk("failed to allocate rbrq\n"); - goto out_free_rbpl_virt; + goto out_free_rbpl; } memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); @@ -920,33 +898,20 @@ out_free_rbpq_base: pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), he_dev->rbrq_base, he_dev->rbrq_phys); - i = CONFIG_RBPL_SIZE; -out_free_rbpl_virt: - while (i--) - pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt, - he_dev->rbpl_base[i].phys); - kfree(he_dev->rbpl_virt); +out_free_rbpl: + list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); -out_free_rbpl_base: pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); out_destroy_rbpl_pool: pci_pool_destroy(he_dev->rbpl_pool); +out_free_rbpl_virt: + kfree(he_dev->rbpl_virt); +out_free_rbpl_table: + kfree(he_dev->rbpl_table); - i = CONFIG_RBPS_SIZE; -out_free_rbps_virt: - while (i--) - pci_pool_free(he_dev->rbps_pool, he_dev->rbps_virt[i].virt, - he_dev->rbps_base[i].phys); - kfree(he_dev->rbps_virt); - -out_free_rbps_base: - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * - sizeof(struct he_rbp), he_dev->rbps_base, - he_dev->rbps_phys); -out_destroy_rbps_pool: - pci_pool_destroy(he_dev->rbps_pool); return -ENOMEM; } @@ -1002,7 +967,8 @@ he_init_irq(struct he_dev *he_dev) he_writel(he_dev, 0x0, GRP_54_MAP); he_writel(he_dev, 0x0, GRP_76_MAP); - if (request_irq(he_dev->pci_dev->irq, he_irq_handler, IRQF_DISABLED|IRQF_SHARED, DEV_LABEL, he_dev)) { + if (request_irq(he_dev->pci_dev->irq, + he_irq_handler, IRQF_SHARED, DEV_LABEL, he_dev)) { hprintk("irq %d already in use\n", he_dev->pci_dev->irq); return -EINVAL; } @@ -1576,9 +1542,10 @@ he_start(struct atm_dev *dev) static void he_stop(struct he_dev *he_dev) { - u16 command; - u32 gen_cntl_0, reg; + struct he_buff *heb, *next; struct pci_dev *pci_dev; + u32 gen_cntl_0, reg; + u16 command; pci_dev = he_dev->pci_dev; @@ -1619,37 +1586,19 @@ he_stop(struct he_dev *he_dev) he_dev->hsp, he_dev->hsp_phys); if (he_dev->rbpl_base) { - int i; - - for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { - void *cpuaddr = he_dev->rbpl_virt[i].virt; - dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; + list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle); - } pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); } + kfree(he_dev->rbpl_virt); + kfree(he_dev->rbpl_table); + if (he_dev->rbpl_pool) pci_pool_destroy(he_dev->rbpl_pool); - if (he_dev->rbps_base) { - int i; - - for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { - void *cpuaddr = he_dev->rbps_virt[i].virt; - dma_addr_t dma_handle = he_dev->rbps_base[i].phys; - - pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle); - } - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE - * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys); - } - - if (he_dev->rbps_pool) - pci_pool_destroy(he_dev->rbps_pool); - if (he_dev->rbrq_base) pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), he_dev->rbrq_base, he_dev->rbrq_phys); @@ -1679,13 +1628,13 @@ static struct he_tpd * __alloc_tpd(struct he_dev *he_dev) { struct he_tpd *tpd; - dma_addr_t dma_handle; + dma_addr_t mapping; - tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle); + tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping); if (tpd == NULL) return NULL; - tpd->status = TPD_ADDR(dma_handle); + tpd->status = TPD_ADDR(mapping); tpd->reserved = 0; tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0; tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0; @@ -1714,13 +1663,12 @@ he_service_rbrq(struct he_dev *he_dev, int group) struct he_rbrq *rbrq_tail = (struct he_rbrq *) ((unsigned long)he_dev->rbrq_base | he_dev->hsp->group[group].rbrq_tail); - struct he_rbp *rbp = NULL; unsigned cid, lastcid = -1; - unsigned buf_len = 0; struct sk_buff *skb; struct atm_vcc *vcc = NULL; struct he_vcc *he_vcc; - struct he_iovec *iov; + struct he_buff *heb, *next; + int i; int pdus_assembled = 0; int updated = 0; @@ -1740,44 +1688,35 @@ he_service_rbrq(struct he_dev *he_dev, int group) RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); - if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF) - rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; - else - rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; - - buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; - cid = RBRQ_CID(he_dev->rbrq_head); + i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET; + heb = he_dev->rbpl_virt[i]; + cid = RBRQ_CID(he_dev->rbrq_head); if (cid != lastcid) vcc = __find_vcc(he_dev, cid); lastcid = cid; - if (vcc == NULL) { - hprintk("vcc == NULL (cid 0x%x)\n", cid); - if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) - rbp->status &= ~RBP_LOANED; + if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) { + hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid); + if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) { + clear_bit(i, he_dev->rbpl_table); + list_del(&heb->entry); + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + } goto next_rbrq_entry; } - he_vcc = HE_VCC(vcc); - if (he_vcc == NULL) { - hprintk("he_vcc == NULL (cid 0x%x)\n", cid); - if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) - rbp->status &= ~RBP_LOANED; - goto next_rbrq_entry; - } - if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) { hprintk("HBUF_ERR! (cid 0x%x)\n", cid); atomic_inc(&vcc->stats->rx_drop); goto return_host_buffers; } - he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head); - he_vcc->iov_tail->iov_len = buf_len; - he_vcc->pdu_len += buf_len; - ++he_vcc->iov_tail; + heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; + clear_bit(i, he_dev->rbpl_table); + list_move_tail(&heb->entry, &he_vcc->buffers); + he_vcc->pdu_len += heb->len; if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) { lastcid = -1; @@ -1786,12 +1725,6 @@ he_service_rbrq(struct he_dev *he_dev, int group) goto return_host_buffers; } -#ifdef notdef - if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) { - hprintk("iovec full! cid 0x%x\n", cid); - goto return_host_buffers; - } -#endif if (!RBRQ_END_PDU(he_dev->rbrq_head)) goto next_rbrq_entry; @@ -1819,15 +1752,8 @@ he_service_rbrq(struct he_dev *he_dev, int group) __net_timestamp(skb); - for (iov = he_vcc->iov_head; - iov < he_vcc->iov_tail; ++iov) { - if (iov->iov_base & RBP_SMALLBUF) - memcpy(skb_put(skb, iov->iov_len), - he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); - else - memcpy(skb_put(skb, iov->iov_len), - he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); - } + list_for_each_entry(heb, &he_vcc->buffers, entry) + memcpy(skb_put(skb, heb->len), &heb->data, heb->len); switch (vcc->qos.aal) { case ATM_AAL0: @@ -1867,17 +1793,9 @@ he_service_rbrq(struct he_dev *he_dev, int group) return_host_buffers: ++pdus_assembled; - for (iov = he_vcc->iov_head; - iov < he_vcc->iov_tail; ++iov) { - if (iov->iov_base & RBP_SMALLBUF) - rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)]; - else - rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)]; - - rbp->status &= ~RBP_LOANED; - } - - he_vcc->iov_tail = he_vcc->iov_head; + list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry) + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + INIT_LIST_HEAD(&he_vcc->buffers); he_vcc->pdu_len = 0; next_rbrq_entry: @@ -1978,59 +1896,51 @@ next_tbrq_entry: } } - static void he_service_rbpl(struct he_dev *he_dev, int group) { - struct he_rbp *newtail; + struct he_rbp *new_tail; struct he_rbp *rbpl_head; + struct he_buff *heb; + dma_addr_t mapping; + int i; int moved = 0; rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); for (;;) { - newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | + new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | RBPL_MASK(he_dev->rbpl_tail+1)); /* table 3.42 -- rbpl_tail should never be set to rbpl_head */ - if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED)) + if (new_tail == rbpl_head) break; - newtail->status |= RBP_LOANED; - he_dev->rbpl_tail = newtail; - ++moved; - } - - if (moved) - he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); -} - -static void -he_service_rbps(struct he_dev *he_dev, int group) -{ - struct he_rbp *newtail; - struct he_rbp *rbps_head; - int moved = 0; - - rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | - RBPS_MASK(he_readl(he_dev, G0_RBPS_S))); - - for (;;) { - newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | - RBPS_MASK(he_dev->rbps_tail+1)); + i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint); + if (i > (RBPL_TABLE_SIZE - 1)) { + i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE); + if (i > (RBPL_TABLE_SIZE - 1)) + break; + } + he_dev->rbpl_hint = i + 1; - /* table 3.42 -- rbps_tail should never be set to rbps_head */ - if ((newtail == rbps_head) || (newtail->status & RBP_LOANED)) + heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping); + if (!heb) break; - - newtail->status |= RBP_LOANED; - he_dev->rbps_tail = newtail; + heb->mapping = mapping; + list_add(&heb->entry, &he_dev->rbpl_outstanding); + he_dev->rbpl_virt[i] = heb; + set_bit(i, he_dev->rbpl_table); + new_tail->idx = i << RBP_IDX_OFFSET; + new_tail->phys = mapping + offsetof(struct he_buff, data); + + he_dev->rbpl_tail = new_tail; ++moved; } if (moved) - he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T); + he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); } static void @@ -2055,10 +1965,8 @@ he_tasklet(unsigned long data) HPRINTK("rbrq%d threshold\n", group); /* fall through */ case ITYPE_RBRQ_TIMER: - if (he_service_rbrq(he_dev, group)) { + if (he_service_rbrq(he_dev, group)) he_service_rbpl(he_dev, group); - he_service_rbps(he_dev, group); - } break; case ITYPE_TBRQ_THRESH: HPRINTK("tbrq%d threshold\n", group); @@ -2070,7 +1978,7 @@ he_tasklet(unsigned long data) he_service_rbpl(he_dev, group); break; case ITYPE_RBPS_THRESH: - he_service_rbps(he_dev, group); + /* shouldn't happen unless small buffers enabled */ break; case ITYPE_PHY: HPRINTK("phy interrupt\n"); @@ -2098,7 +2006,6 @@ he_tasklet(unsigned long data) he_service_rbrq(he_dev, 0); he_service_rbpl(he_dev, 0); - he_service_rbps(he_dev, 0); he_service_tbrq(he_dev, 0); break; default: @@ -2252,7 +2159,7 @@ he_open(struct atm_vcc *vcc) return -ENOMEM; } - he_vcc->iov_tail = he_vcc->iov_head; + INIT_LIST_HEAD(&he_vcc->buffers); he_vcc->pdu_len = 0; he_vcc->rc_index = -1; @@ -2406,8 +2313,8 @@ he_open(struct atm_vcc *vcc) goto open_failed; } - rsr1 = RSR1_GROUP(0); - rsr4 = RSR4_GROUP(0); + rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY; + rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY; rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; @@ -2963,8 +2870,7 @@ module_param(sdh, bool, 0); MODULE_PARM_DESC(sdh, "use SDH framing (default 0)"); static struct pci_device_id he_pci_tbl[] = { - { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 }, + { PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 }, { 0, } }; |