162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * nicstar.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. 862306a36Sopenharmony_ci * It was taken from the frle-0.22 device driver. 962306a36Sopenharmony_ci * As the file doesn't have a copyright notice, in the file 1062306a36Sopenharmony_ci * nicstarmac.copyright I put the copyright notice from the 1162306a36Sopenharmony_ci * frle-0.22 device driver. 1262306a36Sopenharmony_ci * Some code is based on the nicstar driver by M. Welsh. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Author: Rui Prior (rprior@inescn.pt) 1562306a36Sopenharmony_ci * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * (C) INESC 1999 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * IMPORTANT INFORMATION 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * There are currently three types of spinlocks: 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * 1 - Per card interrupt spinlock (to protect structures and such) 2762306a36Sopenharmony_ci * 2 - Per SCQ scq spinlock 2862306a36Sopenharmony_ci * 3 - Per card resource spinlock (to access registers, etc.) 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * These must NEVER be grabbed in reverse order. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Header files */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/kernel.h> 3862306a36Sopenharmony_ci#include <linux/skbuff.h> 3962306a36Sopenharmony_ci#include <linux/atmdev.h> 4062306a36Sopenharmony_ci#include <linux/atm.h> 4162306a36Sopenharmony_ci#include <linux/pci.h> 4262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4362306a36Sopenharmony_ci#include <linux/types.h> 4462306a36Sopenharmony_ci#include <linux/string.h> 4562306a36Sopenharmony_ci#include <linux/delay.h> 4662306a36Sopenharmony_ci#include <linux/init.h> 4762306a36Sopenharmony_ci#include <linux/sched.h> 4862306a36Sopenharmony_ci#include <linux/timer.h> 4962306a36Sopenharmony_ci#include <linux/interrupt.h> 5062306a36Sopenharmony_ci#include <linux/bitops.h> 5162306a36Sopenharmony_ci#include <linux/slab.h> 5262306a36Sopenharmony_ci#include <linux/idr.h> 5362306a36Sopenharmony_ci#include <asm/io.h> 5462306a36Sopenharmony_ci#include <linux/uaccess.h> 5562306a36Sopenharmony_ci#include <linux/atomic.h> 5662306a36Sopenharmony_ci#include <linux/etherdevice.h> 5762306a36Sopenharmony_ci#include "nicstar.h" 5862306a36Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_SUNI 5962306a36Sopenharmony_ci#include "suni.h" 6062306a36Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 6162306a36Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 6262306a36Sopenharmony_ci#include "idt77105.h" 6362306a36Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Additional code */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#include "nicstarmac.c" 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Configurable parameters */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#undef PHY_LOOPBACK 7262306a36Sopenharmony_ci#undef TX_DEBUG 7362306a36Sopenharmony_ci#undef RX_DEBUG 7462306a36Sopenharmony_ci#undef GENERAL_DEBUG 7562306a36Sopenharmony_ci#undef EXTRA_DEBUG 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* Do not touch these */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#ifdef TX_DEBUG 8062306a36Sopenharmony_ci#define TXPRINTK(args...) printk(args) 8162306a36Sopenharmony_ci#else 8262306a36Sopenharmony_ci#define TXPRINTK(args...) 8362306a36Sopenharmony_ci#endif /* TX_DEBUG */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#ifdef RX_DEBUG 8662306a36Sopenharmony_ci#define RXPRINTK(args...) printk(args) 8762306a36Sopenharmony_ci#else 8862306a36Sopenharmony_ci#define RXPRINTK(args...) 8962306a36Sopenharmony_ci#endif /* RX_DEBUG */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#ifdef GENERAL_DEBUG 9262306a36Sopenharmony_ci#define PRINTK(args...) printk(args) 9362306a36Sopenharmony_ci#else 9462306a36Sopenharmony_ci#define PRINTK(args...) do {} while (0) 9562306a36Sopenharmony_ci#endif /* GENERAL_DEBUG */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#ifdef EXTRA_DEBUG 9862306a36Sopenharmony_ci#define XPRINTK(args...) printk(args) 9962306a36Sopenharmony_ci#else 10062306a36Sopenharmony_ci#define XPRINTK(args...) 10162306a36Sopenharmony_ci#endif /* EXTRA_DEBUG */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Macros */ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define NS_DELAY mdelay(1) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define PTR_DIFF(a, b) ((u32)((unsigned long)(a) - (unsigned long)(b))) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#ifndef ATM_SKB 11262306a36Sopenharmony_ci#define ATM_SKB(s) (&(s)->atm) 11362306a36Sopenharmony_ci#endif 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define scq_virt_to_bus(scq, p) \ 11662306a36Sopenharmony_ci (scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org)) 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Function declarations */ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic u32 ns_read_sram(ns_dev * card, u32 sram_address); 12162306a36Sopenharmony_cistatic void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, 12262306a36Sopenharmony_ci int count); 12362306a36Sopenharmony_cistatic int ns_init_card(int i, struct pci_dev *pcidev); 12462306a36Sopenharmony_cistatic void ns_init_card_error(ns_dev * card, int error); 12562306a36Sopenharmony_cistatic scq_info *get_scq(ns_dev *card, int size, u32 scd); 12662306a36Sopenharmony_cistatic void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc); 12762306a36Sopenharmony_cistatic void push_rxbufs(ns_dev *, struct sk_buff *); 12862306a36Sopenharmony_cistatic irqreturn_t ns_irq_handler(int irq, void *dev_id); 12962306a36Sopenharmony_cistatic int ns_open(struct atm_vcc *vcc); 13062306a36Sopenharmony_cistatic void ns_close(struct atm_vcc *vcc); 13162306a36Sopenharmony_cistatic void fill_tst(ns_dev * card, int n, vc_map * vc); 13262306a36Sopenharmony_cistatic int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); 13362306a36Sopenharmony_cistatic int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb); 13462306a36Sopenharmony_cistatic int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 13562306a36Sopenharmony_ci struct sk_buff *skb, bool may_sleep); 13662306a36Sopenharmony_cistatic void process_tsq(ns_dev * card); 13762306a36Sopenharmony_cistatic void drain_scq(ns_dev * card, scq_info * scq, int pos); 13862306a36Sopenharmony_cistatic void process_rsq(ns_dev * card); 13962306a36Sopenharmony_cistatic void dequeue_rx(ns_dev * card, ns_rsqe * rsqe); 14062306a36Sopenharmony_cistatic void recycle_rx_buf(ns_dev * card, struct sk_buff *skb); 14162306a36Sopenharmony_cistatic void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count); 14262306a36Sopenharmony_cistatic void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb); 14362306a36Sopenharmony_cistatic void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb); 14462306a36Sopenharmony_cistatic void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb); 14562306a36Sopenharmony_cistatic int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page); 14662306a36Sopenharmony_cistatic int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg); 14762306a36Sopenharmony_ci#ifdef EXTRA_DEBUG 14862306a36Sopenharmony_cistatic void which_list(ns_dev * card, struct sk_buff *skb); 14962306a36Sopenharmony_ci#endif 15062306a36Sopenharmony_cistatic void ns_poll(struct timer_list *unused); 15162306a36Sopenharmony_cistatic void ns_phy_put(struct atm_dev *dev, unsigned char value, 15262306a36Sopenharmony_ci unsigned long addr); 15362306a36Sopenharmony_cistatic unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Global variables */ 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic struct ns_dev *cards[NS_MAX_CARDS]; 15862306a36Sopenharmony_cistatic unsigned num_cards; 15962306a36Sopenharmony_cistatic const struct atmdev_ops atm_ops = { 16062306a36Sopenharmony_ci .open = ns_open, 16162306a36Sopenharmony_ci .close = ns_close, 16262306a36Sopenharmony_ci .ioctl = ns_ioctl, 16362306a36Sopenharmony_ci .send = ns_send, 16462306a36Sopenharmony_ci .send_bh = ns_send_bh, 16562306a36Sopenharmony_ci .phy_put = ns_phy_put, 16662306a36Sopenharmony_ci .phy_get = ns_phy_get, 16762306a36Sopenharmony_ci .proc_read = ns_proc_read, 16862306a36Sopenharmony_ci .owner = THIS_MODULE, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct timer_list ns_timer; 17262306a36Sopenharmony_cistatic char *mac[NS_MAX_CARDS]; 17362306a36Sopenharmony_cimodule_param_array(mac, charp, NULL, 0); 17462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* Functions */ 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int nicstar_init_one(struct pci_dev *pcidev, 17962306a36Sopenharmony_ci const struct pci_device_id *ent) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci static int index = -1; 18262306a36Sopenharmony_ci unsigned int error; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci index++; 18562306a36Sopenharmony_ci cards[index] = NULL; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci error = ns_init_card(index, pcidev); 18862306a36Sopenharmony_ci if (error) { 18962306a36Sopenharmony_ci cards[index--] = NULL; /* don't increment index */ 19062306a36Sopenharmony_ci goto err_out; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_cierr_out: 19562306a36Sopenharmony_ci return -ENODEV; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void nicstar_remove_one(struct pci_dev *pcidev) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int i, j; 20162306a36Sopenharmony_ci ns_dev *card = pci_get_drvdata(pcidev); 20262306a36Sopenharmony_ci struct sk_buff *hb; 20362306a36Sopenharmony_ci struct sk_buff *iovb; 20462306a36Sopenharmony_ci struct sk_buff *lb; 20562306a36Sopenharmony_ci struct sk_buff *sb; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci i = card->index; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (cards[i] == NULL) 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (card->atmdev->phy && card->atmdev->phy->stop) 21362306a36Sopenharmony_ci card->atmdev->phy->stop(card->atmdev); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Stop everything */ 21662306a36Sopenharmony_ci writel(0x00000000, card->membase + CFG); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* De-register device */ 21962306a36Sopenharmony_ci atm_dev_deregister(card->atmdev); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Disable PCI device */ 22262306a36Sopenharmony_ci pci_disable_device(pcidev); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Free up resources */ 22562306a36Sopenharmony_ci j = 0; 22662306a36Sopenharmony_ci PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); 22762306a36Sopenharmony_ci while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) { 22862306a36Sopenharmony_ci dev_kfree_skb_any(hb); 22962306a36Sopenharmony_ci j++; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); 23262306a36Sopenharmony_ci j = 0; 23362306a36Sopenharmony_ci PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, 23462306a36Sopenharmony_ci card->iovpool.count); 23562306a36Sopenharmony_ci while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) { 23662306a36Sopenharmony_ci dev_kfree_skb_any(iovb); 23762306a36Sopenharmony_ci j++; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); 24062306a36Sopenharmony_ci while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 24162306a36Sopenharmony_ci dev_kfree_skb_any(lb); 24262306a36Sopenharmony_ci while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 24362306a36Sopenharmony_ci dev_kfree_skb_any(sb); 24462306a36Sopenharmony_ci free_scq(card, card->scq0, NULL); 24562306a36Sopenharmony_ci for (j = 0; j < NS_FRSCD_NUM; j++) { 24662306a36Sopenharmony_ci if (card->scd2vc[j] != NULL) 24762306a36Sopenharmony_ci free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci idr_destroy(&card->idr); 25062306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, 25162306a36Sopenharmony_ci card->rsq.org, card->rsq.dma); 25262306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, 25362306a36Sopenharmony_ci card->tsq.org, card->tsq.dma); 25462306a36Sopenharmony_ci free_irq(card->pcidev->irq, card); 25562306a36Sopenharmony_ci iounmap(card->membase); 25662306a36Sopenharmony_ci kfree(card); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic const struct pci_device_id nicstar_pci_tbl[] = { 26062306a36Sopenharmony_ci { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 }, 26162306a36Sopenharmony_ci {0,} /* terminate list */ 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nicstar_pci_tbl); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic struct pci_driver nicstar_driver = { 26762306a36Sopenharmony_ci .name = "nicstar", 26862306a36Sopenharmony_ci .id_table = nicstar_pci_tbl, 26962306a36Sopenharmony_ci .probe = nicstar_init_one, 27062306a36Sopenharmony_ci .remove = nicstar_remove_one, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int __init nicstar_init(void) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci unsigned error = 0; /* Initialized to remove compile warning */ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci XPRINTK("nicstar: nicstar_init() called.\n"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci error = pci_register_driver(&nicstar_driver); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci TXPRINTK("nicstar: TX debug enabled.\n"); 28262306a36Sopenharmony_ci RXPRINTK("nicstar: RX debug enabled.\n"); 28362306a36Sopenharmony_ci PRINTK("nicstar: General debug enabled.\n"); 28462306a36Sopenharmony_ci#ifdef PHY_LOOPBACK 28562306a36Sopenharmony_ci printk("nicstar: using PHY loopback.\n"); 28662306a36Sopenharmony_ci#endif /* PHY_LOOPBACK */ 28762306a36Sopenharmony_ci XPRINTK("nicstar: nicstar_init() returned.\n"); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!error) { 29062306a36Sopenharmony_ci timer_setup(&ns_timer, ns_poll, 0); 29162306a36Sopenharmony_ci ns_timer.expires = jiffies + NS_POLL_PERIOD; 29262306a36Sopenharmony_ci add_timer(&ns_timer); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return error; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void __exit nicstar_cleanup(void) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci XPRINTK("nicstar: nicstar_cleanup() called.\n"); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci del_timer_sync(&ns_timer); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci pci_unregister_driver(&nicstar_driver); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci XPRINTK("nicstar: nicstar_cleanup() returned.\n"); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic u32 ns_read_sram(ns_dev * card, u32 sram_address) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci unsigned long flags; 31262306a36Sopenharmony_ci u32 data; 31362306a36Sopenharmony_ci sram_address <<= 2; 31462306a36Sopenharmony_ci sram_address &= 0x0007FFFC; /* address must be dword aligned */ 31562306a36Sopenharmony_ci sram_address |= 0x50000000; /* SRAM read command */ 31662306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 31762306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 31862306a36Sopenharmony_ci writel(sram_address, card->membase + CMD); 31962306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 32062306a36Sopenharmony_ci data = readl(card->membase + DR0); 32162306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 32262306a36Sopenharmony_ci return data; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, 32662306a36Sopenharmony_ci int count) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci unsigned long flags; 32962306a36Sopenharmony_ci int i, c; 33062306a36Sopenharmony_ci count--; /* count range now is 0..3 instead of 1..4 */ 33162306a36Sopenharmony_ci c = count; 33262306a36Sopenharmony_ci c <<= 2; /* to use increments of 4 */ 33362306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 33462306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 33562306a36Sopenharmony_ci for (i = 0; i <= c; i += 4) 33662306a36Sopenharmony_ci writel(*(value++), card->membase + i); 33762306a36Sopenharmony_ci /* Note: DR# registers are the first 4 dwords in nicstar's memspace, 33862306a36Sopenharmony_ci so card->membase + DR0 == card->membase */ 33962306a36Sopenharmony_ci sram_address <<= 2; 34062306a36Sopenharmony_ci sram_address &= 0x0007FFFC; 34162306a36Sopenharmony_ci sram_address |= (0x40000000 | count); 34262306a36Sopenharmony_ci writel(sram_address, card->membase + CMD); 34362306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int ns_init_card(int i, struct pci_dev *pcidev) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci int j; 34962306a36Sopenharmony_ci struct ns_dev *card = NULL; 35062306a36Sopenharmony_ci unsigned char pci_latency; 35162306a36Sopenharmony_ci unsigned error; 35262306a36Sopenharmony_ci u32 data; 35362306a36Sopenharmony_ci u32 u32d[4]; 35462306a36Sopenharmony_ci u32 ns_cfg_rctsize; 35562306a36Sopenharmony_ci int bcount; 35662306a36Sopenharmony_ci unsigned long membase; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci error = 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (pci_enable_device(pcidev)) { 36162306a36Sopenharmony_ci printk("nicstar%d: can't enable PCI device\n", i); 36262306a36Sopenharmony_ci error = 2; 36362306a36Sopenharmony_ci ns_init_card_error(card, error); 36462306a36Sopenharmony_ci return error; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)) != 0) { 36762306a36Sopenharmony_ci printk(KERN_WARNING 36862306a36Sopenharmony_ci "nicstar%d: No suitable DMA available.\n", i); 36962306a36Sopenharmony_ci error = 2; 37062306a36Sopenharmony_ci ns_init_card_error(card, error); 37162306a36Sopenharmony_ci return error; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci card = kmalloc(sizeof(*card), GFP_KERNEL); 37562306a36Sopenharmony_ci if (!card) { 37662306a36Sopenharmony_ci printk 37762306a36Sopenharmony_ci ("nicstar%d: can't allocate memory for device structure.\n", 37862306a36Sopenharmony_ci i); 37962306a36Sopenharmony_ci error = 2; 38062306a36Sopenharmony_ci ns_init_card_error(card, error); 38162306a36Sopenharmony_ci return error; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci cards[i] = card; 38462306a36Sopenharmony_ci spin_lock_init(&card->int_lock); 38562306a36Sopenharmony_ci spin_lock_init(&card->res_lock); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci pci_set_drvdata(pcidev, card); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci card->index = i; 39062306a36Sopenharmony_ci card->atmdev = NULL; 39162306a36Sopenharmony_ci card->pcidev = pcidev; 39262306a36Sopenharmony_ci membase = pci_resource_start(pcidev, 1); 39362306a36Sopenharmony_ci card->membase = ioremap(membase, NS_IOREMAP_SIZE); 39462306a36Sopenharmony_ci if (!card->membase) { 39562306a36Sopenharmony_ci printk("nicstar%d: can't ioremap() membase.\n", i); 39662306a36Sopenharmony_ci error = 3; 39762306a36Sopenharmony_ci ns_init_card_error(card, error); 39862306a36Sopenharmony_ci return error; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci pci_set_master(pcidev); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) { 40562306a36Sopenharmony_ci printk("nicstar%d: can't read PCI latency timer.\n", i); 40662306a36Sopenharmony_ci error = 6; 40762306a36Sopenharmony_ci ns_init_card_error(card, error); 40862306a36Sopenharmony_ci return error; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci#ifdef NS_PCI_LATENCY 41162306a36Sopenharmony_ci if (pci_latency < NS_PCI_LATENCY) { 41262306a36Sopenharmony_ci PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, 41362306a36Sopenharmony_ci NS_PCI_LATENCY); 41462306a36Sopenharmony_ci for (j = 1; j < 4; j++) { 41562306a36Sopenharmony_ci if (pci_write_config_byte 41662306a36Sopenharmony_ci (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0) 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci if (j == 4) { 42062306a36Sopenharmony_ci printk 42162306a36Sopenharmony_ci ("nicstar%d: can't set PCI latency timer to %d.\n", 42262306a36Sopenharmony_ci i, NS_PCI_LATENCY); 42362306a36Sopenharmony_ci error = 7; 42462306a36Sopenharmony_ci ns_init_card_error(card, error); 42562306a36Sopenharmony_ci return error; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci#endif /* NS_PCI_LATENCY */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Clear timer overflow */ 43162306a36Sopenharmony_ci data = readl(card->membase + STAT); 43262306a36Sopenharmony_ci if (data & NS_STAT_TMROF) 43362306a36Sopenharmony_ci writel(NS_STAT_TMROF, card->membase + STAT); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Software reset */ 43662306a36Sopenharmony_ci writel(NS_CFG_SWRST, card->membase + CFG); 43762306a36Sopenharmony_ci NS_DELAY; 43862306a36Sopenharmony_ci writel(0x00000000, card->membase + CFG); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* PHY reset */ 44162306a36Sopenharmony_ci writel(0x00000008, card->membase + GP); 44262306a36Sopenharmony_ci NS_DELAY; 44362306a36Sopenharmony_ci writel(0x00000001, card->membase + GP); 44462306a36Sopenharmony_ci NS_DELAY; 44562306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 44662306a36Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ 44762306a36Sopenharmony_ci NS_DELAY; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Detect PHY type */ 45062306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 45162306a36Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); 45262306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 45362306a36Sopenharmony_ci data = readl(card->membase + DR0); 45462306a36Sopenharmony_ci switch (data) { 45562306a36Sopenharmony_ci case 0x00000009: 45662306a36Sopenharmony_ci printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); 45762306a36Sopenharmony_ci card->max_pcr = ATM_25_PCR; 45862306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 45962306a36Sopenharmony_ci writel(0x00000008, card->membase + DR0); 46062306a36Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); 46162306a36Sopenharmony_ci /* Clear an eventual pending interrupt */ 46262306a36Sopenharmony_ci writel(NS_STAT_SFBQF, card->membase + STAT); 46362306a36Sopenharmony_ci#ifdef PHY_LOOPBACK 46462306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 46562306a36Sopenharmony_ci writel(0x00000022, card->membase + DR0); 46662306a36Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); 46762306a36Sopenharmony_ci#endif /* PHY_LOOPBACK */ 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case 0x00000030: 47062306a36Sopenharmony_ci case 0x00000031: 47162306a36Sopenharmony_ci printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); 47262306a36Sopenharmony_ci card->max_pcr = ATM_OC3_PCR; 47362306a36Sopenharmony_ci#ifdef PHY_LOOPBACK 47462306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 47562306a36Sopenharmony_ci writel(0x00000002, card->membase + DR0); 47662306a36Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); 47762306a36Sopenharmony_ci#endif /* PHY_LOOPBACK */ 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci default: 48062306a36Sopenharmony_ci printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); 48162306a36Sopenharmony_ci error = 8; 48262306a36Sopenharmony_ci ns_init_card_error(card, error); 48362306a36Sopenharmony_ci return error; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci writel(0x00000000, card->membase + GP); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Determine SRAM size */ 48862306a36Sopenharmony_ci data = 0x76543210; 48962306a36Sopenharmony_ci ns_write_sram(card, 0x1C003, &data, 1); 49062306a36Sopenharmony_ci data = 0x89ABCDEF; 49162306a36Sopenharmony_ci ns_write_sram(card, 0x14003, &data, 1); 49262306a36Sopenharmony_ci if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && 49362306a36Sopenharmony_ci ns_read_sram(card, 0x1C003) == 0x76543210) 49462306a36Sopenharmony_ci card->sram_size = 128; 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci card->sram_size = 32; 49762306a36Sopenharmony_ci PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci card->rct_size = NS_MAX_RCTSIZE; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci#if (NS_MAX_RCTSIZE == 4096) 50262306a36Sopenharmony_ci if (card->sram_size == 128) 50362306a36Sopenharmony_ci printk 50462306a36Sopenharmony_ci ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", 50562306a36Sopenharmony_ci i); 50662306a36Sopenharmony_ci#elif (NS_MAX_RCTSIZE == 16384) 50762306a36Sopenharmony_ci if (card->sram_size == 32) { 50862306a36Sopenharmony_ci printk 50962306a36Sopenharmony_ci ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", 51062306a36Sopenharmony_ci i); 51162306a36Sopenharmony_ci card->rct_size = 4096; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci#else 51462306a36Sopenharmony_ci#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c 51562306a36Sopenharmony_ci#endif 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci card->vpibits = NS_VPIBITS; 51862306a36Sopenharmony_ci if (card->rct_size == 4096) 51962306a36Sopenharmony_ci card->vcibits = 12 - NS_VPIBITS; 52062306a36Sopenharmony_ci else /* card->rct_size == 16384 */ 52162306a36Sopenharmony_ci card->vcibits = 14 - NS_VPIBITS; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ 52462306a36Sopenharmony_ci if (mac[i] == NULL) 52562306a36Sopenharmony_ci nicstar_init_eprom(card->membase); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ 52862306a36Sopenharmony_ci writel(0x00000000, card->membase + VPM); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci card->intcnt = 0; 53162306a36Sopenharmony_ci if (request_irq 53262306a36Sopenharmony_ci (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) { 53362306a36Sopenharmony_ci pr_err("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq); 53462306a36Sopenharmony_ci error = 9; 53562306a36Sopenharmony_ci ns_init_card_error(card, error); 53662306a36Sopenharmony_ci return error; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Initialize TSQ */ 54062306a36Sopenharmony_ci card->tsq.org = dma_alloc_coherent(&card->pcidev->dev, 54162306a36Sopenharmony_ci NS_TSQSIZE + NS_TSQ_ALIGNMENT, 54262306a36Sopenharmony_ci &card->tsq.dma, GFP_KERNEL); 54362306a36Sopenharmony_ci if (card->tsq.org == NULL) { 54462306a36Sopenharmony_ci printk("nicstar%d: can't allocate TSQ.\n", i); 54562306a36Sopenharmony_ci error = 10; 54662306a36Sopenharmony_ci ns_init_card_error(card, error); 54762306a36Sopenharmony_ci return error; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT); 55062306a36Sopenharmony_ci card->tsq.next = card->tsq.base; 55162306a36Sopenharmony_ci card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); 55262306a36Sopenharmony_ci for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) 55362306a36Sopenharmony_ci ns_tsi_init(card->tsq.base + j); 55462306a36Sopenharmony_ci writel(0x00000000, card->membase + TSQH); 55562306a36Sopenharmony_ci writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB); 55662306a36Sopenharmony_ci PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Initialize RSQ */ 55962306a36Sopenharmony_ci card->rsq.org = dma_alloc_coherent(&card->pcidev->dev, 56062306a36Sopenharmony_ci NS_RSQSIZE + NS_RSQ_ALIGNMENT, 56162306a36Sopenharmony_ci &card->rsq.dma, GFP_KERNEL); 56262306a36Sopenharmony_ci if (card->rsq.org == NULL) { 56362306a36Sopenharmony_ci printk("nicstar%d: can't allocate RSQ.\n", i); 56462306a36Sopenharmony_ci error = 11; 56562306a36Sopenharmony_ci ns_init_card_error(card, error); 56662306a36Sopenharmony_ci return error; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT); 56962306a36Sopenharmony_ci card->rsq.next = card->rsq.base; 57062306a36Sopenharmony_ci card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); 57162306a36Sopenharmony_ci for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) 57262306a36Sopenharmony_ci ns_rsqe_init(card->rsq.base + j); 57362306a36Sopenharmony_ci writel(0x00000000, card->membase + RSQH); 57462306a36Sopenharmony_ci writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB); 57562306a36Sopenharmony_ci PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Initialize SCQ0, the only VBR SCQ used */ 57862306a36Sopenharmony_ci card->scq1 = NULL; 57962306a36Sopenharmony_ci card->scq2 = NULL; 58062306a36Sopenharmony_ci card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0); 58162306a36Sopenharmony_ci if (card->scq0 == NULL) { 58262306a36Sopenharmony_ci printk("nicstar%d: can't get SCQ0.\n", i); 58362306a36Sopenharmony_ci error = 12; 58462306a36Sopenharmony_ci ns_init_card_error(card, error); 58562306a36Sopenharmony_ci return error; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base); 58862306a36Sopenharmony_ci u32d[1] = (u32) 0x00000000; 58962306a36Sopenharmony_ci u32d[2] = (u32) 0xffffffff; 59062306a36Sopenharmony_ci u32d[3] = (u32) 0x00000000; 59162306a36Sopenharmony_ci ns_write_sram(card, NS_VRSCD0, u32d, 4); 59262306a36Sopenharmony_ci ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ 59362306a36Sopenharmony_ci ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ 59462306a36Sopenharmony_ci card->scq0->scd = NS_VRSCD0; 59562306a36Sopenharmony_ci PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Initialize TSTs */ 59862306a36Sopenharmony_ci card->tst_addr = NS_TST0; 59962306a36Sopenharmony_ci card->tst_free_entries = NS_TST_NUM_ENTRIES; 60062306a36Sopenharmony_ci data = NS_TST_OPCODE_VARIABLE; 60162306a36Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 60262306a36Sopenharmony_ci ns_write_sram(card, NS_TST0 + j, &data, 1); 60362306a36Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); 60462306a36Sopenharmony_ci ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); 60562306a36Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 60662306a36Sopenharmony_ci ns_write_sram(card, NS_TST1 + j, &data, 1); 60762306a36Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); 60862306a36Sopenharmony_ci ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); 60962306a36Sopenharmony_ci for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 61062306a36Sopenharmony_ci card->tste2vc[j] = NULL; 61162306a36Sopenharmony_ci writel(NS_TST0 << 2, card->membase + TSTB); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Initialize RCT. AAL type is set on opening the VC. */ 61462306a36Sopenharmony_ci#ifdef RCQ_SUPPORT 61562306a36Sopenharmony_ci u32d[0] = NS_RCTE_RAWCELLINTEN; 61662306a36Sopenharmony_ci#else 61762306a36Sopenharmony_ci u32d[0] = 0x00000000; 61862306a36Sopenharmony_ci#endif /* RCQ_SUPPORT */ 61962306a36Sopenharmony_ci u32d[1] = 0x00000000; 62062306a36Sopenharmony_ci u32d[2] = 0x00000000; 62162306a36Sopenharmony_ci u32d[3] = 0xFFFFFFFF; 62262306a36Sopenharmony_ci for (j = 0; j < card->rct_size; j++) 62362306a36Sopenharmony_ci ns_write_sram(card, j * 4, u32d, 4); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci memset(card->vcmap, 0, sizeof(card->vcmap)); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci for (j = 0; j < NS_FRSCD_NUM; j++) 62862306a36Sopenharmony_ci card->scd2vc[j] = NULL; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Initialize buffer levels */ 63162306a36Sopenharmony_ci card->sbnr.min = MIN_SB; 63262306a36Sopenharmony_ci card->sbnr.init = NUM_SB; 63362306a36Sopenharmony_ci card->sbnr.max = MAX_SB; 63462306a36Sopenharmony_ci card->lbnr.min = MIN_LB; 63562306a36Sopenharmony_ci card->lbnr.init = NUM_LB; 63662306a36Sopenharmony_ci card->lbnr.max = MAX_LB; 63762306a36Sopenharmony_ci card->iovnr.min = MIN_IOVB; 63862306a36Sopenharmony_ci card->iovnr.init = NUM_IOVB; 63962306a36Sopenharmony_ci card->iovnr.max = MAX_IOVB; 64062306a36Sopenharmony_ci card->hbnr.min = MIN_HB; 64162306a36Sopenharmony_ci card->hbnr.init = NUM_HB; 64262306a36Sopenharmony_ci card->hbnr.max = MAX_HB; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci card->sm_handle = NULL; 64562306a36Sopenharmony_ci card->sm_addr = 0x00000000; 64662306a36Sopenharmony_ci card->lg_handle = NULL; 64762306a36Sopenharmony_ci card->lg_addr = 0x00000000; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci idr_init(&card->idr); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* Pre-allocate some huge buffers */ 65462306a36Sopenharmony_ci skb_queue_head_init(&card->hbpool.queue); 65562306a36Sopenharmony_ci card->hbpool.count = 0; 65662306a36Sopenharmony_ci for (j = 0; j < NUM_HB; j++) { 65762306a36Sopenharmony_ci struct sk_buff *hb; 65862306a36Sopenharmony_ci hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 65962306a36Sopenharmony_ci if (hb == NULL) { 66062306a36Sopenharmony_ci printk 66162306a36Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d huge buffers.\n", 66262306a36Sopenharmony_ci i, j, NUM_HB); 66362306a36Sopenharmony_ci error = 13; 66462306a36Sopenharmony_ci ns_init_card_error(card, error); 66562306a36Sopenharmony_ci return error; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 66862306a36Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 66962306a36Sopenharmony_ci card->hbpool.count++; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* Allocate large buffers */ 67362306a36Sopenharmony_ci skb_queue_head_init(&card->lbpool.queue); 67462306a36Sopenharmony_ci card->lbpool.count = 0; /* Not used */ 67562306a36Sopenharmony_ci for (j = 0; j < NUM_LB; j++) { 67662306a36Sopenharmony_ci struct sk_buff *lb; 67762306a36Sopenharmony_ci lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 67862306a36Sopenharmony_ci if (lb == NULL) { 67962306a36Sopenharmony_ci printk 68062306a36Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d large buffers.\n", 68162306a36Sopenharmony_ci i, j, NUM_LB); 68262306a36Sopenharmony_ci error = 14; 68362306a36Sopenharmony_ci ns_init_card_error(card, error); 68462306a36Sopenharmony_ci return error; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 68762306a36Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 68862306a36Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 68962306a36Sopenharmony_ci push_rxbufs(card, lb); 69062306a36Sopenharmony_ci /* Due to the implementation of push_rxbufs() this is 1, not 0 */ 69162306a36Sopenharmony_ci if (j == 1) { 69262306a36Sopenharmony_ci card->rcbuf = lb; 69362306a36Sopenharmony_ci card->rawcell = (struct ns_rcqe *) lb->data; 69462306a36Sopenharmony_ci card->rawch = NS_PRV_DMA(lb); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci /* Test for strange behaviour which leads to crashes */ 69862306a36Sopenharmony_ci if ((bcount = 69962306a36Sopenharmony_ci ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) { 70062306a36Sopenharmony_ci printk 70162306a36Sopenharmony_ci ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", 70262306a36Sopenharmony_ci i, j, bcount); 70362306a36Sopenharmony_ci error = 14; 70462306a36Sopenharmony_ci ns_init_card_error(card, error); 70562306a36Sopenharmony_ci return error; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* Allocate small buffers */ 70962306a36Sopenharmony_ci skb_queue_head_init(&card->sbpool.queue); 71062306a36Sopenharmony_ci card->sbpool.count = 0; /* Not used */ 71162306a36Sopenharmony_ci for (j = 0; j < NUM_SB; j++) { 71262306a36Sopenharmony_ci struct sk_buff *sb; 71362306a36Sopenharmony_ci sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 71462306a36Sopenharmony_ci if (sb == NULL) { 71562306a36Sopenharmony_ci printk 71662306a36Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d small buffers.\n", 71762306a36Sopenharmony_ci i, j, NUM_SB); 71862306a36Sopenharmony_ci error = 15; 71962306a36Sopenharmony_ci ns_init_card_error(card, error); 72062306a36Sopenharmony_ci return error; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 72362306a36Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 72462306a36Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 72562306a36Sopenharmony_ci push_rxbufs(card, sb); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci /* Test for strange behaviour which leads to crashes */ 72862306a36Sopenharmony_ci if ((bcount = 72962306a36Sopenharmony_ci ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) { 73062306a36Sopenharmony_ci printk 73162306a36Sopenharmony_ci ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", 73262306a36Sopenharmony_ci i, j, bcount); 73362306a36Sopenharmony_ci error = 15; 73462306a36Sopenharmony_ci ns_init_card_error(card, error); 73562306a36Sopenharmony_ci return error; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* Allocate iovec buffers */ 73962306a36Sopenharmony_ci skb_queue_head_init(&card->iovpool.queue); 74062306a36Sopenharmony_ci card->iovpool.count = 0; 74162306a36Sopenharmony_ci for (j = 0; j < NUM_IOVB; j++) { 74262306a36Sopenharmony_ci struct sk_buff *iovb; 74362306a36Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 74462306a36Sopenharmony_ci if (iovb == NULL) { 74562306a36Sopenharmony_ci printk 74662306a36Sopenharmony_ci ("nicstar%d: can't allocate %dth of %d iovec buffers.\n", 74762306a36Sopenharmony_ci i, j, NUM_IOVB); 74862306a36Sopenharmony_ci error = 16; 74962306a36Sopenharmony_ci ns_init_card_error(card, error); 75062306a36Sopenharmony_ci return error; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 75362306a36Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 75462306a36Sopenharmony_ci card->iovpool.count++; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Configure NICStAR */ 75862306a36Sopenharmony_ci if (card->rct_size == 4096) 75962306a36Sopenharmony_ci ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; 76062306a36Sopenharmony_ci else /* (card->rct_size == 16384) */ 76162306a36Sopenharmony_ci ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci card->efbie = 1; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Register device */ 76662306a36Sopenharmony_ci card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops, 76762306a36Sopenharmony_ci -1, NULL); 76862306a36Sopenharmony_ci if (card->atmdev == NULL) { 76962306a36Sopenharmony_ci printk("nicstar%d: can't register device.\n", i); 77062306a36Sopenharmony_ci error = 17; 77162306a36Sopenharmony_ci ns_init_card_error(card, error); 77262306a36Sopenharmony_ci return error; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (mac[i] == NULL || !mac_pton(mac[i], card->atmdev->esi)) { 77662306a36Sopenharmony_ci nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, 77762306a36Sopenharmony_ci card->atmdev->esi, 6); 77862306a36Sopenharmony_ci if (ether_addr_equal(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00")) { 77962306a36Sopenharmony_ci nicstar_read_eprom(card->membase, 78062306a36Sopenharmony_ci NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, 78162306a36Sopenharmony_ci card->atmdev->esi, 6); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci card->atmdev->dev_data = card; 78862306a36Sopenharmony_ci card->atmdev->ci_range.vpi_bits = card->vpibits; 78962306a36Sopenharmony_ci card->atmdev->ci_range.vci_bits = card->vcibits; 79062306a36Sopenharmony_ci card->atmdev->link_rate = card->max_pcr; 79162306a36Sopenharmony_ci card->atmdev->phy = NULL; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_SUNI 79462306a36Sopenharmony_ci if (card->max_pcr == ATM_OC3_PCR) 79562306a36Sopenharmony_ci suni_init(card->atmdev); 79662306a36Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 79962306a36Sopenharmony_ci if (card->max_pcr == ATM_25_PCR) 80062306a36Sopenharmony_ci idt77105_init(card->atmdev); 80162306a36Sopenharmony_ci#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (card->atmdev->phy && card->atmdev->phy->start) 80462306a36Sopenharmony_ci card->atmdev->phy->start(card->atmdev); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ 80762306a36Sopenharmony_ci NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ 80862306a36Sopenharmony_ci NS_CFG_PHYIE, card->membase + CFG); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci num_cards++; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return error; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void ns_init_card_error(ns_dev *card, int error) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci if (error >= 17) { 81862306a36Sopenharmony_ci writel(0x00000000, card->membase + CFG); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci if (error >= 16) { 82162306a36Sopenharmony_ci struct sk_buff *iovb; 82262306a36Sopenharmony_ci while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) 82362306a36Sopenharmony_ci dev_kfree_skb_any(iovb); 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci if (error >= 15) { 82662306a36Sopenharmony_ci struct sk_buff *sb; 82762306a36Sopenharmony_ci while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 82862306a36Sopenharmony_ci dev_kfree_skb_any(sb); 82962306a36Sopenharmony_ci free_scq(card, card->scq0, NULL); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci if (error >= 14) { 83262306a36Sopenharmony_ci struct sk_buff *lb; 83362306a36Sopenharmony_ci while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 83462306a36Sopenharmony_ci dev_kfree_skb_any(lb); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci if (error >= 13) { 83762306a36Sopenharmony_ci struct sk_buff *hb; 83862306a36Sopenharmony_ci while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) 83962306a36Sopenharmony_ci dev_kfree_skb_any(hb); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci if (error >= 12) { 84262306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, 84362306a36Sopenharmony_ci card->rsq.org, card->rsq.dma); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci if (error >= 11) { 84662306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, 84762306a36Sopenharmony_ci card->tsq.org, card->tsq.dma); 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci if (error >= 10) { 85062306a36Sopenharmony_ci free_irq(card->pcidev->irq, card); 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci if (error >= 4) { 85362306a36Sopenharmony_ci iounmap(card->membase); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci if (error >= 3) { 85662306a36Sopenharmony_ci pci_disable_device(card->pcidev); 85762306a36Sopenharmony_ci kfree(card); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic scq_info *get_scq(ns_dev *card, int size, u32 scd) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci scq_info *scq; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) 86662306a36Sopenharmony_ci return NULL; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci scq = kmalloc(sizeof(*scq), GFP_KERNEL); 86962306a36Sopenharmony_ci if (!scq) 87062306a36Sopenharmony_ci return NULL; 87162306a36Sopenharmony_ci scq->org = dma_alloc_coherent(&card->pcidev->dev, 87262306a36Sopenharmony_ci 2 * size, &scq->dma, GFP_KERNEL); 87362306a36Sopenharmony_ci if (!scq->org) { 87462306a36Sopenharmony_ci kfree(scq); 87562306a36Sopenharmony_ci return NULL; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci scq->skb = kcalloc(size / NS_SCQE_SIZE, sizeof(*scq->skb), 87862306a36Sopenharmony_ci GFP_KERNEL); 87962306a36Sopenharmony_ci if (!scq->skb) { 88062306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, 88162306a36Sopenharmony_ci 2 * size, scq->org, scq->dma); 88262306a36Sopenharmony_ci kfree(scq); 88362306a36Sopenharmony_ci return NULL; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci scq->num_entries = size / NS_SCQE_SIZE; 88662306a36Sopenharmony_ci scq->base = PTR_ALIGN(scq->org, size); 88762306a36Sopenharmony_ci scq->next = scq->base; 88862306a36Sopenharmony_ci scq->last = scq->base + (scq->num_entries - 1); 88962306a36Sopenharmony_ci scq->tail = scq->last; 89062306a36Sopenharmony_ci scq->scd = scd; 89162306a36Sopenharmony_ci scq->tbd_count = 0; 89262306a36Sopenharmony_ci init_waitqueue_head(&scq->scqfull_waitq); 89362306a36Sopenharmony_ci scq->full = 0; 89462306a36Sopenharmony_ci spin_lock_init(&scq->lock); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return scq; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci/* For variable rate SCQ vcc must be NULL */ 90062306a36Sopenharmony_cistatic void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci int i; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) 90562306a36Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 90662306a36Sopenharmony_ci if (scq->skb[i] != NULL) { 90762306a36Sopenharmony_ci vcc = ATM_SKB(scq->skb[i])->vcc; 90862306a36Sopenharmony_ci if (vcc->pop != NULL) 90962306a36Sopenharmony_ci vcc->pop(vcc, scq->skb[i]); 91062306a36Sopenharmony_ci else 91162306a36Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci } else { /* vcc must be != NULL */ 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (vcc == NULL) { 91662306a36Sopenharmony_ci printk 91762306a36Sopenharmony_ci ("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); 91862306a36Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) 91962306a36Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 92062306a36Sopenharmony_ci } else 92162306a36Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 92262306a36Sopenharmony_ci if (scq->skb[i] != NULL) { 92362306a36Sopenharmony_ci if (vcc->pop != NULL) 92462306a36Sopenharmony_ci vcc->pop(vcc, scq->skb[i]); 92562306a36Sopenharmony_ci else 92662306a36Sopenharmony_ci dev_kfree_skb_any(scq->skb[i]); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci kfree(scq->skb); 93162306a36Sopenharmony_ci dma_free_coherent(&card->pcidev->dev, 93262306a36Sopenharmony_ci 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ? 93362306a36Sopenharmony_ci VBR_SCQSIZE : CBR_SCQSIZE), 93462306a36Sopenharmony_ci scq->org, scq->dma); 93562306a36Sopenharmony_ci kfree(scq); 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci/* The handles passed must be pointers to the sk_buff containing the small 93962306a36Sopenharmony_ci or large buffer(s) cast to u32. */ 94062306a36Sopenharmony_cistatic void push_rxbufs(ns_dev * card, struct sk_buff *skb) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct sk_buff *handle1, *handle2; 94362306a36Sopenharmony_ci int id1, id2; 94462306a36Sopenharmony_ci u32 addr1, addr2; 94562306a36Sopenharmony_ci u32 stat; 94662306a36Sopenharmony_ci unsigned long flags; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci /* *BARF* */ 94962306a36Sopenharmony_ci handle2 = NULL; 95062306a36Sopenharmony_ci addr2 = 0; 95162306a36Sopenharmony_ci handle1 = skb; 95262306a36Sopenharmony_ci addr1 = dma_map_single(&card->pcidev->dev, 95362306a36Sopenharmony_ci skb->data, 95462306a36Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 95562306a36Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 95662306a36Sopenharmony_ci DMA_TO_DEVICE); 95762306a36Sopenharmony_ci NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */ 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci#ifdef GENERAL_DEBUG 96062306a36Sopenharmony_ci if (!addr1) 96162306a36Sopenharmony_ci printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", 96262306a36Sopenharmony_ci card->index); 96362306a36Sopenharmony_ci#endif /* GENERAL_DEBUG */ 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci stat = readl(card->membase + STAT); 96662306a36Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 96762306a36Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 96862306a36Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) == BUF_SM) { 96962306a36Sopenharmony_ci if (!addr2) { 97062306a36Sopenharmony_ci if (card->sm_addr) { 97162306a36Sopenharmony_ci addr2 = card->sm_addr; 97262306a36Sopenharmony_ci handle2 = card->sm_handle; 97362306a36Sopenharmony_ci card->sm_addr = 0x00000000; 97462306a36Sopenharmony_ci card->sm_handle = NULL; 97562306a36Sopenharmony_ci } else { /* (!sm_addr) */ 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci card->sm_addr = addr1; 97862306a36Sopenharmony_ci card->sm_handle = handle1; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } else { /* buf_type == BUF_LG */ 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!addr2) { 98462306a36Sopenharmony_ci if (card->lg_addr) { 98562306a36Sopenharmony_ci addr2 = card->lg_addr; 98662306a36Sopenharmony_ci handle2 = card->lg_handle; 98762306a36Sopenharmony_ci card->lg_addr = 0x00000000; 98862306a36Sopenharmony_ci card->lg_handle = NULL; 98962306a36Sopenharmony_ci } else { /* (!lg_addr) */ 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci card->lg_addr = addr1; 99262306a36Sopenharmony_ci card->lg_handle = handle1; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (addr2) { 99862306a36Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) == BUF_SM) { 99962306a36Sopenharmony_ci if (card->sbfqc >= card->sbnr.max) { 100062306a36Sopenharmony_ci skb_unlink(handle1, &card->sbpool.queue); 100162306a36Sopenharmony_ci dev_kfree_skb_any(handle1); 100262306a36Sopenharmony_ci skb_unlink(handle2, &card->sbpool.queue); 100362306a36Sopenharmony_ci dev_kfree_skb_any(handle2); 100462306a36Sopenharmony_ci return; 100562306a36Sopenharmony_ci } else 100662306a36Sopenharmony_ci card->sbfqc += 2; 100762306a36Sopenharmony_ci } else { /* (buf_type == BUF_LG) */ 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (card->lbfqc >= card->lbnr.max) { 101062306a36Sopenharmony_ci skb_unlink(handle1, &card->lbpool.queue); 101162306a36Sopenharmony_ci dev_kfree_skb_any(handle1); 101262306a36Sopenharmony_ci skb_unlink(handle2, &card->lbpool.queue); 101362306a36Sopenharmony_ci dev_kfree_skb_any(handle2); 101462306a36Sopenharmony_ci return; 101562306a36Sopenharmony_ci } else 101662306a36Sopenharmony_ci card->lbfqc += 2; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci id1 = idr_alloc(&card->idr, handle1, 0, 0, GFP_ATOMIC); 102062306a36Sopenharmony_ci if (id1 < 0) 102162306a36Sopenharmony_ci goto out; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci id2 = idr_alloc(&card->idr, handle2, 0, 0, GFP_ATOMIC); 102462306a36Sopenharmony_ci if (id2 < 0) 102562306a36Sopenharmony_ci goto out; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 102862306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 102962306a36Sopenharmony_ci writel(addr2, card->membase + DR3); 103062306a36Sopenharmony_ci writel(id2, card->membase + DR2); 103162306a36Sopenharmony_ci writel(addr1, card->membase + DR1); 103262306a36Sopenharmony_ci writel(id1, card->membase + DR0); 103362306a36Sopenharmony_ci writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb), 103462306a36Sopenharmony_ci card->membase + CMD); 103562306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", 103862306a36Sopenharmony_ci card->index, 103962306a36Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"), 104062306a36Sopenharmony_ci addr1, addr2); 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (!card->efbie && card->sbfqc >= card->sbnr.min && 104462306a36Sopenharmony_ci card->lbfqc >= card->lbnr.min) { 104562306a36Sopenharmony_ci card->efbie = 1; 104662306a36Sopenharmony_ci writel((readl(card->membase + CFG) | NS_CFG_EFBIE), 104762306a36Sopenharmony_ci card->membase + CFG); 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciout: 105162306a36Sopenharmony_ci return; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic irqreturn_t ns_irq_handler(int irq, void *dev_id) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci u32 stat_r; 105762306a36Sopenharmony_ci ns_dev *card; 105862306a36Sopenharmony_ci struct atm_dev *dev; 105962306a36Sopenharmony_ci unsigned long flags; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci card = (ns_dev *) dev_id; 106262306a36Sopenharmony_ci dev = card->atmdev; 106362306a36Sopenharmony_ci card->intcnt++; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci stat_r = readl(card->membase + STAT); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Transmit Status Indicator has been written to T. S. Queue */ 107262306a36Sopenharmony_ci if (stat_r & NS_STAT_TSIF) { 107362306a36Sopenharmony_ci TXPRINTK("nicstar%d: TSI interrupt\n", card->index); 107462306a36Sopenharmony_ci process_tsq(card); 107562306a36Sopenharmony_ci writel(NS_STAT_TSIF, card->membase + STAT); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Incomplete CS-PDU has been transmitted */ 107962306a36Sopenharmony_ci if (stat_r & NS_STAT_TXICP) { 108062306a36Sopenharmony_ci writel(NS_STAT_TXICP, card->membase + STAT); 108162306a36Sopenharmony_ci TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", 108262306a36Sopenharmony_ci card->index); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* Transmit Status Queue 7/8 full */ 108662306a36Sopenharmony_ci if (stat_r & NS_STAT_TSQF) { 108762306a36Sopenharmony_ci writel(NS_STAT_TSQF, card->membase + STAT); 108862306a36Sopenharmony_ci PRINTK("nicstar%d: TSQ full.\n", card->index); 108962306a36Sopenharmony_ci process_tsq(card); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* Timer overflow */ 109362306a36Sopenharmony_ci if (stat_r & NS_STAT_TMROF) { 109462306a36Sopenharmony_ci writel(NS_STAT_TMROF, card->membase + STAT); 109562306a36Sopenharmony_ci PRINTK("nicstar%d: Timer overflow.\n", card->index); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* PHY device interrupt signal active */ 109962306a36Sopenharmony_ci if (stat_r & NS_STAT_PHYI) { 110062306a36Sopenharmony_ci writel(NS_STAT_PHYI, card->membase + STAT); 110162306a36Sopenharmony_ci PRINTK("nicstar%d: PHY interrupt.\n", card->index); 110262306a36Sopenharmony_ci if (dev->phy && dev->phy->interrupt) { 110362306a36Sopenharmony_ci dev->phy->interrupt(dev); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Small Buffer Queue is full */ 110862306a36Sopenharmony_ci if (stat_r & NS_STAT_SFBQF) { 110962306a36Sopenharmony_ci writel(NS_STAT_SFBQF, card->membase + STAT); 111062306a36Sopenharmony_ci printk("nicstar%d: Small free buffer queue is full.\n", 111162306a36Sopenharmony_ci card->index); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* Large Buffer Queue is full */ 111562306a36Sopenharmony_ci if (stat_r & NS_STAT_LFBQF) { 111662306a36Sopenharmony_ci writel(NS_STAT_LFBQF, card->membase + STAT); 111762306a36Sopenharmony_ci printk("nicstar%d: Large free buffer queue is full.\n", 111862306a36Sopenharmony_ci card->index); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* Receive Status Queue is full */ 112262306a36Sopenharmony_ci if (stat_r & NS_STAT_RSQF) { 112362306a36Sopenharmony_ci writel(NS_STAT_RSQF, card->membase + STAT); 112462306a36Sopenharmony_ci printk("nicstar%d: RSQ full.\n", card->index); 112562306a36Sopenharmony_ci process_rsq(card); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Complete CS-PDU received */ 112962306a36Sopenharmony_ci if (stat_r & NS_STAT_EOPDU) { 113062306a36Sopenharmony_ci RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); 113162306a36Sopenharmony_ci process_rsq(card); 113262306a36Sopenharmony_ci writel(NS_STAT_EOPDU, card->membase + STAT); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* Raw cell received */ 113662306a36Sopenharmony_ci if (stat_r & NS_STAT_RAWCF) { 113762306a36Sopenharmony_ci writel(NS_STAT_RAWCF, card->membase + STAT); 113862306a36Sopenharmony_ci#ifndef RCQ_SUPPORT 113962306a36Sopenharmony_ci printk("nicstar%d: Raw cell received and no support yet...\n", 114062306a36Sopenharmony_ci card->index); 114162306a36Sopenharmony_ci#endif /* RCQ_SUPPORT */ 114262306a36Sopenharmony_ci /* NOTE: the following procedure may keep a raw cell pending until the 114362306a36Sopenharmony_ci next interrupt. As this preliminary support is only meant to 114462306a36Sopenharmony_ci avoid buffer leakage, this is not an issue. */ 114562306a36Sopenharmony_ci while (readl(card->membase + RAWCT) != card->rawch) { 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (ns_rcqe_islast(card->rawcell)) { 114862306a36Sopenharmony_ci struct sk_buff *oldbuf; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci oldbuf = card->rcbuf; 115162306a36Sopenharmony_ci card->rcbuf = idr_find(&card->idr, 115262306a36Sopenharmony_ci ns_rcqe_nextbufhandle(card->rawcell)); 115362306a36Sopenharmony_ci card->rawch = NS_PRV_DMA(card->rcbuf); 115462306a36Sopenharmony_ci card->rawcell = (struct ns_rcqe *) 115562306a36Sopenharmony_ci card->rcbuf->data; 115662306a36Sopenharmony_ci recycle_rx_buf(card, oldbuf); 115762306a36Sopenharmony_ci } else { 115862306a36Sopenharmony_ci card->rawch += NS_RCQE_SIZE; 115962306a36Sopenharmony_ci card->rawcell++; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Small buffer queue is empty */ 116562306a36Sopenharmony_ci if (stat_r & NS_STAT_SFBQE) { 116662306a36Sopenharmony_ci int i; 116762306a36Sopenharmony_ci struct sk_buff *sb; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci writel(NS_STAT_SFBQE, card->membase + STAT); 117062306a36Sopenharmony_ci printk("nicstar%d: Small free buffer queue empty.\n", 117162306a36Sopenharmony_ci card->index); 117262306a36Sopenharmony_ci for (i = 0; i < card->sbnr.min; i++) { 117362306a36Sopenharmony_ci sb = dev_alloc_skb(NS_SMSKBSIZE); 117462306a36Sopenharmony_ci if (sb == NULL) { 117562306a36Sopenharmony_ci writel(readl(card->membase + CFG) & 117662306a36Sopenharmony_ci ~NS_CFG_EFBIE, card->membase + CFG); 117762306a36Sopenharmony_ci card->efbie = 0; 117862306a36Sopenharmony_ci break; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 118162306a36Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 118262306a36Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 118362306a36Sopenharmony_ci push_rxbufs(card, sb); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci card->sbfqc = i; 118662306a36Sopenharmony_ci process_rsq(card); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* Large buffer queue empty */ 119062306a36Sopenharmony_ci if (stat_r & NS_STAT_LFBQE) { 119162306a36Sopenharmony_ci int i; 119262306a36Sopenharmony_ci struct sk_buff *lb; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci writel(NS_STAT_LFBQE, card->membase + STAT); 119562306a36Sopenharmony_ci printk("nicstar%d: Large free buffer queue empty.\n", 119662306a36Sopenharmony_ci card->index); 119762306a36Sopenharmony_ci for (i = 0; i < card->lbnr.min; i++) { 119862306a36Sopenharmony_ci lb = dev_alloc_skb(NS_LGSKBSIZE); 119962306a36Sopenharmony_ci if (lb == NULL) { 120062306a36Sopenharmony_ci writel(readl(card->membase + CFG) & 120162306a36Sopenharmony_ci ~NS_CFG_EFBIE, card->membase + CFG); 120262306a36Sopenharmony_ci card->efbie = 0; 120362306a36Sopenharmony_ci break; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 120662306a36Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 120762306a36Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 120862306a36Sopenharmony_ci push_rxbufs(card, lb); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci card->lbfqc = i; 121162306a36Sopenharmony_ci process_rsq(card); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* Receive Status Queue is 7/8 full */ 121562306a36Sopenharmony_ci if (stat_r & NS_STAT_RSQAF) { 121662306a36Sopenharmony_ci writel(NS_STAT_RSQAF, card->membase + STAT); 121762306a36Sopenharmony_ci RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); 121862306a36Sopenharmony_ci process_rsq(card); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 122262306a36Sopenharmony_ci PRINTK("nicstar%d: end of interrupt service\n", card->index); 122362306a36Sopenharmony_ci return IRQ_HANDLED; 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cistatic int ns_open(struct atm_vcc *vcc) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci ns_dev *card; 122962306a36Sopenharmony_ci vc_map *vc; 123062306a36Sopenharmony_ci unsigned long tmpl, modl; 123162306a36Sopenharmony_ci int tcr, tcra; /* target cell rate, and absolute value */ 123262306a36Sopenharmony_ci int n = 0; /* Number of entries in the TST. Initialized to remove 123362306a36Sopenharmony_ci the compiler warning. */ 123462306a36Sopenharmony_ci u32 u32d[4]; 123562306a36Sopenharmony_ci int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler 123662306a36Sopenharmony_ci warning. How I wish compilers were clever enough to 123762306a36Sopenharmony_ci tell which variables can truly be used 123862306a36Sopenharmony_ci uninitialized... */ 123962306a36Sopenharmony_ci int inuse; /* tx or rx vc already in use by another vcc */ 124062306a36Sopenharmony_ci short vpi = vcc->vpi; 124162306a36Sopenharmony_ci int vci = vcc->vci; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci card = (ns_dev *) vcc->dev->dev_data; 124462306a36Sopenharmony_ci PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi, 124562306a36Sopenharmony_ci vci); 124662306a36Sopenharmony_ci if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { 124762306a36Sopenharmony_ci PRINTK("nicstar%d: unsupported AAL.\n", card->index); 124862306a36Sopenharmony_ci return -EINVAL; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci vc = &(card->vcmap[vpi << card->vcibits | vci]); 125262306a36Sopenharmony_ci vcc->dev_data = vc; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci inuse = 0; 125562306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) 125662306a36Sopenharmony_ci inuse = 1; 125762306a36Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) 125862306a36Sopenharmony_ci inuse += 2; 125962306a36Sopenharmony_ci if (inuse) { 126062306a36Sopenharmony_ci printk("nicstar%d: %s vci already in use.\n", card->index, 126162306a36Sopenharmony_ci inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); 126262306a36Sopenharmony_ci return -EINVAL; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci set_bit(ATM_VF_ADDR, &vcc->flags); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* NOTE: You are not allowed to modify an open connection's QOS. To change 126862306a36Sopenharmony_ci that, remove the ATM_VF_PARTIAL flag checking. There may be other changes 126962306a36Sopenharmony_ci needed to do that. */ 127062306a36Sopenharmony_ci if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) { 127162306a36Sopenharmony_ci scq_info *scq; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci set_bit(ATM_VF_PARTIAL, &vcc->flags); 127462306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 127562306a36Sopenharmony_ci /* Check requested cell rate and availability of SCD */ 127662306a36Sopenharmony_ci if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 127762306a36Sopenharmony_ci && vcc->qos.txtp.min_pcr == 0) { 127862306a36Sopenharmony_ci PRINTK 127962306a36Sopenharmony_ci ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", 128062306a36Sopenharmony_ci card->index); 128162306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 128262306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 128362306a36Sopenharmony_ci return -EINVAL; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci tcr = atm_pcr_goal(&(vcc->qos.txtp)); 128762306a36Sopenharmony_ci tcra = tcr >= 0 ? tcr : -tcr; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci PRINTK("nicstar%d: target cell rate = %d.\n", 129062306a36Sopenharmony_ci card->index, vcc->qos.txtp.max_pcr); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci tmpl = 129362306a36Sopenharmony_ci (unsigned long)tcra *(unsigned long) 129462306a36Sopenharmony_ci NS_TST_NUM_ENTRIES; 129562306a36Sopenharmony_ci modl = tmpl % card->max_pcr; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci n = (int)(tmpl / card->max_pcr); 129862306a36Sopenharmony_ci if (tcr > 0) { 129962306a36Sopenharmony_ci if (modl > 0) 130062306a36Sopenharmony_ci n++; 130162306a36Sopenharmony_ci } else if (tcr == 0) { 130262306a36Sopenharmony_ci if ((n = 130362306a36Sopenharmony_ci (card->tst_free_entries - 130462306a36Sopenharmony_ci NS_TST_RESERVED)) <= 0) { 130562306a36Sopenharmony_ci PRINTK 130662306a36Sopenharmony_ci ("nicstar%d: no CBR bandwidth free.\n", 130762306a36Sopenharmony_ci card->index); 130862306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 130962306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 131062306a36Sopenharmony_ci return -EINVAL; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (n == 0) { 131562306a36Sopenharmony_ci printk 131662306a36Sopenharmony_ci ("nicstar%d: selected bandwidth < granularity.\n", 131762306a36Sopenharmony_ci card->index); 131862306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 131962306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 132062306a36Sopenharmony_ci return -EINVAL; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (n > (card->tst_free_entries - NS_TST_RESERVED)) { 132462306a36Sopenharmony_ci PRINTK 132562306a36Sopenharmony_ci ("nicstar%d: not enough free CBR bandwidth.\n", 132662306a36Sopenharmony_ci card->index); 132762306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 132862306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 132962306a36Sopenharmony_ci return -EINVAL; 133062306a36Sopenharmony_ci } else 133162306a36Sopenharmony_ci card->tst_free_entries -= n; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci XPRINTK("nicstar%d: writing %d tst entries.\n", 133462306a36Sopenharmony_ci card->index, n); 133562306a36Sopenharmony_ci for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) { 133662306a36Sopenharmony_ci if (card->scd2vc[frscdi] == NULL) { 133762306a36Sopenharmony_ci card->scd2vc[frscdi] = vc; 133862306a36Sopenharmony_ci break; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci if (frscdi == NS_FRSCD_NUM) { 134262306a36Sopenharmony_ci PRINTK 134362306a36Sopenharmony_ci ("nicstar%d: no SCD available for CBR channel.\n", 134462306a36Sopenharmony_ci card->index); 134562306a36Sopenharmony_ci card->tst_free_entries += n; 134662306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 134762306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 134862306a36Sopenharmony_ci return -EBUSY; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd); 135462306a36Sopenharmony_ci if (scq == NULL) { 135562306a36Sopenharmony_ci PRINTK("nicstar%d: can't get fixed rate SCQ.\n", 135662306a36Sopenharmony_ci card->index); 135762306a36Sopenharmony_ci card->scd2vc[frscdi] = NULL; 135862306a36Sopenharmony_ci card->tst_free_entries += n; 135962306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 136062306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 136162306a36Sopenharmony_ci return -ENOMEM; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci vc->scq = scq; 136462306a36Sopenharmony_ci u32d[0] = scq_virt_to_bus(scq, scq->base); 136562306a36Sopenharmony_ci u32d[1] = (u32) 0x00000000; 136662306a36Sopenharmony_ci u32d[2] = (u32) 0xffffffff; 136762306a36Sopenharmony_ci u32d[3] = (u32) 0x00000000; 136862306a36Sopenharmony_ci ns_write_sram(card, vc->cbr_scd, u32d, 4); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci fill_tst(card, n, vc); 137162306a36Sopenharmony_ci } else if (vcc->qos.txtp.traffic_class == ATM_UBR) { 137262306a36Sopenharmony_ci vc->cbr_scd = 0x00000000; 137362306a36Sopenharmony_ci vc->scq = card->scq0; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 137762306a36Sopenharmony_ci vc->tx = 1; 137862306a36Sopenharmony_ci vc->tx_vcc = vcc; 137962306a36Sopenharmony_ci vc->tbd_count = 0; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 138262306a36Sopenharmony_ci u32 status; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci vc->rx = 1; 138562306a36Sopenharmony_ci vc->rx_vcc = vcc; 138662306a36Sopenharmony_ci vc->rx_iov = NULL; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Open the connection in hardware */ 138962306a36Sopenharmony_ci if (vcc->qos.aal == ATM_AAL5) 139062306a36Sopenharmony_ci status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; 139162306a36Sopenharmony_ci else /* vcc->qos.aal == ATM_AAL0 */ 139262306a36Sopenharmony_ci status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; 139362306a36Sopenharmony_ci#ifdef RCQ_SUPPORT 139462306a36Sopenharmony_ci status |= NS_RCTE_RAWCELLINTEN; 139562306a36Sopenharmony_ci#endif /* RCQ_SUPPORT */ 139662306a36Sopenharmony_ci ns_write_sram(card, 139762306a36Sopenharmony_ci NS_RCT + 139862306a36Sopenharmony_ci (vpi << card->vcibits | vci) * 139962306a36Sopenharmony_ci NS_RCT_ENTRY_SIZE, &status, 1); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci set_bit(ATM_VF_READY, &vcc->flags); 140562306a36Sopenharmony_ci return 0; 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic void ns_close(struct atm_vcc *vcc) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci vc_map *vc; 141162306a36Sopenharmony_ci ns_dev *card; 141262306a36Sopenharmony_ci u32 data; 141362306a36Sopenharmony_ci int i; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci vc = vcc->dev_data; 141662306a36Sopenharmony_ci card = vcc->dev->dev_data; 141762306a36Sopenharmony_ci PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, 141862306a36Sopenharmony_ci (int)vcc->vpi, vcc->vci); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci clear_bit(ATM_VF_READY, &vcc->flags); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (vcc->qos.rxtp.traffic_class != ATM_NONE) { 142362306a36Sopenharmony_ci u32 addr; 142462306a36Sopenharmony_ci unsigned long flags; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci addr = 142762306a36Sopenharmony_ci NS_RCT + 142862306a36Sopenharmony_ci (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; 142962306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 143062306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 143162306a36Sopenharmony_ci writel(NS_CMD_CLOSE_CONNECTION | addr << 2, 143262306a36Sopenharmony_ci card->membase + CMD); 143362306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci vc->rx = 0; 143662306a36Sopenharmony_ci if (vc->rx_iov != NULL) { 143762306a36Sopenharmony_ci struct sk_buff *iovb; 143862306a36Sopenharmony_ci u32 stat; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci stat = readl(card->membase + STAT); 144162306a36Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 144262306a36Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci PRINTK 144562306a36Sopenharmony_ci ("nicstar%d: closing a VC with pending rx buffers.\n", 144662306a36Sopenharmony_ci card->index); 144762306a36Sopenharmony_ci iovb = vc->rx_iov; 144862306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 144962306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 145062306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 145162306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 145262306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 145362306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 145462306a36Sopenharmony_ci vc->rx_iov = NULL; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 145962306a36Sopenharmony_ci vc->tx = 0; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 146362306a36Sopenharmony_ci unsigned long flags; 146462306a36Sopenharmony_ci ns_scqe *scqep; 146562306a36Sopenharmony_ci scq_info *scq; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci scq = vc->scq; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci for (;;) { 147062306a36Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 147162306a36Sopenharmony_ci scqep = scq->next; 147262306a36Sopenharmony_ci if (scqep == scq->base) 147362306a36Sopenharmony_ci scqep = scq->last; 147462306a36Sopenharmony_ci else 147562306a36Sopenharmony_ci scqep--; 147662306a36Sopenharmony_ci if (scqep == scq->tail) { 147762306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci /* If the last entry is not a TSR, place one in the SCQ in order to 148162306a36Sopenharmony_ci be able to completely drain it and then close. */ 148262306a36Sopenharmony_ci if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) { 148362306a36Sopenharmony_ci ns_scqe tsr; 148462306a36Sopenharmony_ci u32 scdi, scqi; 148562306a36Sopenharmony_ci u32 data; 148662306a36Sopenharmony_ci int index; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 148962306a36Sopenharmony_ci scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 149062306a36Sopenharmony_ci scqi = scq->next - scq->base; 149162306a36Sopenharmony_ci tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 149262306a36Sopenharmony_ci tsr.word_3 = 0x00000000; 149362306a36Sopenharmony_ci tsr.word_4 = 0x00000000; 149462306a36Sopenharmony_ci *scq->next = tsr; 149562306a36Sopenharmony_ci index = (int)scqi; 149662306a36Sopenharmony_ci scq->skb[index] = NULL; 149762306a36Sopenharmony_ci if (scq->next == scq->last) 149862306a36Sopenharmony_ci scq->next = scq->base; 149962306a36Sopenharmony_ci else 150062306a36Sopenharmony_ci scq->next++; 150162306a36Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 150262306a36Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 150562306a36Sopenharmony_ci schedule(); 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* Free all TST entries */ 150962306a36Sopenharmony_ci data = NS_TST_OPCODE_VARIABLE; 151062306a36Sopenharmony_ci for (i = 0; i < NS_TST_NUM_ENTRIES; i++) { 151162306a36Sopenharmony_ci if (card->tste2vc[i] == vc) { 151262306a36Sopenharmony_ci ns_write_sram(card, card->tst_addr + i, &data, 151362306a36Sopenharmony_ci 1); 151462306a36Sopenharmony_ci card->tste2vc[i] = NULL; 151562306a36Sopenharmony_ci card->tst_free_entries++; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; 152062306a36Sopenharmony_ci free_scq(card, vc->scq, vcc); 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* remove all references to vcc before deleting it */ 152462306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class != ATM_NONE) { 152562306a36Sopenharmony_ci unsigned long flags; 152662306a36Sopenharmony_ci scq_info *scq = card->scq0; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci for (i = 0; i < scq->num_entries; i++) { 153162306a36Sopenharmony_ci if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) { 153262306a36Sopenharmony_ci ATM_SKB(scq->skb[i])->vcc = NULL; 153362306a36Sopenharmony_ci atm_return(vcc, scq->skb[i]->truesize); 153462306a36Sopenharmony_ci PRINTK 153562306a36Sopenharmony_ci ("nicstar: deleted pending vcc mapping\n"); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci vcc->dev_data = NULL; 154362306a36Sopenharmony_ci clear_bit(ATM_VF_PARTIAL, &vcc->flags); 154462306a36Sopenharmony_ci clear_bit(ATM_VF_ADDR, &vcc->flags); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci#ifdef RX_DEBUG 154762306a36Sopenharmony_ci { 154862306a36Sopenharmony_ci u32 stat, cfg; 154962306a36Sopenharmony_ci stat = readl(card->membase + STAT); 155062306a36Sopenharmony_ci cfg = readl(card->membase + CFG); 155162306a36Sopenharmony_ci printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); 155262306a36Sopenharmony_ci printk 155362306a36Sopenharmony_ci ("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n", 155462306a36Sopenharmony_ci card->tsq.base, card->tsq.next, 155562306a36Sopenharmony_ci card->tsq.last, readl(card->membase + TSQT)); 155662306a36Sopenharmony_ci printk 155762306a36Sopenharmony_ci ("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n", 155862306a36Sopenharmony_ci card->rsq.base, card->rsq.next, 155962306a36Sopenharmony_ci card->rsq.last, readl(card->membase + RSQT)); 156062306a36Sopenharmony_ci printk("Empty free buffer queue interrupt %s \n", 156162306a36Sopenharmony_ci card->efbie ? "enabled" : "disabled"); 156262306a36Sopenharmony_ci printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", 156362306a36Sopenharmony_ci ns_stat_sfbqc_get(stat), card->sbpool.count, 156462306a36Sopenharmony_ci ns_stat_lfbqc_get(stat), card->lbpool.count); 156562306a36Sopenharmony_ci printk("hbpool.count = %d iovpool.count = %d \n", 156662306a36Sopenharmony_ci card->hbpool.count, card->iovpool.count); 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci#endif /* RX_DEBUG */ 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic void fill_tst(ns_dev * card, int n, vc_map * vc) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci u32 new_tst; 157462306a36Sopenharmony_ci unsigned long cl; 157562306a36Sopenharmony_ci int e, r; 157662306a36Sopenharmony_ci u32 data; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* It would be very complicated to keep the two TSTs synchronized while 157962306a36Sopenharmony_ci assuring that writes are only made to the inactive TST. So, for now I 158062306a36Sopenharmony_ci will use only one TST. If problems occur, I will change this again */ 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci new_tst = card->tst_addr; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* Fill procedure */ 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci for (e = 0; e < NS_TST_NUM_ENTRIES; e++) { 158762306a36Sopenharmony_ci if (card->tste2vc[e] == NULL) 158862306a36Sopenharmony_ci break; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci if (e == NS_TST_NUM_ENTRIES) { 159162306a36Sopenharmony_ci printk("nicstar%d: No free TST entries found. \n", card->index); 159262306a36Sopenharmony_ci return; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci r = n; 159662306a36Sopenharmony_ci cl = NS_TST_NUM_ENTRIES; 159762306a36Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci while (r > 0) { 160062306a36Sopenharmony_ci if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) { 160162306a36Sopenharmony_ci card->tste2vc[e] = vc; 160262306a36Sopenharmony_ci ns_write_sram(card, new_tst + e, &data, 1); 160362306a36Sopenharmony_ci cl -= NS_TST_NUM_ENTRIES; 160462306a36Sopenharmony_ci r--; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (++e == NS_TST_NUM_ENTRIES) { 160862306a36Sopenharmony_ci e = 0; 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci cl += n; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* End of fill procedure */ 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci data = ns_tste_make(NS_TST_OPCODE_END, new_tst); 161662306a36Sopenharmony_ci ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); 161762306a36Sopenharmony_ci ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); 161862306a36Sopenharmony_ci card->tst_addr = new_tst; 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic int _ns_send(struct atm_vcc *vcc, struct sk_buff *skb, bool may_sleep) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci ns_dev *card; 162462306a36Sopenharmony_ci vc_map *vc; 162562306a36Sopenharmony_ci scq_info *scq; 162662306a36Sopenharmony_ci unsigned long buflen; 162762306a36Sopenharmony_ci ns_scqe scqe; 162862306a36Sopenharmony_ci u32 flags; /* TBD flags, not CPU flags */ 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci card = vcc->dev->dev_data; 163162306a36Sopenharmony_ci TXPRINTK("nicstar%d: ns_send() called.\n", card->index); 163262306a36Sopenharmony_ci if ((vc = (vc_map *) vcc->dev_data) == NULL) { 163362306a36Sopenharmony_ci printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", 163462306a36Sopenharmony_ci card->index); 163562306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 163662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 163762306a36Sopenharmony_ci return -EINVAL; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci if (!vc->tx) { 164162306a36Sopenharmony_ci printk("nicstar%d: Trying to transmit on a non-tx VC.\n", 164262306a36Sopenharmony_ci card->index); 164362306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 164462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 164562306a36Sopenharmony_ci return -EINVAL; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { 164962306a36Sopenharmony_ci printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", 165062306a36Sopenharmony_ci card->index); 165162306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 165262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 165362306a36Sopenharmony_ci return -EINVAL; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags != 0) { 165762306a36Sopenharmony_ci printk("nicstar%d: No scatter-gather yet.\n", card->index); 165862306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 165962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 166062306a36Sopenharmony_ci return -EINVAL; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci NS_PRV_DMA(skb) = dma_map_single(&card->pcidev->dev, skb->data, 166662306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci if (vcc->qos.aal == ATM_AAL5) { 166962306a36Sopenharmony_ci buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ 167062306a36Sopenharmony_ci flags = NS_TBD_AAL5; 167162306a36Sopenharmony_ci scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb)); 167262306a36Sopenharmony_ci scqe.word_3 = cpu_to_le32(skb->len); 167362306a36Sopenharmony_ci scqe.word_4 = 167462306a36Sopenharmony_ci ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, 167562306a36Sopenharmony_ci ATM_SKB(skb)-> 167662306a36Sopenharmony_ci atm_options & ATM_ATMOPT_CLP ? 1 : 0); 167762306a36Sopenharmony_ci flags |= NS_TBD_EOPDU; 167862306a36Sopenharmony_ci } else { /* (vcc->qos.aal == ATM_AAL0) */ 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ 168162306a36Sopenharmony_ci flags = NS_TBD_AAL0; 168262306a36Sopenharmony_ci scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER); 168362306a36Sopenharmony_ci scqe.word_3 = cpu_to_le32(0x00000000); 168462306a36Sopenharmony_ci if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ 168562306a36Sopenharmony_ci flags |= NS_TBD_EOPDU; 168662306a36Sopenharmony_ci scqe.word_4 = 168762306a36Sopenharmony_ci cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); 168862306a36Sopenharmony_ci /* Force the VPI/VCI to be the same as in VCC struct */ 168962306a36Sopenharmony_ci scqe.word_4 |= 169062306a36Sopenharmony_ci cpu_to_le32((((u32) vcc-> 169162306a36Sopenharmony_ci vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc-> 169262306a36Sopenharmony_ci vci) << 169362306a36Sopenharmony_ci NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK); 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (vcc->qos.txtp.traffic_class == ATM_CBR) { 169762306a36Sopenharmony_ci scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); 169862306a36Sopenharmony_ci scq = ((vc_map *) vcc->dev_data)->scq; 169962306a36Sopenharmony_ci } else { 170062306a36Sopenharmony_ci scqe.word_1 = 170162306a36Sopenharmony_ci ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); 170262306a36Sopenharmony_ci scq = card->scq0; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci if (push_scqe(card, vc, scq, &scqe, skb, may_sleep) != 0) { 170662306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx_err); 170762306a36Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len, 170862306a36Sopenharmony_ci DMA_TO_DEVICE); 170962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 171062306a36Sopenharmony_ci return -EIO; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci atomic_inc(&vcc->stats->tx); 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci return 0; 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci return _ns_send(vcc, skb, true); 172062306a36Sopenharmony_ci} 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_cistatic int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb) 172362306a36Sopenharmony_ci{ 172462306a36Sopenharmony_ci return _ns_send(vcc, skb, false); 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 172862306a36Sopenharmony_ci struct sk_buff *skb, bool may_sleep) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci unsigned long flags; 173162306a36Sopenharmony_ci ns_scqe tsr; 173262306a36Sopenharmony_ci u32 scdi, scqi; 173362306a36Sopenharmony_ci int scq_is_vbr; 173462306a36Sopenharmony_ci u32 data; 173562306a36Sopenharmony_ci int index; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 173862306a36Sopenharmony_ci while (scq->tail == scq->next) { 173962306a36Sopenharmony_ci if (!may_sleep) { 174062306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 174162306a36Sopenharmony_ci printk("nicstar%d: Error pushing TBD.\n", card->index); 174262306a36Sopenharmony_ci return 1; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci scq->full = 1; 174662306a36Sopenharmony_ci wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, 174762306a36Sopenharmony_ci scq->tail != scq->next, 174862306a36Sopenharmony_ci scq->lock, 174962306a36Sopenharmony_ci SCQFULL_TIMEOUT); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (scq->full) { 175262306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 175362306a36Sopenharmony_ci printk("nicstar%d: Timeout pushing TBD.\n", 175462306a36Sopenharmony_ci card->index); 175562306a36Sopenharmony_ci return 1; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci *scq->next = *tbd; 175962306a36Sopenharmony_ci index = (int)(scq->next - scq->base); 176062306a36Sopenharmony_ci scq->skb[index] = skb; 176162306a36Sopenharmony_ci XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n", 176262306a36Sopenharmony_ci card->index, skb, index); 176362306a36Sopenharmony_ci XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", 176462306a36Sopenharmony_ci card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), 176562306a36Sopenharmony_ci le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), 176662306a36Sopenharmony_ci scq->next); 176762306a36Sopenharmony_ci if (scq->next == scq->last) 176862306a36Sopenharmony_ci scq->next = scq->base; 176962306a36Sopenharmony_ci else 177062306a36Sopenharmony_ci scq->next++; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci vc->tbd_count++; 177362306a36Sopenharmony_ci if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) { 177462306a36Sopenharmony_ci scq->tbd_count++; 177562306a36Sopenharmony_ci scq_is_vbr = 1; 177662306a36Sopenharmony_ci } else 177762306a36Sopenharmony_ci scq_is_vbr = 0; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci if (vc->tbd_count >= MAX_TBD_PER_VC 178062306a36Sopenharmony_ci || scq->tbd_count >= MAX_TBD_PER_SCQ) { 178162306a36Sopenharmony_ci int has_run = 0; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci while (scq->tail == scq->next) { 178462306a36Sopenharmony_ci if (!may_sleep) { 178562306a36Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 178662306a36Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 178762306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 178862306a36Sopenharmony_ci printk("nicstar%d: Error pushing TSR.\n", 178962306a36Sopenharmony_ci card->index); 179062306a36Sopenharmony_ci return 0; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci scq->full = 1; 179462306a36Sopenharmony_ci if (has_run++) 179562306a36Sopenharmony_ci break; 179662306a36Sopenharmony_ci wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, 179762306a36Sopenharmony_ci scq->tail != scq->next, 179862306a36Sopenharmony_ci scq->lock, 179962306a36Sopenharmony_ci SCQFULL_TIMEOUT); 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (!scq->full) { 180362306a36Sopenharmony_ci tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 180462306a36Sopenharmony_ci if (scq_is_vbr) 180562306a36Sopenharmony_ci scdi = NS_TSR_SCDISVBR; 180662306a36Sopenharmony_ci else 180762306a36Sopenharmony_ci scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 180862306a36Sopenharmony_ci scqi = scq->next - scq->base; 180962306a36Sopenharmony_ci tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 181062306a36Sopenharmony_ci tsr.word_3 = 0x00000000; 181162306a36Sopenharmony_ci tsr.word_4 = 0x00000000; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci *scq->next = tsr; 181462306a36Sopenharmony_ci index = (int)scqi; 181562306a36Sopenharmony_ci scq->skb[index] = NULL; 181662306a36Sopenharmony_ci XPRINTK 181762306a36Sopenharmony_ci ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", 181862306a36Sopenharmony_ci card->index, le32_to_cpu(tsr.word_1), 181962306a36Sopenharmony_ci le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3), 182062306a36Sopenharmony_ci le32_to_cpu(tsr.word_4), scq->next); 182162306a36Sopenharmony_ci if (scq->next == scq->last) 182262306a36Sopenharmony_ci scq->next = scq->base; 182362306a36Sopenharmony_ci else 182462306a36Sopenharmony_ci scq->next++; 182562306a36Sopenharmony_ci vc->tbd_count = 0; 182662306a36Sopenharmony_ci scq->tbd_count = 0; 182762306a36Sopenharmony_ci } else 182862306a36Sopenharmony_ci PRINTK("nicstar%d: Timeout pushing TSR.\n", 182962306a36Sopenharmony_ci card->index); 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci data = scq_virt_to_bus(scq, scq->next); 183262306a36Sopenharmony_ci ns_write_sram(card, scq->scd, &data, 1); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci return 0; 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic void process_tsq(ns_dev * card) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci u32 scdi; 184262306a36Sopenharmony_ci scq_info *scq; 184362306a36Sopenharmony_ci ns_tsi *previous = NULL, *one_ahead, *two_ahead; 184462306a36Sopenharmony_ci int serviced_entries; /* flag indicating at least on entry was serviced */ 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci serviced_entries = 0; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci if (card->tsq.next == card->tsq.last) 184962306a36Sopenharmony_ci one_ahead = card->tsq.base; 185062306a36Sopenharmony_ci else 185162306a36Sopenharmony_ci one_ahead = card->tsq.next + 1; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (one_ahead == card->tsq.last) 185462306a36Sopenharmony_ci two_ahead = card->tsq.base; 185562306a36Sopenharmony_ci else 185662306a36Sopenharmony_ci two_ahead = one_ahead + 1; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || 185962306a36Sopenharmony_ci !ns_tsi_isempty(two_ahead)) 186062306a36Sopenharmony_ci /* At most two empty, as stated in the 77201 errata */ 186162306a36Sopenharmony_ci { 186262306a36Sopenharmony_ci serviced_entries = 1; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* Skip the one or two possible empty entries */ 186562306a36Sopenharmony_ci while (ns_tsi_isempty(card->tsq.next)) { 186662306a36Sopenharmony_ci if (card->tsq.next == card->tsq.last) 186762306a36Sopenharmony_ci card->tsq.next = card->tsq.base; 186862306a36Sopenharmony_ci else 186962306a36Sopenharmony_ci card->tsq.next++; 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci if (!ns_tsi_tmrof(card->tsq.next)) { 187362306a36Sopenharmony_ci scdi = ns_tsi_getscdindex(card->tsq.next); 187462306a36Sopenharmony_ci if (scdi == NS_TSI_SCDISVBR) 187562306a36Sopenharmony_ci scq = card->scq0; 187662306a36Sopenharmony_ci else { 187762306a36Sopenharmony_ci if (card->scd2vc[scdi] == NULL) { 187862306a36Sopenharmony_ci printk 187962306a36Sopenharmony_ci ("nicstar%d: could not find VC from SCD index.\n", 188062306a36Sopenharmony_ci card->index); 188162306a36Sopenharmony_ci ns_tsi_init(card->tsq.next); 188262306a36Sopenharmony_ci return; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci scq = card->scd2vc[scdi]->scq; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); 188762306a36Sopenharmony_ci scq->full = 0; 188862306a36Sopenharmony_ci wake_up_interruptible(&(scq->scqfull_waitq)); 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci ns_tsi_init(card->tsq.next); 189262306a36Sopenharmony_ci previous = card->tsq.next; 189362306a36Sopenharmony_ci if (card->tsq.next == card->tsq.last) 189462306a36Sopenharmony_ci card->tsq.next = card->tsq.base; 189562306a36Sopenharmony_ci else 189662306a36Sopenharmony_ci card->tsq.next++; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci if (card->tsq.next == card->tsq.last) 189962306a36Sopenharmony_ci one_ahead = card->tsq.base; 190062306a36Sopenharmony_ci else 190162306a36Sopenharmony_ci one_ahead = card->tsq.next + 1; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci if (one_ahead == card->tsq.last) 190462306a36Sopenharmony_ci two_ahead = card->tsq.base; 190562306a36Sopenharmony_ci else 190662306a36Sopenharmony_ci two_ahead = one_ahead + 1; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (serviced_entries) 191062306a36Sopenharmony_ci writel(PTR_DIFF(previous, card->tsq.base), 191162306a36Sopenharmony_ci card->membase + TSQH); 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_cistatic void drain_scq(ns_dev * card, scq_info * scq, int pos) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci struct atm_vcc *vcc; 191762306a36Sopenharmony_ci struct sk_buff *skb; 191862306a36Sopenharmony_ci int i; 191962306a36Sopenharmony_ci unsigned long flags; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n", 192262306a36Sopenharmony_ci card->index, scq, pos); 192362306a36Sopenharmony_ci if (pos >= scq->num_entries) { 192462306a36Sopenharmony_ci printk("nicstar%d: Bad index on drain_scq().\n", card->index); 192562306a36Sopenharmony_ci return; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci spin_lock_irqsave(&scq->lock, flags); 192962306a36Sopenharmony_ci i = (int)(scq->tail - scq->base); 193062306a36Sopenharmony_ci if (++i == scq->num_entries) 193162306a36Sopenharmony_ci i = 0; 193262306a36Sopenharmony_ci while (i != pos) { 193362306a36Sopenharmony_ci skb = scq->skb[i]; 193462306a36Sopenharmony_ci XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n", 193562306a36Sopenharmony_ci card->index, skb, i); 193662306a36Sopenharmony_ci if (skb != NULL) { 193762306a36Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, 193862306a36Sopenharmony_ci NS_PRV_DMA(skb), 193962306a36Sopenharmony_ci skb->len, 194062306a36Sopenharmony_ci DMA_TO_DEVICE); 194162306a36Sopenharmony_ci vcc = ATM_SKB(skb)->vcc; 194262306a36Sopenharmony_ci if (vcc && vcc->pop != NULL) { 194362306a36Sopenharmony_ci vcc->pop(vcc, skb); 194462306a36Sopenharmony_ci } else { 194562306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci scq->skb[i] = NULL; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci if (++i == scq->num_entries) 195062306a36Sopenharmony_ci i = 0; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci scq->tail = scq->base + pos; 195362306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->lock, flags); 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic void process_rsq(ns_dev * card) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci ns_rsqe *previous; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci if (!ns_rsqe_valid(card->rsq.next)) 196162306a36Sopenharmony_ci return; 196262306a36Sopenharmony_ci do { 196362306a36Sopenharmony_ci dequeue_rx(card, card->rsq.next); 196462306a36Sopenharmony_ci ns_rsqe_init(card->rsq.next); 196562306a36Sopenharmony_ci previous = card->rsq.next; 196662306a36Sopenharmony_ci if (card->rsq.next == card->rsq.last) 196762306a36Sopenharmony_ci card->rsq.next = card->rsq.base; 196862306a36Sopenharmony_ci else 196962306a36Sopenharmony_ci card->rsq.next++; 197062306a36Sopenharmony_ci } while (ns_rsqe_valid(card->rsq.next)); 197162306a36Sopenharmony_ci writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH); 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_cistatic void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci u32 vpi, vci; 197762306a36Sopenharmony_ci vc_map *vc; 197862306a36Sopenharmony_ci struct sk_buff *iovb; 197962306a36Sopenharmony_ci struct iovec *iov; 198062306a36Sopenharmony_ci struct atm_vcc *vcc; 198162306a36Sopenharmony_ci struct sk_buff *skb; 198262306a36Sopenharmony_ci unsigned short aal5_len; 198362306a36Sopenharmony_ci int len; 198462306a36Sopenharmony_ci u32 stat; 198562306a36Sopenharmony_ci u32 id; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci stat = readl(card->membase + STAT); 198862306a36Sopenharmony_ci card->sbfqc = ns_stat_sfbqc_get(stat); 198962306a36Sopenharmony_ci card->lbfqc = ns_stat_lfbqc_get(stat); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci id = le32_to_cpu(rsqe->buffer_handle); 199262306a36Sopenharmony_ci skb = idr_remove(&card->idr, id); 199362306a36Sopenharmony_ci if (!skb) { 199462306a36Sopenharmony_ci RXPRINTK(KERN_ERR 199562306a36Sopenharmony_ci "nicstar%d: skb not found!\n", card->index); 199662306a36Sopenharmony_ci return; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci dma_sync_single_for_cpu(&card->pcidev->dev, 199962306a36Sopenharmony_ci NS_PRV_DMA(skb), 200062306a36Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 200162306a36Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 200262306a36Sopenharmony_ci DMA_FROM_DEVICE); 200362306a36Sopenharmony_ci dma_unmap_single(&card->pcidev->dev, 200462306a36Sopenharmony_ci NS_PRV_DMA(skb), 200562306a36Sopenharmony_ci (NS_PRV_BUFTYPE(skb) == BUF_SM 200662306a36Sopenharmony_ci ? NS_SMSKBSIZE : NS_LGSKBSIZE), 200762306a36Sopenharmony_ci DMA_FROM_DEVICE); 200862306a36Sopenharmony_ci vpi = ns_rsqe_vpi(rsqe); 200962306a36Sopenharmony_ci vci = ns_rsqe_vci(rsqe); 201062306a36Sopenharmony_ci if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) { 201162306a36Sopenharmony_ci printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", 201262306a36Sopenharmony_ci card->index, vpi, vci); 201362306a36Sopenharmony_ci recycle_rx_buf(card, skb); 201462306a36Sopenharmony_ci return; 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci vc = &(card->vcmap[vpi << card->vcibits | vci]); 201862306a36Sopenharmony_ci if (!vc->rx) { 201962306a36Sopenharmony_ci RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", 202062306a36Sopenharmony_ci card->index, vpi, vci); 202162306a36Sopenharmony_ci recycle_rx_buf(card, skb); 202262306a36Sopenharmony_ci return; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci vcc = vc->rx_vcc; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (vcc->qos.aal == ATM_AAL0) { 202862306a36Sopenharmony_ci struct sk_buff *sb; 202962306a36Sopenharmony_ci unsigned char *cell; 203062306a36Sopenharmony_ci int i; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci cell = skb->data; 203362306a36Sopenharmony_ci for (i = ns_rsqe_cellcount(rsqe); i; i--) { 203462306a36Sopenharmony_ci sb = dev_alloc_skb(NS_SMSKBSIZE); 203562306a36Sopenharmony_ci if (!sb) { 203662306a36Sopenharmony_ci printk 203762306a36Sopenharmony_ci ("nicstar%d: Can't allocate buffers for aal0.\n", 203862306a36Sopenharmony_ci card->index); 203962306a36Sopenharmony_ci atomic_add(i, &vcc->stats->rx_drop); 204062306a36Sopenharmony_ci break; 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci if (!atm_charge(vcc, sb->truesize)) { 204362306a36Sopenharmony_ci RXPRINTK 204462306a36Sopenharmony_ci ("nicstar%d: atm_charge() dropped aal0 packets.\n", 204562306a36Sopenharmony_ci card->index); 204662306a36Sopenharmony_ci atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */ 204762306a36Sopenharmony_ci dev_kfree_skb_any(sb); 204862306a36Sopenharmony_ci break; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci /* Rebuild the header */ 205162306a36Sopenharmony_ci *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 | 205262306a36Sopenharmony_ci (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); 205362306a36Sopenharmony_ci if (i == 1 && ns_rsqe_eopdu(rsqe)) 205462306a36Sopenharmony_ci *((u32 *) sb->data) |= 0x00000002; 205562306a36Sopenharmony_ci skb_put(sb, NS_AAL0_HEADER); 205662306a36Sopenharmony_ci memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD); 205762306a36Sopenharmony_ci skb_put(sb, ATM_CELL_PAYLOAD); 205862306a36Sopenharmony_ci ATM_SKB(sb)->vcc = vcc; 205962306a36Sopenharmony_ci __net_timestamp(sb); 206062306a36Sopenharmony_ci vcc->push(vcc, sb); 206162306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 206262306a36Sopenharmony_ci cell += ATM_CELL_PAYLOAD; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci recycle_rx_buf(card, skb); 206662306a36Sopenharmony_ci return; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci /* To reach this point, the AAL layer can only be AAL5 */ 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if ((iovb = vc->rx_iov) == NULL) { 207262306a36Sopenharmony_ci iovb = skb_dequeue(&(card->iovpool.queue)); 207362306a36Sopenharmony_ci if (iovb == NULL) { /* No buffers in the queue */ 207462306a36Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); 207562306a36Sopenharmony_ci if (iovb == NULL) { 207662306a36Sopenharmony_ci printk("nicstar%d: Out of iovec buffers.\n", 207762306a36Sopenharmony_ci card->index); 207862306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 207962306a36Sopenharmony_ci recycle_rx_buf(card, skb); 208062306a36Sopenharmony_ci return; 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 208362306a36Sopenharmony_ci } else if (--card->iovpool.count < card->iovnr.min) { 208462306a36Sopenharmony_ci struct sk_buff *new_iovb; 208562306a36Sopenharmony_ci if ((new_iovb = 208662306a36Sopenharmony_ci alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) { 208762306a36Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 208862306a36Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, new_iovb); 208962306a36Sopenharmony_ci card->iovpool.count++; 209062306a36Sopenharmony_ci } 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci vc->rx_iov = iovb; 209362306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 209462306a36Sopenharmony_ci iovb->len = 0; 209562306a36Sopenharmony_ci iovb->data = iovb->head; 209662306a36Sopenharmony_ci skb_reset_tail_pointer(iovb); 209762306a36Sopenharmony_ci /* IMPORTANT: a pointer to the sk_buff containing the small or large 209862306a36Sopenharmony_ci buffer is stored as iovec base, NOT a pointer to the 209962306a36Sopenharmony_ci small or large buffer itself. */ 210062306a36Sopenharmony_ci } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) { 210162306a36Sopenharmony_ci printk("nicstar%d: received too big AAL5 SDU.\n", card->index); 210262306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 210362306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 210462306a36Sopenharmony_ci NS_MAX_IOVECS); 210562306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb) = 0; 210662306a36Sopenharmony_ci iovb->len = 0; 210762306a36Sopenharmony_ci iovb->data = iovb->head; 210862306a36Sopenharmony_ci skb_reset_tail_pointer(iovb); 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++]; 211162306a36Sopenharmony_ci iov->iov_base = (void *)skb; 211262306a36Sopenharmony_ci iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; 211362306a36Sopenharmony_ci iovb->len += iov->iov_len; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci#ifdef EXTRA_DEBUG 211662306a36Sopenharmony_ci if (NS_PRV_IOVCNT(iovb) == 1) { 211762306a36Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) != BUF_SM) { 211862306a36Sopenharmony_ci printk 211962306a36Sopenharmony_ci ("nicstar%d: Expected a small buffer, and this is not one.\n", 212062306a36Sopenharmony_ci card->index); 212162306a36Sopenharmony_ci which_list(card, skb); 212262306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 212362306a36Sopenharmony_ci recycle_rx_buf(card, skb); 212462306a36Sopenharmony_ci vc->rx_iov = NULL; 212562306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 212662306a36Sopenharmony_ci return; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci } else { /* NS_PRV_IOVCNT(iovb) >= 2 */ 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if (NS_PRV_BUFTYPE(skb) != BUF_LG) { 213162306a36Sopenharmony_ci printk 213262306a36Sopenharmony_ci ("nicstar%d: Expected a large buffer, and this is not one.\n", 213362306a36Sopenharmony_ci card->index); 213462306a36Sopenharmony_ci which_list(card, skb); 213562306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 213662306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 213762306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 213862306a36Sopenharmony_ci vc->rx_iov = NULL; 213962306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 214062306a36Sopenharmony_ci return; 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci#endif /* EXTRA_DEBUG */ 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (ns_rsqe_eopdu(rsqe)) { 214662306a36Sopenharmony_ci /* This works correctly regardless of the endianness of the host */ 214762306a36Sopenharmony_ci unsigned char *L1L2 = (unsigned char *) 214862306a36Sopenharmony_ci (skb->data + iov->iov_len - 6); 214962306a36Sopenharmony_ci aal5_len = L1L2[0] << 8 | L1L2[1]; 215062306a36Sopenharmony_ci len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; 215162306a36Sopenharmony_ci if (ns_rsqe_crcerr(rsqe) || 215262306a36Sopenharmony_ci len + 8 > iovb->len || len + (47 + 8) < iovb->len) { 215362306a36Sopenharmony_ci printk("nicstar%d: AAL5 CRC error", card->index); 215462306a36Sopenharmony_ci if (len + 8 > iovb->len || len + (47 + 8) < iovb->len) 215562306a36Sopenharmony_ci printk(" - PDU size mismatch.\n"); 215662306a36Sopenharmony_ci else 215762306a36Sopenharmony_ci printk(".\n"); 215862306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_err); 215962306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, 216062306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 216162306a36Sopenharmony_ci vc->rx_iov = NULL; 216262306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 216362306a36Sopenharmony_ci return; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci /* By this point we (hopefully) have a complete SDU without errors. */ 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (NS_PRV_IOVCNT(iovb) == 1) { /* Just a small buffer */ 216962306a36Sopenharmony_ci /* skb points to a small buffer */ 217062306a36Sopenharmony_ci if (!atm_charge(vcc, skb->truesize)) { 217162306a36Sopenharmony_ci push_rxbufs(card, skb); 217262306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 217362306a36Sopenharmony_ci } else { 217462306a36Sopenharmony_ci skb_put(skb, len); 217562306a36Sopenharmony_ci dequeue_sm_buf(card, skb); 217662306a36Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 217762306a36Sopenharmony_ci __net_timestamp(skb); 217862306a36Sopenharmony_ci vcc->push(vcc, skb); 217962306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */ 218262306a36Sopenharmony_ci struct sk_buff *sb; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci sb = (struct sk_buff *)(iov - 1)->iov_base; 218562306a36Sopenharmony_ci /* skb points to a large buffer */ 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (len <= NS_SMBUFSIZE) { 218862306a36Sopenharmony_ci if (!atm_charge(vcc, sb->truesize)) { 218962306a36Sopenharmony_ci push_rxbufs(card, sb); 219062306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 219162306a36Sopenharmony_ci } else { 219262306a36Sopenharmony_ci skb_put(sb, len); 219362306a36Sopenharmony_ci dequeue_sm_buf(card, sb); 219462306a36Sopenharmony_ci ATM_SKB(sb)->vcc = vcc; 219562306a36Sopenharmony_ci __net_timestamp(sb); 219662306a36Sopenharmony_ci vcc->push(vcc, sb); 219762306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci push_rxbufs(card, skb); 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci } else { /* len > NS_SMBUFSIZE, the usual case */ 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci if (!atm_charge(vcc, skb->truesize)) { 220562306a36Sopenharmony_ci push_rxbufs(card, skb); 220662306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 220762306a36Sopenharmony_ci } else { 220862306a36Sopenharmony_ci dequeue_lg_buf(card, skb); 220962306a36Sopenharmony_ci skb_push(skb, NS_SMBUFSIZE); 221062306a36Sopenharmony_ci skb_copy_from_linear_data(sb, skb->data, 221162306a36Sopenharmony_ci NS_SMBUFSIZE); 221262306a36Sopenharmony_ci skb_put(skb, len - NS_SMBUFSIZE); 221362306a36Sopenharmony_ci ATM_SKB(skb)->vcc = vcc; 221462306a36Sopenharmony_ci __net_timestamp(skb); 221562306a36Sopenharmony_ci vcc->push(vcc, skb); 221662306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci push_rxbufs(card, sb); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci } else { /* Must push a huge buffer */ 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci struct sk_buff *hb, *sb, *lb; 222662306a36Sopenharmony_ci int remaining, tocopy; 222762306a36Sopenharmony_ci int j; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci hb = skb_dequeue(&(card->hbpool.queue)); 223062306a36Sopenharmony_ci if (hb == NULL) { /* No buffers in the queue */ 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci hb = dev_alloc_skb(NS_HBUFSIZE); 223362306a36Sopenharmony_ci if (hb == NULL) { 223462306a36Sopenharmony_ci printk 223562306a36Sopenharmony_ci ("nicstar%d: Out of huge buffers.\n", 223662306a36Sopenharmony_ci card->index); 223762306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 223862306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, 223962306a36Sopenharmony_ci (struct iovec *) 224062306a36Sopenharmony_ci iovb->data, 224162306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 224262306a36Sopenharmony_ci vc->rx_iov = NULL; 224362306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 224462306a36Sopenharmony_ci return; 224562306a36Sopenharmony_ci } else if (card->hbpool.count < card->hbnr.min) { 224662306a36Sopenharmony_ci struct sk_buff *new_hb; 224762306a36Sopenharmony_ci if ((new_hb = 224862306a36Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != 224962306a36Sopenharmony_ci NULL) { 225062306a36Sopenharmony_ci skb_queue_tail(&card->hbpool. 225162306a36Sopenharmony_ci queue, new_hb); 225262306a36Sopenharmony_ci card->hbpool.count++; 225362306a36Sopenharmony_ci } 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 225662306a36Sopenharmony_ci } else if (--card->hbpool.count < card->hbnr.min) { 225762306a36Sopenharmony_ci struct sk_buff *new_hb; 225862306a36Sopenharmony_ci if ((new_hb = 225962306a36Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != NULL) { 226062306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_hb) = BUF_NONE; 226162306a36Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, 226262306a36Sopenharmony_ci new_hb); 226362306a36Sopenharmony_ci card->hbpool.count++; 226462306a36Sopenharmony_ci } 226562306a36Sopenharmony_ci if (card->hbpool.count < card->hbnr.min) { 226662306a36Sopenharmony_ci if ((new_hb = 226762306a36Sopenharmony_ci dev_alloc_skb(NS_HBUFSIZE)) != 226862306a36Sopenharmony_ci NULL) { 226962306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_hb) = 227062306a36Sopenharmony_ci BUF_NONE; 227162306a36Sopenharmony_ci skb_queue_tail(&card->hbpool. 227262306a36Sopenharmony_ci queue, new_hb); 227362306a36Sopenharmony_ci card->hbpool.count++; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci } 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci iov = (struct iovec *)iovb->data; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci if (!atm_charge(vcc, hb->truesize)) { 228162306a36Sopenharmony_ci recycle_iovec_rx_bufs(card, iov, 228262306a36Sopenharmony_ci NS_PRV_IOVCNT(iovb)); 228362306a36Sopenharmony_ci if (card->hbpool.count < card->hbnr.max) { 228462306a36Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 228562306a36Sopenharmony_ci card->hbpool.count++; 228662306a36Sopenharmony_ci } else 228762306a36Sopenharmony_ci dev_kfree_skb_any(hb); 228862306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx_drop); 228962306a36Sopenharmony_ci } else { 229062306a36Sopenharmony_ci /* Copy the small buffer to the huge buffer */ 229162306a36Sopenharmony_ci sb = (struct sk_buff *)iov->iov_base; 229262306a36Sopenharmony_ci skb_copy_from_linear_data(sb, hb->data, 229362306a36Sopenharmony_ci iov->iov_len); 229462306a36Sopenharmony_ci skb_put(hb, iov->iov_len); 229562306a36Sopenharmony_ci remaining = len - iov->iov_len; 229662306a36Sopenharmony_ci iov++; 229762306a36Sopenharmony_ci /* Free the small buffer */ 229862306a36Sopenharmony_ci push_rxbufs(card, sb); 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci /* Copy all large buffers to the huge buffer and free them */ 230162306a36Sopenharmony_ci for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) { 230262306a36Sopenharmony_ci lb = (struct sk_buff *)iov->iov_base; 230362306a36Sopenharmony_ci tocopy = 230462306a36Sopenharmony_ci min_t(int, remaining, iov->iov_len); 230562306a36Sopenharmony_ci skb_copy_from_linear_data(lb, 230662306a36Sopenharmony_ci skb_tail_pointer 230762306a36Sopenharmony_ci (hb), tocopy); 230862306a36Sopenharmony_ci skb_put(hb, tocopy); 230962306a36Sopenharmony_ci iov++; 231062306a36Sopenharmony_ci remaining -= tocopy; 231162306a36Sopenharmony_ci push_rxbufs(card, lb); 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci#ifdef EXTRA_DEBUG 231462306a36Sopenharmony_ci if (remaining != 0 || hb->len != len) 231562306a36Sopenharmony_ci printk 231662306a36Sopenharmony_ci ("nicstar%d: Huge buffer len mismatch.\n", 231762306a36Sopenharmony_ci card->index); 231862306a36Sopenharmony_ci#endif /* EXTRA_DEBUG */ 231962306a36Sopenharmony_ci ATM_SKB(hb)->vcc = vcc; 232062306a36Sopenharmony_ci __net_timestamp(hb); 232162306a36Sopenharmony_ci vcc->push(vcc, hb); 232262306a36Sopenharmony_ci atomic_inc(&vcc->stats->rx); 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci vc->rx_iov = NULL; 232762306a36Sopenharmony_ci recycle_iov_buf(card, iovb); 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_cistatic void recycle_rx_buf(ns_dev * card, struct sk_buff *skb) 233362306a36Sopenharmony_ci{ 233462306a36Sopenharmony_ci if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) { 233562306a36Sopenharmony_ci printk("nicstar%d: What kind of rx buffer is this?\n", 233662306a36Sopenharmony_ci card->index); 233762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 233862306a36Sopenharmony_ci } else 233962306a36Sopenharmony_ci push_rxbufs(card, skb); 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_cistatic void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci while (count-- > 0) 234562306a36Sopenharmony_ci recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base); 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_cistatic void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb) 234962306a36Sopenharmony_ci{ 235062306a36Sopenharmony_ci if (card->iovpool.count < card->iovnr.max) { 235162306a36Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 235262306a36Sopenharmony_ci card->iovpool.count++; 235362306a36Sopenharmony_ci } else 235462306a36Sopenharmony_ci dev_kfree_skb_any(iovb); 235562306a36Sopenharmony_ci} 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_cistatic void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci skb_unlink(sb, &card->sbpool.queue); 236062306a36Sopenharmony_ci if (card->sbfqc < card->sbnr.init) { 236162306a36Sopenharmony_ci struct sk_buff *new_sb; 236262306a36Sopenharmony_ci if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { 236362306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_sb) = BUF_SM; 236462306a36Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, new_sb); 236562306a36Sopenharmony_ci skb_reserve(new_sb, NS_AAL0_HEADER); 236662306a36Sopenharmony_ci push_rxbufs(card, new_sb); 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci if (card->sbfqc < card->sbnr.init) 237062306a36Sopenharmony_ci { 237162306a36Sopenharmony_ci struct sk_buff *new_sb; 237262306a36Sopenharmony_ci if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { 237362306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_sb) = BUF_SM; 237462306a36Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, new_sb); 237562306a36Sopenharmony_ci skb_reserve(new_sb, NS_AAL0_HEADER); 237662306a36Sopenharmony_ci push_rxbufs(card, new_sb); 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci } 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci skb_unlink(lb, &card->lbpool.queue); 238462306a36Sopenharmony_ci if (card->lbfqc < card->lbnr.init) { 238562306a36Sopenharmony_ci struct sk_buff *new_lb; 238662306a36Sopenharmony_ci if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { 238762306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_lb) = BUF_LG; 238862306a36Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, new_lb); 238962306a36Sopenharmony_ci skb_reserve(new_lb, NS_SMBUFSIZE); 239062306a36Sopenharmony_ci push_rxbufs(card, new_lb); 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci if (card->lbfqc < card->lbnr.init) 239462306a36Sopenharmony_ci { 239562306a36Sopenharmony_ci struct sk_buff *new_lb; 239662306a36Sopenharmony_ci if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { 239762306a36Sopenharmony_ci NS_PRV_BUFTYPE(new_lb) = BUF_LG; 239862306a36Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, new_lb); 239962306a36Sopenharmony_ci skb_reserve(new_lb, NS_SMBUFSIZE); 240062306a36Sopenharmony_ci push_rxbufs(card, new_lb); 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci} 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_cistatic int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page) 240662306a36Sopenharmony_ci{ 240762306a36Sopenharmony_ci u32 stat; 240862306a36Sopenharmony_ci ns_dev *card; 240962306a36Sopenharmony_ci int left; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci left = (int)*pos; 241262306a36Sopenharmony_ci card = (ns_dev *) dev->dev_data; 241362306a36Sopenharmony_ci stat = readl(card->membase + STAT); 241462306a36Sopenharmony_ci if (!left--) 241562306a36Sopenharmony_ci return sprintf(page, "Pool count min init max \n"); 241662306a36Sopenharmony_ci if (!left--) 241762306a36Sopenharmony_ci return sprintf(page, "Small %5d %5d %5d %5d \n", 241862306a36Sopenharmony_ci ns_stat_sfbqc_get(stat), card->sbnr.min, 241962306a36Sopenharmony_ci card->sbnr.init, card->sbnr.max); 242062306a36Sopenharmony_ci if (!left--) 242162306a36Sopenharmony_ci return sprintf(page, "Large %5d %5d %5d %5d \n", 242262306a36Sopenharmony_ci ns_stat_lfbqc_get(stat), card->lbnr.min, 242362306a36Sopenharmony_ci card->lbnr.init, card->lbnr.max); 242462306a36Sopenharmony_ci if (!left--) 242562306a36Sopenharmony_ci return sprintf(page, "Huge %5d %5d %5d %5d \n", 242662306a36Sopenharmony_ci card->hbpool.count, card->hbnr.min, 242762306a36Sopenharmony_ci card->hbnr.init, card->hbnr.max); 242862306a36Sopenharmony_ci if (!left--) 242962306a36Sopenharmony_ci return sprintf(page, "Iovec %5d %5d %5d %5d \n", 243062306a36Sopenharmony_ci card->iovpool.count, card->iovnr.min, 243162306a36Sopenharmony_ci card->iovnr.init, card->iovnr.max); 243262306a36Sopenharmony_ci if (!left--) { 243362306a36Sopenharmony_ci int retval; 243462306a36Sopenharmony_ci retval = 243562306a36Sopenharmony_ci sprintf(page, "Interrupt counter: %u \n", card->intcnt); 243662306a36Sopenharmony_ci card->intcnt = 0; 243762306a36Sopenharmony_ci return retval; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci#if 0 244062306a36Sopenharmony_ci /* Dump 25.6 Mbps PHY registers */ 244162306a36Sopenharmony_ci /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it 244262306a36Sopenharmony_ci here just in case it's needed for debugging. */ 244362306a36Sopenharmony_ci if (card->max_pcr == ATM_25_PCR && !left--) { 244462306a36Sopenharmony_ci u32 phy_regs[4]; 244562306a36Sopenharmony_ci u32 i; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 244862306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 244962306a36Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200 | i, 245062306a36Sopenharmony_ci card->membase + CMD); 245162306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 245262306a36Sopenharmony_ci phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; 245362306a36Sopenharmony_ci } 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", 245662306a36Sopenharmony_ci phy_regs[0], phy_regs[1], phy_regs[2], 245762306a36Sopenharmony_ci phy_regs[3]); 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci#endif /* 0 - Dump 25.6 Mbps PHY registers */ 246062306a36Sopenharmony_ci#if 0 246162306a36Sopenharmony_ci /* Dump TST */ 246262306a36Sopenharmony_ci if (left-- < NS_TST_NUM_ENTRIES) { 246362306a36Sopenharmony_ci if (card->tste2vc[left + 1] == NULL) 246462306a36Sopenharmony_ci return sprintf(page, "%5d - VBR/UBR \n", left + 1); 246562306a36Sopenharmony_ci else 246662306a36Sopenharmony_ci return sprintf(page, "%5d - %d %d \n", left + 1, 246762306a36Sopenharmony_ci card->tste2vc[left + 1]->tx_vcc->vpi, 246862306a36Sopenharmony_ci card->tste2vc[left + 1]->tx_vcc->vci); 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci#endif /* 0 */ 247162306a36Sopenharmony_ci return 0; 247262306a36Sopenharmony_ci} 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_cistatic int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg) 247562306a36Sopenharmony_ci{ 247662306a36Sopenharmony_ci ns_dev *card; 247762306a36Sopenharmony_ci pool_levels pl; 247862306a36Sopenharmony_ci long btype; 247962306a36Sopenharmony_ci unsigned long flags; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci card = dev->dev_data; 248262306a36Sopenharmony_ci switch (cmd) { 248362306a36Sopenharmony_ci case NS_GETPSTAT: 248462306a36Sopenharmony_ci if (get_user 248562306a36Sopenharmony_ci (pl.buftype, &((pool_levels __user *) arg)->buftype)) 248662306a36Sopenharmony_ci return -EFAULT; 248762306a36Sopenharmony_ci switch (pl.buftype) { 248862306a36Sopenharmony_ci case NS_BUFTYPE_SMALL: 248962306a36Sopenharmony_ci pl.count = 249062306a36Sopenharmony_ci ns_stat_sfbqc_get(readl(card->membase + STAT)); 249162306a36Sopenharmony_ci pl.level.min = card->sbnr.min; 249262306a36Sopenharmony_ci pl.level.init = card->sbnr.init; 249362306a36Sopenharmony_ci pl.level.max = card->sbnr.max; 249462306a36Sopenharmony_ci break; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci case NS_BUFTYPE_LARGE: 249762306a36Sopenharmony_ci pl.count = 249862306a36Sopenharmony_ci ns_stat_lfbqc_get(readl(card->membase + STAT)); 249962306a36Sopenharmony_ci pl.level.min = card->lbnr.min; 250062306a36Sopenharmony_ci pl.level.init = card->lbnr.init; 250162306a36Sopenharmony_ci pl.level.max = card->lbnr.max; 250262306a36Sopenharmony_ci break; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci case NS_BUFTYPE_HUGE: 250562306a36Sopenharmony_ci pl.count = card->hbpool.count; 250662306a36Sopenharmony_ci pl.level.min = card->hbnr.min; 250762306a36Sopenharmony_ci pl.level.init = card->hbnr.init; 250862306a36Sopenharmony_ci pl.level.max = card->hbnr.max; 250962306a36Sopenharmony_ci break; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci case NS_BUFTYPE_IOVEC: 251262306a36Sopenharmony_ci pl.count = card->iovpool.count; 251362306a36Sopenharmony_ci pl.level.min = card->iovnr.min; 251462306a36Sopenharmony_ci pl.level.init = card->iovnr.init; 251562306a36Sopenharmony_ci pl.level.max = card->iovnr.max; 251662306a36Sopenharmony_ci break; 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci default: 251962306a36Sopenharmony_ci return -ENOIOCTLCMD; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl))) 252362306a36Sopenharmony_ci return (sizeof(pl)); 252462306a36Sopenharmony_ci else 252562306a36Sopenharmony_ci return -EFAULT; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci case NS_SETBUFLEV: 252862306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 252962306a36Sopenharmony_ci return -EPERM; 253062306a36Sopenharmony_ci if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl))) 253162306a36Sopenharmony_ci return -EFAULT; 253262306a36Sopenharmony_ci if (pl.level.min >= pl.level.init 253362306a36Sopenharmony_ci || pl.level.init >= pl.level.max) 253462306a36Sopenharmony_ci return -EINVAL; 253562306a36Sopenharmony_ci if (pl.level.min == 0) 253662306a36Sopenharmony_ci return -EINVAL; 253762306a36Sopenharmony_ci switch (pl.buftype) { 253862306a36Sopenharmony_ci case NS_BUFTYPE_SMALL: 253962306a36Sopenharmony_ci if (pl.level.max > TOP_SB) 254062306a36Sopenharmony_ci return -EINVAL; 254162306a36Sopenharmony_ci card->sbnr.min = pl.level.min; 254262306a36Sopenharmony_ci card->sbnr.init = pl.level.init; 254362306a36Sopenharmony_ci card->sbnr.max = pl.level.max; 254462306a36Sopenharmony_ci break; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci case NS_BUFTYPE_LARGE: 254762306a36Sopenharmony_ci if (pl.level.max > TOP_LB) 254862306a36Sopenharmony_ci return -EINVAL; 254962306a36Sopenharmony_ci card->lbnr.min = pl.level.min; 255062306a36Sopenharmony_ci card->lbnr.init = pl.level.init; 255162306a36Sopenharmony_ci card->lbnr.max = pl.level.max; 255262306a36Sopenharmony_ci break; 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci case NS_BUFTYPE_HUGE: 255562306a36Sopenharmony_ci if (pl.level.max > TOP_HB) 255662306a36Sopenharmony_ci return -EINVAL; 255762306a36Sopenharmony_ci card->hbnr.min = pl.level.min; 255862306a36Sopenharmony_ci card->hbnr.init = pl.level.init; 255962306a36Sopenharmony_ci card->hbnr.max = pl.level.max; 256062306a36Sopenharmony_ci break; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci case NS_BUFTYPE_IOVEC: 256362306a36Sopenharmony_ci if (pl.level.max > TOP_IOVB) 256462306a36Sopenharmony_ci return -EINVAL; 256562306a36Sopenharmony_ci card->iovnr.min = pl.level.min; 256662306a36Sopenharmony_ci card->iovnr.init = pl.level.init; 256762306a36Sopenharmony_ci card->iovnr.max = pl.level.max; 256862306a36Sopenharmony_ci break; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci default: 257162306a36Sopenharmony_ci return -EINVAL; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci return 0; 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci case NS_ADJBUFLEV: 257762306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 257862306a36Sopenharmony_ci return -EPERM; 257962306a36Sopenharmony_ci btype = (long)arg; /* a long is the same size as a pointer or bigger */ 258062306a36Sopenharmony_ci switch (btype) { 258162306a36Sopenharmony_ci case NS_BUFTYPE_SMALL: 258262306a36Sopenharmony_ci while (card->sbfqc < card->sbnr.init) { 258362306a36Sopenharmony_ci struct sk_buff *sb; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 258662306a36Sopenharmony_ci if (sb == NULL) 258762306a36Sopenharmony_ci return -ENOMEM; 258862306a36Sopenharmony_ci NS_PRV_BUFTYPE(sb) = BUF_SM; 258962306a36Sopenharmony_ci skb_queue_tail(&card->sbpool.queue, sb); 259062306a36Sopenharmony_ci skb_reserve(sb, NS_AAL0_HEADER); 259162306a36Sopenharmony_ci push_rxbufs(card, sb); 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_ci break; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci case NS_BUFTYPE_LARGE: 259662306a36Sopenharmony_ci while (card->lbfqc < card->lbnr.init) { 259762306a36Sopenharmony_ci struct sk_buff *lb; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 260062306a36Sopenharmony_ci if (lb == NULL) 260162306a36Sopenharmony_ci return -ENOMEM; 260262306a36Sopenharmony_ci NS_PRV_BUFTYPE(lb) = BUF_LG; 260362306a36Sopenharmony_ci skb_queue_tail(&card->lbpool.queue, lb); 260462306a36Sopenharmony_ci skb_reserve(lb, NS_SMBUFSIZE); 260562306a36Sopenharmony_ci push_rxbufs(card, lb); 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci break; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci case NS_BUFTYPE_HUGE: 261062306a36Sopenharmony_ci while (card->hbpool.count > card->hbnr.init) { 261162306a36Sopenharmony_ci struct sk_buff *hb; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 261462306a36Sopenharmony_ci hb = skb_dequeue(&card->hbpool.queue); 261562306a36Sopenharmony_ci card->hbpool.count--; 261662306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 261762306a36Sopenharmony_ci if (hb == NULL) 261862306a36Sopenharmony_ci printk 261962306a36Sopenharmony_ci ("nicstar%d: huge buffer count inconsistent.\n", 262062306a36Sopenharmony_ci card->index); 262162306a36Sopenharmony_ci else 262262306a36Sopenharmony_ci dev_kfree_skb_any(hb); 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci } 262562306a36Sopenharmony_ci while (card->hbpool.count < card->hbnr.init) { 262662306a36Sopenharmony_ci struct sk_buff *hb; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 262962306a36Sopenharmony_ci if (hb == NULL) 263062306a36Sopenharmony_ci return -ENOMEM; 263162306a36Sopenharmony_ci NS_PRV_BUFTYPE(hb) = BUF_NONE; 263262306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 263362306a36Sopenharmony_ci skb_queue_tail(&card->hbpool.queue, hb); 263462306a36Sopenharmony_ci card->hbpool.count++; 263562306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci break; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci case NS_BUFTYPE_IOVEC: 264062306a36Sopenharmony_ci while (card->iovpool.count > card->iovnr.init) { 264162306a36Sopenharmony_ci struct sk_buff *iovb; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 264462306a36Sopenharmony_ci iovb = skb_dequeue(&card->iovpool.queue); 264562306a36Sopenharmony_ci card->iovpool.count--; 264662306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 264762306a36Sopenharmony_ci if (iovb == NULL) 264862306a36Sopenharmony_ci printk 264962306a36Sopenharmony_ci ("nicstar%d: iovec buffer count inconsistent.\n", 265062306a36Sopenharmony_ci card->index); 265162306a36Sopenharmony_ci else 265262306a36Sopenharmony_ci dev_kfree_skb_any(iovb); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci } 265562306a36Sopenharmony_ci while (card->iovpool.count < card->iovnr.init) { 265662306a36Sopenharmony_ci struct sk_buff *iovb; 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 265962306a36Sopenharmony_ci if (iovb == NULL) 266062306a36Sopenharmony_ci return -ENOMEM; 266162306a36Sopenharmony_ci NS_PRV_BUFTYPE(iovb) = BUF_NONE; 266262306a36Sopenharmony_ci spin_lock_irqsave(&card->int_lock, flags); 266362306a36Sopenharmony_ci skb_queue_tail(&card->iovpool.queue, iovb); 266462306a36Sopenharmony_ci card->iovpool.count++; 266562306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci break; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci default: 267062306a36Sopenharmony_ci return -EINVAL; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci return 0; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci default: 267662306a36Sopenharmony_ci if (dev->phy && dev->phy->ioctl) { 267762306a36Sopenharmony_ci return dev->phy->ioctl(dev, cmd, arg); 267862306a36Sopenharmony_ci } else { 267962306a36Sopenharmony_ci printk("nicstar%d: %s == NULL \n", card->index, 268062306a36Sopenharmony_ci dev->phy ? "dev->phy->ioctl" : "dev->phy"); 268162306a36Sopenharmony_ci return -ENOIOCTLCMD; 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci } 268462306a36Sopenharmony_ci} 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci#ifdef EXTRA_DEBUG 268762306a36Sopenharmony_cistatic void which_list(ns_dev * card, struct sk_buff *skb) 268862306a36Sopenharmony_ci{ 268962306a36Sopenharmony_ci printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb)); 269062306a36Sopenharmony_ci} 269162306a36Sopenharmony_ci#endif /* EXTRA_DEBUG */ 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_cistatic void ns_poll(struct timer_list *unused) 269462306a36Sopenharmony_ci{ 269562306a36Sopenharmony_ci int i; 269662306a36Sopenharmony_ci ns_dev *card; 269762306a36Sopenharmony_ci unsigned long flags; 269862306a36Sopenharmony_ci u32 stat_r, stat_w; 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci PRINTK("nicstar: Entering ns_poll().\n"); 270162306a36Sopenharmony_ci for (i = 0; i < num_cards; i++) { 270262306a36Sopenharmony_ci card = cards[i]; 270362306a36Sopenharmony_ci if (!spin_trylock_irqsave(&card->int_lock, flags)) { 270462306a36Sopenharmony_ci /* Probably it isn't worth spinning */ 270562306a36Sopenharmony_ci continue; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci stat_w = 0; 270962306a36Sopenharmony_ci stat_r = readl(card->membase + STAT); 271062306a36Sopenharmony_ci if (stat_r & NS_STAT_TSIF) 271162306a36Sopenharmony_ci stat_w |= NS_STAT_TSIF; 271262306a36Sopenharmony_ci if (stat_r & NS_STAT_EOPDU) 271362306a36Sopenharmony_ci stat_w |= NS_STAT_EOPDU; 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci process_tsq(card); 271662306a36Sopenharmony_ci process_rsq(card); 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci writel(stat_w, card->membase + STAT); 271962306a36Sopenharmony_ci spin_unlock_irqrestore(&card->int_lock, flags); 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); 272262306a36Sopenharmony_ci PRINTK("nicstar: Leaving ns_poll().\n"); 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_cistatic void ns_phy_put(struct atm_dev *dev, unsigned char value, 272662306a36Sopenharmony_ci unsigned long addr) 272762306a36Sopenharmony_ci{ 272862306a36Sopenharmony_ci ns_dev *card; 272962306a36Sopenharmony_ci unsigned long flags; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci card = dev->dev_data; 273262306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 273362306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 273462306a36Sopenharmony_ci writel((u32) value, card->membase + DR0); 273562306a36Sopenharmony_ci writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF), 273662306a36Sopenharmony_ci card->membase + CMD); 273762306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 273862306a36Sopenharmony_ci} 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_cistatic unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr) 274162306a36Sopenharmony_ci{ 274262306a36Sopenharmony_ci ns_dev *card; 274362306a36Sopenharmony_ci unsigned long flags; 274462306a36Sopenharmony_ci u32 data; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci card = dev->dev_data; 274762306a36Sopenharmony_ci spin_lock_irqsave(&card->res_lock, flags); 274862306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 274962306a36Sopenharmony_ci writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF), 275062306a36Sopenharmony_ci card->membase + CMD); 275162306a36Sopenharmony_ci while (CMD_BUSY(card)) ; 275262306a36Sopenharmony_ci data = readl(card->membase + DR0) & 0x000000FF; 275362306a36Sopenharmony_ci spin_unlock_irqrestore(&card->res_lock, flags); 275462306a36Sopenharmony_ci return (unsigned char)data; 275562306a36Sopenharmony_ci} 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_cimodule_init(nicstar_init); 275862306a36Sopenharmony_cimodule_exit(nicstar_cleanup); 2759