Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

atm: [he] rewrite buffer handling in receive path

Instead of a fixed list of buffers, use the buffer pool correctly and
keep track of the outstanding buffer indexes using a fixed table.
Resolves reported HBUF_ERR's -- failures due to lack of receive buffers.

Signed-off-by: Chas Williams - CONTRACTOR <chas@cmf.nrl.navy.mil>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

chas williams - CONTRACTOR and committed by
David S. Miller
e623d625 1d927870

+126 -103
+101 -80
drivers/atm/he.c
··· 67 67 #include <linux/timer.h> 68 68 #include <linux/interrupt.h> 69 69 #include <linux/dma-mapping.h> 70 + #include <linux/bitmap.h> 70 71 #include <linux/slab.h> 71 72 #include <asm/io.h> 72 73 #include <asm/byteorder.h> ··· 779 778 static int __devinit 780 779 he_init_group(struct he_dev *he_dev, int group) 781 780 { 781 + struct he_buff *heb, *next; 782 + dma_addr_t mapping; 782 783 int i; 783 784 784 785 he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); ··· 789 786 he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), 790 787 G0_RBPS_BS + (group * 32)); 791 788 789 + /* bitmap table */ 790 + he_dev->rbpl_table = kmalloc(BITS_TO_LONGS(RBPL_TABLE_SIZE) 791 + * sizeof(unsigned long), GFP_KERNEL); 792 + if (!he_dev->rbpl_table) { 793 + hprintk("unable to allocate rbpl bitmap table\n"); 794 + return -ENOMEM; 795 + } 796 + bitmap_zero(he_dev->rbpl_table, RBPL_TABLE_SIZE); 797 + 798 + /* rbpl_virt 64-bit pointers */ 799 + he_dev->rbpl_virt = kmalloc(RBPL_TABLE_SIZE 800 + * sizeof(struct he_buff *), GFP_KERNEL); 801 + if (!he_dev->rbpl_virt) { 802 + hprintk("unable to allocate rbpl virt table\n"); 803 + goto out_free_rbpl_table; 804 + } 805 + 792 806 /* large buffer pool */ 793 807 he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, 794 - CONFIG_RBPL_BUFSIZE, 8, 0); 808 + CONFIG_RBPL_BUFSIZE, 64, 0); 795 809 if (he_dev->rbpl_pool == NULL) { 796 810 hprintk("unable to create rbpl pool\n"); 797 - return -ENOMEM; 811 + goto out_free_rbpl_virt; 798 812 } 799 813 800 814 he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, ··· 821 801 goto out_destroy_rbpl_pool; 822 802 } 823 803 memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); 824 - he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); 825 - if (he_dev->rbpl_virt == NULL) { 826 - hprintk("failed to alloc rbpl_virt\n"); 827 - goto out_free_rbpl_base; 828 - } 804 + 805 + INIT_LIST_HEAD(&he_dev->rbpl_outstanding); 829 806 830 807 for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { 831 - dma_addr_t dma_handle; 832 - void *cpuaddr; 833 808 834 - cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); 835 - if (cpuaddr == NULL) 836 - goto out_free_rbpl_virt; 809 + heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping); 810 + if (!heb) 811 + goto out_free_rbpl; 812 + heb->mapping = mapping; 813 + list_add(&heb->entry, &he_dev->rbpl_outstanding); 837 814 838 - he_dev->rbpl_virt[i].virt = cpuaddr; 839 - he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); 840 - he_dev->rbpl_base[i].phys = dma_handle; 815 + set_bit(i, he_dev->rbpl_table); 816 + he_dev->rbpl_virt[i] = heb; 817 + he_dev->rbpl_hint = i + 1; 818 + he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET; 819 + he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data); 841 820 } 842 821 he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; 843 822 844 823 he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); 845 824 he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), 846 825 G0_RBPL_T + (group * 32)); 847 - he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4, 826 + he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4, 848 827 G0_RBPL_BS + (group * 32)); 849 828 he_writel(he_dev, 850 829 RBP_THRESH(CONFIG_RBPL_THRESH) | ··· 857 838 CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); 858 839 if (he_dev->rbrq_base == NULL) { 859 840 hprintk("failed to allocate rbrq\n"); 860 - goto out_free_rbpl_virt; 841 + goto out_free_rbpl; 861 842 } 862 843 memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); 863 844 ··· 898 879 pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * 899 880 sizeof(struct he_rbrq), he_dev->rbrq_base, 900 881 he_dev->rbrq_phys); 901 - i = CONFIG_RBPL_SIZE; 902 - out_free_rbpl_virt: 903 - while (i--) 904 - pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt, 905 - he_dev->rbpl_base[i].phys); 906 - kfree(he_dev->rbpl_virt); 882 + out_free_rbpl: 883 + list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) 884 + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 907 885 908 - out_free_rbpl_base: 909 886 pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * 910 887 sizeof(struct he_rbp), he_dev->rbpl_base, 911 888 he_dev->rbpl_phys); 912 889 out_destroy_rbpl_pool: 913 890 pci_pool_destroy(he_dev->rbpl_pool); 891 + out_free_rbpl_virt: 892 + kfree(he_dev->rbpl_virt); 893 + out_free_rbpl_table: 894 + kfree(he_dev->rbpl_table); 914 895 915 896 return -ENOMEM; 916 897 } ··· 1541 1522 static void 1542 1523 he_stop(struct he_dev *he_dev) 1543 1524 { 1544 - u16 command; 1545 - u32 gen_cntl_0, reg; 1525 + struct he_buff *heb, *next; 1546 1526 struct pci_dev *pci_dev; 1527 + u32 gen_cntl_0, reg; 1528 + u16 command; 1547 1529 1548 1530 pci_dev = he_dev->pci_dev; 1549 1531 ··· 1585 1565 he_dev->hsp, he_dev->hsp_phys); 1586 1566 1587 1567 if (he_dev->rbpl_base) { 1588 - int i; 1568 + list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) 1569 + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 1589 1570 1590 - for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { 1591 - void *cpuaddr = he_dev->rbpl_virt[i].virt; 1592 - dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; 1593 - 1594 - pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle); 1595 - } 1596 1571 pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE 1597 1572 * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); 1598 1573 } 1574 + 1575 + kfree(he_dev->rbpl_virt); 1576 + kfree(he_dev->rbpl_table); 1599 1577 1600 1578 if (he_dev->rbpl_pool) 1601 1579 pci_pool_destroy(he_dev->rbpl_pool); ··· 1627 1609 __alloc_tpd(struct he_dev *he_dev) 1628 1610 { 1629 1611 struct he_tpd *tpd; 1630 - dma_addr_t dma_handle; 1612 + dma_addr_t mapping; 1631 1613 1632 - tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle); 1614 + tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping); 1633 1615 if (tpd == NULL) 1634 1616 return NULL; 1635 1617 1636 - tpd->status = TPD_ADDR(dma_handle); 1618 + tpd->status = TPD_ADDR(mapping); 1637 1619 tpd->reserved = 0; 1638 1620 tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0; 1639 1621 tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0; ··· 1662 1644 struct he_rbrq *rbrq_tail = (struct he_rbrq *) 1663 1645 ((unsigned long)he_dev->rbrq_base | 1664 1646 he_dev->hsp->group[group].rbrq_tail); 1665 - struct he_rbp *rbp = NULL; 1666 1647 unsigned cid, lastcid = -1; 1667 - unsigned buf_len = 0; 1668 1648 struct sk_buff *skb; 1669 1649 struct atm_vcc *vcc = NULL; 1670 1650 struct he_vcc *he_vcc; 1671 - struct he_iovec *iov; 1651 + struct he_buff *heb, *next; 1652 + int i; 1672 1653 int pdus_assembled = 0; 1673 1654 int updated = 0; 1674 1655 ··· 1687 1670 RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", 1688 1671 RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); 1689 1672 1690 - rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; 1691 - 1692 - buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; 1693 - cid = RBRQ_CID(he_dev->rbrq_head); 1673 + i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET; 1674 + heb = he_dev->rbpl_virt[i]; 1694 1675 1676 + cid = RBRQ_CID(he_dev->rbrq_head); 1695 1677 if (cid != lastcid) 1696 1678 vcc = __find_vcc(he_dev, cid); 1697 1679 lastcid = cid; 1698 1680 1699 - if (vcc == NULL) { 1700 - hprintk("vcc == NULL (cid 0x%x)\n", cid); 1701 - if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) 1702 - rbp->status &= ~RBP_LOANED; 1681 + if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) { 1682 + hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid); 1683 + if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) { 1684 + clear_bit(i, he_dev->rbpl_table); 1685 + list_del(&heb->entry); 1686 + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 1687 + } 1703 1688 1704 - goto next_rbrq_entry; 1705 - } 1706 - 1707 - he_vcc = HE_VCC(vcc); 1708 - if (he_vcc == NULL) { 1709 - hprintk("he_vcc == NULL (cid 0x%x)\n", cid); 1710 - if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) 1711 - rbp->status &= ~RBP_LOANED; 1712 1689 goto next_rbrq_entry; 1713 1690 } 1714 1691 ··· 1712 1701 goto return_host_buffers; 1713 1702 } 1714 1703 1715 - he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head); 1716 - he_vcc->iov_tail->iov_len = buf_len; 1717 - he_vcc->pdu_len += buf_len; 1718 - ++he_vcc->iov_tail; 1704 + heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; 1705 + clear_bit(i, he_dev->rbpl_table); 1706 + list_move_tail(&heb->entry, &he_vcc->buffers); 1707 + he_vcc->pdu_len += heb->len; 1719 1708 1720 1709 if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) { 1721 1710 lastcid = -1; ··· 1724 1713 goto return_host_buffers; 1725 1714 } 1726 1715 1727 - #ifdef notdef 1728 - if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) { 1729 - hprintk("iovec full! cid 0x%x\n", cid); 1730 - goto return_host_buffers; 1731 - } 1732 - #endif 1733 1716 if (!RBRQ_END_PDU(he_dev->rbrq_head)) 1734 1717 goto next_rbrq_entry; 1735 1718 ··· 1751 1746 1752 1747 __net_timestamp(skb); 1753 1748 1754 - for (iov = he_vcc->iov_head; iov < he_vcc->iov_tail; ++iov) 1755 - memcpy(skb_put(skb, iov->iov_len), 1756 - he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); 1749 + list_for_each_entry(heb, &he_vcc->buffers, entry) 1750 + memcpy(skb_put(skb, heb->len), &heb->data, heb->len); 1757 1751 1758 1752 switch (vcc->qos.aal) { 1759 1753 case ATM_AAL0: ··· 1792 1788 return_host_buffers: 1793 1789 ++pdus_assembled; 1794 1790 1795 - for (iov = he_vcc->iov_head; iov < he_vcc->iov_tail; ++iov) { 1796 - rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)]; 1797 - rbp->status &= ~RBP_LOANED; 1798 - } 1799 - 1800 - he_vcc->iov_tail = he_vcc->iov_head; 1791 + list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry) 1792 + pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); 1793 + INIT_LIST_HEAD(&he_vcc->buffers); 1801 1794 he_vcc->pdu_len = 0; 1802 1795 1803 1796 next_rbrq_entry: ··· 1898 1897 static void 1899 1898 he_service_rbpl(struct he_dev *he_dev, int group) 1900 1899 { 1901 - struct he_rbp *newtail; 1900 + struct he_rbp *new_tail; 1902 1901 struct he_rbp *rbpl_head; 1902 + struct he_buff *heb; 1903 + dma_addr_t mapping; 1904 + int i; 1903 1905 int moved = 0; 1904 1906 1905 1907 rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | 1906 1908 RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); 1907 1909 1908 1910 for (;;) { 1909 - newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | 1911 + new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | 1910 1912 RBPL_MASK(he_dev->rbpl_tail+1)); 1911 1913 1912 1914 /* table 3.42 -- rbpl_tail should never be set to rbpl_head */ 1913 - if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED)) 1915 + if (new_tail == rbpl_head) 1914 1916 break; 1915 1917 1916 - newtail->status |= RBP_LOANED; 1917 - he_dev->rbpl_tail = newtail; 1918 + i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint); 1919 + if (i > (RBPL_TABLE_SIZE - 1)) { 1920 + i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE); 1921 + if (i > (RBPL_TABLE_SIZE - 1)) 1922 + break; 1923 + } 1924 + he_dev->rbpl_hint = i + 1; 1925 + 1926 + heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping); 1927 + if (!heb) 1928 + break; 1929 + heb->mapping = mapping; 1930 + list_add(&heb->entry, &he_dev->rbpl_outstanding); 1931 + he_dev->rbpl_virt[i] = heb; 1932 + set_bit(i, he_dev->rbpl_table); 1933 + new_tail->idx = i << RBP_IDX_OFFSET; 1934 + new_tail->phys = mapping + offsetof(struct he_buff, data); 1935 + 1936 + he_dev->rbpl_tail = new_tail; 1918 1937 ++moved; 1919 1938 } 1920 1939 ··· 2158 2137 return -ENOMEM; 2159 2138 } 2160 2139 2161 - he_vcc->iov_tail = he_vcc->iov_head; 2140 + INIT_LIST_HEAD(&he_vcc->buffers); 2162 2141 he_vcc->pdu_len = 0; 2163 2142 he_vcc->rc_index = -1; 2164 2143
+25 -23
drivers/atm/he.h
··· 198 198 } group[HE_NUM_GROUPS]; 199 199 }; 200 200 201 - /* figure 2.9 receive buffer pools */ 201 + /* 202 + * figure 2.9 receive buffer pools 203 + * 204 + * since a virtual address might be more than 32 bits, we store an index 205 + * in the virt member of he_rbp. NOTE: the lower six bits in the rbrq 206 + * addr member are used for buffer status further limiting us to 26 bits. 207 + */ 202 208 203 209 struct he_rbp { 204 210 volatile u32 phys; 205 - volatile u32 status; 211 + volatile u32 idx; /* virt */ 206 212 }; 207 213 208 - /* NOTE: it is suggested that virt be the virtual address of the host 209 - buffer. on a 64-bit machine, this would not work. Instead, we 210 - store the real virtual address in another list, and store an index 211 - (and buffer status) in the virt member. 212 - */ 214 + #define RBP_IDX_OFFSET 6 213 215 214 - #define RBP_INDEX_OFF 6 215 - #define RBP_INDEX(x) (((long)(x) >> RBP_INDEX_OFF) & 0xffff) 216 - #define RBP_LOANED 0x80000000 217 - #define RBP_SMALLBUF 0x40000000 216 + /* 217 + * the he dma engine will try to hold an extra 16 buffers in its local 218 + * caches. and add a couple buffers for safety. 219 + */ 218 220 219 - struct he_virt { 220 - void *virt; 221 + #define RBPL_TABLE_SIZE (CONFIG_RBPL_SIZE + 16 + 2) 222 + 223 + struct he_buff { 224 + struct list_head entry; 225 + dma_addr_t mapping; 226 + unsigned long len; 227 + u8 data[]; 221 228 }; 222 229 223 230 #ifdef notyet ··· 293 286 struct he_rbrq *rbrq_base, *rbrq_head; 294 287 int rbrq_peak; 295 288 289 + struct he_buff **rbpl_virt; 290 + unsigned long *rbpl_table; 291 + unsigned long rbpl_hint; 296 292 struct pci_pool *rbpl_pool; 297 293 dma_addr_t rbpl_phys; 298 294 struct he_rbp *rbpl_base, *rbpl_tail; 299 - struct he_virt *rbpl_virt; 295 + struct list_head rbpl_outstanding; 300 296 int rbpl_peak; 301 297 302 298 dma_addr_t tbrq_phys; ··· 314 304 struct he_dev *next; 315 305 }; 316 306 317 - struct he_iovec 318 - { 319 - u32 iov_base; 320 - u32 iov_len; 321 - }; 322 - 323 307 #define HE_MAXIOV 20 324 308 325 309 struct he_vcc 326 310 { 327 - struct he_iovec iov_head[HE_MAXIOV]; 328 - struct he_iovec *iov_tail; 311 + struct list_head buffers; 329 312 int pdu_len; 330 - 331 313 int rc_index; 332 314 333 315 wait_queue_head_t rx_waitq;