xref: /kernel/linux/linux-6.6/drivers/atm/idt77252.c (revision 62306a36)
162306a36Sopenharmony_ci/*******************************************************************
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright (c) 2000 ATecoM GmbH
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * The author may be reached at ecd@atecom.com.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This program is free software; you can redistribute  it and/or modify it
862306a36Sopenharmony_ci * under  the terms of  the GNU General  Public License as published by the
962306a36Sopenharmony_ci * Free Software Foundation;  either version 2 of the  License, or (at your
1062306a36Sopenharmony_ci * option) any later version.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
1362306a36Sopenharmony_ci * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
1462306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
1562306a36Sopenharmony_ci * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
1662306a36Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1762306a36Sopenharmony_ci * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
1862306a36Sopenharmony_ci * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1962306a36Sopenharmony_ci * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
2062306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2162306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * You should have received a copy of the  GNU General Public License along
2462306a36Sopenharmony_ci * with this program; if not, write  to the Free Software Foundation, Inc.,
2562306a36Sopenharmony_ci * 675 Mass Ave, Cambridge, MA 02139, USA.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *******************************************************************/
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/module.h>
3062306a36Sopenharmony_ci#include <linux/pci.h>
3162306a36Sopenharmony_ci#include <linux/poison.h>
3262306a36Sopenharmony_ci#include <linux/skbuff.h>
3362306a36Sopenharmony_ci#include <linux/kernel.h>
3462306a36Sopenharmony_ci#include <linux/vmalloc.h>
3562306a36Sopenharmony_ci#include <linux/netdevice.h>
3662306a36Sopenharmony_ci#include <linux/atmdev.h>
3762306a36Sopenharmony_ci#include <linux/atm.h>
3862306a36Sopenharmony_ci#include <linux/delay.h>
3962306a36Sopenharmony_ci#include <linux/init.h>
4062306a36Sopenharmony_ci#include <linux/interrupt.h>
4162306a36Sopenharmony_ci#include <linux/bitops.h>
4262306a36Sopenharmony_ci#include <linux/wait.h>
4362306a36Sopenharmony_ci#include <linux/jiffies.h>
4462306a36Sopenharmony_ci#include <linux/mutex.h>
4562306a36Sopenharmony_ci#include <linux/slab.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <asm/io.h>
4862306a36Sopenharmony_ci#include <linux/uaccess.h>
4962306a36Sopenharmony_ci#include <linux/atomic.h>
5062306a36Sopenharmony_ci#include <asm/byteorder.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_USE_SUNI
5362306a36Sopenharmony_ci#include "suni.h"
5462306a36Sopenharmony_ci#endif /* CONFIG_ATM_IDT77252_USE_SUNI */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include "idt77252.h"
5862306a36Sopenharmony_ci#include "idt77252_tables.h"
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic unsigned int vpibits = 1;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define ATM_IDT77252_SEND_IDLE 1
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * Debug HACKs.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_ci#define DEBUG_MODULE 1
7062306a36Sopenharmony_ci#undef HAVE_EEPROM	/* does not work, yet. */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
7362306a36Sopenharmony_cistatic unsigned long debug = DBG_GENERAL;
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define SAR_RX_DELAY	(SAR_CFG_RXINT_NODELAY)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/*
8162306a36Sopenharmony_ci * SCQ Handling.
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_cistatic struct scq_info *alloc_scq(struct idt77252_dev *, int);
8462306a36Sopenharmony_cistatic void free_scq(struct idt77252_dev *, struct scq_info *);
8562306a36Sopenharmony_cistatic int queue_skb(struct idt77252_dev *, struct vc_map *,
8662306a36Sopenharmony_ci		     struct sk_buff *, int oam);
8762306a36Sopenharmony_cistatic void drain_scq(struct idt77252_dev *, struct vc_map *);
8862306a36Sopenharmony_cistatic unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *);
8962306a36Sopenharmony_cistatic void fill_scd(struct idt77252_dev *, struct scq_info *, int);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * FBQ Handling.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic int push_rx_skb(struct idt77252_dev *,
9562306a36Sopenharmony_ci		       struct sk_buff *, int queue);
9662306a36Sopenharmony_cistatic void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *);
9762306a36Sopenharmony_cistatic void flush_rx_pool(struct idt77252_dev *, struct rx_pool *);
9862306a36Sopenharmony_cistatic void recycle_rx_pool_skb(struct idt77252_dev *,
9962306a36Sopenharmony_ci				struct rx_pool *);
10062306a36Sopenharmony_cistatic void add_rx_skb(struct idt77252_dev *, int queue,
10162306a36Sopenharmony_ci		       unsigned int size, unsigned int count);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * RSQ Handling.
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_cistatic int init_rsq(struct idt77252_dev *);
10762306a36Sopenharmony_cistatic void deinit_rsq(struct idt77252_dev *);
10862306a36Sopenharmony_cistatic void idt77252_rx(struct idt77252_dev *);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * TSQ handling.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic int init_tsq(struct idt77252_dev *);
11462306a36Sopenharmony_cistatic void deinit_tsq(struct idt77252_dev *);
11562306a36Sopenharmony_cistatic void idt77252_tx(struct idt77252_dev *);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * ATM Interface.
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic void idt77252_dev_close(struct atm_dev *dev);
12262306a36Sopenharmony_cistatic int idt77252_open(struct atm_vcc *vcc);
12362306a36Sopenharmony_cistatic void idt77252_close(struct atm_vcc *vcc);
12462306a36Sopenharmony_cistatic int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb);
12562306a36Sopenharmony_cistatic int idt77252_send_oam(struct atm_vcc *vcc, void *cell,
12662306a36Sopenharmony_ci			     int flags);
12762306a36Sopenharmony_cistatic void idt77252_phy_put(struct atm_dev *dev, unsigned char value,
12862306a36Sopenharmony_ci			     unsigned long addr);
12962306a36Sopenharmony_cistatic unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr);
13062306a36Sopenharmony_cistatic int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos,
13162306a36Sopenharmony_ci			       int flags);
13262306a36Sopenharmony_cistatic int idt77252_proc_read(struct atm_dev *dev, loff_t * pos,
13362306a36Sopenharmony_ci			      char *page);
13462306a36Sopenharmony_cistatic void idt77252_softint(struct work_struct *work);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const struct atmdev_ops idt77252_ops =
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	.dev_close	= idt77252_dev_close,
14062306a36Sopenharmony_ci	.open		= idt77252_open,
14162306a36Sopenharmony_ci	.close		= idt77252_close,
14262306a36Sopenharmony_ci	.send		= idt77252_send,
14362306a36Sopenharmony_ci	.send_oam	= idt77252_send_oam,
14462306a36Sopenharmony_ci	.phy_put	= idt77252_phy_put,
14562306a36Sopenharmony_ci	.phy_get	= idt77252_phy_get,
14662306a36Sopenharmony_ci	.change_qos	= idt77252_change_qos,
14762306a36Sopenharmony_ci	.proc_read	= idt77252_proc_read,
14862306a36Sopenharmony_ci	.owner		= THIS_MODULE
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic struct idt77252_dev *idt77252_chain = NULL;
15262306a36Sopenharmony_cistatic unsigned int idt77252_sram_write_errors = 0;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/*****************************************************************************/
15562306a36Sopenharmony_ci/*                                                                           */
15662306a36Sopenharmony_ci/* I/O and Utility Bus                                                       */
15762306a36Sopenharmony_ci/*                                                                           */
15862306a36Sopenharmony_ci/*****************************************************************************/
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void
16162306a36Sopenharmony_ciwaitfor_idle(struct idt77252_dev *card)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	u32 stat;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	stat = readl(SAR_REG_STAT);
16662306a36Sopenharmony_ci	while (stat & SAR_STAT_CMDBZ)
16762306a36Sopenharmony_ci		stat = readl(SAR_REG_STAT);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic u32
17162306a36Sopenharmony_ciread_sram(struct idt77252_dev *card, unsigned long addr)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	unsigned long flags;
17462306a36Sopenharmony_ci	u32 value;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
17762306a36Sopenharmony_ci	writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD);
17862306a36Sopenharmony_ci	waitfor_idle(card);
17962306a36Sopenharmony_ci	value = readl(SAR_REG_DR0);
18062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
18162306a36Sopenharmony_ci	return value;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void
18562306a36Sopenharmony_ciwrite_sram(struct idt77252_dev *card, unsigned long addr, u32 value)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	unsigned long flags;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if ((idt77252_sram_write_errors == 0) &&
19062306a36Sopenharmony_ci	    (((addr > card->tst[0] + card->tst_size - 2) &&
19162306a36Sopenharmony_ci	      (addr < card->tst[0] + card->tst_size)) ||
19262306a36Sopenharmony_ci	     ((addr > card->tst[1] + card->tst_size - 2) &&
19362306a36Sopenharmony_ci	      (addr < card->tst[1] + card->tst_size)))) {
19462306a36Sopenharmony_ci		printk("%s: ERROR: TST JMP section at %08lx written: %08x\n",
19562306a36Sopenharmony_ci		       card->name, addr, value);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
19962306a36Sopenharmony_ci	writel(value, SAR_REG_DR0);
20062306a36Sopenharmony_ci	writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
20162306a36Sopenharmony_ci	waitfor_idle(card);
20262306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic u8
20662306a36Sopenharmony_ciread_utility(void *dev, unsigned long ubus_addr)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct idt77252_dev *card = dev;
20962306a36Sopenharmony_ci	unsigned long flags;
21062306a36Sopenharmony_ci	u8 value;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (!card) {
21362306a36Sopenharmony_ci		printk("Error: No such device.\n");
21462306a36Sopenharmony_ci		return -1;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
21862306a36Sopenharmony_ci	writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD);
21962306a36Sopenharmony_ci	waitfor_idle(card);
22062306a36Sopenharmony_ci	value = readl(SAR_REG_DR0);
22162306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
22262306a36Sopenharmony_ci	return value;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void
22662306a36Sopenharmony_ciwrite_utility(void *dev, unsigned long ubus_addr, u8 value)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct idt77252_dev *card = dev;
22962306a36Sopenharmony_ci	unsigned long flags;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!card) {
23262306a36Sopenharmony_ci		printk("Error: No such device.\n");
23362306a36Sopenharmony_ci		return;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
23762306a36Sopenharmony_ci	writel((u32) value, SAR_REG_DR0);
23862306a36Sopenharmony_ci	writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD);
23962306a36Sopenharmony_ci	waitfor_idle(card);
24062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#ifdef HAVE_EEPROM
24462306a36Sopenharmony_cistatic u32 rdsrtab[] =
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	SAR_GP_EECS | SAR_GP_EESCLK,
24762306a36Sopenharmony_ci	0,
24862306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
24962306a36Sopenharmony_ci	0,
25062306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
25162306a36Sopenharmony_ci	0,
25262306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
25362306a36Sopenharmony_ci	0,
25462306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
25562306a36Sopenharmony_ci	0,
25662306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
25762306a36Sopenharmony_ci	SAR_GP_EEDO,
25862306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO,	/* 1 */
25962306a36Sopenharmony_ci	0,
26062306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
26162306a36Sopenharmony_ci	SAR_GP_EEDO,
26262306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO	/* 1 */
26362306a36Sopenharmony_ci};
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic u32 wrentab[] =
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	SAR_GP_EECS | SAR_GP_EESCLK,
26862306a36Sopenharmony_ci	0,
26962306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
27062306a36Sopenharmony_ci	0,
27162306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
27262306a36Sopenharmony_ci	0,
27362306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
27462306a36Sopenharmony_ci	0,
27562306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
27662306a36Sopenharmony_ci	SAR_GP_EEDO,
27762306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO,	/* 1 */
27862306a36Sopenharmony_ci	SAR_GP_EEDO,
27962306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO,	/* 1 */
28062306a36Sopenharmony_ci	0,
28162306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
28262306a36Sopenharmony_ci	0,
28362306a36Sopenharmony_ci	SAR_GP_EESCLK			/* 0 */
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic u32 rdtab[] =
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	SAR_GP_EECS | SAR_GP_EESCLK,
28962306a36Sopenharmony_ci	0,
29062306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
29162306a36Sopenharmony_ci	0,
29262306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
29362306a36Sopenharmony_ci	0,
29462306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
29562306a36Sopenharmony_ci	0,
29662306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
29762306a36Sopenharmony_ci	0,
29862306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
29962306a36Sopenharmony_ci	0,
30062306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
30162306a36Sopenharmony_ci	SAR_GP_EEDO,
30262306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO,	/* 1 */
30362306a36Sopenharmony_ci	SAR_GP_EEDO,
30462306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO	/* 1 */
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic u32 wrtab[] =
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	SAR_GP_EECS | SAR_GP_EESCLK,
31062306a36Sopenharmony_ci	0,
31162306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
31262306a36Sopenharmony_ci	0,
31362306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
31462306a36Sopenharmony_ci	0,
31562306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
31662306a36Sopenharmony_ci	0,
31762306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
31862306a36Sopenharmony_ci	0,
31962306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
32062306a36Sopenharmony_ci	0,
32162306a36Sopenharmony_ci	SAR_GP_EESCLK,			/* 0 */
32262306a36Sopenharmony_ci	SAR_GP_EEDO,
32362306a36Sopenharmony_ci	SAR_GP_EESCLK | SAR_GP_EEDO,	/* 1 */
32462306a36Sopenharmony_ci	0,
32562306a36Sopenharmony_ci	SAR_GP_EESCLK			/* 0 */
32662306a36Sopenharmony_ci};
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic u32 clktab[] =
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	0,
33162306a36Sopenharmony_ci	SAR_GP_EESCLK,
33262306a36Sopenharmony_ci	0,
33362306a36Sopenharmony_ci	SAR_GP_EESCLK,
33462306a36Sopenharmony_ci	0,
33562306a36Sopenharmony_ci	SAR_GP_EESCLK,
33662306a36Sopenharmony_ci	0,
33762306a36Sopenharmony_ci	SAR_GP_EESCLK,
33862306a36Sopenharmony_ci	0,
33962306a36Sopenharmony_ci	SAR_GP_EESCLK,
34062306a36Sopenharmony_ci	0,
34162306a36Sopenharmony_ci	SAR_GP_EESCLK,
34262306a36Sopenharmony_ci	0,
34362306a36Sopenharmony_ci	SAR_GP_EESCLK,
34462306a36Sopenharmony_ci	0,
34562306a36Sopenharmony_ci	SAR_GP_EESCLK,
34662306a36Sopenharmony_ci	0
34762306a36Sopenharmony_ci};
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic u32
35062306a36Sopenharmony_ciidt77252_read_gp(struct idt77252_dev *card)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	u32 gp;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	gp = readl(SAR_REG_GP);
35562306a36Sopenharmony_ci#if 0
35662306a36Sopenharmony_ci	printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0");
35762306a36Sopenharmony_ci#endif
35862306a36Sopenharmony_ci	return gp;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void
36262306a36Sopenharmony_ciidt77252_write_gp(struct idt77252_dev *card, u32 value)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	unsigned long flags;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci#if 0
36762306a36Sopenharmony_ci	printk("WR: %s %s %s\n", value & SAR_GP_EECS ? "   " : "/CS",
36862306a36Sopenharmony_ci	       value & SAR_GP_EESCLK ? "HIGH" : "LOW ",
36962306a36Sopenharmony_ci	       value & SAR_GP_EEDO   ? "1" : "0");
37062306a36Sopenharmony_ci#endif
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
37362306a36Sopenharmony_ci	waitfor_idle(card);
37462306a36Sopenharmony_ci	writel(value, SAR_REG_GP);
37562306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic u8
37962306a36Sopenharmony_ciidt77252_eeprom_read_status(struct idt77252_dev *card)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	u8 byte;
38262306a36Sopenharmony_ci	u32 gp;
38362306a36Sopenharmony_ci	int i, j;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) {
38862306a36Sopenharmony_ci		idt77252_write_gp(card, gp | rdsrtab[i]);
38962306a36Sopenharmony_ci		udelay(5);
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
39262306a36Sopenharmony_ci	udelay(5);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	byte = 0;
39562306a36Sopenharmony_ci	for (i = 0, j = 0; i < 8; i++) {
39662306a36Sopenharmony_ci		byte <<= 1;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++]);
39962306a36Sopenharmony_ci		udelay(5);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++]);
40462306a36Sopenharmony_ci		udelay(5);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
40762306a36Sopenharmony_ci	udelay(5);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return byte;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic u8
41362306a36Sopenharmony_ciidt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	u8 byte;
41662306a36Sopenharmony_ci	u32 gp;
41762306a36Sopenharmony_ci	int i, j;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rdtab); i++) {
42262306a36Sopenharmony_ci		idt77252_write_gp(card, gp | rdtab[i]);
42362306a36Sopenharmony_ci		udelay(5);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
42662306a36Sopenharmony_ci	udelay(5);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	for (i = 0, j = 0; i < 8; i++) {
42962306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
43062306a36Sopenharmony_ci					(offset & 1 ? SAR_GP_EEDO : 0));
43162306a36Sopenharmony_ci		udelay(5);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
43462306a36Sopenharmony_ci					(offset & 1 ? SAR_GP_EEDO : 0));
43562306a36Sopenharmony_ci		udelay(5);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		offset >>= 1;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
44062306a36Sopenharmony_ci	udelay(5);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	byte = 0;
44362306a36Sopenharmony_ci	for (i = 0, j = 0; i < 8; i++) {
44462306a36Sopenharmony_ci		byte <<= 1;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++]);
44762306a36Sopenharmony_ci		udelay(5);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++]);
45262306a36Sopenharmony_ci		udelay(5);
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
45562306a36Sopenharmony_ci	udelay(5);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	return byte;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void
46162306a36Sopenharmony_ciidt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	u32 gp;
46462306a36Sopenharmony_ci	int i, j;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(wrentab); i++) {
46962306a36Sopenharmony_ci		idt77252_write_gp(card, gp | wrentab[i]);
47062306a36Sopenharmony_ci		udelay(5);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
47362306a36Sopenharmony_ci	udelay(5);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(wrtab); i++) {
47662306a36Sopenharmony_ci		idt77252_write_gp(card, gp | wrtab[i]);
47762306a36Sopenharmony_ci		udelay(5);
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
48062306a36Sopenharmony_ci	udelay(5);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	for (i = 0, j = 0; i < 8; i++) {
48362306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
48462306a36Sopenharmony_ci					(offset & 1 ? SAR_GP_EEDO : 0));
48562306a36Sopenharmony_ci		udelay(5);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
48862306a36Sopenharmony_ci					(offset & 1 ? SAR_GP_EEDO : 0));
48962306a36Sopenharmony_ci		udelay(5);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		offset >>= 1;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
49462306a36Sopenharmony_ci	udelay(5);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	for (i = 0, j = 0; i < 8; i++) {
49762306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
49862306a36Sopenharmony_ci					(data & 1 ? SAR_GP_EEDO : 0));
49962306a36Sopenharmony_ci		udelay(5);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		idt77252_write_gp(card, gp | clktab[j++] |
50262306a36Sopenharmony_ci					(data & 1 ? SAR_GP_EEDO : 0));
50362306a36Sopenharmony_ci		udelay(5);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		data >>= 1;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
50862306a36Sopenharmony_ci	udelay(5);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void
51262306a36Sopenharmony_ciidt77252_eeprom_init(struct idt77252_dev *card)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	u32 gp;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
51962306a36Sopenharmony_ci	udelay(5);
52062306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
52162306a36Sopenharmony_ci	udelay(5);
52262306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
52362306a36Sopenharmony_ci	udelay(5);
52462306a36Sopenharmony_ci	idt77252_write_gp(card, gp | SAR_GP_EECS);
52562306a36Sopenharmony_ci	udelay(5);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci#endif /* HAVE_EEPROM */
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
53162306a36Sopenharmony_cistatic void
53262306a36Sopenharmony_cidump_tct(struct idt77252_dev *card, int index)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	unsigned long tct;
53562306a36Sopenharmony_ci	int i;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	printk("%s: TCT %x:", card->name, index);
54062306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
54162306a36Sopenharmony_ci		printk(" %08x", read_sram(card, tct + i));
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci	printk("\n");
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic void
54762306a36Sopenharmony_ciidt77252_tx_dump(struct idt77252_dev *card)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct atm_vcc *vcc;
55062306a36Sopenharmony_ci	struct vc_map *vc;
55162306a36Sopenharmony_ci	int i;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	printk("%s\n", __func__);
55462306a36Sopenharmony_ci	for (i = 0; i < card->tct_size; i++) {
55562306a36Sopenharmony_ci		vc = card->vcs[i];
55662306a36Sopenharmony_ci		if (!vc)
55762306a36Sopenharmony_ci			continue;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		vcc = NULL;
56062306a36Sopenharmony_ci		if (vc->rx_vcc)
56162306a36Sopenharmony_ci			vcc = vc->rx_vcc;
56262306a36Sopenharmony_ci		else if (vc->tx_vcc)
56362306a36Sopenharmony_ci			vcc = vc->tx_vcc;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		if (!vcc)
56662306a36Sopenharmony_ci			continue;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		printk("%s: Connection %d:\n", card->name, vc->index);
56962306a36Sopenharmony_ci		dump_tct(card, vc->index);
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci#endif
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/*****************************************************************************/
57662306a36Sopenharmony_ci/*                                                                           */
57762306a36Sopenharmony_ci/* SCQ Handling                                                              */
57862306a36Sopenharmony_ci/*                                                                           */
57962306a36Sopenharmony_ci/*****************************************************************************/
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int
58262306a36Sopenharmony_cisb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct sb_pool *pool = &card->sbpool[queue];
58562306a36Sopenharmony_ci	int index;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	index = pool->index;
58862306a36Sopenharmony_ci	while (pool->skb[index]) {
58962306a36Sopenharmony_ci		index = (index + 1) & FBQ_MASK;
59062306a36Sopenharmony_ci		if (index == pool->index)
59162306a36Sopenharmony_ci			return -ENOBUFS;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	pool->skb[index] = skb;
59562306a36Sopenharmony_ci	IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	pool->index = (index + 1) & FBQ_MASK;
59862306a36Sopenharmony_ci	return 0;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void
60262306a36Sopenharmony_cisb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	unsigned int queue, index;
60562306a36Sopenharmony_ci	u32 handle;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	handle = IDT77252_PRV_POOL(skb);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	queue = POOL_QUEUE(handle);
61062306a36Sopenharmony_ci	if (queue > 3)
61162306a36Sopenharmony_ci		return;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	index = POOL_INDEX(handle);
61462306a36Sopenharmony_ci	if (index > FBQ_SIZE - 1)
61562306a36Sopenharmony_ci		return;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	card->sbpool[queue].skb[index] = NULL;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic struct sk_buff *
62162306a36Sopenharmony_cisb_pool_skb(struct idt77252_dev *card, u32 handle)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	unsigned int queue, index;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	queue = POOL_QUEUE(handle);
62662306a36Sopenharmony_ci	if (queue > 3)
62762306a36Sopenharmony_ci		return NULL;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	index = POOL_INDEX(handle);
63062306a36Sopenharmony_ci	if (index > FBQ_SIZE - 1)
63162306a36Sopenharmony_ci		return NULL;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return card->sbpool[queue].skb[index];
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic struct scq_info *
63762306a36Sopenharmony_cialloc_scq(struct idt77252_dev *card, int class)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct scq_info *scq;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL);
64262306a36Sopenharmony_ci	if (!scq)
64362306a36Sopenharmony_ci		return NULL;
64462306a36Sopenharmony_ci	scq->base = dma_alloc_coherent(&card->pcidev->dev, SCQ_SIZE,
64562306a36Sopenharmony_ci				       &scq->paddr, GFP_KERNEL);
64662306a36Sopenharmony_ci	if (scq->base == NULL) {
64762306a36Sopenharmony_ci		kfree(scq);
64862306a36Sopenharmony_ci		return NULL;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	scq->next = scq->base;
65262306a36Sopenharmony_ci	scq->last = scq->base + (SCQ_ENTRIES - 1);
65362306a36Sopenharmony_ci	atomic_set(&scq->used, 0);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	spin_lock_init(&scq->lock);
65662306a36Sopenharmony_ci	spin_lock_init(&scq->skblock);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	skb_queue_head_init(&scq->transmit);
65962306a36Sopenharmony_ci	skb_queue_head_init(&scq->pending);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08llx\n",
66262306a36Sopenharmony_ci		 scq->base, scq->next, scq->last, (unsigned long long)scq->paddr);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return scq;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void
66862306a36Sopenharmony_cifree_scq(struct idt77252_dev *card, struct scq_info *scq)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct sk_buff *skb;
67162306a36Sopenharmony_ci	struct atm_vcc *vcc;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	dma_free_coherent(&card->pcidev->dev, SCQ_SIZE,
67462306a36Sopenharmony_ci			  scq->base, scq->paddr);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	while ((skb = skb_dequeue(&scq->transmit))) {
67762306a36Sopenharmony_ci		dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
67862306a36Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		vcc = ATM_SKB(skb)->vcc;
68162306a36Sopenharmony_ci		if (vcc->pop)
68262306a36Sopenharmony_ci			vcc->pop(vcc, skb);
68362306a36Sopenharmony_ci		else
68462306a36Sopenharmony_ci			dev_kfree_skb(skb);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	while ((skb = skb_dequeue(&scq->pending))) {
68862306a36Sopenharmony_ci		dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
68962306a36Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		vcc = ATM_SKB(skb)->vcc;
69262306a36Sopenharmony_ci		if (vcc->pop)
69362306a36Sopenharmony_ci			vcc->pop(vcc, skb);
69462306a36Sopenharmony_ci		else
69562306a36Sopenharmony_ci			dev_kfree_skb(skb);
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	kfree(scq);
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int
70362306a36Sopenharmony_cipush_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct scq_info *scq = vc->scq;
70662306a36Sopenharmony_ci	unsigned long flags;
70762306a36Sopenharmony_ci	struct scqe *tbd;
70862306a36Sopenharmony_ci	int entries;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	atomic_inc(&scq->used);
71362306a36Sopenharmony_ci	entries = atomic_read(&scq->used);
71462306a36Sopenharmony_ci	if (entries > (SCQ_ENTRIES - 1)) {
71562306a36Sopenharmony_ci		atomic_dec(&scq->used);
71662306a36Sopenharmony_ci		goto out;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	skb_queue_tail(&scq->transmit, skb);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	spin_lock_irqsave(&vc->lock, flags);
72262306a36Sopenharmony_ci	if (vc->estimator) {
72362306a36Sopenharmony_ci		struct atm_vcc *vcc = vc->tx_vcc;
72462306a36Sopenharmony_ci		struct sock *sk = sk_atm(vcc);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		vc->estimator->cells += (skb->len + 47) / 48;
72762306a36Sopenharmony_ci		if (refcount_read(&sk->sk_wmem_alloc) >
72862306a36Sopenharmony_ci		    (sk->sk_sndbuf >> 1)) {
72962306a36Sopenharmony_ci			u32 cps = vc->estimator->maxcps;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci			vc->estimator->cps = cps;
73262306a36Sopenharmony_ci			vc->estimator->avcps = cps << 5;
73362306a36Sopenharmony_ci			if (vc->lacr < vc->init_er) {
73462306a36Sopenharmony_ci				vc->lacr = vc->init_er;
73562306a36Sopenharmony_ci				writel(TCMDQ_LACR | (vc->lacr << 16) |
73662306a36Sopenharmony_ci				       vc->index, SAR_REG_TCMDQ);
73762306a36Sopenharmony_ci			}
73862306a36Sopenharmony_ci		}
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	spin_unlock_irqrestore(&vc->lock, flags);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	tbd = &IDT77252_PRV_TBD(skb);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	spin_lock_irqsave(&scq->lock, flags);
74562306a36Sopenharmony_ci	scq->next->word_1 = cpu_to_le32(tbd->word_1 |
74662306a36Sopenharmony_ci					SAR_TBD_TSIF | SAR_TBD_GTSI);
74762306a36Sopenharmony_ci	scq->next->word_2 = cpu_to_le32(tbd->word_2);
74862306a36Sopenharmony_ci	scq->next->word_3 = cpu_to_le32(tbd->word_3);
74962306a36Sopenharmony_ci	scq->next->word_4 = cpu_to_le32(tbd->word_4);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (scq->next == scq->last)
75262306a36Sopenharmony_ci		scq->next = scq->base;
75362306a36Sopenharmony_ci	else
75462306a36Sopenharmony_ci		scq->next++;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	write_sram(card, scq->scd,
75762306a36Sopenharmony_ci		   scq->paddr +
75862306a36Sopenharmony_ci		   (u32)((unsigned long)scq->next - (unsigned long)scq->base));
75962306a36Sopenharmony_ci	spin_unlock_irqrestore(&scq->lock, flags);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	scq->trans_start = jiffies;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (test_and_clear_bit(VCF_IDLE, &vc->flags)) {
76462306a36Sopenharmony_ci		writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index,
76562306a36Sopenharmony_ci		       SAR_REG_TCMDQ);
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used));
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n",
77162306a36Sopenharmony_ci		card->name, atomic_read(&scq->used),
77262306a36Sopenharmony_ci		read_sram(card, scq->scd + 1), scq->next);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	return 0;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ciout:
77762306a36Sopenharmony_ci	if (time_after(jiffies, scq->trans_start + HZ)) {
77862306a36Sopenharmony_ci		printk("%s: Error pushing TBD for %d.%d\n",
77962306a36Sopenharmony_ci		       card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci);
78062306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
78162306a36Sopenharmony_ci		idt77252_tx_dump(card);
78262306a36Sopenharmony_ci#endif
78362306a36Sopenharmony_ci		scq->trans_start = jiffies;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return -ENOBUFS;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic void
79162306a36Sopenharmony_cidrain_scq(struct idt77252_dev *card, struct vc_map *vc)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	struct scq_info *scq = vc->scq;
79462306a36Sopenharmony_ci	struct sk_buff *skb;
79562306a36Sopenharmony_ci	struct atm_vcc *vcc;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n",
79862306a36Sopenharmony_ci		 card->name, atomic_read(&scq->used), scq->next);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	skb = skb_dequeue(&scq->transmit);
80162306a36Sopenharmony_ci	if (skb) {
80262306a36Sopenharmony_ci		TXPRINTK("%s: freeing skb at %p.\n", card->name, skb);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
80562306a36Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		vcc = ATM_SKB(skb)->vcc;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		if (vcc->pop)
81062306a36Sopenharmony_ci			vcc->pop(vcc, skb);
81162306a36Sopenharmony_ci		else
81262306a36Sopenharmony_ci			dev_kfree_skb(skb);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx);
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	atomic_dec(&scq->used);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	spin_lock(&scq->skblock);
82062306a36Sopenharmony_ci	while ((skb = skb_dequeue(&scq->pending))) {
82162306a36Sopenharmony_ci		if (push_on_scq(card, vc, skb)) {
82262306a36Sopenharmony_ci			skb_queue_head(&vc->scq->pending, skb);
82362306a36Sopenharmony_ci			break;
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci	spin_unlock(&scq->skblock);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic int
83062306a36Sopenharmony_ciqueue_skb(struct idt77252_dev *card, struct vc_map *vc,
83162306a36Sopenharmony_ci	  struct sk_buff *skb, int oam)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct atm_vcc *vcc;
83462306a36Sopenharmony_ci	struct scqe *tbd;
83562306a36Sopenharmony_ci	unsigned long flags;
83662306a36Sopenharmony_ci	int error;
83762306a36Sopenharmony_ci	int aal;
83862306a36Sopenharmony_ci	u32 word4;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (skb->len == 0) {
84162306a36Sopenharmony_ci		printk("%s: invalid skb->len (%d)\n", card->name, skb->len);
84262306a36Sopenharmony_ci		return -EINVAL;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	TXPRINTK("%s: Sending %d bytes of data.\n",
84662306a36Sopenharmony_ci		 card->name, skb->len);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	tbd = &IDT77252_PRV_TBD(skb);
84962306a36Sopenharmony_ci	vcc = ATM_SKB(skb)->vcc;
85062306a36Sopenharmony_ci	word4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
85162306a36Sopenharmony_ci			(skb->data[2] <<  8) | (skb->data[3] <<  0);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	IDT77252_PRV_PADDR(skb) = dma_map_single(&card->pcidev->dev, skb->data,
85462306a36Sopenharmony_ci						 skb->len, DMA_TO_DEVICE);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	error = -EINVAL;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if (oam) {
85962306a36Sopenharmony_ci		if (skb->len != 52)
86062306a36Sopenharmony_ci			goto errout;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci		tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU;
86362306a36Sopenharmony_ci		tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
86462306a36Sopenharmony_ci		tbd->word_3 = 0x00000000;
86562306a36Sopenharmony_ci		tbd->word_4 = word4;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		if (test_bit(VCF_RSV, &vc->flags))
86862306a36Sopenharmony_ci			vc = card->vcs[0];
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		goto done;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (test_bit(VCF_RSV, &vc->flags)) {
87462306a36Sopenharmony_ci		printk("%s: Trying to transmit on reserved VC\n", card->name);
87562306a36Sopenharmony_ci		goto errout;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	aal = vcc->qos.aal;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	switch (aal) {
88162306a36Sopenharmony_ci	case ATM_AAL0:
88262306a36Sopenharmony_ci	case ATM_AAL34:
88362306a36Sopenharmony_ci		if (skb->len > 52)
88462306a36Sopenharmony_ci			goto errout;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		if (aal == ATM_AAL0)
88762306a36Sopenharmony_ci			tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 |
88862306a36Sopenharmony_ci				      ATM_CELL_PAYLOAD;
88962306a36Sopenharmony_ci		else
89062306a36Sopenharmony_ci			tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 |
89162306a36Sopenharmony_ci				      ATM_CELL_PAYLOAD;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
89462306a36Sopenharmony_ci		tbd->word_3 = 0x00000000;
89562306a36Sopenharmony_ci		tbd->word_4 = word4;
89662306a36Sopenharmony_ci		break;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	case ATM_AAL5:
89962306a36Sopenharmony_ci		tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len;
90062306a36Sopenharmony_ci		tbd->word_2 = IDT77252_PRV_PADDR(skb);
90162306a36Sopenharmony_ci		tbd->word_3 = skb->len;
90262306a36Sopenharmony_ci		tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) |
90362306a36Sopenharmony_ci			      (vcc->vci << SAR_TBD_VCI_SHIFT);
90462306a36Sopenharmony_ci		break;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	case ATM_AAL1:
90762306a36Sopenharmony_ci	case ATM_AAL2:
90862306a36Sopenharmony_ci	default:
90962306a36Sopenharmony_ci		printk("%s: Traffic type not supported.\n", card->name);
91062306a36Sopenharmony_ci		error = -EPROTONOSUPPORT;
91162306a36Sopenharmony_ci		goto errout;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cidone:
91562306a36Sopenharmony_ci	spin_lock_irqsave(&vc->scq->skblock, flags);
91662306a36Sopenharmony_ci	skb_queue_tail(&vc->scq->pending, skb);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	while ((skb = skb_dequeue(&vc->scq->pending))) {
91962306a36Sopenharmony_ci		if (push_on_scq(card, vc, skb)) {
92062306a36Sopenharmony_ci			skb_queue_head(&vc->scq->pending, skb);
92162306a36Sopenharmony_ci			break;
92262306a36Sopenharmony_ci		}
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci	spin_unlock_irqrestore(&vc->scq->skblock, flags);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	return 0;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cierrout:
92962306a36Sopenharmony_ci	dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
93062306a36Sopenharmony_ci			 skb->len, DMA_TO_DEVICE);
93162306a36Sopenharmony_ci	return error;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic unsigned long
93562306a36Sopenharmony_ciget_free_scd(struct idt77252_dev *card, struct vc_map *vc)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	int i;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	for (i = 0; i < card->scd_size; i++) {
94062306a36Sopenharmony_ci		if (!card->scd2vc[i]) {
94162306a36Sopenharmony_ci			card->scd2vc[i] = vc;
94262306a36Sopenharmony_ci			vc->scd_index = i;
94362306a36Sopenharmony_ci			return card->scd_base + i * SAR_SRAM_SCD_SIZE;
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci	return 0;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void
95062306a36Sopenharmony_cifill_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	write_sram(card, scq->scd, scq->paddr);
95362306a36Sopenharmony_ci	write_sram(card, scq->scd + 1, 0x00000000);
95462306a36Sopenharmony_ci	write_sram(card, scq->scd + 2, 0xffffffff);
95562306a36Sopenharmony_ci	write_sram(card, scq->scd + 3, 0x00000000);
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic void
95962306a36Sopenharmony_ciclear_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	return;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci/*****************************************************************************/
96562306a36Sopenharmony_ci/*                                                                           */
96662306a36Sopenharmony_ci/* RSQ Handling                                                              */
96762306a36Sopenharmony_ci/*                                                                           */
96862306a36Sopenharmony_ci/*****************************************************************************/
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic int
97162306a36Sopenharmony_ciinit_rsq(struct idt77252_dev *card)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	struct rsq_entry *rsqe;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	card->rsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE,
97662306a36Sopenharmony_ci					    &card->rsq.paddr, GFP_KERNEL);
97762306a36Sopenharmony_ci	if (card->rsq.base == NULL) {
97862306a36Sopenharmony_ci		printk("%s: can't allocate RSQ.\n", card->name);
97962306a36Sopenharmony_ci		return -1;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1;
98362306a36Sopenharmony_ci	card->rsq.next = card->rsq.last;
98462306a36Sopenharmony_ci	for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++)
98562306a36Sopenharmony_ci		rsqe->word_4 = 0;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base,
98862306a36Sopenharmony_ci	       SAR_REG_RSQH);
98962306a36Sopenharmony_ci	writel(card->rsq.paddr, SAR_REG_RSQB);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name,
99262306a36Sopenharmony_ci		(unsigned long) card->rsq.base,
99362306a36Sopenharmony_ci		readl(SAR_REG_RSQB));
99462306a36Sopenharmony_ci	IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n",
99562306a36Sopenharmony_ci		card->name,
99662306a36Sopenharmony_ci		readl(SAR_REG_RSQH),
99762306a36Sopenharmony_ci		readl(SAR_REG_RSQB),
99862306a36Sopenharmony_ci		readl(SAR_REG_RSQT));
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic void
100462306a36Sopenharmony_cideinit_rsq(struct idt77252_dev *card)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	dma_free_coherent(&card->pcidev->dev, RSQSIZE,
100762306a36Sopenharmony_ci			  card->rsq.base, card->rsq.paddr);
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cistatic void
101162306a36Sopenharmony_cidequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct atm_vcc *vcc;
101462306a36Sopenharmony_ci	struct sk_buff *skb;
101562306a36Sopenharmony_ci	struct rx_pool *rpp;
101662306a36Sopenharmony_ci	struct vc_map *vc;
101762306a36Sopenharmony_ci	u32 header, vpi, vci;
101862306a36Sopenharmony_ci	u32 stat;
101962306a36Sopenharmony_ci	int i;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	stat = le32_to_cpu(rsqe->word_4);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (stat & SAR_RSQE_IDLE) {
102462306a36Sopenharmony_ci		RXPRINTK("%s: message about inactive connection.\n",
102562306a36Sopenharmony_ci			 card->name);
102662306a36Sopenharmony_ci		return;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2));
103062306a36Sopenharmony_ci	if (skb == NULL) {
103162306a36Sopenharmony_ci		printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n",
103262306a36Sopenharmony_ci		       card->name, __func__,
103362306a36Sopenharmony_ci		       le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2),
103462306a36Sopenharmony_ci		       le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4));
103562306a36Sopenharmony_ci		return;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	header = le32_to_cpu(rsqe->word_1);
103962306a36Sopenharmony_ci	vpi = (header >> 16) & 0x00ff;
104062306a36Sopenharmony_ci	vci = (header >>  0) & 0xffff;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n",
104362306a36Sopenharmony_ci		 card->name, vpi, vci, skb, skb->data);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) {
104662306a36Sopenharmony_ci		printk("%s: SDU received for out-of-range vc %u.%u\n",
104762306a36Sopenharmony_ci		       card->name, vpi, vci);
104862306a36Sopenharmony_ci		recycle_rx_skb(card, skb);
104962306a36Sopenharmony_ci		return;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	vc = card->vcs[VPCI2VC(card, vpi, vci)];
105362306a36Sopenharmony_ci	if (!vc || !test_bit(VCF_RX, &vc->flags)) {
105462306a36Sopenharmony_ci		printk("%s: SDU received on non RX vc %u.%u\n",
105562306a36Sopenharmony_ci		       card->name, vpi, vci);
105662306a36Sopenharmony_ci		recycle_rx_skb(card, skb);
105762306a36Sopenharmony_ci		return;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	vcc = vc->rx_vcc;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
106362306a36Sopenharmony_ci				skb_end_pointer(skb) - skb->data,
106462306a36Sopenharmony_ci				DMA_FROM_DEVICE);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if ((vcc->qos.aal == ATM_AAL0) ||
106762306a36Sopenharmony_ci	    (vcc->qos.aal == ATM_AAL34)) {
106862306a36Sopenharmony_ci		struct sk_buff *sb;
106962306a36Sopenharmony_ci		unsigned char *cell;
107062306a36Sopenharmony_ci		u32 aal0;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		cell = skb->data;
107362306a36Sopenharmony_ci		for (i = (stat & SAR_RSQE_CELLCNT); i; i--) {
107462306a36Sopenharmony_ci			if ((sb = dev_alloc_skb(64)) == NULL) {
107562306a36Sopenharmony_ci				printk("%s: Can't allocate buffers for aal0.\n",
107662306a36Sopenharmony_ci				       card->name);
107762306a36Sopenharmony_ci				atomic_add(i, &vcc->stats->rx_drop);
107862306a36Sopenharmony_ci				break;
107962306a36Sopenharmony_ci			}
108062306a36Sopenharmony_ci			if (!atm_charge(vcc, sb->truesize)) {
108162306a36Sopenharmony_ci				RXPRINTK("%s: atm_charge() dropped aal0 packets.\n",
108262306a36Sopenharmony_ci					 card->name);
108362306a36Sopenharmony_ci				atomic_add(i - 1, &vcc->stats->rx_drop);
108462306a36Sopenharmony_ci				dev_kfree_skb(sb);
108562306a36Sopenharmony_ci				break;
108662306a36Sopenharmony_ci			}
108762306a36Sopenharmony_ci			aal0 = (vpi << ATM_HDR_VPI_SHIFT) |
108862306a36Sopenharmony_ci			       (vci << ATM_HDR_VCI_SHIFT);
108962306a36Sopenharmony_ci			aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0;
109062306a36Sopenharmony_ci			aal0 |= (stat & SAR_RSQE_CLP)  ? 0x00000001 : 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci			*((u32 *) sb->data) = aal0;
109362306a36Sopenharmony_ci			skb_put(sb, sizeof(u32));
109462306a36Sopenharmony_ci			skb_put_data(sb, cell, ATM_CELL_PAYLOAD);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci			ATM_SKB(sb)->vcc = vcc;
109762306a36Sopenharmony_ci			__net_timestamp(sb);
109862306a36Sopenharmony_ci			vcc->push(vcc, sb);
109962306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci			cell += ATM_CELL_PAYLOAD;
110262306a36Sopenharmony_ci		}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci		recycle_rx_skb(card, skb);
110562306a36Sopenharmony_ci		return;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	if (vcc->qos.aal != ATM_AAL5) {
110862306a36Sopenharmony_ci		printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n",
110962306a36Sopenharmony_ci		       card->name, vcc->qos.aal);
111062306a36Sopenharmony_ci		recycle_rx_skb(card, skb);
111162306a36Sopenharmony_ci		return;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci	skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	rpp = &vc->rcv.rx_pool;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	__skb_queue_tail(&rpp->queue, skb);
111862306a36Sopenharmony_ci	rpp->len += skb->len;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (stat & SAR_RSQE_EPDU) {
112162306a36Sopenharmony_ci		unsigned char *l1l2;
112262306a36Sopenharmony_ci		unsigned int len;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci		l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		len = (l1l2[0] << 8) | l1l2[1];
112762306a36Sopenharmony_ci		len = len ? len : 0x10000;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		RXPRINTK("%s: PDU has %d bytes.\n", card->name, len);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci		if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) {
113262306a36Sopenharmony_ci			RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. "
113362306a36Sopenharmony_ci			         "(CDC: %08x)\n",
113462306a36Sopenharmony_ci			         card->name, len, rpp->len, readl(SAR_REG_CDC));
113562306a36Sopenharmony_ci			recycle_rx_pool_skb(card, rpp);
113662306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx_err);
113762306a36Sopenharmony_ci			return;
113862306a36Sopenharmony_ci		}
113962306a36Sopenharmony_ci		if (stat & SAR_RSQE_CRC) {
114062306a36Sopenharmony_ci			RXPRINTK("%s: AAL5 CRC error.\n", card->name);
114162306a36Sopenharmony_ci			recycle_rx_pool_skb(card, rpp);
114262306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx_err);
114362306a36Sopenharmony_ci			return;
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci		if (skb_queue_len(&rpp->queue) > 1) {
114662306a36Sopenharmony_ci			struct sk_buff *sb;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci			skb = dev_alloc_skb(rpp->len);
114962306a36Sopenharmony_ci			if (!skb) {
115062306a36Sopenharmony_ci				RXPRINTK("%s: Can't alloc RX skb.\n",
115162306a36Sopenharmony_ci					 card->name);
115262306a36Sopenharmony_ci				recycle_rx_pool_skb(card, rpp);
115362306a36Sopenharmony_ci				atomic_inc(&vcc->stats->rx_err);
115462306a36Sopenharmony_ci				return;
115562306a36Sopenharmony_ci			}
115662306a36Sopenharmony_ci			if (!atm_charge(vcc, skb->truesize)) {
115762306a36Sopenharmony_ci				recycle_rx_pool_skb(card, rpp);
115862306a36Sopenharmony_ci				dev_kfree_skb(skb);
115962306a36Sopenharmony_ci				return;
116062306a36Sopenharmony_ci			}
116162306a36Sopenharmony_ci			skb_queue_walk(&rpp->queue, sb)
116262306a36Sopenharmony_ci				skb_put_data(skb, sb->data, sb->len);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci			recycle_rx_pool_skb(card, rpp);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci			skb_trim(skb, len);
116762306a36Sopenharmony_ci			ATM_SKB(skb)->vcc = vcc;
116862306a36Sopenharmony_ci			__net_timestamp(skb);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci			vcc->push(vcc, skb);
117162306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci			return;
117462306a36Sopenharmony_ci		}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci		flush_rx_pool(card, rpp);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci		if (!atm_charge(vcc, skb->truesize)) {
117962306a36Sopenharmony_ci			recycle_rx_skb(card, skb);
118062306a36Sopenharmony_ci			return;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
118462306a36Sopenharmony_ci				 skb_end_pointer(skb) - skb->data,
118562306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
118662306a36Sopenharmony_ci		sb_pool_remove(card, skb);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		skb_trim(skb, len);
118962306a36Sopenharmony_ci		ATM_SKB(skb)->vcc = vcc;
119062306a36Sopenharmony_ci		__net_timestamp(skb);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		vcc->push(vcc, skb);
119362306a36Sopenharmony_ci		atomic_inc(&vcc->stats->rx);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci		if (skb->truesize > SAR_FB_SIZE_3)
119662306a36Sopenharmony_ci			add_rx_skb(card, 3, SAR_FB_SIZE_3, 1);
119762306a36Sopenharmony_ci		else if (skb->truesize > SAR_FB_SIZE_2)
119862306a36Sopenharmony_ci			add_rx_skb(card, 2, SAR_FB_SIZE_2, 1);
119962306a36Sopenharmony_ci		else if (skb->truesize > SAR_FB_SIZE_1)
120062306a36Sopenharmony_ci			add_rx_skb(card, 1, SAR_FB_SIZE_1, 1);
120162306a36Sopenharmony_ci		else
120262306a36Sopenharmony_ci			add_rx_skb(card, 0, SAR_FB_SIZE_0, 1);
120362306a36Sopenharmony_ci		return;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cistatic void
120862306a36Sopenharmony_ciidt77252_rx(struct idt77252_dev *card)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct rsq_entry *rsqe;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (card->rsq.next == card->rsq.last)
121362306a36Sopenharmony_ci		rsqe = card->rsq.base;
121462306a36Sopenharmony_ci	else
121562306a36Sopenharmony_ci		rsqe = card->rsq.next + 1;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (!(le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID)) {
121862306a36Sopenharmony_ci		RXPRINTK("%s: no entry in RSQ.\n", card->name);
121962306a36Sopenharmony_ci		return;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	do {
122362306a36Sopenharmony_ci		dequeue_rx(card, rsqe);
122462306a36Sopenharmony_ci		rsqe->word_4 = 0;
122562306a36Sopenharmony_ci		card->rsq.next = rsqe;
122662306a36Sopenharmony_ci		if (card->rsq.next == card->rsq.last)
122762306a36Sopenharmony_ci			rsqe = card->rsq.base;
122862306a36Sopenharmony_ci		else
122962306a36Sopenharmony_ci			rsqe = card->rsq.next + 1;
123062306a36Sopenharmony_ci	} while (le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	writel((unsigned long) card->rsq.next - (unsigned long) card->rsq.base,
123362306a36Sopenharmony_ci	       SAR_REG_RSQH);
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic void
123762306a36Sopenharmony_ciidt77252_rx_raw(struct idt77252_dev *card)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	struct sk_buff	*queue;
124062306a36Sopenharmony_ci	u32		head, tail;
124162306a36Sopenharmony_ci	struct atm_vcc	*vcc;
124262306a36Sopenharmony_ci	struct vc_map	*vc;
124362306a36Sopenharmony_ci	struct sk_buff	*sb;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (card->raw_cell_head == NULL) {
124662306a36Sopenharmony_ci		u32 handle = le32_to_cpu(*(card->raw_cell_hnd + 1));
124762306a36Sopenharmony_ci		card->raw_cell_head = sb_pool_skb(card, handle);
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	queue = card->raw_cell_head;
125162306a36Sopenharmony_ci	if (!queue)
125262306a36Sopenharmony_ci		return;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16);
125562306a36Sopenharmony_ci	tail = readl(SAR_REG_RAWCT);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(queue),
125862306a36Sopenharmony_ci				skb_end_offset(queue) - 16,
125962306a36Sopenharmony_ci				DMA_FROM_DEVICE);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	while (head != tail) {
126262306a36Sopenharmony_ci		unsigned int vpi, vci;
126362306a36Sopenharmony_ci		u32 header;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		header = le32_to_cpu(*(u32 *) &queue->data[0]);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
126862306a36Sopenharmony_ci		vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
127162306a36Sopenharmony_ci		if (debug & DBG_RAW_CELL) {
127262306a36Sopenharmony_ci			int i;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci			printk("%s: raw cell %x.%02x.%04x.%x.%x\n",
127562306a36Sopenharmony_ci			       card->name, (header >> 28) & 0x000f,
127662306a36Sopenharmony_ci			       (header >> 20) & 0x00ff,
127762306a36Sopenharmony_ci			       (header >>  4) & 0xffff,
127862306a36Sopenharmony_ci			       (header >>  1) & 0x0007,
127962306a36Sopenharmony_ci			       (header >>  0) & 0x0001);
128062306a36Sopenharmony_ci			for (i = 16; i < 64; i++)
128162306a36Sopenharmony_ci				printk(" %02x", queue->data[i]);
128262306a36Sopenharmony_ci			printk("\n");
128362306a36Sopenharmony_ci		}
128462306a36Sopenharmony_ci#endif
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci		if (vpi >= (1<<card->vpibits) || vci >= (1<<card->vcibits)) {
128762306a36Sopenharmony_ci			RPRINTK("%s: SDU received for out-of-range vc %u.%u\n",
128862306a36Sopenharmony_ci				card->name, vpi, vci);
128962306a36Sopenharmony_ci			goto drop;
129062306a36Sopenharmony_ci		}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci		vc = card->vcs[VPCI2VC(card, vpi, vci)];
129362306a36Sopenharmony_ci		if (!vc || !test_bit(VCF_RX, &vc->flags)) {
129462306a36Sopenharmony_ci			RPRINTK("%s: SDU received on non RX vc %u.%u\n",
129562306a36Sopenharmony_ci				card->name, vpi, vci);
129662306a36Sopenharmony_ci			goto drop;
129762306a36Sopenharmony_ci		}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci		vcc = vc->rx_vcc;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		if (vcc->qos.aal != ATM_AAL0) {
130262306a36Sopenharmony_ci			RPRINTK("%s: raw cell for non AAL0 vc %u.%u\n",
130362306a36Sopenharmony_ci				card->name, vpi, vci);
130462306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx_drop);
130562306a36Sopenharmony_ci			goto drop;
130662306a36Sopenharmony_ci		}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci		if ((sb = dev_alloc_skb(64)) == NULL) {
130962306a36Sopenharmony_ci			printk("%s: Can't allocate buffers for AAL0.\n",
131062306a36Sopenharmony_ci			       card->name);
131162306a36Sopenharmony_ci			atomic_inc(&vcc->stats->rx_err);
131262306a36Sopenharmony_ci			goto drop;
131362306a36Sopenharmony_ci		}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci		if (!atm_charge(vcc, sb->truesize)) {
131662306a36Sopenharmony_ci			RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n",
131762306a36Sopenharmony_ci				 card->name);
131862306a36Sopenharmony_ci			dev_kfree_skb(sb);
131962306a36Sopenharmony_ci			goto drop;
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		*((u32 *) sb->data) = header;
132362306a36Sopenharmony_ci		skb_put(sb, sizeof(u32));
132462306a36Sopenharmony_ci		skb_put_data(sb, &(queue->data[16]), ATM_CELL_PAYLOAD);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci		ATM_SKB(sb)->vcc = vcc;
132762306a36Sopenharmony_ci		__net_timestamp(sb);
132862306a36Sopenharmony_ci		vcc->push(vcc, sb);
132962306a36Sopenharmony_ci		atomic_inc(&vcc->stats->rx);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cidrop:
133262306a36Sopenharmony_ci		skb_pull(queue, 64);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		head = IDT77252_PRV_PADDR(queue)
133562306a36Sopenharmony_ci					+ (queue->data - queue->head - 16);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		if (queue->len < 128) {
133862306a36Sopenharmony_ci			struct sk_buff *next;
133962306a36Sopenharmony_ci			u32 handle;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci			head = le32_to_cpu(*(u32 *) &queue->data[0]);
134262306a36Sopenharmony_ci			handle = le32_to_cpu(*(u32 *) &queue->data[4]);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci			next = sb_pool_skb(card, handle);
134562306a36Sopenharmony_ci			recycle_rx_skb(card, queue);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci			if (next) {
134862306a36Sopenharmony_ci				card->raw_cell_head = next;
134962306a36Sopenharmony_ci				queue = card->raw_cell_head;
135062306a36Sopenharmony_ci				dma_sync_single_for_cpu(&card->pcidev->dev,
135162306a36Sopenharmony_ci							IDT77252_PRV_PADDR(queue),
135262306a36Sopenharmony_ci							(skb_end_pointer(queue) -
135362306a36Sopenharmony_ci							 queue->data),
135462306a36Sopenharmony_ci							DMA_FROM_DEVICE);
135562306a36Sopenharmony_ci			} else {
135662306a36Sopenharmony_ci				card->raw_cell_head = NULL;
135762306a36Sopenharmony_ci				printk("%s: raw cell queue overrun\n",
135862306a36Sopenharmony_ci				       card->name);
135962306a36Sopenharmony_ci				break;
136062306a36Sopenharmony_ci			}
136162306a36Sopenharmony_ci		}
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci/*****************************************************************************/
136762306a36Sopenharmony_ci/*                                                                           */
136862306a36Sopenharmony_ci/* TSQ Handling                                                              */
136962306a36Sopenharmony_ci/*                                                                           */
137062306a36Sopenharmony_ci/*****************************************************************************/
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cistatic int
137362306a36Sopenharmony_ciinit_tsq(struct idt77252_dev *card)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct tsq_entry *tsqe;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	card->tsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE,
137862306a36Sopenharmony_ci					    &card->tsq.paddr, GFP_KERNEL);
137962306a36Sopenharmony_ci	if (card->tsq.base == NULL) {
138062306a36Sopenharmony_ci		printk("%s: can't allocate TSQ.\n", card->name);
138162306a36Sopenharmony_ci		return -1;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1;
138562306a36Sopenharmony_ci	card->tsq.next = card->tsq.last;
138662306a36Sopenharmony_ci	for (tsqe = card->tsq.base; tsqe <= card->tsq.last; tsqe++)
138762306a36Sopenharmony_ci		tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	writel(card->tsq.paddr, SAR_REG_TSQB);
139062306a36Sopenharmony_ci	writel((unsigned long) card->tsq.next - (unsigned long) card->tsq.base,
139162306a36Sopenharmony_ci	       SAR_REG_TSQH);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	return 0;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic void
139762306a36Sopenharmony_cideinit_tsq(struct idt77252_dev *card)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	dma_free_coherent(&card->pcidev->dev, TSQSIZE,
140062306a36Sopenharmony_ci			  card->tsq.base, card->tsq.paddr);
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic void
140462306a36Sopenharmony_ciidt77252_tx(struct idt77252_dev *card)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci	struct tsq_entry *tsqe;
140762306a36Sopenharmony_ci	unsigned int vpi, vci;
140862306a36Sopenharmony_ci	struct vc_map *vc;
140962306a36Sopenharmony_ci	u32 conn, stat;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	if (card->tsq.next == card->tsq.last)
141262306a36Sopenharmony_ci		tsqe = card->tsq.base;
141362306a36Sopenharmony_ci	else
141462306a36Sopenharmony_ci		tsqe = card->tsq.next + 1;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	TXPRINTK("idt77252_tx: tsq  %p: base %p, next %p, last %p\n", tsqe,
141762306a36Sopenharmony_ci		 card->tsq.base, card->tsq.next, card->tsq.last);
141862306a36Sopenharmony_ci	TXPRINTK("idt77252_tx: tsqb %08x, tsqt %08x, tsqh %08x, \n",
141962306a36Sopenharmony_ci		 readl(SAR_REG_TSQB),
142062306a36Sopenharmony_ci		 readl(SAR_REG_TSQT),
142162306a36Sopenharmony_ci		 readl(SAR_REG_TSQH));
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	stat = le32_to_cpu(tsqe->word_2);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (stat & SAR_TSQE_INVALID)
142662306a36Sopenharmony_ci		return;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	do {
142962306a36Sopenharmony_ci		TXPRINTK("tsqe: 0x%p [0x%08x 0x%08x]\n", tsqe,
143062306a36Sopenharmony_ci			 le32_to_cpu(tsqe->word_1),
143162306a36Sopenharmony_ci			 le32_to_cpu(tsqe->word_2));
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		switch (stat & SAR_TSQE_TYPE) {
143462306a36Sopenharmony_ci		case SAR_TSQE_TYPE_TIMER:
143562306a36Sopenharmony_ci			TXPRINTK("%s: Timer RollOver detected.\n", card->name);
143662306a36Sopenharmony_ci			break;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci		case SAR_TSQE_TYPE_IDLE:
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci			conn = le32_to_cpu(tsqe->word_1);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci			if (SAR_TSQE_TAG(stat) == 0x10) {
144362306a36Sopenharmony_ci#ifdef	NOTDEF
144462306a36Sopenharmony_ci				printk("%s: Connection %d halted.\n",
144562306a36Sopenharmony_ci				       card->name,
144662306a36Sopenharmony_ci				       le32_to_cpu(tsqe->word_1) & 0x1fff);
144762306a36Sopenharmony_ci#endif
144862306a36Sopenharmony_ci				break;
144962306a36Sopenharmony_ci			}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci			vc = card->vcs[conn & 0x1fff];
145262306a36Sopenharmony_ci			if (!vc) {
145362306a36Sopenharmony_ci				printk("%s: could not find VC from conn %d\n",
145462306a36Sopenharmony_ci				       card->name, conn & 0x1fff);
145562306a36Sopenharmony_ci				break;
145662306a36Sopenharmony_ci			}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci			printk("%s: Connection %d IDLE.\n",
145962306a36Sopenharmony_ci			       card->name, vc->index);
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci			set_bit(VCF_IDLE, &vc->flags);
146262306a36Sopenharmony_ci			break;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci		case SAR_TSQE_TYPE_TSR:
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci			conn = le32_to_cpu(tsqe->word_1);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci			vc = card->vcs[conn & 0x1fff];
146962306a36Sopenharmony_ci			if (!vc) {
147062306a36Sopenharmony_ci				printk("%s: no VC at index %d\n",
147162306a36Sopenharmony_ci				       card->name,
147262306a36Sopenharmony_ci				       le32_to_cpu(tsqe->word_1) & 0x1fff);
147362306a36Sopenharmony_ci				break;
147462306a36Sopenharmony_ci			}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci			drain_scq(card, vc);
147762306a36Sopenharmony_ci			break;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		case SAR_TSQE_TYPE_TBD_COMP:
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci			conn = le32_to_cpu(tsqe->word_1);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci			vpi = (conn >> SAR_TBD_VPI_SHIFT) & 0x00ff;
148462306a36Sopenharmony_ci			vci = (conn >> SAR_TBD_VCI_SHIFT) & 0xffff;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci			if (vpi >= (1 << card->vpibits) ||
148762306a36Sopenharmony_ci			    vci >= (1 << card->vcibits)) {
148862306a36Sopenharmony_ci				printk("%s: TBD complete: "
148962306a36Sopenharmony_ci				       "out of range VPI.VCI %u.%u\n",
149062306a36Sopenharmony_ci				       card->name, vpi, vci);
149162306a36Sopenharmony_ci				break;
149262306a36Sopenharmony_ci			}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci			vc = card->vcs[VPCI2VC(card, vpi, vci)];
149562306a36Sopenharmony_ci			if (!vc) {
149662306a36Sopenharmony_ci				printk("%s: TBD complete: "
149762306a36Sopenharmony_ci				       "no VC at VPI.VCI %u.%u\n",
149862306a36Sopenharmony_ci				       card->name, vpi, vci);
149962306a36Sopenharmony_ci				break;
150062306a36Sopenharmony_ci			}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci			drain_scq(card, vc);
150362306a36Sopenharmony_ci			break;
150462306a36Sopenharmony_ci		}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci		tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		card->tsq.next = tsqe;
150962306a36Sopenharmony_ci		if (card->tsq.next == card->tsq.last)
151062306a36Sopenharmony_ci			tsqe = card->tsq.base;
151162306a36Sopenharmony_ci		else
151262306a36Sopenharmony_ci			tsqe = card->tsq.next + 1;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		TXPRINTK("tsqe: %p: base %p, next %p, last %p\n", tsqe,
151562306a36Sopenharmony_ci			 card->tsq.base, card->tsq.next, card->tsq.last);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci		stat = le32_to_cpu(tsqe->word_2);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	} while (!(stat & SAR_TSQE_INVALID));
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	writel((unsigned long)card->tsq.next - (unsigned long)card->tsq.base,
152262306a36Sopenharmony_ci	       SAR_REG_TSQH);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	XPRINTK("idt77252_tx-after writel%d: TSQ head = 0x%x, tail = 0x%x, next = 0x%p.\n",
152562306a36Sopenharmony_ci		card->index, readl(SAR_REG_TSQH),
152662306a36Sopenharmony_ci		readl(SAR_REG_TSQT), card->tsq.next);
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_cistatic void
153162306a36Sopenharmony_citst_timer(struct timer_list *t)
153262306a36Sopenharmony_ci{
153362306a36Sopenharmony_ci	struct idt77252_dev *card = from_timer(card, t, tst_timer);
153462306a36Sopenharmony_ci	unsigned long base, idle, jump;
153562306a36Sopenharmony_ci	unsigned long flags;
153662306a36Sopenharmony_ci	u32 pc;
153762306a36Sopenharmony_ci	int e;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	spin_lock_irqsave(&card->tst_lock, flags);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	base = card->tst[card->tst_index];
154262306a36Sopenharmony_ci	idle = card->tst[card->tst_index ^ 1];
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (test_bit(TST_SWITCH_WAIT, &card->tst_state)) {
154562306a36Sopenharmony_ci		jump = base + card->tst_size - 2;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		pc = readl(SAR_REG_NOW) >> 2;
154862306a36Sopenharmony_ci		if ((pc ^ idle) & ~(card->tst_size - 1)) {
154962306a36Sopenharmony_ci			mod_timer(&card->tst_timer, jiffies + 1);
155062306a36Sopenharmony_ci			goto out;
155162306a36Sopenharmony_ci		}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		clear_bit(TST_SWITCH_WAIT, &card->tst_state);
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci		card->tst_index ^= 1;
155662306a36Sopenharmony_ci		write_sram(card, jump, TSTE_OPC_JMP | (base << 2));
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci		base = card->tst[card->tst_index];
155962306a36Sopenharmony_ci		idle = card->tst[card->tst_index ^ 1];
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		for (e = 0; e < card->tst_size - 2; e++) {
156262306a36Sopenharmony_ci			if (card->soft_tst[e].tste & TSTE_PUSH_IDLE) {
156362306a36Sopenharmony_ci				write_sram(card, idle + e,
156462306a36Sopenharmony_ci					   card->soft_tst[e].tste & TSTE_MASK);
156562306a36Sopenharmony_ci				card->soft_tst[e].tste &= ~(TSTE_PUSH_IDLE);
156662306a36Sopenharmony_ci			}
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci	}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	if (test_and_clear_bit(TST_SWITCH_PENDING, &card->tst_state)) {
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		for (e = 0; e < card->tst_size - 2; e++) {
157362306a36Sopenharmony_ci			if (card->soft_tst[e].tste & TSTE_PUSH_ACTIVE) {
157462306a36Sopenharmony_ci				write_sram(card, idle + e,
157562306a36Sopenharmony_ci					   card->soft_tst[e].tste & TSTE_MASK);
157662306a36Sopenharmony_ci				card->soft_tst[e].tste &= ~(TSTE_PUSH_ACTIVE);
157762306a36Sopenharmony_ci				card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
157862306a36Sopenharmony_ci			}
157962306a36Sopenharmony_ci		}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci		jump = base + card->tst_size - 2;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci		write_sram(card, jump, TSTE_OPC_NULL);
158462306a36Sopenharmony_ci		set_bit(TST_SWITCH_WAIT, &card->tst_state);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		mod_timer(&card->tst_timer, jiffies + 1);
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ciout:
159062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->tst_lock, flags);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic int
159462306a36Sopenharmony_ci__fill_tst(struct idt77252_dev *card, struct vc_map *vc,
159562306a36Sopenharmony_ci	   int n, unsigned int opc)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	unsigned long cl, avail;
159862306a36Sopenharmony_ci	unsigned long idle;
159962306a36Sopenharmony_ci	int e, r;
160062306a36Sopenharmony_ci	u32 data;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	avail = card->tst_size - 2;
160362306a36Sopenharmony_ci	for (e = 0; e < avail; e++) {
160462306a36Sopenharmony_ci		if (card->soft_tst[e].vc == NULL)
160562306a36Sopenharmony_ci			break;
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci	if (e >= avail) {
160862306a36Sopenharmony_ci		printk("%s: No free TST entries found\n", card->name);
160962306a36Sopenharmony_ci		return -1;
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	NPRINTK("%s: conn %d: first TST entry at %d.\n",
161362306a36Sopenharmony_ci		card->name, vc ? vc->index : -1, e);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	r = n;
161662306a36Sopenharmony_ci	cl = avail;
161762306a36Sopenharmony_ci	data = opc & TSTE_OPC_MASK;
161862306a36Sopenharmony_ci	if (vc && (opc != TSTE_OPC_NULL))
161962306a36Sopenharmony_ci		data = opc | vc->index;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	idle = card->tst[card->tst_index ^ 1];
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	/*
162462306a36Sopenharmony_ci	 * Fill Soft TST.
162562306a36Sopenharmony_ci	 */
162662306a36Sopenharmony_ci	while (r > 0) {
162762306a36Sopenharmony_ci		if ((cl >= avail) && (card->soft_tst[e].vc == NULL)) {
162862306a36Sopenharmony_ci			if (vc)
162962306a36Sopenharmony_ci				card->soft_tst[e].vc = vc;
163062306a36Sopenharmony_ci			else
163162306a36Sopenharmony_ci				card->soft_tst[e].vc = (void *)-1;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci			card->soft_tst[e].tste = data;
163462306a36Sopenharmony_ci			if (timer_pending(&card->tst_timer))
163562306a36Sopenharmony_ci				card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
163662306a36Sopenharmony_ci			else {
163762306a36Sopenharmony_ci				write_sram(card, idle + e, data);
163862306a36Sopenharmony_ci				card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
163962306a36Sopenharmony_ci			}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci			cl -= card->tst_size;
164262306a36Sopenharmony_ci			r--;
164362306a36Sopenharmony_ci		}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		if (++e == avail)
164662306a36Sopenharmony_ci			e = 0;
164762306a36Sopenharmony_ci		cl += n;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	return 0;
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistatic int
165462306a36Sopenharmony_cifill_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	unsigned long flags;
165762306a36Sopenharmony_ci	int res;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	spin_lock_irqsave(&card->tst_lock, flags);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	res = __fill_tst(card, vc, n, opc);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	set_bit(TST_SWITCH_PENDING, &card->tst_state);
166462306a36Sopenharmony_ci	if (!timer_pending(&card->tst_timer))
166562306a36Sopenharmony_ci		mod_timer(&card->tst_timer, jiffies + 1);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->tst_lock, flags);
166862306a36Sopenharmony_ci	return res;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic int
167262306a36Sopenharmony_ci__clear_tst(struct idt77252_dev *card, struct vc_map *vc)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	unsigned long idle;
167562306a36Sopenharmony_ci	int e;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	idle = card->tst[card->tst_index ^ 1];
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	for (e = 0; e < card->tst_size - 2; e++) {
168062306a36Sopenharmony_ci		if (card->soft_tst[e].vc == vc) {
168162306a36Sopenharmony_ci			card->soft_tst[e].vc = NULL;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci			card->soft_tst[e].tste = TSTE_OPC_VAR;
168462306a36Sopenharmony_ci			if (timer_pending(&card->tst_timer))
168562306a36Sopenharmony_ci				card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
168662306a36Sopenharmony_ci			else {
168762306a36Sopenharmony_ci				write_sram(card, idle + e, TSTE_OPC_VAR);
168862306a36Sopenharmony_ci				card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
168962306a36Sopenharmony_ci			}
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	return 0;
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_cistatic int
169762306a36Sopenharmony_ciclear_tst(struct idt77252_dev *card, struct vc_map *vc)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	unsigned long flags;
170062306a36Sopenharmony_ci	int res;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	spin_lock_irqsave(&card->tst_lock, flags);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	res = __clear_tst(card, vc);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	set_bit(TST_SWITCH_PENDING, &card->tst_state);
170762306a36Sopenharmony_ci	if (!timer_pending(&card->tst_timer))
170862306a36Sopenharmony_ci		mod_timer(&card->tst_timer, jiffies + 1);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->tst_lock, flags);
171162306a36Sopenharmony_ci	return res;
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic int
171562306a36Sopenharmony_cichange_tst(struct idt77252_dev *card, struct vc_map *vc,
171662306a36Sopenharmony_ci	   int n, unsigned int opc)
171762306a36Sopenharmony_ci{
171862306a36Sopenharmony_ci	unsigned long flags;
171962306a36Sopenharmony_ci	int res;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	spin_lock_irqsave(&card->tst_lock, flags);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	__clear_tst(card, vc);
172462306a36Sopenharmony_ci	res = __fill_tst(card, vc, n, opc);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	set_bit(TST_SWITCH_PENDING, &card->tst_state);
172762306a36Sopenharmony_ci	if (!timer_pending(&card->tst_timer))
172862306a36Sopenharmony_ci		mod_timer(&card->tst_timer, jiffies + 1);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->tst_lock, flags);
173162306a36Sopenharmony_ci	return res;
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic int
173662306a36Sopenharmony_ciset_tct(struct idt77252_dev *card, struct vc_map *vc)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	unsigned long tct;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	switch (vc->class) {
174362306a36Sopenharmony_ci	case SCHED_CBR:
174462306a36Sopenharmony_ci		OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
174562306a36Sopenharmony_ci		        card->name, tct, vc->scq->scd);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci		write_sram(card, tct + 0, TCT_CBR | vc->scq->scd);
174862306a36Sopenharmony_ci		write_sram(card, tct + 1, 0);
174962306a36Sopenharmony_ci		write_sram(card, tct + 2, 0);
175062306a36Sopenharmony_ci		write_sram(card, tct + 3, 0);
175162306a36Sopenharmony_ci		write_sram(card, tct + 4, 0);
175262306a36Sopenharmony_ci		write_sram(card, tct + 5, 0);
175362306a36Sopenharmony_ci		write_sram(card, tct + 6, 0);
175462306a36Sopenharmony_ci		write_sram(card, tct + 7, 0);
175562306a36Sopenharmony_ci		break;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	case SCHED_UBR:
175862306a36Sopenharmony_ci		OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
175962306a36Sopenharmony_ci		        card->name, tct, vc->scq->scd);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci		write_sram(card, tct + 0, TCT_UBR | vc->scq->scd);
176262306a36Sopenharmony_ci		write_sram(card, tct + 1, 0);
176362306a36Sopenharmony_ci		write_sram(card, tct + 2, TCT_TSIF);
176462306a36Sopenharmony_ci		write_sram(card, tct + 3, TCT_HALT | TCT_IDLE);
176562306a36Sopenharmony_ci		write_sram(card, tct + 4, 0);
176662306a36Sopenharmony_ci		write_sram(card, tct + 5, vc->init_er);
176762306a36Sopenharmony_ci		write_sram(card, tct + 6, 0);
176862306a36Sopenharmony_ci		write_sram(card, tct + 7, TCT_FLAG_UBR);
176962306a36Sopenharmony_ci		break;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	case SCHED_VBR:
177262306a36Sopenharmony_ci	case SCHED_ABR:
177362306a36Sopenharmony_ci	default:
177462306a36Sopenharmony_ci		return -ENOSYS;
177562306a36Sopenharmony_ci	}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	return 0;
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci/*****************************************************************************/
178162306a36Sopenharmony_ci/*                                                                           */
178262306a36Sopenharmony_ci/* FBQ Handling                                                              */
178362306a36Sopenharmony_ci/*                                                                           */
178462306a36Sopenharmony_ci/*****************************************************************************/
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic __inline__ int
178762306a36Sopenharmony_ciidt77252_fbq_full(struct idt77252_dev *card, int queue)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f;
179062306a36Sopenharmony_ci}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_cistatic int
179362306a36Sopenharmony_cipush_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue)
179462306a36Sopenharmony_ci{
179562306a36Sopenharmony_ci	unsigned long flags;
179662306a36Sopenharmony_ci	u32 handle;
179762306a36Sopenharmony_ci	u32 addr;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	skb->data = skb->head;
180062306a36Sopenharmony_ci	skb_reset_tail_pointer(skb);
180162306a36Sopenharmony_ci	skb->len = 0;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	skb_reserve(skb, 16);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	switch (queue) {
180662306a36Sopenharmony_ci	case 0:
180762306a36Sopenharmony_ci		skb_put(skb, SAR_FB_SIZE_0);
180862306a36Sopenharmony_ci		break;
180962306a36Sopenharmony_ci	case 1:
181062306a36Sopenharmony_ci		skb_put(skb, SAR_FB_SIZE_1);
181162306a36Sopenharmony_ci		break;
181262306a36Sopenharmony_ci	case 2:
181362306a36Sopenharmony_ci		skb_put(skb, SAR_FB_SIZE_2);
181462306a36Sopenharmony_ci		break;
181562306a36Sopenharmony_ci	case 3:
181662306a36Sopenharmony_ci		skb_put(skb, SAR_FB_SIZE_3);
181762306a36Sopenharmony_ci		break;
181862306a36Sopenharmony_ci	default:
181962306a36Sopenharmony_ci		return -1;
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	if (idt77252_fbq_full(card, queue))
182362306a36Sopenharmony_ci		return -1;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32));
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	handle = IDT77252_PRV_POOL(skb);
182862306a36Sopenharmony_ci	addr = IDT77252_PRV_PADDR(skb);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
183162306a36Sopenharmony_ci	writel(handle, card->fbq[queue]);
183262306a36Sopenharmony_ci	writel(addr, card->fbq[queue]);
183362306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	return 0;
183662306a36Sopenharmony_ci}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic void
183962306a36Sopenharmony_ciadd_rx_skb(struct idt77252_dev *card, int queue,
184062306a36Sopenharmony_ci	   unsigned int size, unsigned int count)
184162306a36Sopenharmony_ci{
184262306a36Sopenharmony_ci	struct sk_buff *skb;
184362306a36Sopenharmony_ci	dma_addr_t paddr;
184462306a36Sopenharmony_ci	u32 handle;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	while (count--) {
184762306a36Sopenharmony_ci		skb = dev_alloc_skb(size);
184862306a36Sopenharmony_ci		if (!skb)
184962306a36Sopenharmony_ci			return;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci		if (sb_pool_add(card, skb, queue)) {
185262306a36Sopenharmony_ci			printk("%s: SB POOL full\n", __func__);
185362306a36Sopenharmony_ci			goto outfree;
185462306a36Sopenharmony_ci		}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		paddr = dma_map_single(&card->pcidev->dev, skb->data,
185762306a36Sopenharmony_ci				       skb_end_pointer(skb) - skb->data,
185862306a36Sopenharmony_ci				       DMA_FROM_DEVICE);
185962306a36Sopenharmony_ci		IDT77252_PRV_PADDR(skb) = paddr;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci		if (push_rx_skb(card, skb, queue)) {
186262306a36Sopenharmony_ci			printk("%s: FB QUEUE full\n", __func__);
186362306a36Sopenharmony_ci			goto outunmap;
186462306a36Sopenharmony_ci		}
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	return;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_cioutunmap:
187062306a36Sopenharmony_ci	dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
187162306a36Sopenharmony_ci			 skb_end_pointer(skb) - skb->data, DMA_FROM_DEVICE);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	handle = IDT77252_PRV_POOL(skb);
187462306a36Sopenharmony_ci	card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_cioutfree:
187762306a36Sopenharmony_ci	dev_kfree_skb(skb);
187862306a36Sopenharmony_ci}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_cistatic void
188262306a36Sopenharmony_cirecycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb)
188362306a36Sopenharmony_ci{
188462306a36Sopenharmony_ci	u32 handle = IDT77252_PRV_POOL(skb);
188562306a36Sopenharmony_ci	int err;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	dma_sync_single_for_device(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
188862306a36Sopenharmony_ci				   skb_end_pointer(skb) - skb->data,
188962306a36Sopenharmony_ci				   DMA_FROM_DEVICE);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	err = push_rx_skb(card, skb, POOL_QUEUE(handle));
189262306a36Sopenharmony_ci	if (err) {
189362306a36Sopenharmony_ci		dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
189462306a36Sopenharmony_ci				 skb_end_pointer(skb) - skb->data,
189562306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
189662306a36Sopenharmony_ci		sb_pool_remove(card, skb);
189762306a36Sopenharmony_ci		dev_kfree_skb(skb);
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic void
190262306a36Sopenharmony_ciflush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	skb_queue_head_init(&rpp->queue);
190562306a36Sopenharmony_ci	rpp->len = 0;
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_cistatic void
190962306a36Sopenharmony_cirecycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	struct sk_buff *skb, *tmp;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	skb_queue_walk_safe(&rpp->queue, skb, tmp)
191462306a36Sopenharmony_ci		recycle_rx_skb(card, skb);
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	flush_rx_pool(card, rpp);
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci/*****************************************************************************/
192062306a36Sopenharmony_ci/*                                                                           */
192162306a36Sopenharmony_ci/* ATM Interface                                                             */
192262306a36Sopenharmony_ci/*                                                                           */
192362306a36Sopenharmony_ci/*****************************************************************************/
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_cistatic void
192662306a36Sopenharmony_ciidt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value);
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic unsigned char
193262306a36Sopenharmony_ciidt77252_phy_get(struct atm_dev *dev, unsigned long addr)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff));
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic inline int
193862306a36Sopenharmony_ciidt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam)
193962306a36Sopenharmony_ci{
194062306a36Sopenharmony_ci	struct atm_dev *dev = vcc->dev;
194162306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
194262306a36Sopenharmony_ci	struct vc_map *vc = vcc->dev_data;
194362306a36Sopenharmony_ci	int err;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	if (vc == NULL) {
194662306a36Sopenharmony_ci		printk("%s: NULL connection in send().\n", card->name);
194762306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
194862306a36Sopenharmony_ci		dev_kfree_skb(skb);
194962306a36Sopenharmony_ci		return -EINVAL;
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci	if (!test_bit(VCF_TX, &vc->flags)) {
195262306a36Sopenharmony_ci		printk("%s: Trying to transmit on a non-tx VC.\n", card->name);
195362306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
195462306a36Sopenharmony_ci		dev_kfree_skb(skb);
195562306a36Sopenharmony_ci		return -EINVAL;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	switch (vcc->qos.aal) {
195962306a36Sopenharmony_ci	case ATM_AAL0:
196062306a36Sopenharmony_ci	case ATM_AAL1:
196162306a36Sopenharmony_ci	case ATM_AAL5:
196262306a36Sopenharmony_ci		break;
196362306a36Sopenharmony_ci	default:
196462306a36Sopenharmony_ci		printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal);
196562306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
196662306a36Sopenharmony_ci		dev_kfree_skb(skb);
196762306a36Sopenharmony_ci		return -EINVAL;
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (skb_shinfo(skb)->nr_frags != 0) {
197162306a36Sopenharmony_ci		printk("%s: No scatter-gather yet.\n", card->name);
197262306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
197362306a36Sopenharmony_ci		dev_kfree_skb(skb);
197462306a36Sopenharmony_ci		return -EINVAL;
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci	ATM_SKB(skb)->vcc = vcc;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	err = queue_skb(card, vc, skb, oam);
197962306a36Sopenharmony_ci	if (err) {
198062306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
198162306a36Sopenharmony_ci		dev_kfree_skb(skb);
198262306a36Sopenharmony_ci		return err;
198362306a36Sopenharmony_ci	}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	return 0;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb)
198962306a36Sopenharmony_ci{
199062306a36Sopenharmony_ci	return idt77252_send_skb(vcc, skb, 0);
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_cistatic int
199462306a36Sopenharmony_ciidt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	struct atm_dev *dev = vcc->dev;
199762306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
199862306a36Sopenharmony_ci	struct sk_buff *skb;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	skb = dev_alloc_skb(64);
200162306a36Sopenharmony_ci	if (!skb) {
200262306a36Sopenharmony_ci		printk("%s: Out of memory in send_oam().\n", card->name);
200362306a36Sopenharmony_ci		atomic_inc(&vcc->stats->tx_err);
200462306a36Sopenharmony_ci		return -ENOMEM;
200562306a36Sopenharmony_ci	}
200662306a36Sopenharmony_ci	refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	skb_put_data(skb, cell, 52);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	return idt77252_send_skb(vcc, skb, 1);
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic __inline__ unsigned int
201462306a36Sopenharmony_ciidt77252_fls(unsigned int x)
201562306a36Sopenharmony_ci{
201662306a36Sopenharmony_ci	int r = 1;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	if (x == 0)
201962306a36Sopenharmony_ci		return 0;
202062306a36Sopenharmony_ci	if (x & 0xffff0000) {
202162306a36Sopenharmony_ci		x >>= 16;
202262306a36Sopenharmony_ci		r += 16;
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci	if (x & 0xff00) {
202562306a36Sopenharmony_ci		x >>= 8;
202662306a36Sopenharmony_ci		r += 8;
202762306a36Sopenharmony_ci	}
202862306a36Sopenharmony_ci	if (x & 0xf0) {
202962306a36Sopenharmony_ci		x >>= 4;
203062306a36Sopenharmony_ci		r += 4;
203162306a36Sopenharmony_ci	}
203262306a36Sopenharmony_ci	if (x & 0xc) {
203362306a36Sopenharmony_ci		x >>= 2;
203462306a36Sopenharmony_ci		r += 2;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci	if (x & 0x2)
203762306a36Sopenharmony_ci		r += 1;
203862306a36Sopenharmony_ci	return r;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic u16
204262306a36Sopenharmony_ciidt77252_int_to_atmfp(unsigned int rate)
204362306a36Sopenharmony_ci{
204462306a36Sopenharmony_ci	u16 m, e;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	if (rate == 0)
204762306a36Sopenharmony_ci		return 0;
204862306a36Sopenharmony_ci	e = idt77252_fls(rate) - 1;
204962306a36Sopenharmony_ci	if (e < 9)
205062306a36Sopenharmony_ci		m = (rate - (1 << e)) << (9 - e);
205162306a36Sopenharmony_ci	else if (e == 9)
205262306a36Sopenharmony_ci		m = (rate - (1 << e));
205362306a36Sopenharmony_ci	else /* e > 9 */
205462306a36Sopenharmony_ci		m = (rate - (1 << e)) >> (e - 9);
205562306a36Sopenharmony_ci	return 0x4000 | (e << 9) | m;
205662306a36Sopenharmony_ci}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_cistatic u8
205962306a36Sopenharmony_ciidt77252_rate_logindex(struct idt77252_dev *card, int pcr)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	u16 afp;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr);
206462306a36Sopenharmony_ci	if (pcr < 0)
206562306a36Sopenharmony_ci		return rate_to_log[(afp >> 5) & 0x1ff];
206662306a36Sopenharmony_ci	return rate_to_log[((afp >> 5) + 1) & 0x1ff];
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic void
207062306a36Sopenharmony_ciidt77252_est_timer(struct timer_list *t)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct rate_estimator *est = from_timer(est, t, timer);
207362306a36Sopenharmony_ci	struct vc_map *vc = est->vc;
207462306a36Sopenharmony_ci	struct idt77252_dev *card = vc->card;
207562306a36Sopenharmony_ci	unsigned long flags;
207662306a36Sopenharmony_ci	u32 rate, cps;
207762306a36Sopenharmony_ci	u64 ncells;
207862306a36Sopenharmony_ci	u8 lacr;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	spin_lock_irqsave(&vc->lock, flags);
208162306a36Sopenharmony_ci	if (!vc->estimator)
208262306a36Sopenharmony_ci		goto out;
208362306a36Sopenharmony_ci	ncells = est->cells;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval);
208662306a36Sopenharmony_ci	est->last_cells = ncells;
208762306a36Sopenharmony_ci	est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log;
208862306a36Sopenharmony_ci	est->cps = (est->avcps + 0x1f) >> 5;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	cps = est->cps;
209162306a36Sopenharmony_ci	if (cps < (est->maxcps >> 4))
209262306a36Sopenharmony_ci		cps = est->maxcps >> 4;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	lacr = idt77252_rate_logindex(card, cps);
209562306a36Sopenharmony_ci	if (lacr > vc->max_er)
209662306a36Sopenharmony_ci		lacr = vc->max_er;
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	if (lacr != vc->lacr) {
209962306a36Sopenharmony_ci		vc->lacr = lacr;
210062306a36Sopenharmony_ci		writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ);
210162306a36Sopenharmony_ci	}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	est->timer.expires = jiffies + ((HZ / 4) << est->interval);
210462306a36Sopenharmony_ci	add_timer(&est->timer);
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ciout:
210762306a36Sopenharmony_ci	spin_unlock_irqrestore(&vc->lock, flags);
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_cistatic struct rate_estimator *
211162306a36Sopenharmony_ciidt77252_init_est(struct vc_map *vc, int pcr)
211262306a36Sopenharmony_ci{
211362306a36Sopenharmony_ci	struct rate_estimator *est;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	est = kzalloc(sizeof(struct rate_estimator), GFP_KERNEL);
211662306a36Sopenharmony_ci	if (!est)
211762306a36Sopenharmony_ci		return NULL;
211862306a36Sopenharmony_ci	est->maxcps = pcr < 0 ? -pcr : pcr;
211962306a36Sopenharmony_ci	est->cps = est->maxcps;
212062306a36Sopenharmony_ci	est->avcps = est->cps << 5;
212162306a36Sopenharmony_ci	est->vc = vc;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	est->interval = 2;		/* XXX: make this configurable */
212462306a36Sopenharmony_ci	est->ewma_log = 2;		/* XXX: make this configurable */
212562306a36Sopenharmony_ci	timer_setup(&est->timer, idt77252_est_timer, 0);
212662306a36Sopenharmony_ci	mod_timer(&est->timer, jiffies + ((HZ / 4) << est->interval));
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	return est;
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic int
213262306a36Sopenharmony_ciidt77252_init_cbr(struct idt77252_dev *card, struct vc_map *vc,
213362306a36Sopenharmony_ci		  struct atm_vcc *vcc, struct atm_qos *qos)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci	int tst_free, tst_used, tst_entries;
213662306a36Sopenharmony_ci	unsigned long tmpl, modl;
213762306a36Sopenharmony_ci	int tcr, tcra;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	if ((qos->txtp.max_pcr == 0) &&
214062306a36Sopenharmony_ci	    (qos->txtp.pcr == 0) && (qos->txtp.min_pcr == 0)) {
214162306a36Sopenharmony_ci		printk("%s: trying to open a CBR VC with cell rate = 0\n",
214262306a36Sopenharmony_ci		       card->name);
214362306a36Sopenharmony_ci		return -EINVAL;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	tst_used = 0;
214762306a36Sopenharmony_ci	tst_free = card->tst_free;
214862306a36Sopenharmony_ci	if (test_bit(VCF_TX, &vc->flags))
214962306a36Sopenharmony_ci		tst_used = vc->ntste;
215062306a36Sopenharmony_ci	tst_free += tst_used;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	tcr = atm_pcr_goal(&qos->txtp);
215362306a36Sopenharmony_ci	tcra = tcr >= 0 ? tcr : -tcr;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	TXPRINTK("%s: CBR target cell rate = %d\n", card->name, tcra);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	tmpl = (unsigned long) tcra * ((unsigned long) card->tst_size - 2);
215862306a36Sopenharmony_ci	modl = tmpl % (unsigned long)card->utopia_pcr;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	tst_entries = (int) (tmpl / card->utopia_pcr);
216162306a36Sopenharmony_ci	if (tcr > 0) {
216262306a36Sopenharmony_ci		if (modl > 0)
216362306a36Sopenharmony_ci			tst_entries++;
216462306a36Sopenharmony_ci	} else if (tcr == 0) {
216562306a36Sopenharmony_ci		tst_entries = tst_free - SAR_TST_RESERVED;
216662306a36Sopenharmony_ci		if (tst_entries <= 0) {
216762306a36Sopenharmony_ci			printk("%s: no CBR bandwidth free.\n", card->name);
216862306a36Sopenharmony_ci			return -ENOSR;
216962306a36Sopenharmony_ci		}
217062306a36Sopenharmony_ci	}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	if (tst_entries == 0) {
217362306a36Sopenharmony_ci		printk("%s: selected CBR bandwidth < granularity.\n",
217462306a36Sopenharmony_ci		       card->name);
217562306a36Sopenharmony_ci		return -EINVAL;
217662306a36Sopenharmony_ci	}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	if (tst_entries > (tst_free - SAR_TST_RESERVED)) {
217962306a36Sopenharmony_ci		printk("%s: not enough CBR bandwidth free.\n", card->name);
218062306a36Sopenharmony_ci		return -ENOSR;
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	vc->ntste = tst_entries;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	card->tst_free = tst_free - tst_entries;
218662306a36Sopenharmony_ci	if (test_bit(VCF_TX, &vc->flags)) {
218762306a36Sopenharmony_ci		if (tst_used == tst_entries)
218862306a36Sopenharmony_ci			return 0;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci		OPRINTK("%s: modify %d -> %d entries in TST.\n",
219162306a36Sopenharmony_ci			card->name, tst_used, tst_entries);
219262306a36Sopenharmony_ci		change_tst(card, vc, tst_entries, TSTE_OPC_CBR);
219362306a36Sopenharmony_ci		return 0;
219462306a36Sopenharmony_ci	}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	OPRINTK("%s: setting %d entries in TST.\n", card->name, tst_entries);
219762306a36Sopenharmony_ci	fill_tst(card, vc, tst_entries, TSTE_OPC_CBR);
219862306a36Sopenharmony_ci	return 0;
219962306a36Sopenharmony_ci}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_cistatic int
220262306a36Sopenharmony_ciidt77252_init_ubr(struct idt77252_dev *card, struct vc_map *vc,
220362306a36Sopenharmony_ci		  struct atm_vcc *vcc, struct atm_qos *qos)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct rate_estimator *est = NULL;
220662306a36Sopenharmony_ci	unsigned long flags;
220762306a36Sopenharmony_ci	int tcr;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	spin_lock_irqsave(&vc->lock, flags);
221062306a36Sopenharmony_ci	if (vc->estimator) {
221162306a36Sopenharmony_ci		est = vc->estimator;
221262306a36Sopenharmony_ci		vc->estimator = NULL;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci	spin_unlock_irqrestore(&vc->lock, flags);
221562306a36Sopenharmony_ci	if (est) {
221662306a36Sopenharmony_ci		timer_shutdown_sync(&est->timer);
221762306a36Sopenharmony_ci		kfree(est);
221862306a36Sopenharmony_ci	}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	tcr = atm_pcr_goal(&qos->txtp);
222162306a36Sopenharmony_ci	if (tcr == 0)
222262306a36Sopenharmony_ci		tcr = card->link_pcr;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	vc->estimator = idt77252_init_est(vc, tcr);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	vc->class = SCHED_UBR;
222762306a36Sopenharmony_ci	vc->init_er = idt77252_rate_logindex(card, tcr);
222862306a36Sopenharmony_ci	vc->lacr = vc->init_er;
222962306a36Sopenharmony_ci	if (tcr < 0)
223062306a36Sopenharmony_ci		vc->max_er = vc->init_er;
223162306a36Sopenharmony_ci	else
223262306a36Sopenharmony_ci		vc->max_er = 0xff;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	return 0;
223562306a36Sopenharmony_ci}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_cistatic int
223862306a36Sopenharmony_ciidt77252_init_tx(struct idt77252_dev *card, struct vc_map *vc,
223962306a36Sopenharmony_ci		 struct atm_vcc *vcc, struct atm_qos *qos)
224062306a36Sopenharmony_ci{
224162306a36Sopenharmony_ci	int error;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (test_bit(VCF_TX, &vc->flags))
224462306a36Sopenharmony_ci		return -EBUSY;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	switch (qos->txtp.traffic_class) {
224762306a36Sopenharmony_ci		case ATM_CBR:
224862306a36Sopenharmony_ci			vc->class = SCHED_CBR;
224962306a36Sopenharmony_ci			break;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci		case ATM_UBR:
225262306a36Sopenharmony_ci			vc->class = SCHED_UBR;
225362306a36Sopenharmony_ci			break;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		case ATM_VBR:
225662306a36Sopenharmony_ci		case ATM_ABR:
225762306a36Sopenharmony_ci		default:
225862306a36Sopenharmony_ci			return -EPROTONOSUPPORT;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	vc->scq = alloc_scq(card, vc->class);
226262306a36Sopenharmony_ci	if (!vc->scq) {
226362306a36Sopenharmony_ci		printk("%s: can't get SCQ.\n", card->name);
226462306a36Sopenharmony_ci		return -ENOMEM;
226562306a36Sopenharmony_ci	}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	vc->scq->scd = get_free_scd(card, vc);
226862306a36Sopenharmony_ci	if (vc->scq->scd == 0) {
226962306a36Sopenharmony_ci		printk("%s: no SCD available.\n", card->name);
227062306a36Sopenharmony_ci		free_scq(card, vc->scq);
227162306a36Sopenharmony_ci		return -ENOMEM;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	fill_scd(card, vc->scq, vc->class);
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	if (set_tct(card, vc)) {
227762306a36Sopenharmony_ci		printk("%s: class %d not supported.\n",
227862306a36Sopenharmony_ci		       card->name, qos->txtp.traffic_class);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		card->scd2vc[vc->scd_index] = NULL;
228162306a36Sopenharmony_ci		free_scq(card, vc->scq);
228262306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
228362306a36Sopenharmony_ci	}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	switch (vc->class) {
228662306a36Sopenharmony_ci		case SCHED_CBR:
228762306a36Sopenharmony_ci			error = idt77252_init_cbr(card, vc, vcc, qos);
228862306a36Sopenharmony_ci			if (error) {
228962306a36Sopenharmony_ci				card->scd2vc[vc->scd_index] = NULL;
229062306a36Sopenharmony_ci				free_scq(card, vc->scq);
229162306a36Sopenharmony_ci				return error;
229262306a36Sopenharmony_ci			}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci			clear_bit(VCF_IDLE, &vc->flags);
229562306a36Sopenharmony_ci			writel(TCMDQ_START | vc->index, SAR_REG_TCMDQ);
229662306a36Sopenharmony_ci			break;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		case SCHED_UBR:
229962306a36Sopenharmony_ci			error = idt77252_init_ubr(card, vc, vcc, qos);
230062306a36Sopenharmony_ci			if (error) {
230162306a36Sopenharmony_ci				card->scd2vc[vc->scd_index] = NULL;
230262306a36Sopenharmony_ci				free_scq(card, vc->scq);
230362306a36Sopenharmony_ci				return error;
230462306a36Sopenharmony_ci			}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci			set_bit(VCF_IDLE, &vc->flags);
230762306a36Sopenharmony_ci			break;
230862306a36Sopenharmony_ci	}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	vc->tx_vcc = vcc;
231162306a36Sopenharmony_ci	set_bit(VCF_TX, &vc->flags);
231262306a36Sopenharmony_ci	return 0;
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_cistatic int
231662306a36Sopenharmony_ciidt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc,
231762306a36Sopenharmony_ci		 struct atm_vcc *vcc, struct atm_qos *qos)
231862306a36Sopenharmony_ci{
231962306a36Sopenharmony_ci	unsigned long flags;
232062306a36Sopenharmony_ci	unsigned long addr;
232162306a36Sopenharmony_ci	u32 rcte = 0;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	if (test_bit(VCF_RX, &vc->flags))
232462306a36Sopenharmony_ci		return -EBUSY;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	vc->rx_vcc = vcc;
232762306a36Sopenharmony_ci	set_bit(VCF_RX, &vc->flags);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	if ((vcc->vci == 3) || (vcc->vci == 4))
233062306a36Sopenharmony_ci		return 0;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	flush_rx_pool(card, &vc->rcv.rx_pool);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	rcte |= SAR_RCTE_CONNECTOPEN;
233562306a36Sopenharmony_ci	rcte |= SAR_RCTE_RAWCELLINTEN;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	switch (qos->aal) {
233862306a36Sopenharmony_ci		case ATM_AAL0:
233962306a36Sopenharmony_ci			rcte |= SAR_RCTE_RCQ;
234062306a36Sopenharmony_ci			break;
234162306a36Sopenharmony_ci		case ATM_AAL1:
234262306a36Sopenharmony_ci			rcte |= SAR_RCTE_OAM; /* Let SAR drop Video */
234362306a36Sopenharmony_ci			break;
234462306a36Sopenharmony_ci		case ATM_AAL34:
234562306a36Sopenharmony_ci			rcte |= SAR_RCTE_AAL34;
234662306a36Sopenharmony_ci			break;
234762306a36Sopenharmony_ci		case ATM_AAL5:
234862306a36Sopenharmony_ci			rcte |= SAR_RCTE_AAL5;
234962306a36Sopenharmony_ci			break;
235062306a36Sopenharmony_ci		default:
235162306a36Sopenharmony_ci			rcte |= SAR_RCTE_RCQ;
235262306a36Sopenharmony_ci			break;
235362306a36Sopenharmony_ci	}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	if (qos->aal != ATM_AAL5)
235662306a36Sopenharmony_ci		rcte |= SAR_RCTE_FBP_1;
235762306a36Sopenharmony_ci	else if (qos->rxtp.max_sdu > SAR_FB_SIZE_2)
235862306a36Sopenharmony_ci		rcte |= SAR_RCTE_FBP_3;
235962306a36Sopenharmony_ci	else if (qos->rxtp.max_sdu > SAR_FB_SIZE_1)
236062306a36Sopenharmony_ci		rcte |= SAR_RCTE_FBP_2;
236162306a36Sopenharmony_ci	else if (qos->rxtp.max_sdu > SAR_FB_SIZE_0)
236262306a36Sopenharmony_ci		rcte |= SAR_RCTE_FBP_1;
236362306a36Sopenharmony_ci	else
236462306a36Sopenharmony_ci		rcte |= SAR_RCTE_FBP_01;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	addr = card->rct_base + (vc->index << 2);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	OPRINTK("%s: writing RCT at 0x%lx\n", card->name, addr);
236962306a36Sopenharmony_ci	write_sram(card, addr, rcte);
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	spin_lock_irqsave(&card->cmd_lock, flags);
237262306a36Sopenharmony_ci	writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), SAR_REG_CMD);
237362306a36Sopenharmony_ci	waitfor_idle(card);
237462306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->cmd_lock, flags);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	return 0;
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_cistatic int
238062306a36Sopenharmony_ciidt77252_open(struct atm_vcc *vcc)
238162306a36Sopenharmony_ci{
238262306a36Sopenharmony_ci	struct atm_dev *dev = vcc->dev;
238362306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
238462306a36Sopenharmony_ci	struct vc_map *vc;
238562306a36Sopenharmony_ci	unsigned int index;
238662306a36Sopenharmony_ci	unsigned int inuse;
238762306a36Sopenharmony_ci	int error;
238862306a36Sopenharmony_ci	int vci = vcc->vci;
238962306a36Sopenharmony_ci	short vpi = vcc->vpi;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
239262306a36Sopenharmony_ci		return 0;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	if (vpi >= (1 << card->vpibits)) {
239562306a36Sopenharmony_ci		printk("%s: unsupported VPI: %d\n", card->name, vpi);
239662306a36Sopenharmony_ci		return -EINVAL;
239762306a36Sopenharmony_ci	}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	if (vci >= (1 << card->vcibits)) {
240062306a36Sopenharmony_ci		printk("%s: unsupported VCI: %d\n", card->name, vci);
240162306a36Sopenharmony_ci		return -EINVAL;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	set_bit(ATM_VF_ADDR, &vcc->flags);
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	mutex_lock(&card->mutex);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	OPRINTK("%s: opening vpi.vci: %d.%d\n", card->name, vpi, vci);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	switch (vcc->qos.aal) {
241162306a36Sopenharmony_ci	case ATM_AAL0:
241262306a36Sopenharmony_ci	case ATM_AAL1:
241362306a36Sopenharmony_ci	case ATM_AAL5:
241462306a36Sopenharmony_ci		break;
241562306a36Sopenharmony_ci	default:
241662306a36Sopenharmony_ci		printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal);
241762306a36Sopenharmony_ci		mutex_unlock(&card->mutex);
241862306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	index = VPCI2VC(card, vpi, vci);
242262306a36Sopenharmony_ci	if (!card->vcs[index]) {
242362306a36Sopenharmony_ci		card->vcs[index] = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
242462306a36Sopenharmony_ci		if (!card->vcs[index]) {
242562306a36Sopenharmony_ci			printk("%s: can't alloc vc in open()\n", card->name);
242662306a36Sopenharmony_ci			mutex_unlock(&card->mutex);
242762306a36Sopenharmony_ci			return -ENOMEM;
242862306a36Sopenharmony_ci		}
242962306a36Sopenharmony_ci		card->vcs[index]->card = card;
243062306a36Sopenharmony_ci		card->vcs[index]->index = index;
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci		spin_lock_init(&card->vcs[index]->lock);
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci	vc = card->vcs[index];
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	vcc->dev_data = vc;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	IPRINTK("%s: idt77252_open: vc = %d (%d.%d) %s/%s (max RX SDU: %u)\n",
243962306a36Sopenharmony_ci	        card->name, vc->index, vcc->vpi, vcc->vci,
244062306a36Sopenharmony_ci	        vcc->qos.rxtp.traffic_class != ATM_NONE ? "rx" : "--",
244162306a36Sopenharmony_ci	        vcc->qos.txtp.traffic_class != ATM_NONE ? "tx" : "--",
244262306a36Sopenharmony_ci	        vcc->qos.rxtp.max_sdu);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	inuse = 0;
244562306a36Sopenharmony_ci	if (vcc->qos.txtp.traffic_class != ATM_NONE &&
244662306a36Sopenharmony_ci	    test_bit(VCF_TX, &vc->flags))
244762306a36Sopenharmony_ci		inuse = 1;
244862306a36Sopenharmony_ci	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
244962306a36Sopenharmony_ci	    test_bit(VCF_RX, &vc->flags))
245062306a36Sopenharmony_ci		inuse += 2;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (inuse) {
245362306a36Sopenharmony_ci		printk("%s: %s vci already in use.\n", card->name,
245462306a36Sopenharmony_ci		       inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
245562306a36Sopenharmony_ci		mutex_unlock(&card->mutex);
245662306a36Sopenharmony_ci		return -EADDRINUSE;
245762306a36Sopenharmony_ci	}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
246062306a36Sopenharmony_ci		error = idt77252_init_tx(card, vc, vcc, &vcc->qos);
246162306a36Sopenharmony_ci		if (error) {
246262306a36Sopenharmony_ci			mutex_unlock(&card->mutex);
246362306a36Sopenharmony_ci			return error;
246462306a36Sopenharmony_ci		}
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
246862306a36Sopenharmony_ci		error = idt77252_init_rx(card, vc, vcc, &vcc->qos);
246962306a36Sopenharmony_ci		if (error) {
247062306a36Sopenharmony_ci			mutex_unlock(&card->mutex);
247162306a36Sopenharmony_ci			return error;
247262306a36Sopenharmony_ci		}
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	set_bit(ATM_VF_READY, &vcc->flags);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	mutex_unlock(&card->mutex);
247862306a36Sopenharmony_ci	return 0;
247962306a36Sopenharmony_ci}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_cistatic void
248262306a36Sopenharmony_ciidt77252_close(struct atm_vcc *vcc)
248362306a36Sopenharmony_ci{
248462306a36Sopenharmony_ci	struct atm_dev *dev = vcc->dev;
248562306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
248662306a36Sopenharmony_ci	struct vc_map *vc = vcc->dev_data;
248762306a36Sopenharmony_ci	unsigned long flags;
248862306a36Sopenharmony_ci	unsigned long addr;
248962306a36Sopenharmony_ci	unsigned long timeout;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	mutex_lock(&card->mutex);
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	IPRINTK("%s: idt77252_close: vc = %d (%d.%d)\n",
249462306a36Sopenharmony_ci		card->name, vc->index, vcc->vpi, vcc->vci);
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	clear_bit(ATM_VF_READY, &vcc->flags);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci		spin_lock_irqsave(&vc->lock, flags);
250162306a36Sopenharmony_ci		clear_bit(VCF_RX, &vc->flags);
250262306a36Sopenharmony_ci		vc->rx_vcc = NULL;
250362306a36Sopenharmony_ci		spin_unlock_irqrestore(&vc->lock, flags);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci		if ((vcc->vci == 3) || (vcc->vci == 4))
250662306a36Sopenharmony_ci			goto done;
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci		addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci		spin_lock_irqsave(&card->cmd_lock, flags);
251162306a36Sopenharmony_ci		writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), SAR_REG_CMD);
251262306a36Sopenharmony_ci		waitfor_idle(card);
251362306a36Sopenharmony_ci		spin_unlock_irqrestore(&card->cmd_lock, flags);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci		if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) {
251662306a36Sopenharmony_ci			DPRINTK("%s: closing a VC with pending rx buffers.\n",
251762306a36Sopenharmony_ci				card->name);
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci			recycle_rx_pool_skb(card, &vc->rcv.rx_pool);
252062306a36Sopenharmony_ci		}
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_cidone:
252462306a36Sopenharmony_ci	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci		spin_lock_irqsave(&vc->lock, flags);
252762306a36Sopenharmony_ci		clear_bit(VCF_TX, &vc->flags);
252862306a36Sopenharmony_ci		clear_bit(VCF_IDLE, &vc->flags);
252962306a36Sopenharmony_ci		clear_bit(VCF_RSV, &vc->flags);
253062306a36Sopenharmony_ci		vc->tx_vcc = NULL;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci		if (vc->estimator) {
253362306a36Sopenharmony_ci			timer_shutdown(&vc->estimator->timer);
253462306a36Sopenharmony_ci			kfree(vc->estimator);
253562306a36Sopenharmony_ci			vc->estimator = NULL;
253662306a36Sopenharmony_ci		}
253762306a36Sopenharmony_ci		spin_unlock_irqrestore(&vc->lock, flags);
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci		timeout = 5 * 1000;
254062306a36Sopenharmony_ci		while (atomic_read(&vc->scq->used) > 0) {
254162306a36Sopenharmony_ci			timeout = msleep_interruptible(timeout);
254262306a36Sopenharmony_ci			if (!timeout) {
254362306a36Sopenharmony_ci				pr_warn("%s: SCQ drain timeout: %u used\n",
254462306a36Sopenharmony_ci					card->name, atomic_read(&vc->scq->used));
254562306a36Sopenharmony_ci				break;
254662306a36Sopenharmony_ci			}
254762306a36Sopenharmony_ci		}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci		writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ);
255062306a36Sopenharmony_ci		clear_scd(card, vc->scq, vc->class);
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci		if (vc->class == SCHED_CBR) {
255362306a36Sopenharmony_ci			clear_tst(card, vc);
255462306a36Sopenharmony_ci			card->tst_free += vc->ntste;
255562306a36Sopenharmony_ci			vc->ntste = 0;
255662306a36Sopenharmony_ci		}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		card->scd2vc[vc->scd_index] = NULL;
255962306a36Sopenharmony_ci		free_scq(card, vc->scq);
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	mutex_unlock(&card->mutex);
256362306a36Sopenharmony_ci}
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_cistatic int
256662306a36Sopenharmony_ciidt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
256762306a36Sopenharmony_ci{
256862306a36Sopenharmony_ci	struct atm_dev *dev = vcc->dev;
256962306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
257062306a36Sopenharmony_ci	struct vc_map *vc = vcc->dev_data;
257162306a36Sopenharmony_ci	int error = 0;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	mutex_lock(&card->mutex);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	if (qos->txtp.traffic_class != ATM_NONE) {
257662306a36Sopenharmony_ci	    	if (!test_bit(VCF_TX, &vc->flags)) {
257762306a36Sopenharmony_ci			error = idt77252_init_tx(card, vc, vcc, qos);
257862306a36Sopenharmony_ci			if (error)
257962306a36Sopenharmony_ci				goto out;
258062306a36Sopenharmony_ci		} else {
258162306a36Sopenharmony_ci			switch (qos->txtp.traffic_class) {
258262306a36Sopenharmony_ci			case ATM_CBR:
258362306a36Sopenharmony_ci				error = idt77252_init_cbr(card, vc, vcc, qos);
258462306a36Sopenharmony_ci				if (error)
258562306a36Sopenharmony_ci					goto out;
258662306a36Sopenharmony_ci				break;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci			case ATM_UBR:
258962306a36Sopenharmony_ci				error = idt77252_init_ubr(card, vc, vcc, qos);
259062306a36Sopenharmony_ci				if (error)
259162306a36Sopenharmony_ci					goto out;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci				if (!test_bit(VCF_IDLE, &vc->flags)) {
259462306a36Sopenharmony_ci					writel(TCMDQ_LACR | (vc->lacr << 16) |
259562306a36Sopenharmony_ci					       vc->index, SAR_REG_TCMDQ);
259662306a36Sopenharmony_ci				}
259762306a36Sopenharmony_ci				break;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci			case ATM_VBR:
260062306a36Sopenharmony_ci			case ATM_ABR:
260162306a36Sopenharmony_ci				error = -EOPNOTSUPP;
260262306a36Sopenharmony_ci				goto out;
260362306a36Sopenharmony_ci			}
260462306a36Sopenharmony_ci		}
260562306a36Sopenharmony_ci	}
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	if ((qos->rxtp.traffic_class != ATM_NONE) &&
260862306a36Sopenharmony_ci	    !test_bit(VCF_RX, &vc->flags)) {
260962306a36Sopenharmony_ci		error = idt77252_init_rx(card, vc, vcc, qos);
261062306a36Sopenharmony_ci		if (error)
261162306a36Sopenharmony_ci			goto out;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	set_bit(ATM_VF_HASQOS, &vcc->flags);
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ciout:
261962306a36Sopenharmony_ci	mutex_unlock(&card->mutex);
262062306a36Sopenharmony_ci	return error;
262162306a36Sopenharmony_ci}
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_cistatic int
262462306a36Sopenharmony_ciidt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
262762306a36Sopenharmony_ci	int i, left;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	left = (int) *pos;
263062306a36Sopenharmony_ci	if (!left--)
263162306a36Sopenharmony_ci		return sprintf(page, "IDT77252 Interrupts:\n");
263262306a36Sopenharmony_ci	if (!left--)
263362306a36Sopenharmony_ci		return sprintf(page, "TSIF:  %lu\n", card->irqstat[15]);
263462306a36Sopenharmony_ci	if (!left--)
263562306a36Sopenharmony_ci		return sprintf(page, "TXICP: %lu\n", card->irqstat[14]);
263662306a36Sopenharmony_ci	if (!left--)
263762306a36Sopenharmony_ci		return sprintf(page, "TSQF:  %lu\n", card->irqstat[12]);
263862306a36Sopenharmony_ci	if (!left--)
263962306a36Sopenharmony_ci		return sprintf(page, "TMROF: %lu\n", card->irqstat[11]);
264062306a36Sopenharmony_ci	if (!left--)
264162306a36Sopenharmony_ci		return sprintf(page, "PHYI:  %lu\n", card->irqstat[10]);
264262306a36Sopenharmony_ci	if (!left--)
264362306a36Sopenharmony_ci		return sprintf(page, "FBQ3A: %lu\n", card->irqstat[8]);
264462306a36Sopenharmony_ci	if (!left--)
264562306a36Sopenharmony_ci		return sprintf(page, "FBQ2A: %lu\n", card->irqstat[7]);
264662306a36Sopenharmony_ci	if (!left--)
264762306a36Sopenharmony_ci		return sprintf(page, "RSQF:  %lu\n", card->irqstat[6]);
264862306a36Sopenharmony_ci	if (!left--)
264962306a36Sopenharmony_ci		return sprintf(page, "EPDU:  %lu\n", card->irqstat[5]);
265062306a36Sopenharmony_ci	if (!left--)
265162306a36Sopenharmony_ci		return sprintf(page, "RAWCF: %lu\n", card->irqstat[4]);
265262306a36Sopenharmony_ci	if (!left--)
265362306a36Sopenharmony_ci		return sprintf(page, "FBQ1A: %lu\n", card->irqstat[3]);
265462306a36Sopenharmony_ci	if (!left--)
265562306a36Sopenharmony_ci		return sprintf(page, "FBQ0A: %lu\n", card->irqstat[2]);
265662306a36Sopenharmony_ci	if (!left--)
265762306a36Sopenharmony_ci		return sprintf(page, "RSQAF: %lu\n", card->irqstat[1]);
265862306a36Sopenharmony_ci	if (!left--)
265962306a36Sopenharmony_ci		return sprintf(page, "IDT77252 Transmit Connection Table:\n");
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	for (i = 0; i < card->tct_size; i++) {
266262306a36Sopenharmony_ci		unsigned long tct;
266362306a36Sopenharmony_ci		struct atm_vcc *vcc;
266462306a36Sopenharmony_ci		struct vc_map *vc;
266562306a36Sopenharmony_ci		char *p;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci		vc = card->vcs[i];
266862306a36Sopenharmony_ci		if (!vc)
266962306a36Sopenharmony_ci			continue;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci		vcc = NULL;
267262306a36Sopenharmony_ci		if (vc->tx_vcc)
267362306a36Sopenharmony_ci			vcc = vc->tx_vcc;
267462306a36Sopenharmony_ci		if (!vcc)
267562306a36Sopenharmony_ci			continue;
267662306a36Sopenharmony_ci		if (left--)
267762306a36Sopenharmony_ci			continue;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		p = page;
268062306a36Sopenharmony_ci		p += sprintf(p, "  %4u: %u.%u: ", i, vcc->vpi, vcc->vci);
268162306a36Sopenharmony_ci		tct = (unsigned long) (card->tct_base + i * SAR_SRAM_TCT_SIZE);
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
268462306a36Sopenharmony_ci			p += sprintf(p, " %08x", read_sram(card, tct + i));
268562306a36Sopenharmony_ci		p += sprintf(p, "\n");
268662306a36Sopenharmony_ci		return p - page;
268762306a36Sopenharmony_ci	}
268862306a36Sopenharmony_ci	return 0;
268962306a36Sopenharmony_ci}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci/*****************************************************************************/
269262306a36Sopenharmony_ci/*                                                                           */
269362306a36Sopenharmony_ci/* Interrupt handler                                                         */
269462306a36Sopenharmony_ci/*                                                                           */
269562306a36Sopenharmony_ci/*****************************************************************************/
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_cistatic void
269862306a36Sopenharmony_ciidt77252_collect_stat(struct idt77252_dev *card)
269962306a36Sopenharmony_ci{
270062306a36Sopenharmony_ci	(void) readl(SAR_REG_CDC);
270162306a36Sopenharmony_ci	(void) readl(SAR_REG_VPEC);
270262306a36Sopenharmony_ci	(void) readl(SAR_REG_ICC);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci}
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_cistatic irqreturn_t
270762306a36Sopenharmony_ciidt77252_interrupt(int irq, void *dev_id)
270862306a36Sopenharmony_ci{
270962306a36Sopenharmony_ci	struct idt77252_dev *card = dev_id;
271062306a36Sopenharmony_ci	u32 stat;
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	stat = readl(SAR_REG_STAT) & 0xffff;
271362306a36Sopenharmony_ci	if (!stat)	/* no interrupt for us */
271462306a36Sopenharmony_ci		return IRQ_NONE;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	if (test_and_set_bit(IDT77252_BIT_INTERRUPT, &card->flags)) {
271762306a36Sopenharmony_ci		printk("%s: Re-entering irq_handler()\n", card->name);
271862306a36Sopenharmony_ci		goto out;
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	writel(stat, SAR_REG_STAT);	/* reset interrupt */
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (stat & SAR_STAT_TSIF) {	/* entry written to TSQ  */
272462306a36Sopenharmony_ci		INTPRINTK("%s: TSIF\n", card->name);
272562306a36Sopenharmony_ci		card->irqstat[15]++;
272662306a36Sopenharmony_ci		idt77252_tx(card);
272762306a36Sopenharmony_ci	}
272862306a36Sopenharmony_ci	if (stat & SAR_STAT_TXICP) {	/* Incomplete CS-PDU has  */
272962306a36Sopenharmony_ci		INTPRINTK("%s: TXICP\n", card->name);
273062306a36Sopenharmony_ci		card->irqstat[14]++;
273162306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
273262306a36Sopenharmony_ci		idt77252_tx_dump(card);
273362306a36Sopenharmony_ci#endif
273462306a36Sopenharmony_ci	}
273562306a36Sopenharmony_ci	if (stat & SAR_STAT_TSQF) {	/* TSQ 7/8 full           */
273662306a36Sopenharmony_ci		INTPRINTK("%s: TSQF\n", card->name);
273762306a36Sopenharmony_ci		card->irqstat[12]++;
273862306a36Sopenharmony_ci		idt77252_tx(card);
273962306a36Sopenharmony_ci	}
274062306a36Sopenharmony_ci	if (stat & SAR_STAT_TMROF) {	/* Timer overflow         */
274162306a36Sopenharmony_ci		INTPRINTK("%s: TMROF\n", card->name);
274262306a36Sopenharmony_ci		card->irqstat[11]++;
274362306a36Sopenharmony_ci		idt77252_collect_stat(card);
274462306a36Sopenharmony_ci	}
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	if (stat & SAR_STAT_EPDU) {	/* Got complete CS-PDU    */
274762306a36Sopenharmony_ci		INTPRINTK("%s: EPDU\n", card->name);
274862306a36Sopenharmony_ci		card->irqstat[5]++;
274962306a36Sopenharmony_ci		idt77252_rx(card);
275062306a36Sopenharmony_ci	}
275162306a36Sopenharmony_ci	if (stat & SAR_STAT_RSQAF) {	/* RSQ is 7/8 full        */
275262306a36Sopenharmony_ci		INTPRINTK("%s: RSQAF\n", card->name);
275362306a36Sopenharmony_ci		card->irqstat[1]++;
275462306a36Sopenharmony_ci		idt77252_rx(card);
275562306a36Sopenharmony_ci	}
275662306a36Sopenharmony_ci	if (stat & SAR_STAT_RSQF) {	/* RSQ is full            */
275762306a36Sopenharmony_ci		INTPRINTK("%s: RSQF\n", card->name);
275862306a36Sopenharmony_ci		card->irqstat[6]++;
275962306a36Sopenharmony_ci		idt77252_rx(card);
276062306a36Sopenharmony_ci	}
276162306a36Sopenharmony_ci	if (stat & SAR_STAT_RAWCF) {	/* Raw cell received      */
276262306a36Sopenharmony_ci		INTPRINTK("%s: RAWCF\n", card->name);
276362306a36Sopenharmony_ci		card->irqstat[4]++;
276462306a36Sopenharmony_ci		idt77252_rx_raw(card);
276562306a36Sopenharmony_ci	}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	if (stat & SAR_STAT_PHYI) {	/* PHY device interrupt   */
276862306a36Sopenharmony_ci		INTPRINTK("%s: PHYI", card->name);
276962306a36Sopenharmony_ci		card->irqstat[10]++;
277062306a36Sopenharmony_ci		if (card->atmdev->phy && card->atmdev->phy->interrupt)
277162306a36Sopenharmony_ci			card->atmdev->phy->interrupt(card->atmdev);
277262306a36Sopenharmony_ci	}
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	if (stat & (SAR_STAT_FBQ0A | SAR_STAT_FBQ1A |
277562306a36Sopenharmony_ci		    SAR_STAT_FBQ2A | SAR_STAT_FBQ3A)) {
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci		writel(readl(SAR_REG_CFG) & ~(SAR_CFG_FBIE), SAR_REG_CFG);
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci		INTPRINTK("%s: FBQA: %04x\n", card->name, stat);
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci		if (stat & SAR_STAT_FBQ0A)
278262306a36Sopenharmony_ci			card->irqstat[2]++;
278362306a36Sopenharmony_ci		if (stat & SAR_STAT_FBQ1A)
278462306a36Sopenharmony_ci			card->irqstat[3]++;
278562306a36Sopenharmony_ci		if (stat & SAR_STAT_FBQ2A)
278662306a36Sopenharmony_ci			card->irqstat[7]++;
278762306a36Sopenharmony_ci		if (stat & SAR_STAT_FBQ3A)
278862306a36Sopenharmony_ci			card->irqstat[8]++;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci		schedule_work(&card->tqueue);
279162306a36Sopenharmony_ci	}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ciout:
279462306a36Sopenharmony_ci	clear_bit(IDT77252_BIT_INTERRUPT, &card->flags);
279562306a36Sopenharmony_ci	return IRQ_HANDLED;
279662306a36Sopenharmony_ci}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_cistatic void
279962306a36Sopenharmony_ciidt77252_softint(struct work_struct *work)
280062306a36Sopenharmony_ci{
280162306a36Sopenharmony_ci	struct idt77252_dev *card =
280262306a36Sopenharmony_ci		container_of(work, struct idt77252_dev, tqueue);
280362306a36Sopenharmony_ci	u32 stat;
280462306a36Sopenharmony_ci	int done;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	for (done = 1; ; done = 1) {
280762306a36Sopenharmony_ci		stat = readl(SAR_REG_STAT) >> 16;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci		if ((stat & 0x0f) < SAR_FBQ0_HIGH) {
281062306a36Sopenharmony_ci			add_rx_skb(card, 0, SAR_FB_SIZE_0, 32);
281162306a36Sopenharmony_ci			done = 0;
281262306a36Sopenharmony_ci		}
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci		stat >>= 4;
281562306a36Sopenharmony_ci		if ((stat & 0x0f) < SAR_FBQ1_HIGH) {
281662306a36Sopenharmony_ci			add_rx_skb(card, 1, SAR_FB_SIZE_1, 32);
281762306a36Sopenharmony_ci			done = 0;
281862306a36Sopenharmony_ci		}
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci		stat >>= 4;
282162306a36Sopenharmony_ci		if ((stat & 0x0f) < SAR_FBQ2_HIGH) {
282262306a36Sopenharmony_ci			add_rx_skb(card, 2, SAR_FB_SIZE_2, 32);
282362306a36Sopenharmony_ci			done = 0;
282462306a36Sopenharmony_ci		}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci		stat >>= 4;
282762306a36Sopenharmony_ci		if ((stat & 0x0f) < SAR_FBQ3_HIGH) {
282862306a36Sopenharmony_ci			add_rx_skb(card, 3, SAR_FB_SIZE_3, 32);
282962306a36Sopenharmony_ci			done = 0;
283062306a36Sopenharmony_ci		}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci		if (done)
283362306a36Sopenharmony_ci			break;
283462306a36Sopenharmony_ci	}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	writel(readl(SAR_REG_CFG) | SAR_CFG_FBIE, SAR_REG_CFG);
283762306a36Sopenharmony_ci}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_cistatic int
284162306a36Sopenharmony_ciopen_card_oam(struct idt77252_dev *card)
284262306a36Sopenharmony_ci{
284362306a36Sopenharmony_ci	unsigned long flags;
284462306a36Sopenharmony_ci	unsigned long addr;
284562306a36Sopenharmony_ci	struct vc_map *vc;
284662306a36Sopenharmony_ci	int vpi, vci;
284762306a36Sopenharmony_ci	int index;
284862306a36Sopenharmony_ci	u32 rcte;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	for (vpi = 0; vpi < (1 << card->vpibits); vpi++) {
285162306a36Sopenharmony_ci		for (vci = 3; vci < 5; vci++) {
285262306a36Sopenharmony_ci			index = VPCI2VC(card, vpi, vci);
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci			vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
285562306a36Sopenharmony_ci			if (!vc) {
285662306a36Sopenharmony_ci				printk("%s: can't alloc vc\n", card->name);
285762306a36Sopenharmony_ci				return -ENOMEM;
285862306a36Sopenharmony_ci			}
285962306a36Sopenharmony_ci			vc->index = index;
286062306a36Sopenharmony_ci			card->vcs[index] = vc;
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci			flush_rx_pool(card, &vc->rcv.rx_pool);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci			rcte = SAR_RCTE_CONNECTOPEN |
286562306a36Sopenharmony_ci			       SAR_RCTE_RAWCELLINTEN |
286662306a36Sopenharmony_ci			       SAR_RCTE_RCQ |
286762306a36Sopenharmony_ci			       SAR_RCTE_FBP_1;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci			addr = card->rct_base + (vc->index << 2);
287062306a36Sopenharmony_ci			write_sram(card, addr, rcte);
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci			spin_lock_irqsave(&card->cmd_lock, flags);
287362306a36Sopenharmony_ci			writel(SAR_CMD_OPEN_CONNECTION | (addr << 2),
287462306a36Sopenharmony_ci			       SAR_REG_CMD);
287562306a36Sopenharmony_ci			waitfor_idle(card);
287662306a36Sopenharmony_ci			spin_unlock_irqrestore(&card->cmd_lock, flags);
287762306a36Sopenharmony_ci		}
287862306a36Sopenharmony_ci	}
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	return 0;
288162306a36Sopenharmony_ci}
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_cistatic void
288462306a36Sopenharmony_ciclose_card_oam(struct idt77252_dev *card)
288562306a36Sopenharmony_ci{
288662306a36Sopenharmony_ci	unsigned long flags;
288762306a36Sopenharmony_ci	unsigned long addr;
288862306a36Sopenharmony_ci	struct vc_map *vc;
288962306a36Sopenharmony_ci	int vpi, vci;
289062306a36Sopenharmony_ci	int index;
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	for (vpi = 0; vpi < (1 << card->vpibits); vpi++) {
289362306a36Sopenharmony_ci		for (vci = 3; vci < 5; vci++) {
289462306a36Sopenharmony_ci			index = VPCI2VC(card, vpi, vci);
289562306a36Sopenharmony_ci			vc = card->vcs[index];
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci			addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE;
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci			spin_lock_irqsave(&card->cmd_lock, flags);
290062306a36Sopenharmony_ci			writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2),
290162306a36Sopenharmony_ci			       SAR_REG_CMD);
290262306a36Sopenharmony_ci			waitfor_idle(card);
290362306a36Sopenharmony_ci			spin_unlock_irqrestore(&card->cmd_lock, flags);
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci			if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) {
290662306a36Sopenharmony_ci				DPRINTK("%s: closing a VC "
290762306a36Sopenharmony_ci					"with pending rx buffers.\n",
290862306a36Sopenharmony_ci					card->name);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci				recycle_rx_pool_skb(card, &vc->rcv.rx_pool);
291162306a36Sopenharmony_ci			}
291262306a36Sopenharmony_ci			kfree(vc);
291362306a36Sopenharmony_ci		}
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci}
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_cistatic int
291862306a36Sopenharmony_ciopen_card_ubr0(struct idt77252_dev *card)
291962306a36Sopenharmony_ci{
292062306a36Sopenharmony_ci	struct vc_map *vc;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
292362306a36Sopenharmony_ci	if (!vc) {
292462306a36Sopenharmony_ci		printk("%s: can't alloc vc\n", card->name);
292562306a36Sopenharmony_ci		return -ENOMEM;
292662306a36Sopenharmony_ci	}
292762306a36Sopenharmony_ci	card->vcs[0] = vc;
292862306a36Sopenharmony_ci	vc->class = SCHED_UBR0;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	vc->scq = alloc_scq(card, vc->class);
293162306a36Sopenharmony_ci	if (!vc->scq) {
293262306a36Sopenharmony_ci		printk("%s: can't get SCQ.\n", card->name);
293362306a36Sopenharmony_ci		kfree(card->vcs[0]);
293462306a36Sopenharmony_ci		card->vcs[0] = NULL;
293562306a36Sopenharmony_ci		return -ENOMEM;
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	card->scd2vc[0] = vc;
293962306a36Sopenharmony_ci	vc->scd_index = 0;
294062306a36Sopenharmony_ci	vc->scq->scd = card->scd_base;
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	fill_scd(card, vc->scq, vc->class);
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	write_sram(card, card->tct_base + 0, TCT_UBR | card->scd_base);
294562306a36Sopenharmony_ci	write_sram(card, card->tct_base + 1, 0);
294662306a36Sopenharmony_ci	write_sram(card, card->tct_base + 2, 0);
294762306a36Sopenharmony_ci	write_sram(card, card->tct_base + 3, 0);
294862306a36Sopenharmony_ci	write_sram(card, card->tct_base + 4, 0);
294962306a36Sopenharmony_ci	write_sram(card, card->tct_base + 5, 0);
295062306a36Sopenharmony_ci	write_sram(card, card->tct_base + 6, 0);
295162306a36Sopenharmony_ci	write_sram(card, card->tct_base + 7, TCT_FLAG_UBR);
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	clear_bit(VCF_IDLE, &vc->flags);
295462306a36Sopenharmony_ci	writel(TCMDQ_START | 0, SAR_REG_TCMDQ);
295562306a36Sopenharmony_ci	return 0;
295662306a36Sopenharmony_ci}
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_cistatic void
295962306a36Sopenharmony_ciclose_card_ubr0(struct idt77252_dev *card)
296062306a36Sopenharmony_ci{
296162306a36Sopenharmony_ci	struct vc_map *vc = card->vcs[0];
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	free_scq(card, vc->scq);
296462306a36Sopenharmony_ci	kfree(vc);
296562306a36Sopenharmony_ci}
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_cistatic int
296862306a36Sopenharmony_ciidt77252_dev_open(struct idt77252_dev *card)
296962306a36Sopenharmony_ci{
297062306a36Sopenharmony_ci	u32 conf;
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	if (!test_bit(IDT77252_BIT_INIT, &card->flags)) {
297362306a36Sopenharmony_ci		printk("%s: SAR not yet initialized.\n", card->name);
297462306a36Sopenharmony_ci		return -1;
297562306a36Sopenharmony_ci	}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	conf = SAR_CFG_RXPTH|	/* enable receive path                  */
297862306a36Sopenharmony_ci	    SAR_RX_DELAY |	/* interrupt on complete PDU		*/
297962306a36Sopenharmony_ci	    SAR_CFG_RAWIE |	/* interrupt enable on raw cells        */
298062306a36Sopenharmony_ci	    SAR_CFG_RQFIE |	/* interrupt on RSQ almost full         */
298162306a36Sopenharmony_ci	    SAR_CFG_TMOIE |	/* interrupt on timer overflow          */
298262306a36Sopenharmony_ci	    SAR_CFG_FBIE |	/* interrupt on low free buffers        */
298362306a36Sopenharmony_ci	    SAR_CFG_TXEN |	/* transmit operation enable            */
298462306a36Sopenharmony_ci	    SAR_CFG_TXINT |	/* interrupt on transmit status         */
298562306a36Sopenharmony_ci	    SAR_CFG_TXUIE |	/* interrupt on transmit underrun       */
298662306a36Sopenharmony_ci	    SAR_CFG_TXSFI |	/* interrupt on TSQ almost full         */
298762306a36Sopenharmony_ci	    SAR_CFG_PHYIE	/* enable PHY interrupts		*/
298862306a36Sopenharmony_ci	    ;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_RCV_ALL
299162306a36Sopenharmony_ci	/* Test RAW cell receive. */
299262306a36Sopenharmony_ci	conf |= SAR_CFG_VPECA;
299362306a36Sopenharmony_ci#endif
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	if (open_card_oam(card)) {
299862306a36Sopenharmony_ci		printk("%s: Error initializing OAM.\n", card->name);
299962306a36Sopenharmony_ci		return -1;
300062306a36Sopenharmony_ci	}
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	if (open_card_ubr0(card)) {
300362306a36Sopenharmony_ci		printk("%s: Error initializing UBR0.\n", card->name);
300462306a36Sopenharmony_ci		return -1;
300562306a36Sopenharmony_ci	}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	IPRINTK("%s: opened IDT77252 ABR SAR.\n", card->name);
300862306a36Sopenharmony_ci	return 0;
300962306a36Sopenharmony_ci}
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_cistatic void idt77252_dev_close(struct atm_dev *dev)
301262306a36Sopenharmony_ci{
301362306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
301462306a36Sopenharmony_ci	u32 conf;
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	close_card_ubr0(card);
301762306a36Sopenharmony_ci	close_card_oam(card);
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	conf = SAR_CFG_RXPTH |	/* enable receive path           */
302062306a36Sopenharmony_ci	    SAR_RX_DELAY |	/* interrupt on complete PDU     */
302162306a36Sopenharmony_ci	    SAR_CFG_RAWIE |	/* interrupt enable on raw cells */
302262306a36Sopenharmony_ci	    SAR_CFG_RQFIE |	/* interrupt on RSQ almost full  */
302362306a36Sopenharmony_ci	    SAR_CFG_TMOIE |	/* interrupt on timer overflow   */
302462306a36Sopenharmony_ci	    SAR_CFG_FBIE |	/* interrupt on low free buffers */
302562306a36Sopenharmony_ci	    SAR_CFG_TXEN |	/* transmit operation enable     */
302662306a36Sopenharmony_ci	    SAR_CFG_TXINT |	/* interrupt on transmit status  */
302762306a36Sopenharmony_ci	    SAR_CFG_TXUIE |	/* interrupt on xmit underrun    */
302862306a36Sopenharmony_ci	    SAR_CFG_TXSFI	/* interrupt on TSQ almost full  */
302962306a36Sopenharmony_ci	    ;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	writel(readl(SAR_REG_CFG) & ~(conf), SAR_REG_CFG);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	DIPRINTK("%s: closed IDT77252 ABR SAR.\n", card->name);
303462306a36Sopenharmony_ci}
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci/*****************************************************************************/
303862306a36Sopenharmony_ci/*                                                                           */
303962306a36Sopenharmony_ci/* Initialisation and Deinitialization of IDT77252                           */
304062306a36Sopenharmony_ci/*                                                                           */
304162306a36Sopenharmony_ci/*****************************************************************************/
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_cistatic void
304562306a36Sopenharmony_cideinit_card(struct idt77252_dev *card)
304662306a36Sopenharmony_ci{
304762306a36Sopenharmony_ci	struct sk_buff *skb;
304862306a36Sopenharmony_ci	int i, j;
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	if (!test_bit(IDT77252_BIT_INIT, &card->flags)) {
305162306a36Sopenharmony_ci		printk("%s: SAR not yet initialized.\n", card->name);
305262306a36Sopenharmony_ci		return;
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci	DIPRINTK("idt77252: deinitialize card %u\n", card->index);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	writel(0, SAR_REG_CFG);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	if (card->atmdev)
305962306a36Sopenharmony_ci		atm_dev_deregister(card->atmdev);
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
306262306a36Sopenharmony_ci		for (j = 0; j < FBQ_SIZE; j++) {
306362306a36Sopenharmony_ci			skb = card->sbpool[i].skb[j];
306462306a36Sopenharmony_ci			if (skb) {
306562306a36Sopenharmony_ci				dma_unmap_single(&card->pcidev->dev,
306662306a36Sopenharmony_ci						 IDT77252_PRV_PADDR(skb),
306762306a36Sopenharmony_ci						 (skb_end_pointer(skb) -
306862306a36Sopenharmony_ci						  skb->data),
306962306a36Sopenharmony_ci						 DMA_FROM_DEVICE);
307062306a36Sopenharmony_ci				card->sbpool[i].skb[j] = NULL;
307162306a36Sopenharmony_ci				dev_kfree_skb(skb);
307262306a36Sopenharmony_ci			}
307362306a36Sopenharmony_ci		}
307462306a36Sopenharmony_ci	}
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	vfree(card->soft_tst);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	vfree(card->scd2vc);
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	vfree(card->vcs);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	if (card->raw_cell_hnd) {
308362306a36Sopenharmony_ci		dma_free_coherent(&card->pcidev->dev, 2 * sizeof(u32),
308462306a36Sopenharmony_ci				  card->raw_cell_hnd, card->raw_cell_paddr);
308562306a36Sopenharmony_ci	}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	if (card->rsq.base) {
308862306a36Sopenharmony_ci		DIPRINTK("%s: Release RSQ ...\n", card->name);
308962306a36Sopenharmony_ci		deinit_rsq(card);
309062306a36Sopenharmony_ci	}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if (card->tsq.base) {
309362306a36Sopenharmony_ci		DIPRINTK("%s: Release TSQ ...\n", card->name);
309462306a36Sopenharmony_ci		deinit_tsq(card);
309562306a36Sopenharmony_ci	}
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	DIPRINTK("idt77252: Release IRQ.\n");
309862306a36Sopenharmony_ci	free_irq(card->pcidev->irq, card);
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
310162306a36Sopenharmony_ci		if (card->fbq[i])
310262306a36Sopenharmony_ci			iounmap(card->fbq[i]);
310362306a36Sopenharmony_ci	}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	if (card->membase)
310662306a36Sopenharmony_ci		iounmap(card->membase);
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	clear_bit(IDT77252_BIT_INIT, &card->flags);
310962306a36Sopenharmony_ci	DIPRINTK("%s: Card deinitialized.\n", card->name);
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_cistatic void init_sram(struct idt77252_dev *card)
311462306a36Sopenharmony_ci{
311562306a36Sopenharmony_ci	int i;
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci	for (i = 0; i < card->sramsize; i += 4)
311862306a36Sopenharmony_ci		write_sram(card, (i >> 2), 0);
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	/* set SRAM layout for THIS card */
312162306a36Sopenharmony_ci	if (card->sramsize == (512 * 1024)) {
312262306a36Sopenharmony_ci		card->tct_base = SAR_SRAM_TCT_128_BASE;
312362306a36Sopenharmony_ci		card->tct_size = (SAR_SRAM_TCT_128_TOP - card->tct_base + 1)
312462306a36Sopenharmony_ci		    / SAR_SRAM_TCT_SIZE;
312562306a36Sopenharmony_ci		card->rct_base = SAR_SRAM_RCT_128_BASE;
312662306a36Sopenharmony_ci		card->rct_size = (SAR_SRAM_RCT_128_TOP - card->rct_base + 1)
312762306a36Sopenharmony_ci		    / SAR_SRAM_RCT_SIZE;
312862306a36Sopenharmony_ci		card->rt_base = SAR_SRAM_RT_128_BASE;
312962306a36Sopenharmony_ci		card->scd_base = SAR_SRAM_SCD_128_BASE;
313062306a36Sopenharmony_ci		card->scd_size = (SAR_SRAM_SCD_128_TOP - card->scd_base + 1)
313162306a36Sopenharmony_ci		    / SAR_SRAM_SCD_SIZE;
313262306a36Sopenharmony_ci		card->tst[0] = SAR_SRAM_TST1_128_BASE;
313362306a36Sopenharmony_ci		card->tst[1] = SAR_SRAM_TST2_128_BASE;
313462306a36Sopenharmony_ci		card->tst_size = SAR_SRAM_TST1_128_TOP - card->tst[0] + 1;
313562306a36Sopenharmony_ci		card->abrst_base = SAR_SRAM_ABRSTD_128_BASE;
313662306a36Sopenharmony_ci		card->abrst_size = SAR_ABRSTD_SIZE_8K;
313762306a36Sopenharmony_ci		card->fifo_base = SAR_SRAM_FIFO_128_BASE;
313862306a36Sopenharmony_ci		card->fifo_size = SAR_RXFD_SIZE_32K;
313962306a36Sopenharmony_ci	} else {
314062306a36Sopenharmony_ci		card->tct_base = SAR_SRAM_TCT_32_BASE;
314162306a36Sopenharmony_ci		card->tct_size = (SAR_SRAM_TCT_32_TOP - card->tct_base + 1)
314262306a36Sopenharmony_ci		    / SAR_SRAM_TCT_SIZE;
314362306a36Sopenharmony_ci		card->rct_base = SAR_SRAM_RCT_32_BASE;
314462306a36Sopenharmony_ci		card->rct_size = (SAR_SRAM_RCT_32_TOP - card->rct_base + 1)
314562306a36Sopenharmony_ci		    / SAR_SRAM_RCT_SIZE;
314662306a36Sopenharmony_ci		card->rt_base = SAR_SRAM_RT_32_BASE;
314762306a36Sopenharmony_ci		card->scd_base = SAR_SRAM_SCD_32_BASE;
314862306a36Sopenharmony_ci		card->scd_size = (SAR_SRAM_SCD_32_TOP - card->scd_base + 1)
314962306a36Sopenharmony_ci		    / SAR_SRAM_SCD_SIZE;
315062306a36Sopenharmony_ci		card->tst[0] = SAR_SRAM_TST1_32_BASE;
315162306a36Sopenharmony_ci		card->tst[1] = SAR_SRAM_TST2_32_BASE;
315262306a36Sopenharmony_ci		card->tst_size = (SAR_SRAM_TST1_32_TOP - card->tst[0] + 1);
315362306a36Sopenharmony_ci		card->abrst_base = SAR_SRAM_ABRSTD_32_BASE;
315462306a36Sopenharmony_ci		card->abrst_size = SAR_ABRSTD_SIZE_1K;
315562306a36Sopenharmony_ci		card->fifo_base = SAR_SRAM_FIFO_32_BASE;
315662306a36Sopenharmony_ci		card->fifo_size = SAR_RXFD_SIZE_4K;
315762306a36Sopenharmony_ci	}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	/* Initialize TCT */
316062306a36Sopenharmony_ci	for (i = 0; i < card->tct_size; i++) {
316162306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 0, 0);
316262306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 1, 0);
316362306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 2, 0);
316462306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 3, 0);
316562306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 4, 0);
316662306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 5, 0);
316762306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 6, 0);
316862306a36Sopenharmony_ci		write_sram(card, i * SAR_SRAM_TCT_SIZE + 7, 0);
316962306a36Sopenharmony_ci	}
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	/* Initialize RCT */
317262306a36Sopenharmony_ci	for (i = 0; i < card->rct_size; i++) {
317362306a36Sopenharmony_ci		write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE,
317462306a36Sopenharmony_ci				    (u32) SAR_RCTE_RAWCELLINTEN);
317562306a36Sopenharmony_ci		write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 1,
317662306a36Sopenharmony_ci				    (u32) 0);
317762306a36Sopenharmony_ci		write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 2,
317862306a36Sopenharmony_ci				    (u32) 0);
317962306a36Sopenharmony_ci		write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 3,
318062306a36Sopenharmony_ci				    (u32) 0xffffffff);
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	writel((SAR_FBQ0_LOW << 28) | (SAR_FB_SIZE_0 / 48), SAR_REG_FBQS0);
318462306a36Sopenharmony_ci	writel((SAR_FBQ1_LOW << 28) | (SAR_FB_SIZE_1 / 48), SAR_REG_FBQS1);
318562306a36Sopenharmony_ci	writel((SAR_FBQ2_LOW << 28) | (SAR_FB_SIZE_2 / 48), SAR_REG_FBQS2);
318662306a36Sopenharmony_ci	writel((SAR_FBQ3_LOW << 28) | (SAR_FB_SIZE_3 / 48), SAR_REG_FBQS3);
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	/* Initialize rate table  */
318962306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
319062306a36Sopenharmony_ci		write_sram(card, card->rt_base + i, log_to_rate[i]);
319162306a36Sopenharmony_ci	}
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	for (i = 0; i < 128; i++) {
319462306a36Sopenharmony_ci		unsigned int tmp;
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci		tmp  = rate_to_log[(i << 2) + 0] << 0;
319762306a36Sopenharmony_ci		tmp |= rate_to_log[(i << 2) + 1] << 8;
319862306a36Sopenharmony_ci		tmp |= rate_to_log[(i << 2) + 2] << 16;
319962306a36Sopenharmony_ci		tmp |= rate_to_log[(i << 2) + 3] << 24;
320062306a36Sopenharmony_ci		write_sram(card, card->rt_base + 256 + i, tmp);
320162306a36Sopenharmony_ci	}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci#if 0 /* Fill RDF and AIR tables. */
320462306a36Sopenharmony_ci	for (i = 0; i < 128; i++) {
320562306a36Sopenharmony_ci		unsigned int tmp;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci		tmp = RDF[0][(i << 1) + 0] << 16;
320862306a36Sopenharmony_ci		tmp |= RDF[0][(i << 1) + 1] << 0;
320962306a36Sopenharmony_ci		write_sram(card, card->rt_base + 512 + i, tmp);
321062306a36Sopenharmony_ci	}
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	for (i = 0; i < 128; i++) {
321362306a36Sopenharmony_ci		unsigned int tmp;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci		tmp = AIR[0][(i << 1) + 0] << 16;
321662306a36Sopenharmony_ci		tmp |= AIR[0][(i << 1) + 1] << 0;
321762306a36Sopenharmony_ci		write_sram(card, card->rt_base + 640 + i, tmp);
321862306a36Sopenharmony_ci	}
321962306a36Sopenharmony_ci#endif
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	IPRINTK("%s: initialize rate table ...\n", card->name);
322262306a36Sopenharmony_ci	writel(card->rt_base << 2, SAR_REG_RTBL);
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	/* Initialize TSTs */
322562306a36Sopenharmony_ci	IPRINTK("%s: initialize TST ...\n", card->name);
322662306a36Sopenharmony_ci	card->tst_free = card->tst_size - 2;	/* last two are jumps */
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	for (i = card->tst[0]; i < card->tst[0] + card->tst_size - 2; i++)
322962306a36Sopenharmony_ci		write_sram(card, i, TSTE_OPC_VAR);
323062306a36Sopenharmony_ci	write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2));
323162306a36Sopenharmony_ci	idt77252_sram_write_errors = 1;
323262306a36Sopenharmony_ci	write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2));
323362306a36Sopenharmony_ci	idt77252_sram_write_errors = 0;
323462306a36Sopenharmony_ci	for (i = card->tst[1]; i < card->tst[1] + card->tst_size - 2; i++)
323562306a36Sopenharmony_ci		write_sram(card, i, TSTE_OPC_VAR);
323662306a36Sopenharmony_ci	write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2));
323762306a36Sopenharmony_ci	idt77252_sram_write_errors = 1;
323862306a36Sopenharmony_ci	write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2));
323962306a36Sopenharmony_ci	idt77252_sram_write_errors = 0;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	card->tst_index = 0;
324262306a36Sopenharmony_ci	writel(card->tst[0] << 2, SAR_REG_TSTB);
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	/* Initialize ABRSTD and Receive FIFO */
324562306a36Sopenharmony_ci	IPRINTK("%s: initialize ABRSTD ...\n", card->name);
324662306a36Sopenharmony_ci	writel(card->abrst_size | (card->abrst_base << 2),
324762306a36Sopenharmony_ci	       SAR_REG_ABRSTD);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	IPRINTK("%s: initialize receive fifo ...\n", card->name);
325062306a36Sopenharmony_ci	writel(card->fifo_size | (card->fifo_base << 2),
325162306a36Sopenharmony_ci	       SAR_REG_RXFD);
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	IPRINTK("%s: SRAM initialization complete.\n", card->name);
325462306a36Sopenharmony_ci}
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_cistatic int init_card(struct atm_dev *dev)
325762306a36Sopenharmony_ci{
325862306a36Sopenharmony_ci	struct idt77252_dev *card = dev->dev_data;
325962306a36Sopenharmony_ci	struct pci_dev *pcidev = card->pcidev;
326062306a36Sopenharmony_ci	unsigned long tmpl, modl;
326162306a36Sopenharmony_ci	unsigned int linkrate, rsvdcr;
326262306a36Sopenharmony_ci	unsigned int tst_entries;
326362306a36Sopenharmony_ci	struct net_device *tmp;
326462306a36Sopenharmony_ci	char tname[10];
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	u32 size;
326762306a36Sopenharmony_ci	u_char pci_byte;
326862306a36Sopenharmony_ci	u32 conf;
326962306a36Sopenharmony_ci	int i, k;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	if (test_bit(IDT77252_BIT_INIT, &card->flags)) {
327262306a36Sopenharmony_ci		printk("Error: SAR already initialized.\n");
327362306a36Sopenharmony_ci		return -1;
327462306a36Sopenharmony_ci	}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci/*****************************************************************/
327762306a36Sopenharmony_ci/*   P C I   C O N F I G U R A T I O N                           */
327862306a36Sopenharmony_ci/*****************************************************************/
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	/* Set PCI Retry-Timeout and TRDY timeout */
328162306a36Sopenharmony_ci	IPRINTK("%s: Checking PCI retries.\n", card->name);
328262306a36Sopenharmony_ci	if (pci_read_config_byte(pcidev, 0x40, &pci_byte) != 0) {
328362306a36Sopenharmony_ci		printk("%s: can't read PCI retry timeout.\n", card->name);
328462306a36Sopenharmony_ci		deinit_card(card);
328562306a36Sopenharmony_ci		return -1;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci	if (pci_byte != 0) {
328862306a36Sopenharmony_ci		IPRINTK("%s: PCI retry timeout: %d, set to 0.\n",
328962306a36Sopenharmony_ci			card->name, pci_byte);
329062306a36Sopenharmony_ci		if (pci_write_config_byte(pcidev, 0x40, 0) != 0) {
329162306a36Sopenharmony_ci			printk("%s: can't set PCI retry timeout.\n",
329262306a36Sopenharmony_ci			       card->name);
329362306a36Sopenharmony_ci			deinit_card(card);
329462306a36Sopenharmony_ci			return -1;
329562306a36Sopenharmony_ci		}
329662306a36Sopenharmony_ci	}
329762306a36Sopenharmony_ci	IPRINTK("%s: Checking PCI TRDY.\n", card->name);
329862306a36Sopenharmony_ci	if (pci_read_config_byte(pcidev, 0x41, &pci_byte) != 0) {
329962306a36Sopenharmony_ci		printk("%s: can't read PCI TRDY timeout.\n", card->name);
330062306a36Sopenharmony_ci		deinit_card(card);
330162306a36Sopenharmony_ci		return -1;
330262306a36Sopenharmony_ci	}
330362306a36Sopenharmony_ci	if (pci_byte != 0) {
330462306a36Sopenharmony_ci		IPRINTK("%s: PCI TRDY timeout: %d, set to 0.\n",
330562306a36Sopenharmony_ci		        card->name, pci_byte);
330662306a36Sopenharmony_ci		if (pci_write_config_byte(pcidev, 0x41, 0) != 0) {
330762306a36Sopenharmony_ci			printk("%s: can't set PCI TRDY timeout.\n", card->name);
330862306a36Sopenharmony_ci			deinit_card(card);
330962306a36Sopenharmony_ci			return -1;
331062306a36Sopenharmony_ci		}
331162306a36Sopenharmony_ci	}
331262306a36Sopenharmony_ci	/* Reset Timer register */
331362306a36Sopenharmony_ci	if (readl(SAR_REG_STAT) & SAR_STAT_TMROF) {
331462306a36Sopenharmony_ci		printk("%s: resetting timer overflow.\n", card->name);
331562306a36Sopenharmony_ci		writel(SAR_STAT_TMROF, SAR_REG_STAT);
331662306a36Sopenharmony_ci	}
331762306a36Sopenharmony_ci	IPRINTK("%s: Request IRQ ... ", card->name);
331862306a36Sopenharmony_ci	if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_SHARED,
331962306a36Sopenharmony_ci			card->name, card) != 0) {
332062306a36Sopenharmony_ci		printk("%s: can't allocate IRQ.\n", card->name);
332162306a36Sopenharmony_ci		deinit_card(card);
332262306a36Sopenharmony_ci		return -1;
332362306a36Sopenharmony_ci	}
332462306a36Sopenharmony_ci	IPRINTK("got %d.\n", pcidev->irq);
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci/*****************************************************************/
332762306a36Sopenharmony_ci/*   C H E C K   A N D   I N I T   S R A M                       */
332862306a36Sopenharmony_ci/*****************************************************************/
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	IPRINTK("%s: Initializing SRAM\n", card->name);
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	/* preset size of connecton table, so that init_sram() knows about it */
333362306a36Sopenharmony_ci	conf =	SAR_CFG_TX_FIFO_SIZE_9 |	/* Use maximum fifo size */
333462306a36Sopenharmony_ci		SAR_CFG_RXSTQ_SIZE_8k |		/* Receive Status Queue is 8k */
333562306a36Sopenharmony_ci		SAR_CFG_IDLE_CLP |		/* Set CLP on idle cells */
333662306a36Sopenharmony_ci#ifndef ATM_IDT77252_SEND_IDLE
333762306a36Sopenharmony_ci		SAR_CFG_NO_IDLE |		/* Do not send idle cells */
333862306a36Sopenharmony_ci#endif
333962306a36Sopenharmony_ci		0;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	if (card->sramsize == (512 * 1024))
334262306a36Sopenharmony_ci		conf |= SAR_CFG_CNTBL_1k;
334362306a36Sopenharmony_ci	else
334462306a36Sopenharmony_ci		conf |= SAR_CFG_CNTBL_512;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	switch (vpibits) {
334762306a36Sopenharmony_ci	case 0:
334862306a36Sopenharmony_ci		conf |= SAR_CFG_VPVCS_0;
334962306a36Sopenharmony_ci		break;
335062306a36Sopenharmony_ci	default:
335162306a36Sopenharmony_ci	case 1:
335262306a36Sopenharmony_ci		conf |= SAR_CFG_VPVCS_1;
335362306a36Sopenharmony_ci		break;
335462306a36Sopenharmony_ci	case 2:
335562306a36Sopenharmony_ci		conf |= SAR_CFG_VPVCS_2;
335662306a36Sopenharmony_ci		break;
335762306a36Sopenharmony_ci	case 8:
335862306a36Sopenharmony_ci		conf |= SAR_CFG_VPVCS_8;
335962306a36Sopenharmony_ci		break;
336062306a36Sopenharmony_ci	}
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	init_sram(card);
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci/********************************************************************/
336762306a36Sopenharmony_ci/*  A L L O C   R A M   A N D   S E T   V A R I O U S   T H I N G S */
336862306a36Sopenharmony_ci/********************************************************************/
336962306a36Sopenharmony_ci	/* Initialize TSQ */
337062306a36Sopenharmony_ci	if (0 != init_tsq(card)) {
337162306a36Sopenharmony_ci		deinit_card(card);
337262306a36Sopenharmony_ci		return -1;
337362306a36Sopenharmony_ci	}
337462306a36Sopenharmony_ci	/* Initialize RSQ */
337562306a36Sopenharmony_ci	if (0 != init_rsq(card)) {
337662306a36Sopenharmony_ci		deinit_card(card);
337762306a36Sopenharmony_ci		return -1;
337862306a36Sopenharmony_ci	}
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	card->vpibits = vpibits;
338162306a36Sopenharmony_ci	if (card->sramsize == (512 * 1024)) {
338262306a36Sopenharmony_ci		card->vcibits = 10 - card->vpibits;
338362306a36Sopenharmony_ci	} else {
338462306a36Sopenharmony_ci		card->vcibits = 9 - card->vpibits;
338562306a36Sopenharmony_ci	}
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	card->vcimask = 0;
338862306a36Sopenharmony_ci	for (k = 0, i = 1; k < card->vcibits; k++) {
338962306a36Sopenharmony_ci		card->vcimask |= i;
339062306a36Sopenharmony_ci		i <<= 1;
339162306a36Sopenharmony_ci	}
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	IPRINTK("%s: Setting VPI/VCI mask to zero.\n", card->name);
339462306a36Sopenharmony_ci	writel(0, SAR_REG_VPM);
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	/* Little Endian Order   */
339762306a36Sopenharmony_ci	writel(0, SAR_REG_GP);
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	/* Initialize RAW Cell Handle Register  */
340062306a36Sopenharmony_ci	card->raw_cell_hnd = dma_alloc_coherent(&card->pcidev->dev,
340162306a36Sopenharmony_ci						2 * sizeof(u32),
340262306a36Sopenharmony_ci						&card->raw_cell_paddr,
340362306a36Sopenharmony_ci						GFP_KERNEL);
340462306a36Sopenharmony_ci	if (!card->raw_cell_hnd) {
340562306a36Sopenharmony_ci		printk("%s: memory allocation failure.\n", card->name);
340662306a36Sopenharmony_ci		deinit_card(card);
340762306a36Sopenharmony_ci		return -1;
340862306a36Sopenharmony_ci	}
340962306a36Sopenharmony_ci	writel(card->raw_cell_paddr, SAR_REG_RAWHND);
341062306a36Sopenharmony_ci	IPRINTK("%s: raw cell handle is at 0x%p.\n", card->name,
341162306a36Sopenharmony_ci		card->raw_cell_hnd);
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	size = sizeof(struct vc_map *) * card->tct_size;
341462306a36Sopenharmony_ci	IPRINTK("%s: allocate %d byte for VC map.\n", card->name, size);
341562306a36Sopenharmony_ci	card->vcs = vzalloc(size);
341662306a36Sopenharmony_ci	if (!card->vcs) {
341762306a36Sopenharmony_ci		printk("%s: memory allocation failure.\n", card->name);
341862306a36Sopenharmony_ci		deinit_card(card);
341962306a36Sopenharmony_ci		return -1;
342062306a36Sopenharmony_ci	}
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	size = sizeof(struct vc_map *) * card->scd_size;
342362306a36Sopenharmony_ci	IPRINTK("%s: allocate %d byte for SCD to VC mapping.\n",
342462306a36Sopenharmony_ci	        card->name, size);
342562306a36Sopenharmony_ci	card->scd2vc = vzalloc(size);
342662306a36Sopenharmony_ci	if (!card->scd2vc) {
342762306a36Sopenharmony_ci		printk("%s: memory allocation failure.\n", card->name);
342862306a36Sopenharmony_ci		deinit_card(card);
342962306a36Sopenharmony_ci		return -1;
343062306a36Sopenharmony_ci	}
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	size = sizeof(struct tst_info) * (card->tst_size - 2);
343362306a36Sopenharmony_ci	IPRINTK("%s: allocate %d byte for TST to VC mapping.\n",
343462306a36Sopenharmony_ci		card->name, size);
343562306a36Sopenharmony_ci	card->soft_tst = vmalloc(size);
343662306a36Sopenharmony_ci	if (!card->soft_tst) {
343762306a36Sopenharmony_ci		printk("%s: memory allocation failure.\n", card->name);
343862306a36Sopenharmony_ci		deinit_card(card);
343962306a36Sopenharmony_ci		return -1;
344062306a36Sopenharmony_ci	}
344162306a36Sopenharmony_ci	for (i = 0; i < card->tst_size - 2; i++) {
344262306a36Sopenharmony_ci		card->soft_tst[i].tste = TSTE_OPC_VAR;
344362306a36Sopenharmony_ci		card->soft_tst[i].vc = NULL;
344462306a36Sopenharmony_ci	}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci	if (dev->phy == NULL) {
344762306a36Sopenharmony_ci		printk("%s: No LT device defined.\n", card->name);
344862306a36Sopenharmony_ci		deinit_card(card);
344962306a36Sopenharmony_ci		return -1;
345062306a36Sopenharmony_ci	}
345162306a36Sopenharmony_ci	if (dev->phy->ioctl == NULL) {
345262306a36Sopenharmony_ci		printk("%s: LT had no IOCTL function defined.\n", card->name);
345362306a36Sopenharmony_ci		deinit_card(card);
345462306a36Sopenharmony_ci		return -1;
345562306a36Sopenharmony_ci	}
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci#ifdef	CONFIG_ATM_IDT77252_USE_SUNI
345862306a36Sopenharmony_ci	/*
345962306a36Sopenharmony_ci	 * this is a jhs hack to get around special functionality in the
346062306a36Sopenharmony_ci	 * phy driver for the atecom hardware; the functionality doesn't
346162306a36Sopenharmony_ci	 * exist in the linux atm suni driver
346262306a36Sopenharmony_ci	 *
346362306a36Sopenharmony_ci	 * it isn't the right way to do things, but as the guy from NIST
346462306a36Sopenharmony_ci	 * said, talking about their measurement of the fine structure
346562306a36Sopenharmony_ci	 * constant, "it's good enough for government work."
346662306a36Sopenharmony_ci	 */
346762306a36Sopenharmony_ci	linkrate = 149760000;
346862306a36Sopenharmony_ci#endif
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	card->link_pcr = (linkrate / 8 / 53);
347162306a36Sopenharmony_ci	printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
347262306a36Sopenharmony_ci	       card->name, linkrate, card->link_pcr);
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci#ifdef ATM_IDT77252_SEND_IDLE
347562306a36Sopenharmony_ci	card->utopia_pcr = card->link_pcr;
347662306a36Sopenharmony_ci#else
347762306a36Sopenharmony_ci	card->utopia_pcr = (160000000 / 8 / 54);
347862306a36Sopenharmony_ci#endif
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	rsvdcr = 0;
348162306a36Sopenharmony_ci	if (card->utopia_pcr > card->link_pcr)
348262306a36Sopenharmony_ci		rsvdcr = card->utopia_pcr - card->link_pcr;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	tmpl = (unsigned long) rsvdcr * ((unsigned long) card->tst_size - 2);
348562306a36Sopenharmony_ci	modl = tmpl % (unsigned long)card->utopia_pcr;
348662306a36Sopenharmony_ci	tst_entries = (int) (tmpl / (unsigned long)card->utopia_pcr);
348762306a36Sopenharmony_ci	if (modl)
348862306a36Sopenharmony_ci		tst_entries++;
348962306a36Sopenharmony_ci	card->tst_free -= tst_entries;
349062306a36Sopenharmony_ci	fill_tst(card, NULL, tst_entries, TSTE_OPC_NULL);
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci#ifdef HAVE_EEPROM
349362306a36Sopenharmony_ci	idt77252_eeprom_init(card);
349462306a36Sopenharmony_ci	printk("%s: EEPROM: %02x:", card->name,
349562306a36Sopenharmony_ci		idt77252_eeprom_read_status(card));
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	for (i = 0; i < 0x80; i++) {
349862306a36Sopenharmony_ci		printk(" %02x",
349962306a36Sopenharmony_ci		idt77252_eeprom_read_byte(card, i)
350062306a36Sopenharmony_ci		);
350162306a36Sopenharmony_ci	}
350262306a36Sopenharmony_ci	printk("\n");
350362306a36Sopenharmony_ci#endif /* HAVE_EEPROM */
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	/*
350662306a36Sopenharmony_ci	 * XXX: <hack>
350762306a36Sopenharmony_ci	 */
350862306a36Sopenharmony_ci	sprintf(tname, "eth%d", card->index);
350962306a36Sopenharmony_ci	tmp = dev_get_by_name(&init_net, tname);	/* jhs: was "tmp = dev_get(tname);" */
351062306a36Sopenharmony_ci	if (tmp) {
351162306a36Sopenharmony_ci		memcpy(card->atmdev->esi, tmp->dev_addr, 6);
351262306a36Sopenharmony_ci		dev_put(tmp);
351362306a36Sopenharmony_ci		printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
351462306a36Sopenharmony_ci	}
351562306a36Sopenharmony_ci	/*
351662306a36Sopenharmony_ci	 * XXX: </hack>
351762306a36Sopenharmony_ci	 */
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	/* Set Maximum Deficit Count for now. */
352062306a36Sopenharmony_ci	writel(0xffff, SAR_REG_MDFCT);
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	set_bit(IDT77252_BIT_INIT, &card->flags);
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	XPRINTK("%s: IDT77252 ABR SAR initialization complete.\n", card->name);
352562306a36Sopenharmony_ci	return 0;
352662306a36Sopenharmony_ci}
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci/*****************************************************************************/
353062306a36Sopenharmony_ci/*                                                                           */
353162306a36Sopenharmony_ci/* Probing of IDT77252 ABR SAR                                               */
353262306a36Sopenharmony_ci/*                                                                           */
353362306a36Sopenharmony_ci/*****************************************************************************/
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_cistatic int idt77252_preset(struct idt77252_dev *card)
353762306a36Sopenharmony_ci{
353862306a36Sopenharmony_ci	u16 pci_command;
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci/*****************************************************************/
354162306a36Sopenharmony_ci/*   P C I   C O N F I G U R A T I O N                           */
354262306a36Sopenharmony_ci/*****************************************************************/
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	XPRINTK("%s: Enable PCI master and memory access for SAR.\n",
354562306a36Sopenharmony_ci		card->name);
354662306a36Sopenharmony_ci	if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command)) {
354762306a36Sopenharmony_ci		printk("%s: can't read PCI_COMMAND.\n", card->name);
354862306a36Sopenharmony_ci		deinit_card(card);
354962306a36Sopenharmony_ci		return -1;
355062306a36Sopenharmony_ci	}
355162306a36Sopenharmony_ci	if (!(pci_command & PCI_COMMAND_IO)) {
355262306a36Sopenharmony_ci		printk("%s: PCI_COMMAND: %04x (?)\n",
355362306a36Sopenharmony_ci		       card->name, pci_command);
355462306a36Sopenharmony_ci		deinit_card(card);
355562306a36Sopenharmony_ci		return (-1);
355662306a36Sopenharmony_ci	}
355762306a36Sopenharmony_ci	pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
355862306a36Sopenharmony_ci	if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command)) {
355962306a36Sopenharmony_ci		printk("%s: can't write PCI_COMMAND.\n", card->name);
356062306a36Sopenharmony_ci		deinit_card(card);
356162306a36Sopenharmony_ci		return -1;
356262306a36Sopenharmony_ci	}
356362306a36Sopenharmony_ci/*****************************************************************/
356462306a36Sopenharmony_ci/*   G E N E R I C   R E S E T                                   */
356562306a36Sopenharmony_ci/*****************************************************************/
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	/* Software reset */
356862306a36Sopenharmony_ci	writel(SAR_CFG_SWRST, SAR_REG_CFG);
356962306a36Sopenharmony_ci	mdelay(1);
357062306a36Sopenharmony_ci	writel(0, SAR_REG_CFG);
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	IPRINTK("%s: Software resetted.\n", card->name);
357362306a36Sopenharmony_ci	return 0;
357462306a36Sopenharmony_ci}
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_cistatic unsigned long probe_sram(struct idt77252_dev *card)
357862306a36Sopenharmony_ci{
357962306a36Sopenharmony_ci	u32 data, addr;
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci	writel(0, SAR_REG_DR0);
358262306a36Sopenharmony_ci	writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD);
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	for (addr = 0x4000; addr < 0x80000; addr += 0x4000) {
358562306a36Sopenharmony_ci		writel(ATM_POISON, SAR_REG_DR0);
358662306a36Sopenharmony_ci		writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci		writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD);
358962306a36Sopenharmony_ci		data = readl(SAR_REG_DR0);
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci		if (data != 0)
359262306a36Sopenharmony_ci			break;
359362306a36Sopenharmony_ci	}
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	return addr * sizeof(u32);
359662306a36Sopenharmony_ci}
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_cistatic int idt77252_init_one(struct pci_dev *pcidev,
359962306a36Sopenharmony_ci			     const struct pci_device_id *id)
360062306a36Sopenharmony_ci{
360162306a36Sopenharmony_ci	static struct idt77252_dev **last = &idt77252_chain;
360262306a36Sopenharmony_ci	static int index = 0;
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	unsigned long membase, srambase;
360562306a36Sopenharmony_ci	struct idt77252_dev *card;
360662306a36Sopenharmony_ci	struct atm_dev *dev;
360762306a36Sopenharmony_ci	int i, err;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	if ((err = pci_enable_device(pcidev))) {
361162306a36Sopenharmony_ci		printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev));
361262306a36Sopenharmony_ci		return err;
361362306a36Sopenharmony_ci	}
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	if ((err = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)))) {
361662306a36Sopenharmony_ci		printk("idt77252: can't enable DMA for PCI device at %s\n", pci_name(pcidev));
361762306a36Sopenharmony_ci		goto err_out_disable_pdev;
361862306a36Sopenharmony_ci	}
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
362162306a36Sopenharmony_ci	if (!card) {
362262306a36Sopenharmony_ci		printk("idt77252-%d: can't allocate private data\n", index);
362362306a36Sopenharmony_ci		err = -ENOMEM;
362462306a36Sopenharmony_ci		goto err_out_disable_pdev;
362562306a36Sopenharmony_ci	}
362662306a36Sopenharmony_ci	card->revision = pcidev->revision;
362762306a36Sopenharmony_ci	card->index = index;
362862306a36Sopenharmony_ci	card->pcidev = pcidev;
362962306a36Sopenharmony_ci	sprintf(card->name, "idt77252-%d", card->index);
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	INIT_WORK(&card->tqueue, idt77252_softint);
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	membase = pci_resource_start(pcidev, 1);
363462306a36Sopenharmony_ci	srambase = pci_resource_start(pcidev, 2);
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	mutex_init(&card->mutex);
363762306a36Sopenharmony_ci	spin_lock_init(&card->cmd_lock);
363862306a36Sopenharmony_ci	spin_lock_init(&card->tst_lock);
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	timer_setup(&card->tst_timer, tst_timer, 0);
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	/* Do the I/O remapping... */
364362306a36Sopenharmony_ci	card->membase = ioremap(membase, 1024);
364462306a36Sopenharmony_ci	if (!card->membase) {
364562306a36Sopenharmony_ci		printk("%s: can't ioremap() membase\n", card->name);
364662306a36Sopenharmony_ci		err = -EIO;
364762306a36Sopenharmony_ci		goto err_out_free_card;
364862306a36Sopenharmony_ci	}
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	if (idt77252_preset(card)) {
365162306a36Sopenharmony_ci		printk("%s: preset failed\n", card->name);
365262306a36Sopenharmony_ci		err = -EIO;
365362306a36Sopenharmony_ci		goto err_out_iounmap;
365462306a36Sopenharmony_ci	}
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1,
365762306a36Sopenharmony_ci			       NULL);
365862306a36Sopenharmony_ci	if (!dev) {
365962306a36Sopenharmony_ci		printk("%s: can't register atm device\n", card->name);
366062306a36Sopenharmony_ci		err = -EIO;
366162306a36Sopenharmony_ci		goto err_out_iounmap;
366262306a36Sopenharmony_ci	}
366362306a36Sopenharmony_ci	dev->dev_data = card;
366462306a36Sopenharmony_ci	card->atmdev = dev;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci#ifdef	CONFIG_ATM_IDT77252_USE_SUNI
366762306a36Sopenharmony_ci	suni_init(dev);
366862306a36Sopenharmony_ci	if (!dev->phy) {
366962306a36Sopenharmony_ci		printk("%s: can't init SUNI\n", card->name);
367062306a36Sopenharmony_ci		err = -EIO;
367162306a36Sopenharmony_ci		goto err_out_deinit_card;
367262306a36Sopenharmony_ci	}
367362306a36Sopenharmony_ci#endif	/* CONFIG_ATM_IDT77252_USE_SUNI */
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	card->sramsize = probe_sram(card);
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
367862306a36Sopenharmony_ci		card->fbq[i] = ioremap(srambase | 0x200000 | (i << 18), 4);
367962306a36Sopenharmony_ci		if (!card->fbq[i]) {
368062306a36Sopenharmony_ci			printk("%s: can't ioremap() FBQ%d\n", card->name, i);
368162306a36Sopenharmony_ci			err = -EIO;
368262306a36Sopenharmony_ci			goto err_out_deinit_card;
368362306a36Sopenharmony_ci		}
368462306a36Sopenharmony_ci	}
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	printk("%s: ABR SAR (Rev %c): MEM %08lx SRAM %08lx [%u KB]\n",
368762306a36Sopenharmony_ci	       card->name, ((card->revision > 1) && (card->revision < 25)) ?
368862306a36Sopenharmony_ci	       'A' + card->revision - 1 : '?', membase, srambase,
368962306a36Sopenharmony_ci	       card->sramsize / 1024);
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci	if (init_card(dev)) {
369262306a36Sopenharmony_ci		printk("%s: init_card failed\n", card->name);
369362306a36Sopenharmony_ci		err = -EIO;
369462306a36Sopenharmony_ci		goto err_out_deinit_card;
369562306a36Sopenharmony_ci	}
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	dev->ci_range.vpi_bits = card->vpibits;
369862306a36Sopenharmony_ci	dev->ci_range.vci_bits = card->vcibits;
369962306a36Sopenharmony_ci	dev->link_rate = card->link_pcr;
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	if (dev->phy->start)
370262306a36Sopenharmony_ci		dev->phy->start(dev);
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	if (idt77252_dev_open(card)) {
370562306a36Sopenharmony_ci		printk("%s: dev_open failed\n", card->name);
370662306a36Sopenharmony_ci		err = -EIO;
370762306a36Sopenharmony_ci		goto err_out_stop;
370862306a36Sopenharmony_ci	}
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	*last = card;
371162306a36Sopenharmony_ci	last = &card->next;
371262306a36Sopenharmony_ci	index++;
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci	return 0;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_cierr_out_stop:
371762306a36Sopenharmony_ci	if (dev->phy->stop)
371862306a36Sopenharmony_ci		dev->phy->stop(dev);
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_cierr_out_deinit_card:
372162306a36Sopenharmony_ci	deinit_card(card);
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_cierr_out_iounmap:
372462306a36Sopenharmony_ci	iounmap(card->membase);
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_cierr_out_free_card:
372762306a36Sopenharmony_ci	kfree(card);
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_cierr_out_disable_pdev:
373062306a36Sopenharmony_ci	pci_disable_device(pcidev);
373162306a36Sopenharmony_ci	return err;
373262306a36Sopenharmony_ci}
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_cistatic const struct pci_device_id idt77252_pci_tbl[] =
373562306a36Sopenharmony_ci{
373662306a36Sopenharmony_ci	{ PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77252), 0 },
373762306a36Sopenharmony_ci	{ 0, }
373862306a36Sopenharmony_ci};
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, idt77252_pci_tbl);
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_cistatic struct pci_driver idt77252_driver = {
374362306a36Sopenharmony_ci	.name		= "idt77252",
374462306a36Sopenharmony_ci	.id_table	= idt77252_pci_tbl,
374562306a36Sopenharmony_ci	.probe		= idt77252_init_one,
374662306a36Sopenharmony_ci};
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_cistatic int __init idt77252_init(void)
374962306a36Sopenharmony_ci{
375062306a36Sopenharmony_ci	struct sk_buff *skb;
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	printk("%s: at %p\n", __func__, idt77252_init);
375362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct idt77252_skb_prv) + sizeof(struct atm_skb_data));
375462306a36Sopenharmony_ci	return pci_register_driver(&idt77252_driver);
375562306a36Sopenharmony_ci}
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_cistatic void __exit idt77252_exit(void)
375862306a36Sopenharmony_ci{
375962306a36Sopenharmony_ci	struct idt77252_dev *card;
376062306a36Sopenharmony_ci	struct atm_dev *dev;
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_ci	pci_unregister_driver(&idt77252_driver);
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	while (idt77252_chain) {
376562306a36Sopenharmony_ci		card = idt77252_chain;
376662306a36Sopenharmony_ci		dev = card->atmdev;
376762306a36Sopenharmony_ci		idt77252_chain = card->next;
376862306a36Sopenharmony_ci		timer_shutdown_sync(&card->tst_timer);
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci		if (dev->phy->stop)
377162306a36Sopenharmony_ci			dev->phy->stop(dev);
377262306a36Sopenharmony_ci		deinit_card(card);
377362306a36Sopenharmony_ci		pci_disable_device(card->pcidev);
377462306a36Sopenharmony_ci		kfree(card);
377562306a36Sopenharmony_ci	}
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	DIPRINTK("idt77252: finished cleanup-module().\n");
377862306a36Sopenharmony_ci}
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_cimodule_init(idt77252_init);
378162306a36Sopenharmony_cimodule_exit(idt77252_exit);
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_cimodule_param(vpibits, uint, 0);
378662306a36Sopenharmony_ciMODULE_PARM_DESC(vpibits, "number of VPI bits supported (0, 1, or 2)");
378762306a36Sopenharmony_ci#ifdef CONFIG_ATM_IDT77252_DEBUG
378862306a36Sopenharmony_cimodule_param(debug, ulong, 0644);
378962306a36Sopenharmony_ciMODULE_PARM_DESC(debug,   "debug bitmap, see drivers/atm/idt77252.h");
379062306a36Sopenharmony_ci#endif
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ciMODULE_AUTHOR("Eddie C. Dost <ecd@atecom.com>");
379362306a36Sopenharmony_ciMODULE_DESCRIPTION("IDT77252 ABR SAR Driver");
3794