cregit-Linux how code gets into the kernel

Release 4.11 drivers/atm/idt77252.c

Directory: drivers/atm
/******************************************************************* 
 *
 * Copyright (c) 2000 ATecoM GmbH 
 *
 * The author may be reached at ecd@atecom.com.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
 * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *******************************************************************/

#include <linux/module.h>
#include <linux/pci.h>
#include <linux/poison.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/netdevice.h>
#include <linux/atmdev.h>
#include <linux/atm.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/slab.h>

#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <asm/byteorder.h>

#ifdef CONFIG_ATM_IDT77252_USE_SUNI
#include "suni.h"
#endif /* CONFIG_ATM_IDT77252_USE_SUNI */


#include "idt77252.h"
#include "idt77252_tables.h"


static unsigned int vpibits = 1;



#define ATM_IDT77252_SEND_IDLE 1


/*
 * Debug HACKs.
 */

#define DEBUG_MODULE 1

#undef HAVE_EEPROM	
/* does not work, yet. */

#ifdef CONFIG_ATM_IDT77252_DEBUG

static unsigned long debug = DBG_GENERAL;
#endif



#define SAR_RX_DELAY	(SAR_CFG_RXINT_NODELAY)


/*
 * SCQ Handling.
 */
static struct scq_info *alloc_scq(struct idt77252_dev *, int);
static void free_scq(struct idt77252_dev *, struct scq_info *);
static int queue_skb(struct idt77252_dev *, struct vc_map *,
		     struct sk_buff *, int oam);
static void drain_scq(struct idt77252_dev *, struct vc_map *);
static unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *);
static void fill_scd(struct idt77252_dev *, struct scq_info *, int);

/*
 * FBQ Handling.
 */
static int push_rx_skb(struct idt77252_dev *,
		       struct sk_buff *, int queue);
static void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *);
static void flush_rx_pool(struct idt77252_dev *, struct rx_pool *);
static void recycle_rx_pool_skb(struct idt77252_dev *,
				struct rx_pool *);
static void add_rx_skb(struct idt77252_dev *, int queue,
		       unsigned int size, unsigned int count);

/*
 * RSQ Handling.
 */
static int init_rsq(struct idt77252_dev *);
static void deinit_rsq(struct idt77252_dev *);
static void idt77252_rx(struct idt77252_dev *);

/*
 * TSQ handling.
 */
static int init_tsq(struct idt77252_dev *);
static void deinit_tsq(struct idt77252_dev *);
static void idt77252_tx(struct idt77252_dev *);


/*
 * ATM Interface.
 */
static void idt77252_dev_close(struct atm_dev *dev);
static int idt77252_open(struct atm_vcc *vcc);
static void idt77252_close(struct atm_vcc *vcc);
static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb);
static int idt77252_send_oam(struct atm_vcc *vcc, void *cell,
			     int flags);
static void idt77252_phy_put(struct atm_dev *dev, unsigned char value,
			     unsigned long addr);
static unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr);
static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos,
			       int flags);
static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos,
			      char *page);
static void idt77252_softint(struct work_struct *work);



static struct atmdev_ops idt77252_ops =
{
	.dev_close	= idt77252_dev_close,
	.open		= idt77252_open,
	.close		= idt77252_close,
	.send		= idt77252_send,
	.send_oam	= idt77252_send_oam,
	.phy_put	= idt77252_phy_put,
	.phy_get	= idt77252_phy_get,
	.change_qos	= idt77252_change_qos,
	.proc_read	= idt77252_proc_read,
	.owner		= THIS_MODULE
};


static struct idt77252_dev *idt77252_chain = NULL;

static unsigned int idt77252_sram_write_errors = 0;

/*****************************************************************************/
/*                                                                           */
/* I/O and Utility Bus                                                       */
/*                                                                           */
/*****************************************************************************/


