/drivers/atm/idt77252.c
https://bitbucket.org/evzijst/gittest · C · 3882 lines · 3041 code · 697 blank · 144 comment · 458 complexity · 5b1576b7a89b438049713ee5c31c407e MD5 · raw file
Large files are truncated click here to view the full file
- /*******************************************************************
- * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"
- *
- * $Author: ecd $
- * $Date: 2001/11/11 08:13:54 $
- *
- * Copyright (c) 2000 ATecoM GmbH
- *
- * The author may be reached at ecd@atecom.com.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *******************************************************************/
- static char const rcsid[] =
- "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $";
- #include <linux/module.h>
- #include <linux/config.h>
- #include <linux/pci.h>
- #include <linux/skbuff.h>
- #include <linux/kernel.h>
- #include <linux/vmalloc.h>
- #include <linux/netdevice.h>
- #include <linux/atmdev.h>
- #include <linux/atm.h>
- #include <linux/delay.h>
- #include <linux/init.h>
- #include <linux/bitops.h>
- #include <linux/wait.h>
- #include <asm/semaphore.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <asm/atomic.h>
- #include <asm/byteorder.h>
- #ifdef CONFIG_ATM_IDT77252_USE_SUNI
- #include "suni.h"
- #endif /* CONFIG_ATM_IDT77252_USE_SUNI */
- #include "idt77252.h"
- #include "idt77252_tables.h"
- static unsigned int vpibits = 1;
- #define CONFIG_ATM_IDT77252_SEND_IDLE 1
- /*
- * Debug HACKs.
- */
- #define DEBUG_MODULE 1
- #undef HAVE_EEPROM /* does not work, yet. */
- #ifdef CONFIG_ATM_IDT77252_DEBUG
- static unsigned long debug = DBG_GENERAL;
- #endif
- #define SAR_RX_DELAY (SAR_CFG_RXINT_NODELAY)
- /*
- * SCQ Handling.
- */
- static struct scq_info *alloc_scq(struct idt77252_dev *, int);
- static void free_scq(struct idt77252_dev *, struct scq_info *);
- static int queue_skb(struct idt77252_dev *, struct vc_map *,
- struct sk_buff *, int oam);
- static void drain_scq(struct idt77252_dev *, struct vc_map *);
- static unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *);
- static void fill_scd(struct idt77252_dev *, struct scq_info *, int);
- /*
- * FBQ Handling.
- */
- static int push_rx_skb(struct idt77252_dev *,
- struct sk_buff *, int queue);
- static void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *);
- static void flush_rx_pool(struct idt77252_dev *, struct rx_pool *);
- static void recycle_rx_pool_skb(struct idt77252_dev *,
- struct rx_pool *);
- static void add_rx_skb(struct idt77252_dev *, int queue,
- unsigned int size, unsigned int count);
- /*
- * RSQ Handling.
- */
- static int init_rsq(struct idt77252_dev *);
- static void deinit_rsq(struct idt77252_dev *);
- static void idt77252_rx(struct idt77252_dev *);
- /*
- * TSQ handling.
- */
- static int init_tsq(struct idt77252_dev *);
- static void deinit_tsq(struct idt77252_dev *);
- static void idt77252_tx(struct idt77252_dev *);
- /*
- * ATM Interface.
- */
- static void idt77252_dev_close(struct atm_dev *dev);
- static int idt77252_open(struct atm_vcc *vcc);
- static void idt77252_close(struct atm_vcc *vcc);
- static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb);
- static int idt77252_send_oam(struct atm_vcc *vcc, void *cell,
- int flags);
- static void idt77252_phy_put(struct atm_dev *dev, unsigned char value,
- unsigned long addr);
- static unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr);
- static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos,
- int flags);
- static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos,
- char *page);
- static void idt77252_softint(void *dev_id);
- static struct atmdev_ops idt77252_ops =
- {
- .dev_close = idt77252_dev_close,
- .open = idt77252_open,
- .close = idt77252_close,
- .send = idt77252_send,
- .send_oam = idt77252_send_oam,
- .phy_put = idt77252_phy_put,
- .phy_get = idt77252_phy_get,
- .change_qos = idt77252_change_qos,
- .proc_read = idt77252_proc_read,
- .owner = THIS_MODULE
- };
- static struct idt77252_dev *idt77252_chain = NULL;
- static unsigned int idt77252_sram_write_errors = 0;
- /*****************************************************************************/
- /* */
- /* I/O and Utility Bus */
- /* */
- /*****************************************************************************/
- static void
- waitfor_idle(struct idt77252_dev *card)
- {
- u32 stat;
- stat = readl(SAR_REG_STAT);
- while (stat & SAR_STAT_CMDBZ)
- stat = readl(SAR_REG_STAT);
- }
- static u32
- read_sram(struct idt77252_dev *card, unsigned long addr)
- {
- unsigned long flags;
- u32 value;
- spin_lock_irqsave(&card->cmd_lock, flags);
- writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD);
- waitfor_idle(card);
- value = readl(SAR_REG_DR0);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- return value;
- }
- static void
- write_sram(struct idt77252_dev *card, unsigned long addr, u32 value)
- {
- unsigned long flags;
- if ((idt77252_sram_write_errors == 0) &&
- (((addr > card->tst[0] + card->tst_size - 2) &&
- (addr < card->tst[0] + card->tst_size)) ||
- ((addr > card->tst[1] + card->tst_size - 2) &&
- (addr < card->tst[1] + card->tst_size)))) {
- printk("%s: ERROR: TST JMP section at %08lx written: %08x\n",
- card->name, addr, value);
- }
- spin_lock_irqsave(&card->cmd_lock, flags);
- writel(value, SAR_REG_DR0);
- writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
- waitfor_idle(card);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- }
- static u8
- read_utility(void *dev, unsigned long ubus_addr)
- {
- struct idt77252_dev *card = dev;
- unsigned long flags;
- u8 value;
- if (!card) {
- printk("Error: No such device.\n");
- return -1;
- }
- spin_lock_irqsave(&card->cmd_lock, flags);
- writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD);
- waitfor_idle(card);
- value = readl(SAR_REG_DR0);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- return value;
- }
- static void
- write_utility(void *dev, unsigned long ubus_addr, u8 value)
- {
- struct idt77252_dev *card = dev;
- unsigned long flags;
- if (!card) {
- printk("Error: No such device.\n");
- return;
- }
- spin_lock_irqsave(&card->cmd_lock, flags);
- writel((u32) value, SAR_REG_DR0);
- writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD);
- waitfor_idle(card);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- }
- #ifdef HAVE_EEPROM
- static u32 rdsrtab[] =
- {
- SAR_GP_EECS | SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */
- };
- static u32 wrentab[] =
- {
- SAR_GP_EECS | SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK /* 0 */
- };
- static u32 rdtab[] =
- {
- SAR_GP_EECS | SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */
- };
- static u32 wrtab[] =
- {
- SAR_GP_EECS | SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- 0,
- SAR_GP_EESCLK, /* 0 */
- SAR_GP_EEDO,
- SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
- 0,
- SAR_GP_EESCLK /* 0 */
- };
- static u32 clktab[] =
- {
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0,
- SAR_GP_EESCLK,
- 0
- };
- static u32
- idt77252_read_gp(struct idt77252_dev *card)
- {
- u32 gp;
- gp = readl(SAR_REG_GP);
- #if 0
- printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0");
- #endif
- return gp;
- }
- static void
- idt77252_write_gp(struct idt77252_dev *card, u32 value)
- {
- unsigned long flags;
- #if 0
- printk("WR: %s %s %s\n", value & SAR_GP_EECS ? " " : "/CS",
- value & SAR_GP_EESCLK ? "HIGH" : "LOW ",
- value & SAR_GP_EEDO ? "1" : "0");
- #endif
- spin_lock_irqsave(&card->cmd_lock, flags);
- waitfor_idle(card);
- writel(value, SAR_REG_GP);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- }
- static u8
- idt77252_eeprom_read_status(struct idt77252_dev *card)
- {
- u8 byte;
- u32 gp;
- int i, j;
- gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) {
- idt77252_write_gp(card, gp | rdsrtab[i]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- byte = 0;
- for (i = 0, j = 0; i < 8; i++) {
- byte <<= 1;
- idt77252_write_gp(card, gp | clktab[j++]);
- udelay(5);
- byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
- idt77252_write_gp(card, gp | clktab[j++]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- return byte;
- }
- static u8
- idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset)
- {
- u8 byte;
- u32 gp;
- int i, j;
- gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) {
- idt77252_write_gp(card, gp | rdtab[i]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- for (i = 0, j = 0; i < 8; i++) {
- idt77252_write_gp(card, gp | clktab[j++] |
- (offset & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- idt77252_write_gp(card, gp | clktab[j++] |
- (offset & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- offset >>= 1;
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- byte = 0;
- for (i = 0, j = 0; i < 8; i++) {
- byte <<= 1;
- idt77252_write_gp(card, gp | clktab[j++]);
- udelay(5);
- byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
- idt77252_write_gp(card, gp | clktab[j++]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- return byte;
- }
- static void
- idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data)
- {
- u32 gp;
- int i, j;
- gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) {
- idt77252_write_gp(card, gp | wrentab[i]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) {
- idt77252_write_gp(card, gp | wrtab[i]);
- udelay(5);
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- for (i = 0, j = 0; i < 8; i++) {
- idt77252_write_gp(card, gp | clktab[j++] |
- (offset & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- idt77252_write_gp(card, gp | clktab[j++] |
- (offset & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- offset >>= 1;
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- for (i = 0, j = 0; i < 8; i++) {
- idt77252_write_gp(card, gp | clktab[j++] |
- (data & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- idt77252_write_gp(card, gp | clktab[j++] |
- (data & 1 ? SAR_GP_EEDO : 0));
- udelay(5);
- data >>= 1;
- }
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- }
- static void
- idt77252_eeprom_init(struct idt77252_dev *card)
- {
- u32 gp;
- gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
- udelay(5);
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
- udelay(5);
- idt77252_write_gp(card, gp | SAR_GP_EECS);
- udelay(5);
- }
- #endif /* HAVE_EEPROM */
- #ifdef CONFIG_ATM_IDT77252_DEBUG
- static void
- dump_tct(struct idt77252_dev *card, int index)
- {
- unsigned long tct;
- int i;
- tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE);
- printk("%s: TCT %x:", card->name, index);
- for (i = 0; i < 8; i++) {
- printk(" %08x", read_sram(card, tct + i));
- }
- printk("\n");
- }
- static void
- idt77252_tx_dump(struct idt77252_dev *card)
- {
- struct atm_vcc *vcc;
- struct vc_map *vc;
- int i;
- printk("%s\n", __FUNCTION__);
- for (i = 0; i < card->tct_size; i++) {
- vc = card->vcs[i];
- if (!vc)
- continue;
- vcc = NULL;
- if (vc->rx_vcc)
- vcc = vc->rx_vcc;
- else if (vc->tx_vcc)
- vcc = vc->tx_vcc;
- if (!vcc)
- continue;
- printk("%s: Connection %d:\n", card->name, vc->index);
- dump_tct(card, vc->index);
- }
- }
- #endif
- /*****************************************************************************/
- /* */
- /* SCQ Handling */
- /* */
- /*****************************************************************************/
- static int
- sb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue)
- {
- struct sb_pool *pool = &card->sbpool[queue];
- int index;
- index = pool->index;
- while (pool->skb[index]) {
- index = (index + 1) & FBQ_MASK;
- if (index == pool->index)
- return -ENOBUFS;
- }
- pool->skb[index] = skb;
- IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index);
- pool->index = (index + 1) & FBQ_MASK;
- return 0;
- }
- static void
- sb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb)
- {
- unsigned int queue, index;
- u32 handle;
- handle = IDT77252_PRV_POOL(skb);
- queue = POOL_QUEUE(handle);
- if (queue > 3)
- return;
- index = POOL_INDEX(handle);
- if (index > FBQ_SIZE - 1)
- return;
- card->sbpool[queue].skb[index] = NULL;
- }
- static struct sk_buff *
- sb_pool_skb(struct idt77252_dev *card, u32 handle)
- {
- unsigned int queue, index;
- queue = POOL_QUEUE(handle);
- if (queue > 3)
- return NULL;
- index = POOL_INDEX(handle);
- if (index > FBQ_SIZE - 1)
- return NULL;
- return card->sbpool[queue].skb[index];
- }
- static struct scq_info *
- alloc_scq(struct idt77252_dev *card, int class)
- {
- struct scq_info *scq;
- scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL);
- if (!scq)
- return NULL;
- memset(scq, 0, sizeof(struct scq_info));
- scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE,
- &scq->paddr);
- if (scq->base == NULL) {
- kfree(scq);
- return NULL;
- }
- memset(scq->base, 0, SCQ_SIZE);
- scq->next = scq->base;
- scq->last = scq->base + (SCQ_ENTRIES - 1);
- atomic_set(&scq->used, 0);
- spin_lock_init(&scq->lock);
- spin_lock_init(&scq->skblock);
- skb_queue_head_init(&scq->transmit);
- skb_queue_head_init(&scq->pending);
- TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08llx\n",
- scq->base, scq->next, scq->last, (unsigned long long)scq->paddr);
- return scq;
- }
- static void
- free_scq(struct idt77252_dev *card, struct scq_info *scq)
- {
- struct sk_buff *skb;
- struct atm_vcc *vcc;
- pci_free_consistent(card->pcidev, SCQ_SIZE,
- scq->base, scq->paddr);
- while ((skb = skb_dequeue(&scq->transmit))) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
- vcc = ATM_SKB(skb)->vcc;
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
- dev_kfree_skb(skb);
- }
- while ((skb = skb_dequeue(&scq->pending))) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
- vcc = ATM_SKB(skb)->vcc;
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
- dev_kfree_skb(skb);
- }
- kfree(scq);
- }
- static int
- push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
- {
- struct scq_info *scq = vc->scq;
- unsigned long flags;
- struct scqe *tbd;
- int entries;
- TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next);
- atomic_inc(&scq->used);
- entries = atomic_read(&scq->used);
- if (entries > (SCQ_ENTRIES - 1)) {
- atomic_dec(&scq->used);
- goto out;
- }
- skb_queue_tail(&scq->transmit, skb);
- spin_lock_irqsave(&vc->lock, flags);
- if (vc->estimator) {
- struct atm_vcc *vcc = vc->tx_vcc;
- struct sock *sk = sk_atm(vcc);
- vc->estimator->cells += (skb->len + 47) / 48;
- if (atomic_read(&sk->sk_wmem_alloc) >
- (sk->sk_sndbuf >> 1)) {
- u32 cps = vc->estimator->maxcps;
- vc->estimator->cps = cps;
- vc->estimator->avcps = cps << 5;
- if (vc->lacr < vc->init_er) {
- vc->lacr = vc->init_er;
- writel(TCMDQ_LACR | (vc->lacr << 16) |
- vc->index, SAR_REG_TCMDQ);
- }
- }
- }
- spin_unlock_irqrestore(&vc->lock, flags);
- tbd = &IDT77252_PRV_TBD(skb);
- spin_lock_irqsave(&scq->lock, flags);
- scq->next->word_1 = cpu_to_le32(tbd->word_1 |
- SAR_TBD_TSIF | SAR_TBD_GTSI);
- scq->next->word_2 = cpu_to_le32(tbd->word_2);
- scq->next->word_3 = cpu_to_le32(tbd->word_3);
- scq->next->word_4 = cpu_to_le32(tbd->word_4);
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
- write_sram(card, scq->scd,
- scq->paddr +
- (u32)((unsigned long)scq->next - (unsigned long)scq->base));
- spin_unlock_irqrestore(&scq->lock, flags);
- scq->trans_start = jiffies;
- if (test_and_clear_bit(VCF_IDLE, &vc->flags)) {
- writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index,
- SAR_REG_TCMDQ);
- }
- TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used));
- XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n",
- card->name, atomic_read(&scq->used),
- read_sram(card, scq->scd + 1), scq->next);
- return 0;
- out:
- if (jiffies - scq->trans_start > HZ) {
- printk("%s: Error pushing TBD for %d.%d\n",
- card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci);
- #ifdef CONFIG_ATM_IDT77252_DEBUG
- idt77252_tx_dump(card);
- #endif
- scq->trans_start = jiffies;
- }
- return -ENOBUFS;
- }
- static void
- drain_scq(struct idt77252_dev *card, struct vc_map *vc)
- {
- struct scq_info *scq = vc->scq;
- struct sk_buff *skb;
- struct atm_vcc *vcc;
- TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n",
- card->name, atomic_read(&scq->used), scq->next);
- skb = skb_dequeue(&scq->transmit);
- if (skb) {
- TXPRINTK("%s: freeing skb at %p.\n", card->name, skb);
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
- vcc = ATM_SKB(skb)->vcc;
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
- dev_kfree_skb(skb);
- atomic_inc(&vcc->stats->tx);
- }
- atomic_dec(&scq->used);
- spin_lock(&scq->skblock);
- while ((skb = skb_dequeue(&scq->pending))) {
- if (push_on_scq(card, vc, skb)) {
- skb_queue_head(&vc->scq->pending, skb);
- break;
- }
- }
- spin_unlock(&scq->skblock);
- }
- static int
- queue_skb(struct idt77252_dev *card, struct vc_map *vc,
- struct sk_buff *skb, int oam)
- {
- struct atm_vcc *vcc;
- struct scqe *tbd;
- unsigned long flags;
- int error;
- int aal;
- if (skb->len == 0) {
- printk("%s: invalid skb->len (%d)\n", card->name, skb->len);
- return -EINVAL;
- }
- TXPRINTK("%s: Sending %d bytes of data.\n",
- card->name, skb->len);
- tbd = &IDT77252_PRV_TBD(skb);
- vcc = ATM_SKB(skb)->vcc;
- IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
- error = -EINVAL;
- if (oam) {
- if (skb->len != 52)
- goto errout;
- tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU;
- tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
- tbd->word_3 = 0x00000000;
- tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
- (skb->data[2] << 8) | (skb->data[3] << 0);
- if (test_bit(VCF_RSV, &vc->flags))
- vc = card->vcs[0];
- goto done;
- }
- if (test_bit(VCF_RSV, &vc->flags)) {
- printk("%s: Trying to transmit on reserved VC\n", card->name);
- goto errout;
- }
- aal = vcc->qos.aal;
- switch (aal) {
- case ATM_AAL0:
- case ATM_AAL34:
- if (skb->len > 52)
- goto errout;
- if (aal == ATM_AAL0)
- tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 |
- ATM_CELL_PAYLOAD;
- else
- tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 |
- ATM_CELL_PAYLOAD;
- tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
- tbd->word_3 = 0x00000000;
- tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
- (skb->data[2] << 8) | (skb->data[3] << 0);
- break;
- case ATM_AAL5:
- tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len;
- tbd->word_2 = IDT77252_PRV_PADDR(skb);
- tbd->word_3 = skb->len;
- tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) |
- (vcc->vci << SAR_TBD_VCI_SHIFT);
- break;
- case ATM_AAL1:
- case ATM_AAL2:
- default:
- printk("%s: Traffic type not supported.\n", card->name);
- error = -EPROTONOSUPPORT;
- goto errout;
- }
- done:
- spin_lock_irqsave(&vc->scq->skblock, flags);
- skb_queue_tail(&vc->scq->pending, skb);
- while ((skb = skb_dequeue(&vc->scq->pending))) {
- if (push_on_scq(card, vc, skb)) {
- skb_queue_head(&vc->scq->pending, skb);
- break;
- }
- }
- spin_unlock_irqrestore(&vc->scq->skblock, flags);
- return 0;
- errout:
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
- return error;
- }
- static unsigned long
- get_free_scd(struct idt77252_dev *card, struct vc_map *vc)
- {
- int i;
- for (i = 0; i < card->scd_size; i++) {
- if (!card->scd2vc[i]) {
- card->scd2vc[i] = vc;
- vc->scd_index = i;
- return card->scd_base + i * SAR_SRAM_SCD_SIZE;
- }
- }
- return 0;
- }
- static void
- fill_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
- {
- write_sram(card, scq->scd, scq->paddr);
- write_sram(card, scq->scd + 1, 0x00000000);
- write_sram(card, scq->scd + 2, 0xffffffff);
- write_sram(card, scq->scd + 3, 0x00000000);
- }
- static void
- clear_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
- {
- return;
- }
- /*****************************************************************************/
- /* */
- /* RSQ Handling */
- /* */
- /*****************************************************************************/
- static int
- init_rsq(struct idt77252_dev *card)
- {
- struct rsq_entry *rsqe;
- card->rsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE,
- &card->rsq.paddr);
- if (card->rsq.base == NULL) {
- printk("%s: can't allocate RSQ.\n", card->name);
- return -1;
- }
- memset(card->rsq.base, 0, RSQSIZE);
- card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1;
- card->rsq.next = card->rsq.last;
- for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++)
- rsqe->word_4 = 0;
- writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base,
- SAR_REG_RSQH);
- writel(card->rsq.paddr, SAR_REG_RSQB);
- IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name,
- (unsigned long) card->rsq.base,
- readl(SAR_REG_RSQB));
- IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n",
- card->name,
- readl(SAR_REG_RSQH),
- readl(SAR_REG_RSQB),
- readl(SAR_REG_RSQT));
- return 0;
- }
- static void
- deinit_rsq(struct idt77252_dev *card)
- {
- pci_free_consistent(card->pcidev, RSQSIZE,
- card->rsq.base, card->rsq.paddr);
- }
- static void
- dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
- {
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- struct rx_pool *rpp;
- struct vc_map *vc;
- u32 header, vpi, vci;
- u32 stat;
- int i;
- stat = le32_to_cpu(rsqe->word_4);
- if (stat & SAR_RSQE_IDLE) {
- RXPRINTK("%s: message about inactive connection.\n",
- card->name);
- return;
- }
- skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2));
- if (skb == NULL) {
- printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n",
- card->name, __FUNCTION__,
- le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2),
- le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4));
- return;
- }
- header = le32_to_cpu(rsqe->word_1);
- vpi = (header >> 16) & 0x00ff;
- vci = (header >> 0) & 0xffff;
- RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n",
- card->name, vpi, vci, skb, skb->data);
- if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) {
- printk("%s: SDU received for out-of-range vc %u.%u\n",
- card->name, vpi, vci);
- recycle_rx_skb(card, skb);
- return;
- }
- vc = card->vcs[VPCI2VC(card, vpi, vci)];
- if (!vc || !test_bit(VCF_RX, &vc->flags)) {
- printk("%s: SDU received on non RX vc %u.%u\n",
- card->name, vpi, vci);
- recycle_rx_skb(card, skb);
- return;
- }
- vcc = vc->rx_vcc;
- pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
- if ((vcc->qos.aal == ATM_AAL0) ||
- (vcc->qos.aal == ATM_AAL34)) {
- struct sk_buff *sb;
- unsigned char *cell;
- u32 aal0;
- cell = skb->data;
- for (i = (stat & SAR_RSQE_CELLCNT); i; i--) {
- if ((sb = dev_alloc_skb(64)) == NULL) {
- printk("%s: Can't allocate buffers for aal0.\n",
- card->name);
- atomic_add(i, &vcc->stats->rx_drop);
- break;
- }
- if (!atm_charge(vcc, sb->truesize)) {
- RXPRINTK("%s: atm_charge() dropped aal0 packets.\n",
- card->name);
- atomic_add(i - 1, &vcc->stats->rx_drop);
- dev_kfree_skb(sb);
- break;
- }
- aal0 = (vpi << ATM_HDR_VPI_SHIFT) |
- (vci << ATM_HDR_VCI_SHIFT);
- aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0;
- aal0 |= (stat & SAR_RSQE_CLP) ? 0x00000001 : 0;
- *((u32 *) sb->data) = aal0;
- skb_put(sb, sizeof(u32));
- memcpy(skb_put(sb, ATM_CELL_PAYLOAD),
- cell, ATM_CELL_PAYLOAD);
- ATM_SKB(sb)->vcc = vcc;
- do_gettimeofday(&sb->stamp);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- cell += ATM_CELL_PAYLOAD;
- }
- recycle_rx_skb(card, skb);
- return;
- }
- if (vcc->qos.aal != ATM_AAL5) {
- printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n",
- card->name, vcc->qos.aal);
- recycle_rx_skb(card, skb);
- return;
- }
- skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD;
- rpp = &vc->rcv.rx_pool;
- rpp->len += skb->len;
- if (!rpp->count++)
- rpp->first = skb;
- *rpp->last = skb;
- rpp->last = &skb->next;
- if (stat & SAR_RSQE_EPDU) {
- unsigned char *l1l2;
- unsigned int len;
- l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6);
- len = (l1l2[0] << 8) | l1l2[1];
- len = len ? len : 0x10000;
- RXPRINTK("%s: PDU has %d bytes.\n", card->name, len);
- if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) {
- RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. "
- "(CDC: %08x)\n",
- card->name, len, rpp->len, readl(SAR_REG_CDC));
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
- return;
- }
- if (stat & SAR_RSQE_CRC) {
- RXPRINTK("%s: AAL5 CRC error.\n", card->name);
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
- return;
- }
- if (rpp->count > 1) {
- struct sk_buff *sb;
- skb = dev_alloc_skb(rpp->len);
- if (!skb) {
- RXPRINTK("%s: Can't alloc RX skb.\n",
- card->name);
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
- return;
- }
- if (!atm_charge(vcc, skb->truesize)) {
- recycle_rx_pool_skb(card, rpp);
- dev_kfree_skb(skb);
- return;
- }
- sb = rpp->first;
- for (i = 0; i < rpp->count; i++) {
- memcpy(skb_put(skb, sb->len),
- sb->data, sb->len);
- sb = sb->next;
- }
- recycle_rx_pool_skb(card, rpp);
- skb_trim(skb, len);
- ATM_SKB(skb)->vcc = vcc;
- do_gettimeofday(&skb->stamp);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- return;
- }
- skb->next = NULL;
- flush_rx_pool(card, rpp);
- if (!atm_charge(vcc, skb->truesize)) {
- recycle_rx_skb(card, skb);
- return;
- }
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
- sb_pool_remove(card, skb);
- skb_trim(skb, len);
- ATM_SKB(skb)->vcc = vcc;
- do_gettimeofday(&skb->stamp);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- if (skb->truesize > SAR_FB_SIZE_3)
- add_rx_skb(card, 3, SAR_FB_SIZE_3, 1);
- else if (skb->truesize > SAR_FB_SIZE_2)
- add_rx_skb(card, 2, SAR_FB_SIZE_2, 1);
- else if (skb->truesize > SAR_FB_SIZE_1)
- add_rx_skb(card, 1, SAR_FB_SIZE_1, 1);
- else
- add_rx_skb(card, 0, SAR_FB_SIZE_0, 1);
- return;
- }
- }
- static void
- idt77252_rx(struct idt77252_dev *card)
- {
- struct rsq_entry *rsqe;
- if (card->rsq.next == card->rsq.last)
- rsqe = card->rsq.base;
- else
- rsqe = card->rsq.next + 1;
- if (!(le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID)) {
- RXPRINTK("%s: no entry in RSQ.\n", card->name);
- return;
- }
- do {
- dequeue_rx(card, rsqe);
- rsqe->word_4 = 0;
- card->rsq.next = rsqe;
- if (card->rsq.next == card->rsq.last)
- rsqe = card->rsq.base;
- else
- rsqe = card->rsq.next + 1;
- } while (le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID);
- writel((unsigned long) card->rsq.next - (unsigned long) card->rsq.base,
- SAR_REG_RSQH);
- }
- static void
- idt77252_rx_raw(struct idt77252_dev *card)
- {
- struct sk_buff *queue;
- u32 head, tail;
- struct atm_vcc *vcc;
- struct vc_map *vc;
- struct sk_buff *sb;
- if (card->raw_cell_head == NULL) {
- u32 handle = le32_to_cpu(*(card->raw_cell_hnd + 1));
- card->raw_cell_head = sb_pool_skb(card, handle);
- }
- queue = card->raw_cell_head;
- if (!queue)
- return;
- head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16);
- tail = readl(SAR_REG_RAWCT);
- pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue),
- queue->end - queue->head - 16,
- PCI_DMA_FROMDEVICE);
- while (head != tail) {
- unsigned int vpi, vci, pti;
- u32 header;
- header = le32_to_cpu(*(u32 *) &queue->data[0]);
- vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
- vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
- pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
- #ifdef CONFIG_ATM_IDT77252_DEBUG
- if (debug & DBG_RAW_CELL) {
- int i;
- printk("%s: raw cell %x.%02x.%04x.%x.%x\n",
- card->name, (header >> 28) & 0x000f,
- (header >> 20) & 0x00ff,
- (header >> 4) & 0xffff,
- (header >> 1) & 0x0007,
- (header >> 0) & 0x0001);
- for (i = 16; i < 64; i++)
- printk(" %02x", queue->data[i]);
- printk("\n");
- }
- #endif
- if (vpi >= (1<<card->vpibits) || vci >= (1<<card->vcibits)) {
- RPRINTK("%s: SDU received for out-of-range vc %u.%u\n",
- card->name, vpi, vci);
- goto drop;
- }
- vc = card->vcs[VPCI2VC(card, vpi, vci)];
- if (!vc || !test_bit(VCF_RX, &vc->flags)) {
- RPRINTK("%s: SDU received on non RX vc %u.%u\n",
- card->name, vpi, vci);
- goto drop;
- }
- vcc = vc->rx_vcc;
- if (vcc->qos.aal != ATM_AAL0) {
- RPRINTK("%s: raw cell for non AAL0 vc %u.%u\n",
- card->name, vpi, vci);
- atomic_inc(&vcc->stats->rx_drop);
- goto drop;
- }
-
- if ((sb = dev_alloc_skb(64)) == NULL) {
- printk("%s: Can't allocate buffers for AAL0.\n",
- card->name);
- atomic_inc(&vcc->stats->rx_err);
- goto drop;
- }
- if (!atm_charge(vcc, sb->truesize)) {
- RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n",
- card->name);
- dev_kfree_skb(sb);
- goto drop;
- }
- *((u32 *) sb->data) = header;
- skb_put(sb, sizeof(u32));
- memcpy(skb_put(sb, ATM_CELL_PAYLOAD), &(queue->data[16]),
- ATM_CELL_PAYLOAD);
- ATM_SKB(sb)->vcc = vcc;
- do_gettimeofday(&sb->stamp);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- drop:
- skb_pull(queue, 64);
- head = IDT77252_PRV_PADDR(queue)
- + (queue->data - queue->head - 16);
- if (queue->len < 128) {
- struct sk_buff *next;
- u32 handle;
- head = le32_to_cpu(*(u32 *) &queue->data[0]);
- handle = le32_to_cpu(*(u32 *) &queue->data[4]);
- next = sb_pool_skb(card, handle);
- recycle_rx_skb(card, queue);
- if (next) {
- card->raw_cell_head = next;
- queue = card->raw_cell_head;
- pci_dma_sync_single_for_cpu(card->pcidev,
- IDT77252_PRV_PADDR(queue),
- queue->end - queue->data,
- PCI_DMA_FROMDEVICE);
- } else {
- card->raw_cell_head = NULL;
- printk("%s: raw cell queue overrun\n",
- card->name);
- break;
- }
- }
- }
- }
- /*****************************************************************************/
- /* */
- /* TSQ Handling */
- /* */
- /*****************************************************************************/
- static int
- init_tsq(struct idt77252_dev *card)
- {
- struct tsq_entry *tsqe;
- card->tsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE,
- &card->tsq.paddr);
- if (card->tsq.base == NULL) {
- printk("%s: can't allocate TSQ.\n", card->name);
- return -1;
- }
- memset(card->tsq.base, 0, TSQSIZE);
- card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1;
- card->tsq.next = card->tsq.last;
- for (tsqe = card->tsq.base; tsqe <= card->tsq.last; tsqe++)
- tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
- writel(card->tsq.paddr, SAR_REG_TSQB);
- writel((unsigned long) card->tsq.next - (unsigned long) card->tsq.base,
- SAR_REG_TSQH);
- return 0;
- }
- static void
- deinit_tsq(struct idt77252_dev *card)
- {
- pci_free_consistent(card->pcidev, TSQSIZE,
- card->tsq.base, card->tsq.paddr);
- }
- static void
- idt77252_tx(struct idt77252_dev *card)
- {
- struct tsq_entry *tsqe;
- unsigned int vpi, vci;
- struct vc_map *vc;
- u32 conn, stat;
- if (card->tsq.next == card->tsq.last)
- tsqe = card->tsq.base;
- else
- tsqe = card->tsq.next + 1;
- TXPRINTK("idt77252_tx: tsq %p: base %p, next %p, last %p\n", tsqe,
- card->tsq.base, card->tsq.next, card->tsq.last);
- TXPRINTK("idt77252_tx: tsqb %08x, tsqt %08x, tsqh %08x, \n",
- readl(SAR_REG_TSQB),
- readl(SAR_REG_TSQT),
- readl(SAR_REG_TSQH));
- stat = le32_to_cpu(tsqe->word_2);
- if (stat & SAR_TSQE_INVALID)
- return;
- do {
- TXPRINTK("tsqe: 0x%p [0x%08x 0x%08x]\n", tsqe,
- le32_to_cpu(tsqe->word_1),
- le32_to_cpu(tsqe->word_2));
- switch (stat & SAR_TSQE_TYPE) {
- case SAR_TSQE_TYPE_TIMER:
- TXPRINTK("%s: Timer RollOver detected.\n", card->name);
- break;
- case SAR_TSQE_TYPE_IDLE:
- conn = le32_to_cpu(tsqe->word_1);
- if (SAR_TSQE_TAG(stat) == 0x10) {
- #ifdef NOTDEF
- printk("%s: Connection %d halted.\n",
- card->name,
- le32_to_cpu(tsqe->word_1) & 0x1fff);
- #endif
- break;
- }
- vc = card->vcs[conn & 0x1fff];
- if (!vc) {
- printk("%s: could not find VC from conn %d\n",
- card->name, conn & 0x1fff);
- break;
- }
- printk("%s: Connection %d IDLE.\n",
- card->name, vc->index);
- set_bit(VCF_IDLE, &vc->flags);
- break;
- case SAR_TSQE_TYPE_TSR:
- conn = le32_to_cpu(tsqe->word_1);
- vc = card->vcs[conn & 0x1fff];
- if (!vc) {
- printk("%s: no VC at index %d\n",
- card->name,
- le32_to_cpu(tsqe->word_1) & 0x1fff);
- break;
- }
- drain_scq(card, vc);
- break;
- case SAR_TSQE_TYPE_TBD_COMP:
- conn = le32_to_cpu(tsqe->word_1);
- vpi = (conn >> SAR_TBD_VPI_SHIFT) & 0x00ff;
- vci = (conn >> SAR_TBD_VCI_SHIFT) & 0xffff;
- if (vpi >= (1 << card->vpibits) ||
- vci >= (1 << card->vcibits)) {
- printk("%s: TBD complete: "
- "out of range VPI.VCI %u.%u\n",
- card->name, vpi, vci);
- break;
- }
- vc = card->vcs[VPCI2VC(card, vpi, vci)];
- if (!vc) {
- printk("%s: TBD complete: "
- "no VC at VPI.VCI %u.%u\n",
- card->name, vpi, vci);
- break;
- }
- drain_scq(card, vc);
- break;
- }
- tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
- card->tsq.next = tsqe;
- if (card->tsq.next == card->tsq.last)
- tsqe = card->tsq.base;
- else
- tsqe = card->tsq.next + 1;
- TXPRINTK("tsqe: %p: base %p, next %p, last %p\n", tsqe,
- card->tsq.base, card->tsq.next, card->tsq.last);
- stat = le32_to_cpu(tsqe->word_2);
- } while (!(stat & SAR_TSQE_INVALID));
- writel((unsigned long)card->tsq.next - (unsigned long)card->tsq.base,
- SAR_REG_TSQH);
- XPRINTK("idt77252_tx-after writel%d: TSQ head = 0x%x, tail = 0x%x, next = 0x%p.\n",
- card->index, readl(SAR_REG_TSQH),
- readl(SAR_REG_TSQT), card->tsq.next);
- }
- static void
- tst_timer(unsigned long data)
- {
- struct idt77252_dev *card = (struct idt77252_dev *)data;
- unsigned long base, idle, jump;
- unsigned long flags;
- u32 pc;
- int e;
- spin_lock_irqsave(&card->tst_lock, flags);
- base = card->tst[card->tst_index];
- idle = card->tst[card->tst_index ^ 1];
- if (test_bit(TST_SWITCH_WAIT, &card->tst_state)) {
- jump = base + card->tst_size - 2;
- pc = readl(SAR_REG_NOW) >> 2;
- if ((pc ^ idle) & ~(card->tst_size - 1)) {
- mod_timer(&card->tst_timer, jiffies + 1);
- goto out;
- }
- clear_bit(TST_SWITCH_WAIT, &card->tst_state);
- card->tst_index ^= 1;
- write_sram(card, jump, TSTE_OPC_JMP | (base << 2));
- base = card->tst[card->tst_index];
- idle = card->tst[card->tst_index ^ 1];
- for (e = 0; e < card->tst_size - 2; e++) {
- if (card->soft_tst[e].tste & TSTE_PUSH_IDLE) {
- write_sram(card, idle + e,
- card->soft_tst[e].tste & TSTE_MASK);
- card->soft_tst[e].tste &= ~(TSTE_PUSH_IDLE);
- }
- }
- }
- if (test_and_clear_bit(TST_SWITCH_PENDING, &card->tst_state)) {
- for (e = 0; e < card->tst_size - 2; e++) {
- if (card->soft_tst[e].tste & TSTE_PUSH_ACTIVE) {
- write_sram(card, idle + e,
- card->soft_tst[e].tste & TSTE_MASK);
- card->soft_tst[e].tste &= ~(TSTE_PUSH_ACTIVE);
- card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
- }
- }
- jump = base + card->tst_size - 2;
- write_sram(card, jump, TSTE_OPC_NULL);
- set_bit(TST_SWITCH_WAIT, &card->tst_state);
- mod_timer(&card->tst_timer, jiffies + 1);
- }
- out:
- spin_unlock_irqrestore(&card->tst_lock, flags);
- }
- static int
- __fill_tst(struct idt77252_dev *card, struct vc_map *vc,
- int n, unsigned int opc)
- {
- unsigned long cl, avail;
- unsigned long idle;
- int e, r;
- u32 data;
- avail = card->tst_size - 2;
- for (e = 0; e < avail; e++) {
- if (card->soft_tst[e].vc == NULL)
- break;
- }
- if (e >= avail) {
- printk("%s: No free TST entries found\n", card->name);
- return -1;
- }
- NPRINTK("%s: conn %d: first TST entry at %d.\n",
- card->name, vc ? vc->index : -1, e);
- r = n;
- cl = avail;
- data = opc & TSTE_OPC_MASK;
- if (vc && (opc != TSTE_OPC_NULL))
- data = opc | vc->index;
- idle = card->tst[card->tst_index ^ 1];
- /*
- * Fill Soft TST.
- */
- while (r > 0) {
- if ((cl >= avail) && (card->soft_tst[e].vc == NULL)) {
- if (vc)
- card->soft_tst[e].vc = vc;
- else
- card->soft_tst[e].vc = (void *)-1;
- card->soft_tst[e].tste = data;
- if (timer_pending(&card->tst_timer))
- card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
- else {
- write_sram(card, idle + e, data);
- card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
- }
- cl -= card->tst_size;
- r--;
- }
- if (++e == avail)
- e = 0;
- cl += n;
- }
- return 0;
- }
- static int
- fill_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc)
- {
- unsigned long flags;
- int res;
- spin_lock_irqsave(&card->tst_lock, flags);
- res = __fill_tst(card, vc, n, opc);
- set_bit(TST_SWITCH_PENDING, &card->tst_state);
- if (!timer_pending(&card->tst_timer))
- mod_timer(&card->tst_timer, jiffies + 1);
- spin_unlock_irqrestore(&card->tst_lock, flags);
- return res;
- }
- static int
- __clear_tst(struct idt77252_dev *card, struct vc_map *vc)
- {
- unsigned long idle;
- int e;
- idle = card->tst[card->tst_index ^ 1];
- for (e = 0; e < card->tst_size - 2; e++) {
- if (card->soft_tst[e].vc == vc) {
- card->soft_tst[e].vc = NULL;
- card->soft_tst[e].tste = TSTE_OPC_VAR;
- if (timer_pending(&card->tst_timer))
- card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
- else {
- write_sram(card, idle + e, TSTE_OPC_VAR);
- card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
- }
- }
- }
- return 0;
- }
- static int
- clear_tst(struct idt77252_dev *card, struct vc_map *vc)
- {
- unsigned long flags;
- int res;
- spin_lock_irqsave(&card->tst_lock, flags);
- res = __clear_tst(card, vc);
- set_bit(TST_SWITCH_PENDING, &card->tst_state);
- if (!timer_pending(&card->tst_timer))
- mod_timer(&card->tst_timer, jiffies + 1);
- spin_unlock_irqrestore(&card->tst_lock, flags);
- return res;
- }
- static int
- change_tst(struct idt77252_dev *card, struct vc_map *vc,
- int n, unsigned int opc)
- {
- unsigned long flags;
- int res;
- spin_lock_irqsave(&card->tst_lock, flags);
- __clear_tst(card, vc);
- res = __fill_tst(card, vc, n, opc);
- set_bit(TST_SWITCH_PENDING, &card->tst_state);
- if (!timer_pending(&card->tst_timer))
- mod_timer(&card->tst_timer, jiffies + 1);
- spin_unlock_irqrestore(&card->tst_lock, flags);
- return res;
- }
- static int
- set_tct(struct idt77252_dev *card, struct vc_map *vc)
- {
- unsigned long tct;
- tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE);
- switch (vc->class) {
- case SCHED_CBR:
- OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
- card->name, tct, vc->scq->scd);
- write_sram(card, tct + 0, TCT_CBR | vc->scq->scd);
- write_sram(card, tct + 1, 0);
- write_sram(card, tct + 2, 0);
- write_sram(card, tct + 3, 0);
- write_sram(card, tct + 4, 0);
- write_sram(card, tct + 5, 0);
- write_sram(card, tct + 6, 0);
- write_sram(card, tct + 7, 0);
- break;
- case SCHED_UBR:
- OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
- card->name, tct, vc->scq->scd);
- write_sram(card, tct + 0, TCT_UBR | vc->scq->scd);
- write_sram(card, tct + 1, 0);
- write_sram(card, tct + 2, TCT_TSIF);
- write_sram(card, tct + 3, TCT_HALT | TCT_IDLE);
- write_sram(card, tct + 4, 0);
- write_sram(card, tct + 5, vc->init_er);
- write_sram(card, tct + 6, 0);
- write_sram(card, tct + 7, TCT_FLAG_UBR);
- break;
- case SCHED_VBR:
- case SCHED_ABR:
- default:
- return -ENOSYS;
- }
- return 0;
- }
- /*****************************************************************************/
- /* */
- /* FBQ Handling */
- /* */
- /*****************************************************************************/
- static __inline__ int
- idt77252_fbq_level(struct idt77252_dev *card, int queue)
- {
- return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f;
- }
- static __inline__ int
- idt77252_fbq_full(struct idt77252_dev *card, int queue)
- {
- return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f;
- }
- static int
- push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue)
- {
- unsigned long flags;
- u32 handle;
- u32 addr;
- skb->data = skb->tail = skb->head;
- skb->len = 0;
- skb_reserve(skb, 16);
- switch (queue) {
- case 0:
- skb_put(skb, SAR_FB_SIZE_0);
- break;
- case 1:
- skb_put(skb, SAR_FB_SIZE_1);
- break;
- case 2:
- skb_put(skb, SAR_FB_SIZE_2);
- break;
- case 3:
- skb_put(skb, SAR_FB_SIZE_3);
- break;
- default:
- dev_kfree_skb(skb);
- return -1;
- }
- if (idt77252_fbq_full(card, queue))
- return -1;
- memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32));
- handle = IDT77252_PRV_POOL(skb);
- addr = IDT77252_PRV_PADDR(skb);
- spin_lock_irqsave(&card->cmd_lock, flags);
- writel(handle, card->fbq[queue]);
- writel(addr, card->fbq[queue]);
- spin_unlock_irqrestore(&card->cmd_lock, flags);
- return 0;
- }
- static void
- add_rx_skb(struct idt77252_dev *card, int queue,
- unsigned int size, unsigned int count)
- {
- struct sk_buff *skb;
- dma_addr_t paddr;
- u32 handle;
- while (count--) {
- skb = dev_alloc_skb(size);
- if (!skb)
- return;
- if (sb_pool_add(card, skb, queue)) {
- printk("%s: SB POOL full\n", __FUNCTION__);
- goto outfree;
- }
- paddr = pci_map_single(card->pcidev, skb->data,
- skb->end - skb->data,
- PCI_DMA_FROMDEVICE);
- IDT77252_PRV_PADDR(skb) = paddr;
- if (push_rx_skb(card, skb, queue)) {
- printk("%s: FB QUEUE full\n", __FUNCTION__);
- goto outunmap;
- }
- }
- return;
- outunmap:
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
- handle = IDT77252_PRV_POOL(skb);
- card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;
- outfree:
- dev_kfree_skb(skb);
- }
- static void
- recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb)
- {
- u32 handle = IDT77252_PRV_POOL(skb);
- int err;
- pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
- err = push_rx_skb(card, skb, POOL_QUEUE(handle));
- if (err) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
- sb_pool_remove(card, skb);
- dev_kfree_skb(skb);
- }
- }
- static void
- flush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp)
- {
- rpp->len = 0;
- rpp->count = 0;
- rpp->first = NULL;
- rpp->last = &rpp->first;
- }
- static void
- recycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp)
- {
- struct sk_buff *skb, *next;
- int i;
- skb = rpp->first;
- for (i = 0; i < rpp->count; i++) {
- next = skb->next;
- skb->next = NULL;
- recycle_rx_skb(card, skb);
- skb = next;
- }
- flush_rx_pool(card, rpp);
- }
- /*****************************************************************************/
- /* */
- /* ATM Interface */
- /* */
- /*****************************************************************************/
- static void
- idt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr)
- {
- write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value);
- }
- static unsigned char
- idt77252_phy_get(struct atm_dev *dev, unsigned long addr)
- {
- return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff));
- }
- static inline int
- idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam)
- {
- struct atm_dev *dev = vcc->dev;
- struct idt77252_dev *card = dev->dev_data;
- struct vc_map *vc = vcc->dev_data;
- int err;
- if (vc == NULL) {
- printk("%s: NULL connection in send().\n", card->name);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- if (!test_bit(VCF_TX, &vc->flags)) {
- printk("%s: Trying to transmit on a non-tx VC.\n", card->name);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- switch (vcc->qos.aal) {
- case ATM_AAL0:
- case ATM_AAL1:
- case ATM_AAL5:
- break;
- default:
- printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- if (skb_shinfo(skb)->nr_frags != 0) {
- printk("%s: No scatter-gather yet.\n", card->name);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- ATM_SKB(skb)->vcc = vcc;
- err = queue_skb(card, vc, skb, oam);
- if (err) {
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
- return err;
- }
- return 0;
- }
- int
- idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb)
- {
- return idt77252_send_skb(vcc, skb, 0);
- }
- static int
- idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
- {
- struct atm_dev *dev = vcc->dev;
- struct idt77252_dev *card = dev->dev_data;
- struct sk_buff *skb;
- skb = dev_alloc_skb(64);
- if (!skb) {
- printk("%s: Out of memory in send_oam().\n", card->name);
- atomic_inc(&vcc->stats->tx_err);
- return -ENOMEM;
- }
- atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
- memcpy(skb_put(skb, 52), cell, 52);
- return idt77252_send_skb(vcc, skb, 1);
- }
- static __inline__ unsigned int
- idt77252_fls(unsigned int x)
- {
- int r = 1;
- if (x == 0)
- return 0;
- if (x & 0xffff0000) {
- x >>= 16;
- r += 16;
- }
- if (x & 0xff00) {
- x >>= 8;
- r += 8;
- }
- if (x & 0xf0) {
- x >>= 4;
- r += 4;
- }
- if (x & 0xc) {
- x >>= 2;
- r += 2;
- }
- if (x & 0x2)
- r += 1;
- return r;
- }
- static u16
- idt77252_int_to_atmfp(unsigned int rate)
- {
- u16 m, e;
- if (rate == 0)
- return 0;
- e = idt77252_fls(rate) - 1;
- if (e < 9)
- m = (rate - (1 << e)) << (9 - e);
- else if (e == 9)
- m = (rate - (1 << e));
- else /* e > 9 */
- m = (rate - (1 << e)) >> (e - 9);
- return 0x4000 | (e << 9) | m;
- }
- static u8
- idt77252_rate_logindex(struct idt77252_dev *card, int pcr)
- {
- u16 afp;
- afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr);
- if (pcr < 0)
- return rate_to_log[(afp >> 5) & 0x1ff];
- return rate_to_log[((afp >> 5) + 1) & 0x1ff];
- }
- static void
- idt77252_est_timer(unsigned long data)
- {
- struct vc_map *vc = (struct vc_map *)data;
- struct idt77252_dev *card = vc->card;
- struct rate_estimator *est;
- unsigned long flags;
- u32 rate, cps;
- u64 ncells;
- u8 lacr;
- spin_lock_irqsave(&vc->lock, flags);
- est = vc->estimator;
- if (!est)
- goto out;
- ncells = est->cells;
- rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval);
- est->last_cells = ncells;
- est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log;
- est->cps = (est->avcps + 0x1f) >> 5;
- cps = est->cps;
- if (cps < (est->maxcps >> 4))
- cps = est->maxcps >> 4;
- lacr = idt77252_rate_logindex(card, cps);
- if (lacr > vc->max_er)
- lacr = vc->max_er;
- if (lacr != vc->lacr) {
- vc->lacr = lacr;
- writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ);
- }
- est->timer.expires = jiffies + ((HZ / 4) << est->interval);
- add_timer(&est->timer);
- out:
- spin_unlock_irqrestore(&vc->lock, flags);
- }
- static struct rate_estimator *
- idt77252_init_est(struct vc_map *vc, int pcr)
- {
- struct rate_estimator *est;
- est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL);
- if (!est)
- return NULL;
- memset(est, 0, sizeof(*est));
- est->maxcps = pcr < 0 ? -pcr : pcr;
- est->cps = est->maxcps;
- est->avcps = est->cps << 5;
- est->interval = 2; /* XXX: make this configurable */
- est->ewma_log = 2; /* XXX: make this c…