diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/atm/he.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/atm/he.c | 2897 |
1 files changed, 0 insertions, 2897 deletions
diff --git a/ANDROID_3.4.5/drivers/atm/he.c b/ANDROID_3.4.5/drivers/atm/he.c deleted file mode 100644 index b182c2f7..00000000 --- a/ANDROID_3.4.5/drivers/atm/he.c +++ /dev/null @@ -1,2897 +0,0 @@ -/* - - he.c - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2001 Naval Research Laboratory - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/* - - he.c - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2001 Naval Research Laboratory - - Permission to use, copy, modify and distribute this software and its - documentation is hereby granted, provided that both the copyright - notice and this permission notice appear in all copies of the software, - derivative works or modified versions, and any portions thereof, and - that both notices appear in supporting documentation. - - NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND - DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER - RESULTING FROM THE USE OF THIS SOFTWARE. - - This driver was written using the "Programmer's Reference Manual for - ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98. - - AUTHORS: - chas williams <chas@cmf.nrl.navy.mil> - eric kinzie <ekinzie@cmf.nrl.navy.mil> - - NOTES: - 4096 supported 'connections' - group 0 is used for all traffic - interrupt queue 0 is used for all interrupts - aal0 support (based on work from ulrich.u.muller@nokia.com) - - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#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> -#include <asm/uaccess.h> - -#include <linux/atmdev.h> -#include <linux/atm.h> -#include <linux/sonet.h> - -#undef USE_SCATTERGATHER -#undef USE_CHECKSUM_HW /* still confused about this */ -/* #undef HE_DEBUG */ - -#include "he.h" -#include "suni.h" -#include <linux/atm_he.h> - -#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number , ##args) - -#ifdef HE_DEBUG -#define HPRINTK(fmt,args...) printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args) -#else /* !HE_DEBUG */ -#define HPRINTK(fmt,args...) do { } while (0) -#endif /* HE_DEBUG */ - -/* declarations */ - -static int he_open(struct atm_vcc *vcc); -static void he_close(struct atm_vcc *vcc); -static int he_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); -static irqreturn_t he_irq_handler(int irq, void *dev_id); -static void he_tasklet(unsigned long data); -static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); -static int he_start(struct atm_dev *dev); -static void he_stop(struct he_dev *dev); -static void he_phy_put(struct atm_dev *, unsigned char, unsigned long); -static unsigned char he_phy_get(struct atm_dev *, unsigned long); - -static u8 read_prom_byte(struct he_dev *he_dev, int addr); - -/* globals */ - -static struct he_dev *he_devs; -static bool disable64; -static short nvpibits = -1; -static short nvcibits = -1; -static short rx_skb_reserve = 16; -static bool irq_coalesce = 1; -static bool sdh = 0; - -/* Read from EEPROM = 0000 0011b */ -static unsigned int readtab[] = { - CS_HIGH | CLK_HIGH, - CS_LOW | CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH, /* 1 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH /* 1 */ -}; - -/* Clock to read from/write to the EEPROM */ -static unsigned int clocktab[] = { - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW -}; - -static struct atmdev_ops he_ops = -{ - .open = he_open, - .close = he_close, - .ioctl = he_ioctl, - .send = he_send, - .phy_put = he_phy_put, - .phy_get = he_phy_get, - .proc_read = he_proc_read, - .owner = THIS_MODULE -}; - -#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0) -#define he_readl(dev, reg) readl((dev)->membase + (reg)) - -/* section 2.12 connection memory access */ - -static __inline__ void -he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr, - unsigned flags) -{ - he_writel(he_dev, val, CON_DAT); - (void) he_readl(he_dev, CON_DAT); /* flush posted writes */ - he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL); - while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); -} - -#define he_writel_rcm(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_RCM) - -#define he_writel_tcm(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_TCM) - -#define he_writel_mbox(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_MBOX) - -static unsigned -he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) -{ - he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL); - while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); - return he_readl(he_dev, CON_DAT); -} - -#define he_readl_rcm(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_RCM) - -#define he_readl_tcm(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_TCM) - -#define he_readl_mbox(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_MBOX) - - -/* figure 2.2 connection id */ - -#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff) - -/* 2.5.1 per connection transmit state registers */ - -#define he_writel_tsr0(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0) -#define he_readl_tsr0(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0) - -#define he_writel_tsr1(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1) - -#define he_writel_tsr2(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2) - -#define he_writel_tsr3(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3) - -#define he_writel_tsr4(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4) - - /* from page 2-20 - * - * NOTE While the transmit connection is active, bits 23 through 0 - * of this register must not be written by the host. Byte - * enables should be used during normal operation when writing - * the most significant byte. - */ - -#define he_writel_tsr4_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \ - CON_CTL_TCM \ - | CON_BYTE_DISABLE_2 \ - | CON_BYTE_DISABLE_1 \ - | CON_BYTE_DISABLE_0) - -#define he_readl_tsr4(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4) - -#define he_writel_tsr5(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5) - -#define he_writel_tsr6(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6) - -#define he_writel_tsr7(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7) - - -#define he_writel_tsr8(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0) - -#define he_writel_tsr9(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1) - -#define he_writel_tsr10(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2) - -#define he_writel_tsr11(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3) - - -#define he_writel_tsr12(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0) - -#define he_writel_tsr13(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1) - - -#define he_writel_tsr14(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRD | cid) - -#define he_writel_tsr14_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRD | cid, \ - CON_CTL_TCM \ - | CON_BYTE_DISABLE_2 \ - | CON_BYTE_DISABLE_1 \ - | CON_BYTE_DISABLE_0) - -/* 2.7.1 per connection receive state registers */ - -#define he_writel_rsr0(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0) -#define he_readl_rsr0(dev, cid) \ - he_readl_rcm(dev, 0x00000 | (cid << 3) | 0) - -#define he_writel_rsr1(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1) - -#define he_writel_rsr2(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2) - -#define he_writel_rsr3(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3) - -#define he_writel_rsr4(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4) - -#define he_writel_rsr5(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5) - -#define he_writel_rsr6(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6) - -#define he_writel_rsr7(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) - -static __inline__ struct atm_vcc* -__find_vcc(struct he_dev *he_dev, unsigned cid) -{ - struct hlist_head *head; - struct atm_vcc *vcc; - struct hlist_node *node; - struct sock *s; - short vpi; - int vci; - - vpi = cid >> he_dev->vcibits; - vci = cid & ((1 << he_dev->vcibits) - 1); - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; - - sk_for_each(s, node, head) { - vcc = atm_sk(s); - if (vcc->dev == he_dev->atm_dev && - vcc->vci == vci && vcc->vpi == vpi && - vcc->qos.rxtp.traffic_class != ATM_NONE) { - return vcc; - } - } - return NULL; -} - -static int __devinit -he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) -{ - struct atm_dev *atm_dev = NULL; - struct he_dev *he_dev = NULL; - int err = 0; - - printk(KERN_INFO "ATM he driver\n"); - - if (pci_enable_device(pci_dev)) - return -EIO; - if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING "he: no suitable dma available\n"); - err = -EIO; - goto init_one_failure; - } - - atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL); - if (!atm_dev) { - err = -ENODEV; - goto init_one_failure; - } - pci_set_drvdata(pci_dev, atm_dev); - - he_dev = kzalloc(sizeof(struct he_dev), - GFP_KERNEL); - if (!he_dev) { - err = -ENOMEM; - goto init_one_failure; - } - he_dev->pci_dev = pci_dev; - he_dev->atm_dev = atm_dev; - he_dev->atm_dev->dev_data = he_dev; - atm_dev->dev_data = he_dev; - he_dev->number = atm_dev->number; - tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); - spin_lock_init(&he_dev->global_lock); - - if (he_start(atm_dev)) { - he_stop(he_dev); - err = -ENODEV; - goto init_one_failure; - } - he_dev->next = NULL; - if (he_devs) - he_dev->next = he_devs; - he_devs = he_dev; - return 0; - -init_one_failure: - if (atm_dev) - atm_dev_deregister(atm_dev); - kfree(he_dev); - pci_disable_device(pci_dev); - return err; -} - -static void __devexit -he_remove_one (struct pci_dev *pci_dev) -{ - struct atm_dev *atm_dev; - struct he_dev *he_dev; - - atm_dev = pci_get_drvdata(pci_dev); - he_dev = HE_DEV(atm_dev); - - /* need to remove from he_devs */ - - he_stop(he_dev); - atm_dev_deregister(atm_dev); - kfree(he_dev); - - pci_set_drvdata(pci_dev, NULL); - pci_disable_device(pci_dev); -} - - -static unsigned -rate_to_atmf(unsigned rate) /* cps to atm forum format */ -{ -#define NONZERO (1 << 14) - - unsigned exp = 0; - - if (rate == 0) - return 0; - - rate <<= 9; - while (rate > 0x3ff) { - ++exp; - rate >>= 1; - } - - return (NONZERO | (exp << 9) | (rate & 0x1ff)); -} - -static void __devinit -he_init_rx_lbfp0(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; - - lbufd_index = 0; - lbm_offset = he_readl(he_dev, RCMLBM_BA); - - he_writel(he_dev, lbufd_index, RLBF0_H); - - for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { - lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF0_T); - he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); -} - -static void __devinit -he_init_rx_lbfp1(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; - - lbufd_index = 1; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); - - he_writel(he_dev, lbufd_index, RLBF1_H); - - for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { - lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF1_T); - he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); -} - -static void __devinit -he_init_tx_lbfp(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; - - lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); - - he_writel(he_dev, lbufd_index, TLBF_H); - - for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { - lbufd_index += 1; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 2; - } - - he_writel(he_dev, lbufd_index - 1, TLBF_T); -} - -static int __devinit -he_init_tpdrq(struct he_dev *he_dev) -{ - he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys); - if (he_dev->tpdrq_base == NULL) { - hprintk("failed to alloc tpdrq\n"); - return -ENOMEM; - } - memset(he_dev->tpdrq_base, 0, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq)); - - he_dev->tpdrq_tail = he_dev->tpdrq_base; - he_dev->tpdrq_head = he_dev->tpdrq_base; - - he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H); - he_writel(he_dev, 0, TPDRQ_T); - he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S); - - return 0; -} - -static void __devinit -he_init_cs_block(struct he_dev *he_dev) -{ - unsigned clock, rate, delta; - int reg; - - /* 5.1.7 cs block initialization */ - - for (reg = 0; reg < 0x20; ++reg) - he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg); - - /* rate grid timer reload values */ - - clock = he_is622(he_dev) ? 66667000 : 50000000; - rate = he_dev->atm_dev->link_rate; - delta = rate / 16 / 2; - - for (reg = 0; reg < 0x10; ++reg) { - /* 2.4 internal transmit function - * - * we initialize the first row in the rate grid. - * values are period (in clock cycles) of timer - */ - unsigned period = clock / rate; - - he_writel_mbox(he_dev, period, CS_TGRLD0 + reg); - rate -= delta; - } - - if (he_is622(he_dev)) { - /* table 5.2 (4 cells per lbuf) */ - he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0); - he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1); - he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2); - he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3); - he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4); - - /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ - he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0); - he_writel_mbox(he_dev, 0x1801, CS_ERCTL1); - he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2); - he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); - he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1); - he_writel_mbox(he_dev, 0x14585, CS_RTFWR); - - he_writel_mbox(he_dev, 0x4680, CS_RTATR); - - /* table 5.8 */ - he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET); - he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX); - he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN); - he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC); - he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC); - he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL); - - /* table 5.9 */ - he_writel_mbox(he_dev, 0x5, CS_OTPPER); - he_writel_mbox(he_dev, 0x14, CS_OTWPER); - } else { - /* table 5.1 (4 cells per lbuf) */ - he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0); - he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1); - he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2); - he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3); - he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4); - - /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ - he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0); - he_writel_mbox(he_dev, 0x4701, CS_ERCTL1); - he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2); - he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); - he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1); - he_writel_mbox(he_dev, 0xf424, CS_RTFWR); - - he_writel_mbox(he_dev, 0x4680, CS_RTATR); - - /* table 5.8 */ - he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET); - he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX); - he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN); - he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC); - he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC); - he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL); - - /* table 5.9 */ - he_writel_mbox(he_dev, 0x6, CS_OTPPER); - he_writel_mbox(he_dev, 0x1e, CS_OTWPER); - } - - he_writel_mbox(he_dev, 0x8, CS_OTTLIM); - - for (reg = 0; reg < 0x8; ++reg) - he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg); - -} - -static int __devinit -he_init_cs_block_rcm(struct he_dev *he_dev) -{ - unsigned (*rategrid)[16][16]; - unsigned rate, delta; - int i, j, reg; - - unsigned rate_atmf, exp, man; - unsigned long long rate_cps; - int mult, buf, buf_limit = 4; - - rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL); - if (!rategrid) - return -ENOMEM; - - /* initialize rate grid group table */ - - for (reg = 0x0; reg < 0xff; ++reg) - he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); - - /* initialize rate controller groups */ - - for (reg = 0x100; reg < 0x1ff; ++reg) - he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); - - /* initialize tNrm lookup table */ - - /* the manual makes reference to a routine in a sample driver - for proper configuration; fortunately, we only need this - in order to support abr connection */ - - /* initialize rate to group table */ - - rate = he_dev->atm_dev->link_rate; - delta = rate / 32; - - /* - * 2.4 transmit internal functions - * - * we construct a copy of the rate grid used by the scheduler - * in order to construct the rate to group table below - */ - - for (j = 0; j < 16; j++) { - (*rategrid)[0][j] = rate; - rate -= delta; - } - - for (i = 1; i < 16; i++) - for (j = 0; j < 16; j++) - if (i > 14) - (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4; - else - (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2; - - /* - * 2.4 transmit internal function - * - * this table maps the upper 5 bits of exponent and mantissa - * of the atm forum representation of the rate into an index - * on rate grid - */ - - rate_atmf = 0; - while (rate_atmf < 0x400) { - man = (rate_atmf & 0x1f) << 4; - exp = rate_atmf >> 5; - - /* - instead of '/ 512', use '>> 9' to prevent a call - to divdu3 on x86 platforms - */ - rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9; - - if (rate_cps < 10) - rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */ - - for (i = 255; i > 0; i--) - if ((*rategrid)[i/16][i%16] >= rate_cps) - break; /* pick nearest rate instead? */ - - /* - * each table entry is 16 bits: (rate grid index (8 bits) - * and a buffer limit (8 bits) - * there are two table entries in each 32-bit register - */ - -#ifdef notdef - buf = rate_cps * he_dev->tx_numbuffs / - (he_dev->atm_dev->link_rate * 2); -#else - /* this is pretty, but avoids _divdu3 and is mostly correct */ - mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; - if (rate_cps > (272 * mult)) - buf = 4; - else if (rate_cps > (204 * mult)) - buf = 3; - else if (rate_cps > (136 * mult)) - buf = 2; - else if (rate_cps > (68 * mult)) - buf = 1; - else - buf = 0; -#endif - if (buf > buf_limit) - buf = buf_limit; - reg = (reg << 16) | ((i << 8) | buf); - -#define RTGTBL_OFFSET 0x400 - - if (rate_atmf & 0x1) - he_writel_rcm(he_dev, reg, - CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf >> 1)); - - ++rate_atmf; - } - - kfree(rategrid); - return 0; -} - -static int __devinit -he_init_group(struct he_dev *he_dev, int group) -{ - struct he_buff *heb, *next; - dma_addr_t mapping; - int i; - - 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); - - /* 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; - } - - /* large buffer pool */ - he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, - CONFIG_RBPL_BUFSIZE, 64, 0); - if (he_dev->rbpl_pool == NULL) { - hprintk("unable to create rbpl pool\n"); - goto out_free_rbpl_virt; - } - - he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, - CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); - if (he_dev->rbpl_base == NULL) { - hprintk("failed to alloc rbpl_base\n"); - goto out_destroy_rbpl_pool; - } - memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); - - INIT_LIST_HEAD(&he_dev->rbpl_outstanding); - - for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { - - 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); - - 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 - sizeof(struct he_buff))/4, - G0_RBPL_BS + (group * 32)); - he_writel(he_dev, - RBP_THRESH(CONFIG_RBPL_THRESH) | - RBP_QSIZE(CONFIG_RBPL_SIZE - 1) | - RBP_INT_ENB, - G0_RBPL_QI + (group * 32)); - - /* rx buffer ready queue */ - - he_dev->rbrq_base = pci_alloc_consistent(he_dev->pci_dev, - 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; - } - memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); - - he_dev->rbrq_head = he_dev->rbrq_base; - he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); - he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); - he_writel(he_dev, - RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE - 1), - G0_RBRQ_Q + (group * 16)); - if (irq_coalesce) { - hprintk("coalescing interrupts\n"); - he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), - G0_RBRQ_I + (group * 16)); - } else - he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1), - G0_RBRQ_I + (group * 16)); - - /* tx buffer ready queue */ - - he_dev->tbrq_base = pci_alloc_consistent(he_dev->pci_dev, - CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); - if (he_dev->tbrq_base == NULL) { - hprintk("failed to allocate tbrq\n"); - goto out_free_rbpq_base; - } - memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq)); - - he_dev->tbrq_head = he_dev->tbrq_base; - - he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16)); - he_writel(he_dev, 0, G0_TBRQ_H + (group * 16)); - he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16)); - he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); - - return 0; - -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); -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); - - 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); - - return -ENOMEM; -} - -static int __devinit -he_init_irq(struct he_dev *he_dev) -{ - int i; - - /* 2.9.3.5 tail offset for each interrupt queue is located after the - end of the interrupt queue */ - - he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, - (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); - if (he_dev->irq_base == NULL) { - hprintk("failed to allocate irq\n"); - return -ENOMEM; - } - he_dev->irq_tailoffset = (unsigned *) - &he_dev->irq_base[CONFIG_IRQ_SIZE]; - *he_dev->irq_tailoffset = 0; - he_dev->irq_head = he_dev->irq_base; - he_dev->irq_tail = he_dev->irq_base; - - for (i = 0; i < CONFIG_IRQ_SIZE; ++i) - he_dev->irq_base[i].isw = ITYPE_INVALID; - - he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); - he_writel(he_dev, - IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH), - IRQ0_HEAD); - he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL); - he_writel(he_dev, 0x0, IRQ0_DATA); - - he_writel(he_dev, 0x0, IRQ1_BASE); - he_writel(he_dev, 0x0, IRQ1_HEAD); - he_writel(he_dev, 0x0, IRQ1_CNTL); - he_writel(he_dev, 0x0, IRQ1_DATA); - - he_writel(he_dev, 0x0, IRQ2_BASE); - he_writel(he_dev, 0x0, IRQ2_HEAD); - he_writel(he_dev, 0x0, IRQ2_CNTL); - he_writel(he_dev, 0x0, IRQ2_DATA); - - he_writel(he_dev, 0x0, IRQ3_BASE); - he_writel(he_dev, 0x0, IRQ3_HEAD); - he_writel(he_dev, 0x0, IRQ3_CNTL); - he_writel(he_dev, 0x0, IRQ3_DATA); - - /* 2.9.3.2 interrupt queue mapping registers */ - - he_writel(he_dev, 0x0, GRP_10_MAP); - he_writel(he_dev, 0x0, GRP_32_MAP); - 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_SHARED, DEV_LABEL, he_dev)) { - hprintk("irq %d already in use\n", he_dev->pci_dev->irq); - return -EINVAL; - } - - he_dev->irq = he_dev->pci_dev->irq; - - return 0; -} - -static int __devinit -he_start(struct atm_dev *dev) -{ - struct he_dev *he_dev; - struct pci_dev *pci_dev; - unsigned long membase; - - u16 command; - u32 gen_cntl_0, host_cntl, lb_swap; - u8 cache_size, timer; - - unsigned err; - unsigned int status, reg; - int i, group; - - he_dev = HE_DEV(dev); - pci_dev = he_dev->pci_dev; - - membase = pci_resource_start(pci_dev, 0); - HPRINTK("membase = 0x%lx irq = %d.\n", membase, pci_dev->irq); - - /* - * pci bus controller initialization - */ - - /* 4.3 pci bus controller-specific initialization */ - if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) { - hprintk("can't read GEN_CNTL_0\n"); - return -EINVAL; - } - gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); - if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) { - hprintk("can't write GEN_CNTL_0.\n"); - return -EINVAL; - } - - if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) { - hprintk("can't read PCI_COMMAND.\n"); - return -EINVAL; - } - - command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); - if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) { - hprintk("can't enable memory.\n"); - return -EINVAL; - } - - if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) { - hprintk("can't read cache line size?\n"); - return -EINVAL; - } - - if (cache_size < 16) { - cache_size = 16; - if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size)) - hprintk("can't set cache line size to %d\n", cache_size); - } - - if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) { - hprintk("can't read latency timer?\n"); - return -EINVAL; - } - - /* from table 3.9 - * - * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE - * - * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles] - * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles] - * - */ -#define LAT_TIMER 209 - if (timer < LAT_TIMER) { - HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER); - timer = LAT_TIMER; - if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer)) - hprintk("can't set latency timer to %d\n", timer); - } - - if (!(he_dev->membase = ioremap(membase, HE_REGMAP_SIZE))) { - hprintk("can't set up page mapping\n"); - return -EINVAL; - } - - /* 4.4 card reset */ - he_writel(he_dev, 0x0, RESET_CNTL); - he_writel(he_dev, 0xff, RESET_CNTL); - - udelay(16*1000); /* 16 ms */ - status = he_readl(he_dev, RESET_CNTL); - if ((status & BOARD_RST_STATUS) == 0) { - hprintk("reset failed\n"); - return -EINVAL; - } - - /* 4.5 set bus width */ - host_cntl = he_readl(he_dev, HOST_CNTL); - if (host_cntl & PCI_BUS_SIZE64) - gen_cntl_0 |= ENBL_64; - else - gen_cntl_0 &= ~ENBL_64; - - if (disable64 == 1) { - hprintk("disabling 64-bit pci bus transfers\n"); - gen_cntl_0 &= ~ENBL_64; - } - - if (gen_cntl_0 & ENBL_64) - hprintk("64-bit transfers enabled\n"); - - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - /* 4.7 read prom contents */ - for (i = 0; i < PROD_ID_LEN; ++i) - he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i); - - he_dev->media = read_prom_byte(he_dev, MEDIA); - - for (i = 0; i < 6; ++i) - dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); - - hprintk("%s%s, %x:%x:%x:%x:%x:%x\n", - he_dev->prod_id, - he_dev->media & 0x40 ? "SM" : "MM", - dev->esi[0], - dev->esi[1], - dev->esi[2], - dev->esi[3], - dev->esi[4], - dev->esi[5]); - he_dev->atm_dev->link_rate = he_is622(he_dev) ? - ATM_OC12_PCR : ATM_OC3_PCR; - - /* 4.6 set host endianess */ - lb_swap = he_readl(he_dev, LB_SWAP); - if (he_is622(he_dev)) - lb_swap &= ~XFER_SIZE; /* 4 cells */ - else - lb_swap |= XFER_SIZE; /* 8 cells */ -#ifdef __BIG_ENDIAN - lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST; -#else - lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST | - DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP); -#endif /* __BIG_ENDIAN */ - he_writel(he_dev, lb_swap, LB_SWAP); - - /* 4.8 sdram controller initialization */ - he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL); - - /* 4.9 initialize rnum value */ - lb_swap |= SWAP_RNUM_MAX(0xf); - he_writel(he_dev, lb_swap, LB_SWAP); - - /* 4.10 initialize the interrupt queues */ - if ((err = he_init_irq(he_dev)) != 0) - return err; - - /* 4.11 enable pci bus controller state machines */ - host_cntl |= (OUTFF_ENB | CMDFF_ENB | - QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB); - he_writel(he_dev, host_cntl, HOST_CNTL); - - gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB; - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - /* - * atm network controller initialization - */ - - /* 5.1.1 generic configuration state */ - - /* - * local (cell) buffer memory map - * - * HE155 HE622 - * - * 0 ____________1023 bytes 0 _______________________2047 bytes - * | | | | | - * | utility | | rx0 | | - * 5|____________| 255|___________________| u | - * 6| | 256| | t | - * | | | | i | - * | rx0 | row | tx | l | - * | | | | i | - * | | 767|___________________| t | - * 517|____________| 768| | y | - * row 518| | | rx1 | | - * | | 1023|___________________|___| - * | | - * | tx | - * | | - * | | - * 1535|____________| - * 1536| | - * | rx1 | - * 2047|____________| - * - */ - - /* total 4096 connections */ - he_dev->vcibits = CONFIG_DEFAULT_VCIBITS; - he_dev->vpibits = CONFIG_DEFAULT_VPIBITS; - - if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) { - hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS); - return -ENODEV; - } - - if (nvpibits != -1) { - he_dev->vpibits = nvpibits; - he_dev->vcibits = HE_MAXCIDBITS - nvpibits; - } - - if (nvcibits != -1) { - he_dev->vcibits = nvcibits; - he_dev->vpibits = HE_MAXCIDBITS - nvcibits; - } - - - if (he_is622(he_dev)) { - he_dev->cells_per_row = 40; - he_dev->bytes_per_row = 2048; - he_dev->r0_numrows = 256; - he_dev->tx_numrows = 512; - he_dev->r1_numrows = 256; - he_dev->r0_startrow = 0; - he_dev->tx_startrow = 256; - he_dev->r1_startrow = 768; - } else { - he_dev->cells_per_row = 20; - he_dev->bytes_per_row = 1024; - he_dev->r0_numrows = 512; - he_dev->tx_numrows = 1018; - he_dev->r1_numrows = 512; - he_dev->r0_startrow = 6; - he_dev->tx_startrow = 518; - he_dev->r1_startrow = 1536; - } - - he_dev->cells_per_lbuf = 4; - he_dev->buffer_limit = 4; - he_dev->r0_numbuffs = he_dev->r0_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r0_numbuffs > 2560) - he_dev->r0_numbuffs = 2560; - - he_dev->r1_numbuffs = he_dev->r1_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r1_numbuffs > 2560) - he_dev->r1_numbuffs = 2560; - - he_dev->tx_numbuffs = he_dev->tx_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->tx_numbuffs > 5120) - he_dev->tx_numbuffs = 5120; - - /* 5.1.2 configure hardware dependent registers */ - - he_writel(he_dev, - SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) | - RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) | - (he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) | - (he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)), - LBARB); - - he_writel(he_dev, BANK_ON | - (he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)), - SDRAMCON); - - he_writel(he_dev, - (he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) | - RM_RW_WAIT(1), RCMCONFIG); - he_writel(he_dev, - (he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) | - TM_RW_WAIT(1), TCMCONFIG); - - he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG); - - he_writel(he_dev, - (he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) | - (he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) | - RX_VALVP(he_dev->vpibits) | - RX_VALVC(he_dev->vcibits), RC_CONFIG); - - he_writel(he_dev, DRF_THRESH(0x20) | - (he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) | - TX_VCI_MASK(he_dev->vcibits) | - LBFREE_CNT(he_dev->tx_numbuffs), TX_CONFIG); - - he_writel(he_dev, 0x0, TXAAL5_PROTO); - - he_writel(he_dev, PHY_INT_ENB | - (he_is622(he_dev) ? PTMR_PRE(67 - 1) : PTMR_PRE(50 - 1)), - RH_CONFIG); - - /* 5.1.3 initialize connection memory */ - - for (i = 0; i < TCM_MEM_SIZE; ++i) - he_writel_tcm(he_dev, 0, i); - - for (i = 0; i < RCM_MEM_SIZE; ++i) - he_writel_rcm(he_dev, 0, i); - - /* - * transmit connection memory map - * - * tx memory - * 0x0 ___________________ - * | | - * | | - * | TSRa | - * | | - * | | - * 0x8000|___________________| - * | | - * | TSRb | - * 0xc000|___________________| - * | | - * | TSRc | - * 0xe000|___________________| - * | TSRd | - * 0xf000|___________________| - * | tmABR | - * 0x10000|___________________| - * | | - * | tmTPD | - * |___________________| - * | | - * .... - * 0x1ffff|___________________| - * - * - */ - - he_writel(he_dev, CONFIG_TSRB, TSRB_BA); - he_writel(he_dev, CONFIG_TSRC, TSRC_BA); - he_writel(he_dev, CONFIG_TSRD, TSRD_BA); - he_writel(he_dev, CONFIG_TMABR, TMABR_BA); - he_writel(he_dev, CONFIG_TPDBA, TPD_BA); - - - /* - * receive connection memory map - * - * 0x0 ___________________ - * | | - * | | - * | RSRa | - * | | - * | | - * 0x8000|___________________| - * | | - * | rx0/1 | - * | LBM | link lists of local - * | tx | buffer memory - * | | - * 0xd000|___________________| - * | | - * | rmABR | - * 0xe000|___________________| - * | | - * | RSRb | - * |___________________| - * | | - * .... - * 0xffff|___________________| - */ - - he_writel(he_dev, 0x08000, RCMLBM_BA); - he_writel(he_dev, 0x0e000, RCMRSRB_BA); - he_writel(he_dev, 0x0d800, RCMABR_BA); - - /* 5.1.4 initialize local buffer free pools linked lists */ - - he_init_rx_lbfp0(he_dev); - he_init_rx_lbfp1(he_dev); - - he_writel(he_dev, 0x0, RLBC_H); - he_writel(he_dev, 0x0, RLBC_T); - he_writel(he_dev, 0x0, RLBC_H2); - - he_writel(he_dev, 512, RXTHRSH); /* 10% of r0+r1 buffers */ - he_writel(he_dev, 256, LITHRSH); /* 5% of r0+r1 buffers */ - - he_init_tx_lbfp(he_dev); - - he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA); - - /* 5.1.5 initialize intermediate receive queues */ - - if (he_is622(he_dev)) { - he_writel(he_dev, 0x000f, G0_INMQ_S); - he_writel(he_dev, 0x200f, G0_INMQ_L); - - he_writel(he_dev, 0x001f, G1_INMQ_S); - he_writel(he_dev, 0x201f, G1_INMQ_L); - - he_writel(he_dev, 0x002f, G2_INMQ_S); - he_writel(he_dev, 0x202f, G2_INMQ_L); - - he_writel(he_dev, 0x003f, G3_INMQ_S); - he_writel(he_dev, 0x203f, G3_INMQ_L); - - he_writel(he_dev, 0x004f, G4_INMQ_S); - he_writel(he_dev, 0x204f, G4_INMQ_L); - - he_writel(he_dev, 0x005f, G5_INMQ_S); - he_writel(he_dev, 0x205f, G5_INMQ_L); - - he_writel(he_dev, 0x006f, G6_INMQ_S); - he_writel(he_dev, 0x206f, G6_INMQ_L); - - he_writel(he_dev, 0x007f, G7_INMQ_S); - he_writel(he_dev, 0x207f, G7_INMQ_L); - } else { - he_writel(he_dev, 0x0000, G0_INMQ_S); - he_writel(he_dev, 0x0008, G0_INMQ_L); - - he_writel(he_dev, 0x0001, G1_INMQ_S); - he_writel(he_dev, 0x0009, G1_INMQ_L); - - he_writel(he_dev, 0x0002, G2_INMQ_S); - he_writel(he_dev, 0x000a, G2_INMQ_L); - - he_writel(he_dev, 0x0003, G3_INMQ_S); - he_writel(he_dev, 0x000b, G3_INMQ_L); - - he_writel(he_dev, 0x0004, G4_INMQ_S); - he_writel(he_dev, 0x000c, G4_INMQ_L); - - he_writel(he_dev, 0x0005, G5_INMQ_S); - he_writel(he_dev, 0x000d, G5_INMQ_L); - - he_writel(he_dev, 0x0006, G6_INMQ_S); - he_writel(he_dev, 0x000e, G6_INMQ_L); - - he_writel(he_dev, 0x0007, G7_INMQ_S); - he_writel(he_dev, 0x000f, G7_INMQ_L); - } - - /* 5.1.6 application tunable parameters */ - - he_writel(he_dev, 0x0, MCC); - he_writel(he_dev, 0x0, OEC); - he_writel(he_dev, 0x0, DCC); - he_writel(he_dev, 0x0, CEC); - - /* 5.1.7 cs block initialization */ - - he_init_cs_block(he_dev); - - /* 5.1.8 cs block connection memory initialization */ - - if (he_init_cs_block_rcm(he_dev) < 0) - return -ENOMEM; - - /* 5.1.10 initialize host structures */ - - he_init_tpdrq(he_dev); - - he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, - sizeof(struct he_tpd), TPD_ALIGNMENT, 0); - if (he_dev->tpd_pool == NULL) { - hprintk("unable to create tpd pci_pool\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&he_dev->outstanding_tpds); - - if (he_init_group(he_dev, 0) != 0) - return -ENOMEM; - - for (group = 1; group < HE_NUM_GROUPS; ++group) { - 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)); - - he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32)); - he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), - G0_RBPL_QI + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32)); - - he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16)); - he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16)); - he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0), - G0_RBRQ_Q + (group * 16)); - he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16)); - - he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16)); - he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16)); - he_writel(he_dev, TBRQ_THRESH(0x1), - G0_TBRQ_THRESH + (group * 16)); - he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16)); - } - - /* host status page */ - - he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev, - sizeof(struct he_hsp), &he_dev->hsp_phys); - if (he_dev->hsp == NULL) { - hprintk("failed to allocate host status page\n"); - return -ENOMEM; - } - memset(he_dev->hsp, 0, sizeof(struct he_hsp)); - he_writel(he_dev, he_dev->hsp_phys, HSP_BA); - - /* initialize framer */ - -#ifdef CONFIG_ATM_HE_USE_SUNI - if (he_isMM(he_dev)) - suni_init(he_dev->atm_dev); - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start) - he_dev->atm_dev->phy->start(he_dev->atm_dev); -#endif /* CONFIG_ATM_HE_USE_SUNI */ - - if (sdh) { - /* this really should be in suni.c but for now... */ - int val; - - val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM); - val = (val & ~SUNI_TPOP_APM_S) | (SUNI_TPOP_S_SDH << SUNI_TPOP_APM_S_SHIFT); - he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM); - he_phy_put(he_dev->atm_dev, SUNI_TACP_IUCHP_CLP, SUNI_TACP_IUCHP); - } - - /* 5.1.12 enable transmit and receive */ - - reg = he_readl_mbox(he_dev, CS_ERCTL0); - reg |= TX_ENABLE|ER_ENABLE; - he_writel_mbox(he_dev, reg, CS_ERCTL0); - - reg = he_readl(he_dev, RC_CONFIG); - reg |= RX_ENABLE; - he_writel(he_dev, reg, RC_CONFIG); - - for (i = 0; i < HE_NUM_CS_STPER; ++i) { - he_dev->cs_stper[i].inuse = 0; - he_dev->cs_stper[i].pcr = -1; - } - he_dev->total_bw = 0; - - - /* atm linux initialization */ - - he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits; - he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits; - - he_dev->irq_peak = 0; - he_dev->rbrq_peak = 0; - he_dev->rbpl_peak = 0; - he_dev->tbrq_peak = 0; - - HPRINTK("hell bent for leather!\n"); - - return 0; -} - -static void -he_stop(struct he_dev *he_dev) -{ - struct he_buff *heb, *next; - struct pci_dev *pci_dev; - u32 gen_cntl_0, reg; - u16 command; - - pci_dev = he_dev->pci_dev; - - /* disable interrupts */ - - if (he_dev->membase) { - pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0); - gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - tasklet_disable(&he_dev->tasklet); - - /* disable recv and transmit */ - - reg = he_readl_mbox(he_dev, CS_ERCTL0); - reg &= ~(TX_ENABLE|ER_ENABLE); - he_writel_mbox(he_dev, reg, CS_ERCTL0); - - reg = he_readl(he_dev, RC_CONFIG); - reg &= ~(RX_ENABLE); - he_writel(he_dev, reg, RC_CONFIG); - } - -#ifdef CONFIG_ATM_HE_USE_SUNI - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop) - he_dev->atm_dev->phy->stop(he_dev->atm_dev); -#endif /* CONFIG_ATM_HE_USE_SUNI */ - - if (he_dev->irq) - free_irq(he_dev->irq, he_dev); - - if (he_dev->irq_base) - pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) - * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); - - if (he_dev->hsp) - pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp), - he_dev->hsp, he_dev->hsp_phys); - - if (he_dev->rbpl_base) { - list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) - pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - - 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->rbrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - he_dev->rbrq_base, he_dev->rbrq_phys); - - if (he_dev->tbrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - he_dev->tbrq_base, he_dev->tbrq_phys); - - if (he_dev->tpdrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - he_dev->tpdrq_base, he_dev->tpdrq_phys); - - if (he_dev->tpd_pool) - pci_pool_destroy(he_dev->tpd_pool); - - if (he_dev->pci_dev) { - pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); - command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command); - } - - if (he_dev->membase) - iounmap(he_dev->membase); -} - -static struct he_tpd * -__alloc_tpd(struct he_dev *he_dev) -{ - struct he_tpd *tpd; - dma_addr_t mapping; - - tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping); - if (tpd == NULL) - return NULL; - - 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; - tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0; - - return tpd; -} - -#define AAL5_LEN(buf,len) \ - ((((unsigned char *)(buf))[(len)-6] << 8) | \ - (((unsigned char *)(buf))[(len)-5])) - -/* 2.10.1.2 receive - * - * aal5 packets can optionally return the tcp checksum in the lower - * 16 bits of the crc (RSR0_TCP_CKSUM) - */ - -#define TCP_CKSUM(buf,len) \ - ((((unsigned char *)(buf))[(len)-2] << 8) | \ - (((unsigned char *)(buf))[(len-1)])) - -static int -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); - unsigned cid, lastcid = -1; - struct sk_buff *skb; - struct atm_vcc *vcc = NULL; - struct he_vcc *he_vcc; - struct he_buff *heb, *next; - int i; - int pdus_assembled = 0; - int updated = 0; - - read_lock(&vcc_sklist_lock); - while (he_dev->rbrq_head != rbrq_tail) { - ++updated; - - HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n", - he_dev->rbrq_head, group, - RBRQ_ADDR(he_dev->rbrq_head), - RBRQ_BUFLEN(he_dev->rbrq_head), - RBRQ_CID(he_dev->rbrq_head), - RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "", - RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "", - RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "", - RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "", - RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", - RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); - - 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 || (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; - } - - 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; - } - - 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; - HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid); - wake_up(&he_vcc->rx_waitq); - goto return_host_buffers; - } - - if (!RBRQ_END_PDU(he_dev->rbrq_head)) - goto next_rbrq_entry; - - if (RBRQ_LEN_ERR(he_dev->rbrq_head) - || RBRQ_CRC_ERR(he_dev->rbrq_head)) { - HPRINTK("%s%s (%d.%d)\n", - RBRQ_CRC_ERR(he_dev->rbrq_head) - ? "CRC_ERR " : "", - RBRQ_LEN_ERR(he_dev->rbrq_head) - ? "LEN_ERR" : "", - vcc->vpi, vcc->vci); - atomic_inc(&vcc->stats->rx_err); - goto return_host_buffers; - } - - skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve, - GFP_ATOMIC); - if (!skb) { - HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci); - goto return_host_buffers; - } - - if (rx_skb_reserve > 0) - skb_reserve(skb, rx_skb_reserve); - - __net_timestamp(skb); - - 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: - /* 2.10.1.5 raw cell receive */ - skb->len = ATM_AAL0_SDU; - skb_set_tail_pointer(skb, skb->len); - break; - case ATM_AAL5: - /* 2.10.1.2 aal5 receive */ - - skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); - skb_set_tail_pointer(skb, skb->len); -#ifdef USE_CHECKSUM_HW - if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = TCP_CKSUM(skb->data, - he_vcc->pdu_len); - } -#endif - break; - } - -#ifdef should_never_happen - if (skb->len > vcc->qos.rxtp.max_sdu) - hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)! cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid); -#endif - -#ifdef notdef - ATM_SKB(skb)->vcc = vcc; -#endif - spin_unlock(&he_dev->global_lock); - vcc->push(vcc, skb); - spin_lock(&he_dev->global_lock); - - atomic_inc(&vcc->stats->rx); - -return_host_buffers: - ++pdus_assembled; - - 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: - he_dev->rbrq_head = (struct he_rbrq *) - ((unsigned long) he_dev->rbrq_base | - RBRQ_MASK(he_dev->rbrq_head + 1)); - - } - read_unlock(&vcc_sklist_lock); - - if (updated) { - if (updated > he_dev->rbrq_peak) - he_dev->rbrq_peak = updated; - - he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head), - G0_RBRQ_H + (group * 16)); - } - - return pdus_assembled; -} - -static void -he_service_tbrq(struct he_dev *he_dev, int group) -{ - struct he_tbrq *tbrq_tail = (struct he_tbrq *) - ((unsigned long)he_dev->tbrq_base | - he_dev->hsp->group[group].tbrq_tail); - struct he_tpd *tpd; - int slot, updated = 0; - struct he_tpd *__tpd; - - /* 2.1.6 transmit buffer return queue */ - - while (he_dev->tbrq_head != tbrq_tail) { - ++updated; - - HPRINTK("tbrq%d 0x%x%s%s\n", - group, - TBRQ_TPD(he_dev->tbrq_head), - TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "", - TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); - tpd = NULL; - list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { - if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { - tpd = __tpd; - list_del(&__tpd->entry); - break; - } - } - - if (tpd == NULL) { - hprintk("unable to locate tpd for dma buffer %x\n", - TBRQ_TPD(he_dev->tbrq_head)); - goto next_tbrq_entry; - } - - if (TBRQ_EOS(he_dev->tbrq_head)) { - HPRINTK("wake_up(tx_waitq) cid 0x%x\n", - he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci)); - if (tpd->vcc) - wake_up(&HE_VCC(tpd->vcc)->tx_waitq); - - goto next_tbrq_entry; - } - - for (slot = 0; slot < TPD_MAXIOV; ++slot) { - if (tpd->iovec[slot].addr) - pci_unmap_single(he_dev->pci_dev, - tpd->iovec[slot].addr, - tpd->iovec[slot].len & TPD_LEN_MASK, - PCI_DMA_TODEVICE); - if (tpd->iovec[slot].len & TPD_LST) - break; - - } - - if (tpd->skb) { /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ - if (tpd->vcc && tpd->vcc->pop) - tpd->vcc->pop(tpd->vcc, tpd->skb); - else - dev_kfree_skb_any(tpd->skb); - } - -next_tbrq_entry: - if (tpd) - pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); - he_dev->tbrq_head = (struct he_tbrq *) - ((unsigned long) he_dev->tbrq_base | - TBRQ_MASK(he_dev->tbrq_head + 1)); - } - - if (updated) { - if (updated > he_dev->tbrq_peak) - he_dev->tbrq_peak = updated; - - he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head), - G0_TBRQ_H + (group * 16)); - } -} - -static void -he_service_rbpl(struct he_dev *he_dev, int group) -{ - 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 (;;) { - 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 (new_tail == rbpl_head) - break; - - 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; - - heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping); - if (!heb) - break; - 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, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); -} - -static void -he_tasklet(unsigned long data) -{ - unsigned long flags; - struct he_dev *he_dev = (struct he_dev *) data; - int group, type; - int updated = 0; - - HPRINTK("tasklet (0x%lx)\n", data); - spin_lock_irqsave(&he_dev->global_lock, flags); - - while (he_dev->irq_head != he_dev->irq_tail) { - ++updated; - - type = ITYPE_TYPE(he_dev->irq_head->isw); - group = ITYPE_GROUP(he_dev->irq_head->isw); - - switch (type) { - case ITYPE_RBRQ_THRESH: - HPRINTK("rbrq%d threshold\n", group); - /* fall through */ - case ITYPE_RBRQ_TIMER: - if (he_service_rbrq(he_dev, group)) - he_service_rbpl(he_dev, group); - break; - case ITYPE_TBRQ_THRESH: - HPRINTK("tbrq%d threshold\n", group); - /* fall through */ - case ITYPE_TPD_COMPLETE: - he_service_tbrq(he_dev, group); - break; - case ITYPE_RBPL_THRESH: - he_service_rbpl(he_dev, group); - break; - case ITYPE_RBPS_THRESH: - /* shouldn't happen unless small buffers enabled */ - break; - case ITYPE_PHY: - HPRINTK("phy interrupt\n"); -#ifdef CONFIG_ATM_HE_USE_SUNI - spin_unlock_irqrestore(&he_dev->global_lock, flags); - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) - he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); - spin_lock_irqsave(&he_dev->global_lock, flags); -#endif - break; - case ITYPE_OTHER: - switch (type|group) { - case ITYPE_PARITY: - hprintk("parity error\n"); - break; - case ITYPE_ABORT: - hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR)); - break; - } - break; - case ITYPE_TYPE(ITYPE_INVALID): - /* see 8.1.1 -- check all queues */ - - HPRINTK("isw not updated 0x%x\n", he_dev->irq_head->isw); - - he_service_rbrq(he_dev, 0); - he_service_rbpl(he_dev, 0); - he_service_tbrq(he_dev, 0); - break; - default: - hprintk("bad isw 0x%x?\n", he_dev->irq_head->isw); - } - - he_dev->irq_head->isw = ITYPE_INVALID; - - he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK); - } - - if (updated) { - if (updated > he_dev->irq_peak) - he_dev->irq_peak = updated; - - he_writel(he_dev, - IRQ_SIZE(CONFIG_IRQ_SIZE) | - IRQ_THRESH(CONFIG_IRQ_THRESH) | - IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD); - (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata; flush posted writes */ - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); -} - -static irqreturn_t -he_irq_handler(int irq, void *dev_id) -{ - unsigned long flags; - struct he_dev *he_dev = (struct he_dev * )dev_id; - int handled = 0; - - if (he_dev == NULL) - return IRQ_NONE; - - spin_lock_irqsave(&he_dev->global_lock, flags); - - he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | - (*he_dev->irq_tailoffset << 2)); - - if (he_dev->irq_tail == he_dev->irq_head) { - HPRINTK("tailoffset not updated?\n"); - he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | - ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); - (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ - } - -#ifdef DEBUG - if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */) - hprintk("spurious (or shared) interrupt?\n"); -#endif - - if (he_dev->irq_head != he_dev->irq_tail) { - handled = 1; - tasklet_schedule(&he_dev->tasklet); - he_writel(he_dev, INT_CLEAR_A, INT_FIFO); /* clear interrupt */ - (void) he_readl(he_dev, INT_FIFO); /* flush posted writes */ - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return IRQ_RETVAL(handled); - -} - -static __inline__ void -__enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) -{ - struct he_tpdrq *new_tail; - - HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n", - tpd, cid, he_dev->tpdrq_tail); - - /* new_tail = he_dev->tpdrq_tail; */ - new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base | - TPDRQ_MASK(he_dev->tpdrq_tail+1)); - - /* - * check to see if we are about to set the tail == head - * if true, update the head pointer from the adapter - * to see if this is really the case (reading the queue - * head for every enqueue would be unnecessarily slow) - */ - - if (new_tail == he_dev->tpdrq_head) { - he_dev->tpdrq_head = (struct he_tpdrq *) - (((unsigned long)he_dev->tpdrq_base) | - TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H))); - - if (new_tail == he_dev->tpdrq_head) { - int slot; - - hprintk("tpdrq full (cid 0x%x)\n", cid); - /* - * FIXME - * push tpd onto a transmit backlog queue - * after service_tbrq, service the backlog - * for now, we just drop the pdu - */ - for (slot = 0; slot < TPD_MAXIOV; ++slot) { - if (tpd->iovec[slot].addr) - pci_unmap_single(he_dev->pci_dev, - tpd->iovec[slot].addr, - tpd->iovec[slot].len & TPD_LEN_MASK, - PCI_DMA_TODEVICE); - } - if (tpd->skb) { - if (tpd->vcc->pop) - tpd->vcc->pop(tpd->vcc, tpd->skb); - else - dev_kfree_skb_any(tpd->skb); - atomic_inc(&tpd->vcc->stats->tx_err); - } - pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); - return; - } - } - - /* 2.1.5 transmit packet descriptor ready queue */ - list_add_tail(&tpd->entry, &he_dev->outstanding_tpds); - he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status); - he_dev->tpdrq_tail->cid = cid; - wmb(); - - he_dev->tpdrq_tail = new_tail; - - he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T); - (void) he_readl(he_dev, TPDRQ_T); /* flush posted writes */ -} - -static int -he_open(struct atm_vcc *vcc) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(vcc->dev); - struct he_vcc *he_vcc; - int err = 0; - unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock; - short vpi = vcc->vpi; - int vci = vcc->vci; - - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) - return 0; - - HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci); - - set_bit(ATM_VF_ADDR, &vcc->flags); - - cid = he_mkcid(he_dev, vpi, vci); - - he_vcc = kmalloc(sizeof(struct he_vcc), GFP_ATOMIC); - if (he_vcc == NULL) { - hprintk("unable to allocate he_vcc during open\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&he_vcc->buffers); - he_vcc->pdu_len = 0; - he_vcc->rc_index = -1; - - init_waitqueue_head(&he_vcc->rx_waitq); - init_waitqueue_head(&he_vcc->tx_waitq); - - vcc->dev_data = he_vcc; - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - int pcr_goal; - - pcr_goal = atm_pcr_goal(&vcc->qos.txtp); - if (pcr_goal == 0) - pcr_goal = he_dev->atm_dev->link_rate; - if (pcr_goal < 0) /* means round down, technically */ - pcr_goal = -pcr_goal; - - HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); - - switch (vcc->qos.aal) { - case ATM_AAL5: - tsr0_aal = TSR0_AAL5; - tsr4 = TSR4_AAL5; - break; - case ATM_AAL0: - tsr0_aal = TSR0_AAL0_SDU; - tsr4 = TSR4_AAL0_SDU; - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - tsr0 = he_readl_tsr0(he_dev, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - if (TSR0_CONN_STATE(tsr0) != 0) { - hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); - err = -EBUSY; - goto open_failed; - } - - switch (vcc->qos.txtp.traffic_class) { - case ATM_UBR: - /* 2.3.3.1 open connection ubr */ - - tsr0 = TSR0_UBR | TSR0_GROUP(0) | tsr0_aal | - TSR0_USE_WMIN | TSR0_UPDATE_GER; - break; - - case ATM_CBR: - /* 2.3.3.2 open connection cbr */ - - /* 8.2.3 cbr scheduler wrap problem -- limit to 90% total link rate */ - if ((he_dev->total_bw + pcr_goal) - > (he_dev->atm_dev->link_rate * 9 / 10)) - { - err = -EBUSY; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); /* also protects he_dev->cs_stper[] */ - - /* find an unused cs_stper register */ - for (reg = 0; reg < HE_NUM_CS_STPER; ++reg) - if (he_dev->cs_stper[reg].inuse == 0 || - he_dev->cs_stper[reg].pcr == pcr_goal) - break; - - if (reg == HE_NUM_CS_STPER) { - err = -EBUSY; - spin_unlock_irqrestore(&he_dev->global_lock, flags); - goto open_failed; - } - - he_dev->total_bw += pcr_goal; - - he_vcc->rc_index = reg; - ++he_dev->cs_stper[reg].inuse; - he_dev->cs_stper[reg].pcr = pcr_goal; - - clock = he_is622(he_dev) ? 66667000 : 50000000; - period = clock / pcr_goal; - - HPRINTK("rc_index = %d period = %d\n", - reg, period); - - he_writel_mbox(he_dev, rate_to_atmf(period/2), - CS_STPER0 + reg); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | - TSR0_RC_INDEX(reg); - - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - - he_writel_tsr0(he_dev, tsr0, cid); - he_writel_tsr4(he_dev, tsr4 | 1, cid); - he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) | - TSR1_PCR(rate_to_atmf(pcr_goal)), cid); - he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid); - he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid); - - he_writel_tsr3(he_dev, 0x0, cid); - he_writel_tsr5(he_dev, 0x0, cid); - he_writel_tsr6(he_dev, 0x0, cid); - he_writel_tsr7(he_dev, 0x0, cid); - he_writel_tsr8(he_dev, 0x0, cid); - he_writel_tsr10(he_dev, 0x0, cid); - he_writel_tsr11(he_dev, 0x0, cid); - he_writel_tsr12(he_dev, 0x0, cid); - he_writel_tsr13(he_dev, 0x0, cid); - he_writel_tsr14(he_dev, 0x0, cid); - (void) he_readl_tsr0(he_dev, cid); /* flush posted writes */ - spin_unlock_irqrestore(&he_dev->global_lock, flags); - } - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - unsigned aal; - - HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid, - &HE_VCC(vcc)->rx_waitq); - - switch (vcc->qos.aal) { - case ATM_AAL5: - aal = RSR0_AAL5; - break; - case ATM_AAL0: - aal = RSR0_RAWCELL; - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - - rsr0 = he_readl_rsr0(he_dev, cid); - if (rsr0 & RSR0_OPEN_CONN) { - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); - err = -EBUSY; - goto open_failed; - } - - 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; - -#ifdef USE_CHECKSUM_HW - if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) - rsr0 |= RSR0_TCP_CKSUM; -#endif - - he_writel_rsr4(he_dev, rsr4, cid); - he_writel_rsr1(he_dev, rsr1, cid); - /* 5.1.11 last parameter initialized should be - the open/closed indication in rsr0 */ - he_writel_rsr0(he_dev, - rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); - (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ - - spin_unlock_irqrestore(&he_dev->global_lock, flags); - } - -open_failed: - - if (err) { - kfree(he_vcc); - clear_bit(ATM_VF_ADDR, &vcc->flags); - } - else - set_bit(ATM_VF_READY, &vcc->flags); - - return err; -} - -static void -he_close(struct atm_vcc *vcc) -{ - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - struct he_dev *he_dev = HE_DEV(vcc->dev); - struct he_tpd *tpd; - unsigned cid; - struct he_vcc *he_vcc = HE_VCC(vcc); -#define MAX_RETRY 30 - int retry = 0, sleep = 1, tx_inuse; - - HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci); - - clear_bit(ATM_VF_READY, &vcc->flags); - cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - int timeout; - - HPRINTK("close rx cid 0x%x\n", cid); - - /* 2.7.2.2 close receive operation */ - - /* wait for previous close (if any) to finish */ - - spin_lock_irqsave(&he_dev->global_lock, flags); - while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) { - HPRINTK("close cid 0x%x RCC_BUSY\n", cid); - udelay(250); - } - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&he_vcc->rx_waitq, &wait); - - he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid); - (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ - he_writel_mbox(he_dev, cid, RXCON_CLOSE); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - timeout = schedule_timeout(30*HZ); - - remove_wait_queue(&he_vcc->rx_waitq, &wait); - set_current_state(TASK_RUNNING); - - if (timeout == 0) - hprintk("close rx timeout cid 0x%x\n", cid); - - HPRINTK("close rx cid 0x%x complete\n", cid); - - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - volatile unsigned tsr4, tsr0; - int timeout; - - HPRINTK("close tx cid 0x%x\n", cid); - - /* 2.1.2 - * - * ... the host must first stop queueing packets to the TPDRQ - * on the connection to be closed, then wait for all outstanding - * packets to be transmitted and their buffers returned to the - * TBRQ. When the last packet on the connection arrives in the - * TBRQ, the host issues the close command to the adapter. - */ - - while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) && - (retry < MAX_RETRY)) { - msleep(sleep); - if (sleep < 250) - sleep = sleep * 2; - - ++retry; - } - - if (tx_inuse > 1) - hprintk("close tx cid 0x%x tx_inuse = %d\n", cid, tx_inuse); - - /* 2.3.1.1 generic close operations with flush */ - - spin_lock_irqsave(&he_dev->global_lock, flags); - he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); - /* also clears TSR4_SESSION_ENDED */ - - switch (vcc->qos.txtp.traffic_class) { - case ATM_UBR: - he_writel_tsr1(he_dev, - TSR1_MCR(rate_to_atmf(200000)) - | TSR1_PCR(0), cid); - break; - case ATM_CBR: - he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid); - break; - } - (void) he_readl_tsr4(he_dev, cid); /* flush posted writes */ - - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid); - goto close_tx_incomplete; - } - tpd->status |= TPD_EOS | TPD_INT; - tpd->skb = NULL; - tpd->vcc = vcc; - wmb(); - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&he_vcc->tx_waitq, &wait); - __enqueue_tpd(he_dev, tpd, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - timeout = schedule_timeout(30*HZ); - - remove_wait_queue(&he_vcc->tx_waitq, &wait); - set_current_state(TASK_RUNNING); - - spin_lock_irqsave(&he_dev->global_lock, flags); - - if (timeout == 0) { - hprintk("close tx timeout cid 0x%x\n", cid); - goto close_tx_incomplete; - } - - while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { - HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); - udelay(250); - } - - while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) { - HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0); - udelay(250); - } - -close_tx_incomplete: - - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - int reg = he_vcc->rc_index; - - HPRINTK("cs_stper reg = %d\n", reg); - - if (he_dev->cs_stper[reg].inuse == 0) - hprintk("cs_stper[%d].inuse = 0!\n", reg); - else - --he_dev->cs_stper[reg].inuse; - - he_dev->total_bw -= he_dev->cs_stper[reg].pcr; - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - HPRINTK("close tx cid 0x%x complete\n", cid); - } - - kfree(he_vcc); - - clear_bit(ATM_VF_ADDR, &vcc->flags); -} - -static int -he_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(vcc->dev); - unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); - struct he_tpd *tpd; -#ifdef USE_SCATTERGATHER - int i, slot = 0; -#endif - -#define HE_TPD_BUFSIZE 0xffff - - HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci); - - if ((skb->len > HE_TPD_BUFSIZE) || - ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) { - hprintk("buffer too large (or small) -- %d bytes\n", skb->len ); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - return -EINVAL; - } - -#ifndef USE_SCATTERGATHER - if (skb_shinfo(skb)->nr_frags) { - hprintk("no scatter/gather support\n"); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - return -EINVAL; - } -#endif - spin_lock_irqsave(&he_dev->global_lock, flags); - - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return -ENOMEM; - } - - if (vcc->qos.aal == ATM_AAL5) - tpd->status |= TPD_CELLTYPE(TPD_USERCELL); - else { - char *pti_clp = (void *) (skb->data + 3); - int clp, pti; - - pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; - clp = (*pti_clp & ATM_HDR_CLP); - tpd->status |= TPD_CELLTYPE(pti); - if (clp) - tpd->status |= TPD_CLP; - - skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD); - } - -#ifdef USE_SCATTERGATHER - tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - tpd->iovec[slot].len = skb_headlen(skb); - ++slot; - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - if (slot == TPD_MAXIOV) { /* queue tpd; start new tpd */ - tpd->vcc = vcc; - tpd->skb = NULL; /* not the last fragment - so dont ->push() yet */ - wmb(); - - __enqueue_tpd(he_dev, tpd, cid); - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return -ENOMEM; - } - tpd->status |= TPD_USERCELL; - slot = 0; - } - - tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, - (void *) page_address(frag->page) + frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - tpd->iovec[slot].len = frag->size; - ++slot; - - } - - tpd->iovec[slot - 1].len |= TPD_LST; -#else - tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - tpd->length0 = skb->len | TPD_LST; -#endif - tpd->status |= TPD_INT; - - tpd->vcc = vcc; - tpd->skb = skb; - wmb(); - ATM_SKB(skb)->vcc = vcc; - - __enqueue_tpd(he_dev, tpd, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - atomic_inc(&vcc->stats->tx); - - return 0; -} - -static int -he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - struct he_ioctl_reg reg; - int err = 0; - - switch (cmd) { - case HE_GET_REG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(®, arg, - sizeof(struct he_ioctl_reg))) - return -EFAULT; - - spin_lock_irqsave(&he_dev->global_lock, flags); - switch (reg.type) { - case HE_REGTYPE_PCI: - if (reg.addr >= HE_REGMAP_SIZE) { - err = -EINVAL; - break; - } - - reg.val = he_readl(he_dev, reg.addr); - break; - case HE_REGTYPE_RCM: - reg.val = - he_readl_rcm(he_dev, reg.addr); - break; - case HE_REGTYPE_TCM: - reg.val = - he_readl_tcm(he_dev, reg.addr); - break; - case HE_REGTYPE_MBOX: - reg.val = - he_readl_mbox(he_dev, reg.addr); - break; - default: - err = -EINVAL; - break; - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - if (err == 0) - if (copy_to_user(arg, ®, - sizeof(struct he_ioctl_reg))) - return -EFAULT; - break; - default: -#ifdef CONFIG_ATM_HE_USE_SUNI - if (atm_dev->phy && atm_dev->phy->ioctl) - err = atm_dev->phy->ioctl(atm_dev, cmd, arg); -#else /* CONFIG_ATM_HE_USE_SUNI */ - err = -EINVAL; -#endif /* CONFIG_ATM_HE_USE_SUNI */ - break; - } - - return err; -} - -static void -he_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - - HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); - - spin_lock_irqsave(&he_dev->global_lock, flags); - he_writel(he_dev, val, FRAMER + (addr*4)); - (void) he_readl(he_dev, FRAMER + (addr*4)); /* flush posted writes */ - spin_unlock_irqrestore(&he_dev->global_lock, flags); -} - - -static unsigned char -he_phy_get(struct atm_dev *atm_dev, unsigned long addr) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - unsigned reg; - - spin_lock_irqsave(&he_dev->global_lock, flags); - reg = he_readl(he_dev, FRAMER + (addr*4)); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); - return reg; -} - -static int -he_proc_read(struct atm_dev *dev, loff_t *pos, char *page) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(dev); - int left, i; -#ifdef notdef - struct he_rbrq *rbrq_tail; - struct he_tpdrq *tpdrq_head; - int rbpl_head, rbpl_tail; -#endif - static long mcc = 0, oec = 0, dcc = 0, cec = 0; - - - left = *pos; - if (!left--) - return sprintf(page, "ATM he driver\n"); - - if (!left--) - return sprintf(page, "%s%s\n\n", - he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM"); - - if (!left--) - return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); - - spin_lock_irqsave(&he_dev->global_lock, flags); - mcc += he_readl(he_dev, MCC); - oec += he_readl(he_dev, OEC); - dcc += he_readl(he_dev, DCC); - cec += he_readl(he_dev, CEC); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - if (!left--) - return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", - mcc, oec, dcc, cec); - - if (!left--) - return sprintf(page, "irq_size = %d inuse = ? peak = %d\n", - CONFIG_IRQ_SIZE, he_dev->irq_peak); - - if (!left--) - return sprintf(page, "tpdrq_size = %d inuse = ?\n", - CONFIG_TPDRQ_SIZE); - - if (!left--) - return sprintf(page, "rbrq_size = %d inuse = ? peak = %d\n", - CONFIG_RBRQ_SIZE, he_dev->rbrq_peak); - - if (!left--) - return sprintf(page, "tbrq_size = %d peak = %d\n", - CONFIG_TBRQ_SIZE, he_dev->tbrq_peak); - - -#ifdef notdef - rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); - rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); - - inuse = rbpl_head - rbpl_tail; - if (inuse < 0) - inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); - inuse /= sizeof(struct he_rbp); - - if (!left--) - return sprintf(page, "rbpl_size = %d inuse = %d\n\n", - CONFIG_RBPL_SIZE, inuse); -#endif - - if (!left--) - return sprintf(page, "rate controller periods (cbr)\n pcr #vc\n"); - - for (i = 0; i < HE_NUM_CS_STPER; ++i) - if (!left--) - return sprintf(page, "cs_stper%-2d %8ld %3d\n", i, - he_dev->cs_stper[i].pcr, - he_dev->cs_stper[i].inuse); - - if (!left--) - return sprintf(page, "total bw (cbr): %d (limit %d)\n", - he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9); - - return 0; -} - -/* eeprom routines -- see 4.7 */ - -static u8 read_prom_byte(struct he_dev *he_dev, int addr) -{ - u32 val = 0, tmp_read = 0; - int i, j = 0; - u8 byte_read = 0; - - val = readl(he_dev->membase + HOST_CNTL); - val &= 0xFFFFE0FF; - - /* Turn on write enable */ - val |= 0x800; - he_writel(he_dev, val, HOST_CNTL); - - /* Send READ instruction */ - for (i = 0; i < ARRAY_SIZE(readtab); i++) { - he_writel(he_dev, val | readtab[i], HOST_CNTL); - udelay(EEPROM_DELAY); - } - - /* Next, we need to send the byte address to read from */ - for (i = 7; i >= 0; i--) { - he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); - udelay(EEPROM_DELAY); - he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); - udelay(EEPROM_DELAY); - } - - j = 0; - - val &= 0xFFFFF7FF; /* Turn off write enable */ - he_writel(he_dev, val, HOST_CNTL); - - /* Now, we can read data from the EEPROM by clocking it in */ - for (i = 7; i >= 0; i--) { - he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - tmp_read = he_readl(he_dev, HOST_CNTL); - byte_read |= (unsigned char) - ((tmp_read & ID_DOUT) >> ID_DOFFSET << i); - he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - } - - he_writel(he_dev, val | ID_CS, HOST_CNTL); - udelay(EEPROM_DELAY); - - return byte_read; -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>"); -MODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver"); -module_param(disable64, bool, 0); -MODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers"); -module_param(nvpibits, short, 0); -MODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)"); -module_param(nvcibits, short, 0); -MODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)"); -module_param(rx_skb_reserve, short, 0); -MODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)"); -module_param(irq_coalesce, bool, 0); -MODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)"); -module_param(sdh, bool, 0); -MODULE_PARM_DESC(sdh, "use SDH framing (default 0)"); - -static struct pci_device_id he_pci_tbl[] = { - { PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, he_pci_tbl); - -static struct pci_driver he_driver = { - .name = "he", - .probe = he_init_one, - .remove = __devexit_p(he_remove_one), - .id_table = he_pci_tbl, -}; - -static int __init he_init(void) -{ - return pci_register_driver(&he_driver); -} - -static void __exit he_cleanup(void) -{ - pci_unregister_driver(&he_driver); -} - -module_init(he_init); -module_exit(he_cleanup); |