static void waitfor_idle(struct idt77252_dev *card) { u32 stat; stat = readl(SAR_REG_STAT); while (stat & SAR_STAT_CMDBZ) stat = readl(SAR_REG_STAT); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds34100.00%1100.00%
Total34100.00%1100.00%


static u32 read_sram(struct idt77252_dev *card, unsigned long addr) { unsigned long flags; u32 value; spin_lock_irqsave(&card->cmd_lock, flags); writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD); waitfor_idle(card); value = readl(SAR_REG_DR0); spin_unlock_irqrestore(&card->cmd_lock, flags); return value; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds70100.00%1100.00%
Total70100.00%1100.00%


static void write_sram(struct idt77252_dev *card, unsigned long addr, u32 value) { unsigned long flags; if ((idt77252_sram_write_errors == 0) && (((addr > card->tst[0] + card->tst_size - 2) && (addr < card->tst[0] + card->tst_size)) || ((addr > card->tst[1] + card->tst_size - 2) && (addr < card->tst[1] + card->tst_size)))) { printk("%s: ERROR: TST JMP section at %08lx written: %08x\n", card->name, addr, value); } spin_lock_irqsave(&card->cmd_lock, flags); writel(value, SAR_REG_DR0); writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); waitfor_idle(card); spin_unlock_irqrestore(&card->cmd_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds160100.00%1100.00%
Total160100.00%1100.00%


static u8 read_utility(void *dev, unsigned long ubus_addr) { struct idt77252_dev *card = dev; unsigned long flags; u8 value; if (!card) { printk("Error: No such device.\n"); return -1; } spin_lock_irqsave(&card->cmd_lock, flags); writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD); waitfor_idle(card); value = readl(SAR_REG_DR0); spin_unlock_irqrestore(&card->cmd_lock, flags); return value; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds88100.00%1100.00%
Total88100.00%1100.00%


static void write_utility(void *dev, unsigned long ubus_addr, u8 value) { struct idt77252_dev *card = dev; unsigned long flags; if (!card) { printk("Error: No such device.\n"); return; } spin_lock_irqsave(&card->cmd_lock, flags); writel((u32) value, SAR_REG_DR0); writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD); waitfor_idle(card); spin_unlock_irqrestore(&card->cmd_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds85100.00%1100.00%
Total85100.00%1100.00%

#ifdef HAVE_EEPROM static u32 rdsrtab[] = { SAR_GP_EECS | SAR_GP_EESCLK, 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ 0, SAR_GP_EESCLK, /* 0 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ }; static u32 wrentab[] = { SAR_GP_EECS | SAR_GP_EESCLK, 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK /* 0 */ }; static u32 rdtab[] = { SAR_GP_EECS | SAR_GP_EESCLK, 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ }; static u32 wrtab[] = { SAR_GP_EECS | SAR_GP_EESCLK, 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ 0, SAR_GP_EESCLK, /* 0 */ SAR_GP_EEDO, SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ 0, SAR_GP_EESCLK /* 0 */ }; static u32 clktab[] = { 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0, SAR_GP_EESCLK, 0 };
static u32 idt77252_read_gp(struct idt77252_dev *card) { u32 gp; gp = readl(SAR_REG_GP); #if 0 printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0"); #endif return gp; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds30100.00%1100.00%
Total30100.00%1100.00%


static void idt77252_write_gp(struct idt77252_dev *card, u32 value) { unsigned long flags; #if 0 printk("WR: %s %s %s\n", value & SAR_GP_EECS ? " " : "/CS", value & SAR_GP_EESCLK ? "HIGH" : "LOW ", value & SAR_GP_EEDO ? "1" : "0"); #endif spin_lock_irqsave(&card->cmd_lock, flags); waitfor_idle(card); writel(value, SAR_REG_GP); spin_unlock_irqrestore(&card->cmd_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds56100.00%1100.00%
Total56100.00%1100.00%


static u8 idt77252_eeprom_read_status(struct idt77252_dev *card) { u8 byte; u32 gp; int i, j; gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { idt77252_write_gp(card, gp | rdsrtab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); byte = 0; for (i = 0, j = 0; i < 8; i++) { byte <<= 1; idt77252_write_gp(card, gp | clktab[j++]); udelay(5); byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; idt77252_write_gp(card, gp | clktab[j++]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); return byte; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds17999.44%150.00%
Ahmed S. Darwish10.56%150.00%
Total180100.00%2100.00%


static u8 idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset) { u8 byte; u32 gp; int i, j; gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); for (i = 0; i < ARRAY_SIZE(rdtab); i++) { idt77252_write_gp(card, gp | rdtab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); for (i = 0, j = 0; i < 8; i++) { idt77252_write_gp(card, gp | clktab[j++] | (offset & 1 ? SAR_GP_EEDO : 0)); udelay(5); idt77252_write_gp(card, gp | clktab[j++] | (offset & 1 ? SAR_GP_EEDO : 0)); udelay(5); offset >>= 1; } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); byte = 0; for (i = 0, j = 0; i < 8; i++) { byte <<= 1; idt77252_write_gp(card, gp | clktab[j++]); udelay(5); byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; idt77252_write_gp(card, gp | clktab[j++]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); return byte; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds27599.64%150.00%
Ahmed S. Darwish10.36%150.00%
Total276100.00%2100.00%


static void idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data) { u32 gp; int i, j; gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); for (i = 0; i < ARRAY_SIZE(wrentab); i++) { idt77252_write_gp(card, gp | wrentab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); for (i = 0; i < ARRAY_SIZE(wrtab); i++) { idt77252_write_gp(card, gp | wrtab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); for (i = 0, j = 0; i < 8; i++) { idt77252_write_gp(card, gp | clktab[j++] | (offset & 1 ? SAR_GP_EEDO : 0)); udelay(5); idt77252_write_gp(card, gp | clktab[j++] | (offset & 1 ? SAR_GP_EEDO : 0)); udelay(5); offset >>= 1; } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); for (i = 0, j = 0; i < 8; i++) { idt77252_write_gp(card, gp | clktab[j++] | (data & 1 ? SAR_GP_EEDO : 0)); udelay(5); idt77252_write_gp(card, gp | clktab[j++] | (data & 1 ? SAR_GP_EEDO : 0)); udelay(5); data >>= 1; } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds32399.38%150.00%
Ahmed S. Darwish20.62%150.00%
Total325100.00%2100.00%


static void idt77252_eeprom_init(struct idt77252_dev *card) { u32 gp; gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); udelay(5); idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); udelay(5); idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds90100.00%1100.00%
Total90100.00%1100.00%

#endif /* HAVE_EEPROM */ #ifdef CONFIG_ATM_IDT77252_DEBUG
static void dump_tct(struct idt77252_dev *card, int index) { unsigned long tct; int i; tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE); printk("%s: TCT %x:", card->name, index); for (i = 0; i < 8; i++) { printk(" %08x", read_sram(card, tct + i)); } printk("\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds82100.00%1100.00%
Total82100.00%1100.00%


static void idt77252_tx_dump(struct idt77252_dev *card) { struct atm_vcc *vcc; struct vc_map *vc; int i; printk("%s\n", __func__); for (i = 0; i < card->tct_size; i++) { vc = card->vcs[i]; if (!vc) continue; vcc = NULL; if (vc->rx_vcc) vcc = vc->rx_vcc; else if (vc->tx_vcc) vcc = vc->tx_vcc; if (!vcc) continue; printk("%s: Connection %d:\n", card->name, vc->index); dump_tct(card, vc->index); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds11999.17%150.00%
Harvey Harrison10.83%150.00%
Total120100.00%2100.00%

#endif /*****************************************************************************/ /* */ /* SCQ Handling */ /* */ /*****************************************************************************/
static int sb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue) { struct sb_pool *pool = &card->sbpool[queue]; int index; index = pool->index; while (pool->skb[index]) { index = (index + 1) & FBQ_MASK; if (index == pool->index) return -ENOBUFS; } pool->skb[index] = skb; IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index); pool->index = (index + 1) & FBQ_MASK; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds110100.00%1100.00%
Total110100.00%1100.00%


static void sb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb) { unsigned int queue, index; u32 handle; handle = IDT77252_PRV_POOL(skb); queue = POOL_QUEUE(handle); if (queue > 3) return; index = POOL_INDEX(handle); if (index > FBQ_SIZE - 1) return; card->sbpool[queue].skb[index] = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds76100.00%1100.00%
Total76100.00%1100.00%


static struct sk_buff * sb_pool_skb(struct idt77252_dev *card, u32 handle) { unsigned int queue, index; queue = POOL_QUEUE(handle); if (queue > 3) return NULL; index = POOL_INDEX(handle); if (index > FBQ_SIZE - 1) return NULL; return card->sbpool[queue].skb[index]; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds69100.00%1100.00%
Total69100.00%1100.00%


static struct scq_info * alloc_scq(struct idt77252_dev *card, int class) { struct scq_info *scq; scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL); if (!scq) return NULL; scq->base = dma_zalloc_coherent(&card->pcidev->dev, SCQ_SIZE, &scq->paddr, GFP_KERNEL); if (scq->base == NULL) { kfree(scq); return NULL; } scq->next = scq->base; scq->last = scq->base + (SCQ_ENTRIES - 1); atomic_set(&scq->used, 0); spin_lock_init(&scq->lock); spin_lock_init(&scq->skblock); skb_queue_head_init(&scq->transmit); skb_queue_head_init(&scq->pending); TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08llx\n", scq->base, scq->next, scq->last, (unsigned long long)scq->paddr); return scq; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds16392.61%125.00%
Chas Williams126.82%250.00%
Om Narasimhan10.57%125.00%
Total176100.00%4100.00%


static void free_scq(struct idt77252_dev *card, struct scq_info *scq) { struct sk_buff *skb; struct atm_vcc *vcc; dma_free_coherent(&card->pcidev->dev, SCQ_SIZE, scq->base, scq->paddr); while ((skb = skb_dequeue(&scq->transmit))) { dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), skb->len, DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); } while ((skb = skb_dequeue(&scq->pending))) { dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), skb->len, DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); } kfree(scq); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds17192.43%150.00%
Chas Williams147.57%150.00%
Total185100.00%2100.00%


static int push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb) { struct scq_info *scq = vc->scq; unsigned long flags; struct scqe *tbd; int entries; TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next); atomic_inc(&scq->used); entries = atomic_read(&scq->used); if (entries > (SCQ_ENTRIES - 1)) { atomic_dec(&scq->used); goto out; } skb_queue_tail(&scq->transmit, skb); spin_lock_irqsave(&vc->lock, flags); if (vc->estimator) { struct atm_vcc *vcc = vc->tx_vcc; struct sock *sk = sk_atm(vcc); vc->estimator->cells += (skb->len + 47) / 48; if (atomic_read(&sk->sk_wmem_alloc) > (sk->sk_sndbuf >> 1)) { u32 cps = vc->estimator->maxcps; vc->estimator->cps = cps;