11da177e4SLinus Torvalds /****************************************************************************** 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * nicstar.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. 81da177e4SLinus Torvalds * It was taken from the frle-0.22 device driver. 91da177e4SLinus Torvalds * As the file doesn't have a copyright notice, in the file 101da177e4SLinus Torvalds * nicstarmac.copyright I put the copyright notice from the 111da177e4SLinus Torvalds * frle-0.22 device driver. 121da177e4SLinus Torvalds * Some code is based on the nicstar driver by M. Welsh. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Author: Rui Prior (rprior@inescn.pt) 151da177e4SLinus Torvalds * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * (C) INESC 1999 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds ******************************************************************************/ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /**** IMPORTANT INFORMATION *************************************************** 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * There are currently three types of spinlocks: 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * 1 - Per card interrupt spinlock (to protect structures and such) 291da177e4SLinus Torvalds * 2 - Per SCQ scq spinlock 301da177e4SLinus Torvalds * 3 - Per card resource spinlock (to access registers, etc.) 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds * These must NEVER be grabbed in reverse order. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds ******************************************************************************/ 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds /* Header files ***************************************************************/ 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds #include <linux/module.h> 391da177e4SLinus Torvalds #include <linux/kernel.h> 401da177e4SLinus Torvalds #include <linux/skbuff.h> 411da177e4SLinus Torvalds #include <linux/atmdev.h> 421da177e4SLinus Torvalds #include <linux/atm.h> 431da177e4SLinus Torvalds #include <linux/pci.h> 441da177e4SLinus Torvalds #include <linux/types.h> 451da177e4SLinus Torvalds #include <linux/string.h> 461da177e4SLinus Torvalds #include <linux/delay.h> 471da177e4SLinus Torvalds #include <linux/init.h> 481da177e4SLinus Torvalds #include <linux/sched.h> 491da177e4SLinus Torvalds #include <linux/timer.h> 501da177e4SLinus Torvalds #include <linux/interrupt.h> 511da177e4SLinus Torvalds #include <linux/bitops.h> 521da177e4SLinus Torvalds #include <asm/io.h> 531da177e4SLinus Torvalds #include <asm/uaccess.h> 541da177e4SLinus Torvalds #include <asm/atomic.h> 551da177e4SLinus Torvalds #include "nicstar.h" 561da177e4SLinus Torvalds #ifdef CONFIG_ATM_NICSTAR_USE_SUNI 571da177e4SLinus Torvalds #include "suni.h" 581da177e4SLinus Torvalds #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 591da177e4SLinus Torvalds #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 601da177e4SLinus Torvalds #include "idt77105.h" 611da177e4SLinus Torvalds #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds #if BITS_PER_LONG != 32 641da177e4SLinus Torvalds # error FIXME: this driver requires a 32-bit platform 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* Additional code ************************************************************/ 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds #include "nicstarmac.c" 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* Configurable parameters ****************************************************/ 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #undef PHY_LOOPBACK 751da177e4SLinus Torvalds #undef TX_DEBUG 761da177e4SLinus Torvalds #undef RX_DEBUG 771da177e4SLinus Torvalds #undef GENERAL_DEBUG 781da177e4SLinus Torvalds #undef EXTRA_DEBUG 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds #undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know 811da177e4SLinus Torvalds you're going to use only raw ATM */ 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* Do not touch these *********************************************************/ 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds #ifdef TX_DEBUG 871da177e4SLinus Torvalds #define TXPRINTK(args...) printk(args) 881da177e4SLinus Torvalds #else 891da177e4SLinus Torvalds #define TXPRINTK(args...) 901da177e4SLinus Torvalds #endif /* TX_DEBUG */ 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds #ifdef RX_DEBUG 931da177e4SLinus Torvalds #define RXPRINTK(args...) printk(args) 941da177e4SLinus Torvalds #else 951da177e4SLinus Torvalds #define RXPRINTK(args...) 961da177e4SLinus Torvalds #endif /* RX_DEBUG */ 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds #ifdef GENERAL_DEBUG 991da177e4SLinus Torvalds #define PRINTK(args...) printk(args) 1001da177e4SLinus Torvalds #else 1011da177e4SLinus Torvalds #define PRINTK(args...) 1021da177e4SLinus Torvalds #endif /* GENERAL_DEBUG */ 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds #ifdef EXTRA_DEBUG 1051da177e4SLinus Torvalds #define XPRINTK(args...) printk(args) 1061da177e4SLinus Torvalds #else 1071da177e4SLinus Torvalds #define XPRINTK(args...) 1081da177e4SLinus Torvalds #endif /* EXTRA_DEBUG */ 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* Macros *********************************************************************/ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds #define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds #define NS_DELAY mdelay(1) 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds #define ALIGN_BUS_ADDR(addr, alignment) \ 1181da177e4SLinus Torvalds ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1)) 1191da177e4SLinus Torvalds #define ALIGN_ADDRESS(addr, alignment) \ 1201da177e4SLinus Torvalds bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment)) 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds #undef CEIL 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds #ifndef ATM_SKB 1251da177e4SLinus Torvalds #define ATM_SKB(s) (&(s)->atm) 1261da177e4SLinus Torvalds #endif 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* Spinlock debugging stuff */ 1291da177e4SLinus Torvalds #ifdef NS_DEBUG_SPINLOCKS /* See nicstar.h */ 1301da177e4SLinus Torvalds #define ns_grab_int_lock(card,flags) \ 1311da177e4SLinus Torvalds do { \ 1321da177e4SLinus Torvalds unsigned long nsdsf, nsdsf2; \ 1331da177e4SLinus Torvalds local_irq_save(flags); \ 1341da177e4SLinus Torvalds save_flags(nsdsf); cli();\ 1351da177e4SLinus Torvalds if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \ 1361da177e4SLinus Torvalds (flags)&(1<<9)?"en":"dis"); \ 1371da177e4SLinus Torvalds if (spin_is_locked(&(card)->int_lock) && \ 1381da177e4SLinus Torvalds (card)->cpu_int == smp_processor_id()) { \ 1391da177e4SLinus Torvalds printk("nicstar.c: line %d (cpu %d) int_lock already locked at line %d (cpu %d)\n", \ 1401da177e4SLinus Torvalds __LINE__, smp_processor_id(), (card)->has_int_lock, \ 1411da177e4SLinus Torvalds (card)->cpu_int); \ 1421da177e4SLinus Torvalds printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \ 1431da177e4SLinus Torvalds } \ 1441da177e4SLinus Torvalds if (spin_is_locked(&(card)->res_lock) && \ 1451da177e4SLinus Torvalds (card)->cpu_res == smp_processor_id()) { \ 1461da177e4SLinus Torvalds printk("nicstar.c: line %d (cpu %d) res_lock locked at line %d (cpu %d)(trying int)\n", \ 1471da177e4SLinus Torvalds __LINE__, smp_processor_id(), (card)->has_res_lock, \ 1481da177e4SLinus Torvalds (card)->cpu_res); \ 1491da177e4SLinus Torvalds printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \ 1501da177e4SLinus Torvalds } \ 1511da177e4SLinus Torvalds spin_lock_irq(&(card)->int_lock); \ 1521da177e4SLinus Torvalds (card)->has_int_lock = __LINE__; \ 1531da177e4SLinus Torvalds (card)->cpu_int = smp_processor_id(); \ 1541da177e4SLinus Torvalds restore_flags(nsdsf); } while (0) 1551da177e4SLinus Torvalds #define ns_grab_res_lock(card,flags) \ 1561da177e4SLinus Torvalds do { \ 1571da177e4SLinus Torvalds unsigned long nsdsf, nsdsf2; \ 1581da177e4SLinus Torvalds local_irq_save(flags); \ 1591da177e4SLinus Torvalds save_flags(nsdsf); cli();\ 1601da177e4SLinus Torvalds if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \ 1611da177e4SLinus Torvalds (flags)&(1<<9)?"en":"dis"); \ 1621da177e4SLinus Torvalds if (spin_is_locked(&(card)->res_lock) && \ 1631da177e4SLinus Torvalds (card)->cpu_res == smp_processor_id()) { \ 1641da177e4SLinus Torvalds printk("nicstar.c: line %d (cpu %d) res_lock already locked at line %d (cpu %d)\n", \ 1651da177e4SLinus Torvalds __LINE__, smp_processor_id(), (card)->has_res_lock, \ 1661da177e4SLinus Torvalds (card)->cpu_res); \ 1671da177e4SLinus Torvalds printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \ 1681da177e4SLinus Torvalds } \ 1691da177e4SLinus Torvalds spin_lock_irq(&(card)->res_lock); \ 1701da177e4SLinus Torvalds (card)->has_res_lock = __LINE__; \ 1711da177e4SLinus Torvalds (card)->cpu_res = smp_processor_id(); \ 1721da177e4SLinus Torvalds restore_flags(nsdsf); } while (0) 1731da177e4SLinus Torvalds #define ns_grab_scq_lock(card,scq,flags) \ 1741da177e4SLinus Torvalds do { \ 1751da177e4SLinus Torvalds unsigned long nsdsf, nsdsf2; \ 1761da177e4SLinus Torvalds local_irq_save(flags); \ 1771da177e4SLinus Torvalds save_flags(nsdsf); cli();\ 1781da177e4SLinus Torvalds if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \ 1791da177e4SLinus Torvalds (flags)&(1<<9)?"en":"dis"); \ 1801da177e4SLinus Torvalds if (spin_is_locked(&(scq)->lock) && \ 1811da177e4SLinus Torvalds (scq)->cpu_lock == smp_processor_id()) { \ 1821da177e4SLinus Torvalds printk("nicstar.c: line %d (cpu %d) this scq_lock already locked at line %d (cpu %d)\n", \ 1831da177e4SLinus Torvalds __LINE__, smp_processor_id(), (scq)->has_lock, \ 1841da177e4SLinus Torvalds (scq)->cpu_lock); \ 1851da177e4SLinus Torvalds printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \ 1861da177e4SLinus Torvalds } \ 1871da177e4SLinus Torvalds if (spin_is_locked(&(card)->res_lock) && \ 1881da177e4SLinus Torvalds (card)->cpu_res == smp_processor_id()) { \ 1891da177e4SLinus Torvalds printk("nicstar.c: line %d (cpu %d) res_lock locked at line %d (cpu %d)(trying scq)\n", \ 1901da177e4SLinus Torvalds __LINE__, smp_processor_id(), (card)->has_res_lock, \ 1911da177e4SLinus Torvalds (card)->cpu_res); \ 1921da177e4SLinus Torvalds printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \ 1931da177e4SLinus Torvalds } \ 1941da177e4SLinus Torvalds spin_lock_irq(&(scq)->lock); \ 1951da177e4SLinus Torvalds (scq)->has_lock = __LINE__; \ 1961da177e4SLinus Torvalds (scq)->cpu_lock = smp_processor_id(); \ 1971da177e4SLinus Torvalds restore_flags(nsdsf); } while (0) 1981da177e4SLinus Torvalds #else /* !NS_DEBUG_SPINLOCKS */ 1991da177e4SLinus Torvalds #define ns_grab_int_lock(card,flags) \ 2001da177e4SLinus Torvalds spin_lock_irqsave(&(card)->int_lock,(flags)) 2011da177e4SLinus Torvalds #define ns_grab_res_lock(card,flags) \ 2021da177e4SLinus Torvalds spin_lock_irqsave(&(card)->res_lock,(flags)) 2031da177e4SLinus Torvalds #define ns_grab_scq_lock(card,scq,flags) \ 2041da177e4SLinus Torvalds spin_lock_irqsave(&(scq)->lock,flags) 2051da177e4SLinus Torvalds #endif /* NS_DEBUG_SPINLOCKS */ 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Function declarations ******************************************************/ 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds static u32 ns_read_sram(ns_dev *card, u32 sram_address); 2111da177e4SLinus Torvalds static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count); 2121da177e4SLinus Torvalds static int __devinit ns_init_card(int i, struct pci_dev *pcidev); 2131da177e4SLinus Torvalds static void __devinit ns_init_card_error(ns_dev *card, int error); 2141da177e4SLinus Torvalds static scq_info *get_scq(int size, u32 scd); 2151da177e4SLinus Torvalds static void free_scq(scq_info *scq, struct atm_vcc *vcc); 2168728b834SDavid S. Miller static void push_rxbufs(ns_dev *, struct sk_buff *); 2177d12e780SDavid Howells static irqreturn_t ns_irq_handler(int irq, void *dev_id); 2181da177e4SLinus Torvalds static int ns_open(struct atm_vcc *vcc); 2191da177e4SLinus Torvalds static void ns_close(struct atm_vcc *vcc); 2201da177e4SLinus Torvalds static void fill_tst(ns_dev *card, int n, vc_map *vc); 2211da177e4SLinus Torvalds static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); 2221da177e4SLinus Torvalds static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, 2231da177e4SLinus Torvalds struct sk_buff *skb); 2241da177e4SLinus Torvalds static void process_tsq(ns_dev *card); 2251da177e4SLinus Torvalds static void drain_scq(ns_dev *card, scq_info *scq, int pos); 2261da177e4SLinus Torvalds static void process_rsq(ns_dev *card); 2271da177e4SLinus Torvalds static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe); 2281da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 2291da177e4SLinus Torvalds static void ns_sb_destructor(struct sk_buff *sb); 2301da177e4SLinus Torvalds static void ns_lb_destructor(struct sk_buff *lb); 2311da177e4SLinus Torvalds static void ns_hb_destructor(struct sk_buff *hb); 2321da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 2331da177e4SLinus Torvalds static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb); 2341da177e4SLinus Torvalds static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count); 2351da177e4SLinus Torvalds static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb); 2361da177e4SLinus Torvalds static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb); 2371da177e4SLinus Torvalds static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb); 2381da177e4SLinus Torvalds static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page); 2391da177e4SLinus Torvalds static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); 2401da177e4SLinus Torvalds static void which_list(ns_dev *card, struct sk_buff *skb); 2411da177e4SLinus Torvalds static void ns_poll(unsigned long arg); 2421da177e4SLinus Torvalds static int ns_parse_mac(char *mac, unsigned char *esi); 2431da177e4SLinus Torvalds static short ns_h2i(char c); 2441da177e4SLinus Torvalds static void ns_phy_put(struct atm_dev *dev, unsigned char value, 2451da177e4SLinus Torvalds unsigned long addr); 2461da177e4SLinus Torvalds static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* Global variables ***********************************************************/ 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds static struct ns_dev *cards[NS_MAX_CARDS]; 2531da177e4SLinus Torvalds static unsigned num_cards; 2541da177e4SLinus Torvalds static struct atmdev_ops atm_ops = 2551da177e4SLinus Torvalds { 2561da177e4SLinus Torvalds .open = ns_open, 2571da177e4SLinus Torvalds .close = ns_close, 2581da177e4SLinus Torvalds .ioctl = ns_ioctl, 2591da177e4SLinus Torvalds .send = ns_send, 2601da177e4SLinus Torvalds .phy_put = ns_phy_put, 2611da177e4SLinus Torvalds .phy_get = ns_phy_get, 2621da177e4SLinus Torvalds .proc_read = ns_proc_read, 2631da177e4SLinus Torvalds .owner = THIS_MODULE, 2641da177e4SLinus Torvalds }; 2651da177e4SLinus Torvalds static struct timer_list ns_timer; 2661da177e4SLinus Torvalds static char *mac[NS_MAX_CARDS]; 2671da177e4SLinus Torvalds module_param_array(mac, charp, NULL, 0); 2681da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds /* Functions*******************************************************************/ 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static int __devinit nicstar_init_one(struct pci_dev *pcidev, 2741da177e4SLinus Torvalds const struct pci_device_id *ent) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds static int index = -1; 2771da177e4SLinus Torvalds unsigned int error; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds index++; 2801da177e4SLinus Torvalds cards[index] = NULL; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds error = ns_init_card(index, pcidev); 2831da177e4SLinus Torvalds if (error) { 2841da177e4SLinus Torvalds cards[index--] = NULL; /* don't increment index */ 2851da177e4SLinus Torvalds goto err_out; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds return 0; 2891da177e4SLinus Torvalds err_out: 2901da177e4SLinus Torvalds return -ENODEV; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds static void __devexit nicstar_remove_one(struct pci_dev *pcidev) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds int i, j; 2981da177e4SLinus Torvalds ns_dev *card = pci_get_drvdata(pcidev); 2991da177e4SLinus Torvalds struct sk_buff *hb; 3001da177e4SLinus Torvalds struct sk_buff *iovb; 3011da177e4SLinus Torvalds struct sk_buff *lb; 3021da177e4SLinus Torvalds struct sk_buff *sb; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds i = card->index; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (cards[i] == NULL) 3071da177e4SLinus Torvalds return; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds if (card->atmdev->phy && card->atmdev->phy->stop) 3101da177e4SLinus Torvalds card->atmdev->phy->stop(card->atmdev); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds /* Stop everything */ 3131da177e4SLinus Torvalds writel(0x00000000, card->membase + CFG); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* De-register device */ 3161da177e4SLinus Torvalds atm_dev_deregister(card->atmdev); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* Disable PCI device */ 3191da177e4SLinus Torvalds pci_disable_device(pcidev); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* Free up resources */ 3221da177e4SLinus Torvalds j = 0; 3231da177e4SLinus Torvalds PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); 3241da177e4SLinus Torvalds while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) 3251da177e4SLinus Torvalds { 3261da177e4SLinus Torvalds dev_kfree_skb_any(hb); 3271da177e4SLinus Torvalds j++; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); 3301da177e4SLinus Torvalds j = 0; 3311da177e4SLinus Torvalds PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count); 3321da177e4SLinus Torvalds while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) 3331da177e4SLinus Torvalds { 3341da177e4SLinus Torvalds dev_kfree_skb_any(iovb); 3351da177e4SLinus Torvalds j++; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); 3381da177e4SLinus Torvalds while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 3391da177e4SLinus Torvalds dev_kfree_skb_any(lb); 3401da177e4SLinus Torvalds while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 3411da177e4SLinus Torvalds dev_kfree_skb_any(sb); 3421da177e4SLinus Torvalds free_scq(card->scq0, NULL); 3431da177e4SLinus Torvalds for (j = 0; j < NS_FRSCD_NUM; j++) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds if (card->scd2vc[j] != NULL) 3461da177e4SLinus Torvalds free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds kfree(card->rsq.org); 3491da177e4SLinus Torvalds kfree(card->tsq.org); 3501da177e4SLinus Torvalds free_irq(card->pcidev->irq, card); 3511da177e4SLinus Torvalds iounmap(card->membase); 3521da177e4SLinus Torvalds kfree(card); 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds static struct pci_device_id nicstar_pci_tbl[] __devinitdata = 3581da177e4SLinus Torvalds { 3591da177e4SLinus Torvalds {PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201, 3601da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 3611da177e4SLinus Torvalds {0,} /* terminate list */ 3621da177e4SLinus Torvalds }; 3631da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl); 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds static struct pci_driver nicstar_driver = { 3681da177e4SLinus Torvalds .name = "nicstar", 3691da177e4SLinus Torvalds .id_table = nicstar_pci_tbl, 3701da177e4SLinus Torvalds .probe = nicstar_init_one, 3711da177e4SLinus Torvalds .remove = __devexit_p(nicstar_remove_one), 3721da177e4SLinus Torvalds }; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds static int __init nicstar_init(void) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds unsigned error = 0; /* Initialized to remove compile warning */ 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds XPRINTK("nicstar: nicstar_init() called.\n"); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds error = pci_register_driver(&nicstar_driver); 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds TXPRINTK("nicstar: TX debug enabled.\n"); 3851da177e4SLinus Torvalds RXPRINTK("nicstar: RX debug enabled.\n"); 3861da177e4SLinus Torvalds PRINTK("nicstar: General debug enabled.\n"); 3871da177e4SLinus Torvalds #ifdef PHY_LOOPBACK 3881da177e4SLinus Torvalds printk("nicstar: using PHY loopback.\n"); 3891da177e4SLinus Torvalds #endif /* PHY_LOOPBACK */ 3901da177e4SLinus Torvalds XPRINTK("nicstar: nicstar_init() returned.\n"); 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds if (!error) { 3931da177e4SLinus Torvalds init_timer(&ns_timer); 3941da177e4SLinus Torvalds ns_timer.expires = jiffies + NS_POLL_PERIOD; 3951da177e4SLinus Torvalds ns_timer.data = 0UL; 3961da177e4SLinus Torvalds ns_timer.function = ns_poll; 3971da177e4SLinus Torvalds add_timer(&ns_timer); 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds return error; 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds static void __exit nicstar_cleanup(void) 4061da177e4SLinus Torvalds { 4071da177e4SLinus Torvalds XPRINTK("nicstar: nicstar_cleanup() called.\n"); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds del_timer(&ns_timer); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds pci_unregister_driver(&nicstar_driver); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds XPRINTK("nicstar: nicstar_cleanup() returned.\n"); 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds static u32 ns_read_sram(ns_dev *card, u32 sram_address) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds unsigned long flags; 4211da177e4SLinus Torvalds u32 data; 4221da177e4SLinus Torvalds sram_address <<= 2; 4231da177e4SLinus Torvalds sram_address &= 0x0007FFFC; /* address must be dword aligned */ 4241da177e4SLinus Torvalds sram_address |= 0x50000000; /* SRAM read command */ 4251da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 4261da177e4SLinus Torvalds while (CMD_BUSY(card)); 4271da177e4SLinus Torvalds writel(sram_address, card->membase + CMD); 4281da177e4SLinus Torvalds while (CMD_BUSY(card)); 4291da177e4SLinus Torvalds data = readl(card->membase + DR0); 4301da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 4311da177e4SLinus Torvalds return data; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds unsigned long flags; 4391da177e4SLinus Torvalds int i, c; 4401da177e4SLinus Torvalds count--; /* count range now is 0..3 instead of 1..4 */ 4411da177e4SLinus Torvalds c = count; 4421da177e4SLinus Torvalds c <<= 2; /* to use increments of 4 */ 4431da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 4441da177e4SLinus Torvalds while (CMD_BUSY(card)); 4451da177e4SLinus Torvalds for (i = 0; i <= c; i += 4) 4461da177e4SLinus Torvalds writel(*(value++), card->membase + i); 4471da177e4SLinus Torvalds /* Note: DR# registers are the first 4 dwords in nicstar's memspace, 4481da177e4SLinus Torvalds so card->membase + DR0 == card->membase */ 4491da177e4SLinus Torvalds sram_address <<= 2; 4501da177e4SLinus Torvalds sram_address &= 0x0007FFFC; 4511da177e4SLinus Torvalds sram_address |= (0x40000000 | count); 4521da177e4SLinus Torvalds writel(sram_address, card->membase + CMD); 4531da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds static int __devinit ns_init_card(int i, struct pci_dev *pcidev) 4581da177e4SLinus Torvalds { 4591da177e4SLinus Torvalds int j; 4601da177e4SLinus Torvalds struct ns_dev *card = NULL; 4611da177e4SLinus Torvalds unsigned char pci_latency; 4621da177e4SLinus Torvalds unsigned error; 4631da177e4SLinus Torvalds u32 data; 4641da177e4SLinus Torvalds u32 u32d[4]; 4651da177e4SLinus Torvalds u32 ns_cfg_rctsize; 4661da177e4SLinus Torvalds int bcount; 4671da177e4SLinus Torvalds unsigned long membase; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds error = 0; 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds if (pci_enable_device(pcidev)) 4721da177e4SLinus Torvalds { 4731da177e4SLinus Torvalds printk("nicstar%d: can't enable PCI device\n", i); 4741da177e4SLinus Torvalds error = 2; 4751da177e4SLinus Torvalds ns_init_card_error(card, error); 4761da177e4SLinus Torvalds return error; 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) 4801da177e4SLinus Torvalds { 4811da177e4SLinus Torvalds printk("nicstar%d: can't allocate memory for device structure.\n", i); 4821da177e4SLinus Torvalds error = 2; 4831da177e4SLinus Torvalds ns_init_card_error(card, error); 4841da177e4SLinus Torvalds return error; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds cards[i] = card; 4871da177e4SLinus Torvalds spin_lock_init(&card->int_lock); 4881da177e4SLinus Torvalds spin_lock_init(&card->res_lock); 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds pci_set_drvdata(pcidev, card); 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds card->index = i; 4931da177e4SLinus Torvalds card->atmdev = NULL; 4941da177e4SLinus Torvalds card->pcidev = pcidev; 4951da177e4SLinus Torvalds membase = pci_resource_start(pcidev, 1); 4961da177e4SLinus Torvalds card->membase = ioremap(membase, NS_IOREMAP_SIZE); 4971da177e4SLinus Torvalds if (card->membase == 0) 4981da177e4SLinus Torvalds { 4991da177e4SLinus Torvalds printk("nicstar%d: can't ioremap() membase.\n",i); 5001da177e4SLinus Torvalds error = 3; 5011da177e4SLinus Torvalds ns_init_card_error(card, error); 5021da177e4SLinus Torvalds return error; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase); 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds pci_set_master(pcidev); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds printk("nicstar%d: can't read PCI latency timer.\n", i); 5111da177e4SLinus Torvalds error = 6; 5121da177e4SLinus Torvalds ns_init_card_error(card, error); 5131da177e4SLinus Torvalds return error; 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds #ifdef NS_PCI_LATENCY 5161da177e4SLinus Torvalds if (pci_latency < NS_PCI_LATENCY) 5171da177e4SLinus Torvalds { 5181da177e4SLinus Torvalds PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); 5191da177e4SLinus Torvalds for (j = 1; j < 4; j++) 5201da177e4SLinus Torvalds { 5211da177e4SLinus Torvalds if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0) 5221da177e4SLinus Torvalds break; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds if (j == 4) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY); 5271da177e4SLinus Torvalds error = 7; 5281da177e4SLinus Torvalds ns_init_card_error(card, error); 5291da177e4SLinus Torvalds return error; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds #endif /* NS_PCI_LATENCY */ 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* Clear timer overflow */ 5351da177e4SLinus Torvalds data = readl(card->membase + STAT); 5361da177e4SLinus Torvalds if (data & NS_STAT_TMROF) 5371da177e4SLinus Torvalds writel(NS_STAT_TMROF, card->membase + STAT); 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds /* Software reset */ 5401da177e4SLinus Torvalds writel(NS_CFG_SWRST, card->membase + CFG); 5411da177e4SLinus Torvalds NS_DELAY; 5421da177e4SLinus Torvalds writel(0x00000000, card->membase + CFG); 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds /* PHY reset */ 5451da177e4SLinus Torvalds writel(0x00000008, card->membase + GP); 5461da177e4SLinus Torvalds NS_DELAY; 5471da177e4SLinus Torvalds writel(0x00000001, card->membase + GP); 5481da177e4SLinus Torvalds NS_DELAY; 5491da177e4SLinus Torvalds while (CMD_BUSY(card)); 5501da177e4SLinus Torvalds writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ 5511da177e4SLinus Torvalds NS_DELAY; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* Detect PHY type */ 5541da177e4SLinus Torvalds while (CMD_BUSY(card)); 5551da177e4SLinus Torvalds writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); 5561da177e4SLinus Torvalds while (CMD_BUSY(card)); 5571da177e4SLinus Torvalds data = readl(card->membase + DR0); 5581da177e4SLinus Torvalds switch(data) { 5591da177e4SLinus Torvalds case 0x00000009: 5601da177e4SLinus Torvalds printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); 5611da177e4SLinus Torvalds card->max_pcr = ATM_25_PCR; 5621da177e4SLinus Torvalds while(CMD_BUSY(card)); 5631da177e4SLinus Torvalds writel(0x00000008, card->membase + DR0); 5641da177e4SLinus Torvalds writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); 5651da177e4SLinus Torvalds /* Clear an eventual pending interrupt */ 5661da177e4SLinus Torvalds writel(NS_STAT_SFBQF, card->membase + STAT); 5671da177e4SLinus Torvalds #ifdef PHY_LOOPBACK 5681da177e4SLinus Torvalds while(CMD_BUSY(card)); 5691da177e4SLinus Torvalds writel(0x00000022, card->membase + DR0); 5701da177e4SLinus Torvalds writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); 5711da177e4SLinus Torvalds #endif /* PHY_LOOPBACK */ 5721da177e4SLinus Torvalds break; 5731da177e4SLinus Torvalds case 0x00000030: 5741da177e4SLinus Torvalds case 0x00000031: 5751da177e4SLinus Torvalds printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); 5761da177e4SLinus Torvalds card->max_pcr = ATM_OC3_PCR; 5771da177e4SLinus Torvalds #ifdef PHY_LOOPBACK 5781da177e4SLinus Torvalds while(CMD_BUSY(card)); 5791da177e4SLinus Torvalds writel(0x00000002, card->membase + DR0); 5801da177e4SLinus Torvalds writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); 5811da177e4SLinus Torvalds #endif /* PHY_LOOPBACK */ 5821da177e4SLinus Torvalds break; 5831da177e4SLinus Torvalds default: 5841da177e4SLinus Torvalds printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); 5851da177e4SLinus Torvalds error = 8; 5861da177e4SLinus Torvalds ns_init_card_error(card, error); 5871da177e4SLinus Torvalds return error; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds writel(0x00000000, card->membase + GP); 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* Determine SRAM size */ 5921da177e4SLinus Torvalds data = 0x76543210; 5931da177e4SLinus Torvalds ns_write_sram(card, 0x1C003, &data, 1); 5941da177e4SLinus Torvalds data = 0x89ABCDEF; 5951da177e4SLinus Torvalds ns_write_sram(card, 0x14003, &data, 1); 5961da177e4SLinus Torvalds if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && 5971da177e4SLinus Torvalds ns_read_sram(card, 0x1C003) == 0x76543210) 5981da177e4SLinus Torvalds card->sram_size = 128; 5991da177e4SLinus Torvalds else 6001da177e4SLinus Torvalds card->sram_size = 32; 6011da177e4SLinus Torvalds PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds card->rct_size = NS_MAX_RCTSIZE; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds #if (NS_MAX_RCTSIZE == 4096) 6061da177e4SLinus Torvalds if (card->sram_size == 128) 6071da177e4SLinus Torvalds printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i); 6081da177e4SLinus Torvalds #elif (NS_MAX_RCTSIZE == 16384) 6091da177e4SLinus Torvalds if (card->sram_size == 32) 6101da177e4SLinus Torvalds { 6111da177e4SLinus Torvalds printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i); 6121da177e4SLinus Torvalds card->rct_size = 4096; 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds #else 6151da177e4SLinus Torvalds #error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c 6161da177e4SLinus Torvalds #endif 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds card->vpibits = NS_VPIBITS; 6191da177e4SLinus Torvalds if (card->rct_size == 4096) 6201da177e4SLinus Torvalds card->vcibits = 12 - NS_VPIBITS; 6211da177e4SLinus Torvalds else /* card->rct_size == 16384 */ 6221da177e4SLinus Torvalds card->vcibits = 14 - NS_VPIBITS; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ 6251da177e4SLinus Torvalds if (mac[i] == NULL) 6261da177e4SLinus Torvalds nicstar_init_eprom(card->membase); 6271da177e4SLinus Torvalds 628dace1453SThomas Gleixner if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0) 6291da177e4SLinus Torvalds { 6301da177e4SLinus Torvalds printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq); 6311da177e4SLinus Torvalds error = 9; 6321da177e4SLinus Torvalds ns_init_card_error(card, error); 6331da177e4SLinus Torvalds return error; 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ 6371da177e4SLinus Torvalds writel(0x00000000, card->membase + VPM); 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds /* Initialize TSQ */ 6401da177e4SLinus Torvalds card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL); 6411da177e4SLinus Torvalds if (card->tsq.org == NULL) 6421da177e4SLinus Torvalds { 6431da177e4SLinus Torvalds printk("nicstar%d: can't allocate TSQ.\n", i); 6441da177e4SLinus Torvalds error = 10; 6451da177e4SLinus Torvalds ns_init_card_error(card, error); 6461da177e4SLinus Torvalds return error; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT); 6491da177e4SLinus Torvalds card->tsq.next = card->tsq.base; 6501da177e4SLinus Torvalds card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); 6511da177e4SLinus Torvalds for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) 6521da177e4SLinus Torvalds ns_tsi_init(card->tsq.base + j); 6531da177e4SLinus Torvalds writel(0x00000000, card->membase + TSQH); 6541da177e4SLinus Torvalds writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB); 6551da177e4SLinus Torvalds PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base, 6561da177e4SLinus Torvalds (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB)); 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds /* Initialize RSQ */ 6591da177e4SLinus Torvalds card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL); 6601da177e4SLinus Torvalds if (card->rsq.org == NULL) 6611da177e4SLinus Torvalds { 6621da177e4SLinus Torvalds printk("nicstar%d: can't allocate RSQ.\n", i); 6631da177e4SLinus Torvalds error = 11; 6641da177e4SLinus Torvalds ns_init_card_error(card, error); 6651da177e4SLinus Torvalds return error; 6661da177e4SLinus Torvalds } 6671da177e4SLinus Torvalds card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT); 6681da177e4SLinus Torvalds card->rsq.next = card->rsq.base; 6691da177e4SLinus Torvalds card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); 6701da177e4SLinus Torvalds for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) 6711da177e4SLinus Torvalds ns_rsqe_init(card->rsq.base + j); 6721da177e4SLinus Torvalds writel(0x00000000, card->membase + RSQH); 6731da177e4SLinus Torvalds writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB); 6741da177e4SLinus Torvalds PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base); 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds /* Initialize SCQ0, the only VBR SCQ used */ 677a2c1aa54SJesper Juhl card->scq1 = NULL; 678a2c1aa54SJesper Juhl card->scq2 = NULL; 6791da177e4SLinus Torvalds card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); 680a2c1aa54SJesper Juhl if (card->scq0 == NULL) 6811da177e4SLinus Torvalds { 6821da177e4SLinus Torvalds printk("nicstar%d: can't get SCQ0.\n", i); 6831da177e4SLinus Torvalds error = 12; 6841da177e4SLinus Torvalds ns_init_card_error(card, error); 6851da177e4SLinus Torvalds return error; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds u32d[0] = (u32) virt_to_bus(card->scq0->base); 6881da177e4SLinus Torvalds u32d[1] = (u32) 0x00000000; 6891da177e4SLinus Torvalds u32d[2] = (u32) 0xffffffff; 6901da177e4SLinus Torvalds u32d[3] = (u32) 0x00000000; 6911da177e4SLinus Torvalds ns_write_sram(card, NS_VRSCD0, u32d, 4); 6921da177e4SLinus Torvalds ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ 6931da177e4SLinus Torvalds ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ 6941da177e4SLinus Torvalds card->scq0->scd = NS_VRSCD0; 6951da177e4SLinus Torvalds PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base); 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds /* Initialize TSTs */ 6981da177e4SLinus Torvalds card->tst_addr = NS_TST0; 6991da177e4SLinus Torvalds card->tst_free_entries = NS_TST_NUM_ENTRIES; 7001da177e4SLinus Torvalds data = NS_TST_OPCODE_VARIABLE; 7011da177e4SLinus Torvalds for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 7021da177e4SLinus Torvalds ns_write_sram(card, NS_TST0 + j, &data, 1); 7031da177e4SLinus Torvalds data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); 7041da177e4SLinus Torvalds ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); 7051da177e4SLinus Torvalds for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 7061da177e4SLinus Torvalds ns_write_sram(card, NS_TST1 + j, &data, 1); 7071da177e4SLinus Torvalds data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); 7081da177e4SLinus Torvalds ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); 7091da177e4SLinus Torvalds for (j = 0; j < NS_TST_NUM_ENTRIES; j++) 7101da177e4SLinus Torvalds card->tste2vc[j] = NULL; 7111da177e4SLinus Torvalds writel(NS_TST0 << 2, card->membase + TSTB); 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds /* Initialize RCT. AAL type is set on opening the VC. */ 7151da177e4SLinus Torvalds #ifdef RCQ_SUPPORT 7161da177e4SLinus Torvalds u32d[0] = NS_RCTE_RAWCELLINTEN; 7171da177e4SLinus Torvalds #else 7181da177e4SLinus Torvalds u32d[0] = 0x00000000; 7191da177e4SLinus Torvalds #endif /* RCQ_SUPPORT */ 7201da177e4SLinus Torvalds u32d[1] = 0x00000000; 7211da177e4SLinus Torvalds u32d[2] = 0x00000000; 7221da177e4SLinus Torvalds u32d[3] = 0xFFFFFFFF; 7231da177e4SLinus Torvalds for (j = 0; j < card->rct_size; j++) 7241da177e4SLinus Torvalds ns_write_sram(card, j * 4, u32d, 4); 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map)); 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds for (j = 0; j < NS_FRSCD_NUM; j++) 7291da177e4SLinus Torvalds card->scd2vc[j] = NULL; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds /* Initialize buffer levels */ 7321da177e4SLinus Torvalds card->sbnr.min = MIN_SB; 7331da177e4SLinus Torvalds card->sbnr.init = NUM_SB; 7341da177e4SLinus Torvalds card->sbnr.max = MAX_SB; 7351da177e4SLinus Torvalds card->lbnr.min = MIN_LB; 7361da177e4SLinus Torvalds card->lbnr.init = NUM_LB; 7371da177e4SLinus Torvalds card->lbnr.max = MAX_LB; 7381da177e4SLinus Torvalds card->iovnr.min = MIN_IOVB; 7391da177e4SLinus Torvalds card->iovnr.init = NUM_IOVB; 7401da177e4SLinus Torvalds card->iovnr.max = MAX_IOVB; 7411da177e4SLinus Torvalds card->hbnr.min = MIN_HB; 7421da177e4SLinus Torvalds card->hbnr.init = NUM_HB; 7431da177e4SLinus Torvalds card->hbnr.max = MAX_HB; 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds card->sm_handle = 0x00000000; 7461da177e4SLinus Torvalds card->sm_addr = 0x00000000; 7471da177e4SLinus Torvalds card->lg_handle = 0x00000000; 7481da177e4SLinus Torvalds card->lg_addr = 0x00000000; 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds /* Pre-allocate some huge buffers */ 7531da177e4SLinus Torvalds skb_queue_head_init(&card->hbpool.queue); 7541da177e4SLinus Torvalds card->hbpool.count = 0; 7551da177e4SLinus Torvalds for (j = 0; j < NUM_HB; j++) 7561da177e4SLinus Torvalds { 7571da177e4SLinus Torvalds struct sk_buff *hb; 7581da177e4SLinus Torvalds hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 7591da177e4SLinus Torvalds if (hb == NULL) 7601da177e4SLinus Torvalds { 7611da177e4SLinus Torvalds printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", 7621da177e4SLinus Torvalds i, j, NUM_HB); 7631da177e4SLinus Torvalds error = 13; 7641da177e4SLinus Torvalds ns_init_card_error(card, error); 7651da177e4SLinus Torvalds return error; 7661da177e4SLinus Torvalds } 7678728b834SDavid S. Miller NS_SKB_CB(hb)->buf_type = BUF_NONE; 7681da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, hb); 7691da177e4SLinus Torvalds card->hbpool.count++; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds /* Allocate large buffers */ 7741da177e4SLinus Torvalds skb_queue_head_init(&card->lbpool.queue); 7751da177e4SLinus Torvalds card->lbpool.count = 0; /* Not used */ 7761da177e4SLinus Torvalds for (j = 0; j < NUM_LB; j++) 7771da177e4SLinus Torvalds { 7781da177e4SLinus Torvalds struct sk_buff *lb; 7791da177e4SLinus Torvalds lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 7801da177e4SLinus Torvalds if (lb == NULL) 7811da177e4SLinus Torvalds { 7821da177e4SLinus Torvalds printk("nicstar%d: can't allocate %dth of %d large buffers.\n", 7831da177e4SLinus Torvalds i, j, NUM_LB); 7841da177e4SLinus Torvalds error = 14; 7851da177e4SLinus Torvalds ns_init_card_error(card, error); 7861da177e4SLinus Torvalds return error; 7871da177e4SLinus Torvalds } 7888728b834SDavid S. Miller NS_SKB_CB(lb)->buf_type = BUF_LG; 7891da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, lb); 7901da177e4SLinus Torvalds skb_reserve(lb, NS_SMBUFSIZE); 7918728b834SDavid S. Miller push_rxbufs(card, lb); 7921da177e4SLinus Torvalds /* Due to the implementation of push_rxbufs() this is 1, not 0 */ 7931da177e4SLinus Torvalds if (j == 1) 7941da177e4SLinus Torvalds { 7951da177e4SLinus Torvalds card->rcbuf = lb; 7961da177e4SLinus Torvalds card->rawch = (u32) virt_to_bus(lb->data); 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds /* Test for strange behaviour which leads to crashes */ 8001da177e4SLinus Torvalds if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) 8011da177e4SLinus Torvalds { 8021da177e4SLinus Torvalds printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", 8031da177e4SLinus Torvalds i, j, bcount); 8041da177e4SLinus Torvalds error = 14; 8051da177e4SLinus Torvalds ns_init_card_error(card, error); 8061da177e4SLinus Torvalds return error; 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds /* Allocate small buffers */ 8111da177e4SLinus Torvalds skb_queue_head_init(&card->sbpool.queue); 8121da177e4SLinus Torvalds card->sbpool.count = 0; /* Not used */ 8131da177e4SLinus Torvalds for (j = 0; j < NUM_SB; j++) 8141da177e4SLinus Torvalds { 8151da177e4SLinus Torvalds struct sk_buff *sb; 8161da177e4SLinus Torvalds sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 8171da177e4SLinus Torvalds if (sb == NULL) 8181da177e4SLinus Torvalds { 8191da177e4SLinus Torvalds printk("nicstar%d: can't allocate %dth of %d small buffers.\n", 8201da177e4SLinus Torvalds i, j, NUM_SB); 8211da177e4SLinus Torvalds error = 15; 8221da177e4SLinus Torvalds ns_init_card_error(card, error); 8231da177e4SLinus Torvalds return error; 8241da177e4SLinus Torvalds } 8258728b834SDavid S. Miller NS_SKB_CB(sb)->buf_type = BUF_SM; 8261da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, sb); 8271da177e4SLinus Torvalds skb_reserve(sb, NS_AAL0_HEADER); 8288728b834SDavid S. Miller push_rxbufs(card, sb); 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds /* Test for strange behaviour which leads to crashes */ 8311da177e4SLinus Torvalds if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) 8321da177e4SLinus Torvalds { 8331da177e4SLinus Torvalds printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", 8341da177e4SLinus Torvalds i, j, bcount); 8351da177e4SLinus Torvalds error = 15; 8361da177e4SLinus Torvalds ns_init_card_error(card, error); 8371da177e4SLinus Torvalds return error; 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* Allocate iovec buffers */ 8421da177e4SLinus Torvalds skb_queue_head_init(&card->iovpool.queue); 8431da177e4SLinus Torvalds card->iovpool.count = 0; 8441da177e4SLinus Torvalds for (j = 0; j < NUM_IOVB; j++) 8451da177e4SLinus Torvalds { 8461da177e4SLinus Torvalds struct sk_buff *iovb; 8471da177e4SLinus Torvalds iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 8481da177e4SLinus Torvalds if (iovb == NULL) 8491da177e4SLinus Torvalds { 8501da177e4SLinus Torvalds printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", 8511da177e4SLinus Torvalds i, j, NUM_IOVB); 8521da177e4SLinus Torvalds error = 16; 8531da177e4SLinus Torvalds ns_init_card_error(card, error); 8541da177e4SLinus Torvalds return error; 8551da177e4SLinus Torvalds } 8568728b834SDavid S. Miller NS_SKB_CB(iovb)->buf_type = BUF_NONE; 8571da177e4SLinus Torvalds skb_queue_tail(&card->iovpool.queue, iovb); 8581da177e4SLinus Torvalds card->iovpool.count++; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds card->intcnt = 0; 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds /* Configure NICStAR */ 8641da177e4SLinus Torvalds if (card->rct_size == 4096) 8651da177e4SLinus Torvalds ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; 8661da177e4SLinus Torvalds else /* (card->rct_size == 16384) */ 8671da177e4SLinus Torvalds ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds card->efbie = 1; 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds /* Register device */ 8721da177e4SLinus Torvalds card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL); 8731da177e4SLinus Torvalds if (card->atmdev == NULL) 8741da177e4SLinus Torvalds { 8751da177e4SLinus Torvalds printk("nicstar%d: can't register device.\n", i); 8761da177e4SLinus Torvalds error = 17; 8771da177e4SLinus Torvalds ns_init_card_error(card, error); 8781da177e4SLinus Torvalds return error; 8791da177e4SLinus Torvalds } 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds if (ns_parse_mac(mac[i], card->atmdev->esi)) { 8821da177e4SLinus Torvalds nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, 8831da177e4SLinus Torvalds card->atmdev->esi, 6); 8841da177e4SLinus Torvalds if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) { 8851da177e4SLinus Torvalds nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, 8861da177e4SLinus Torvalds card->atmdev->esi, 6); 8871da177e4SLinus Torvalds } 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, 8911da177e4SLinus Torvalds card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], 8921da177e4SLinus Torvalds card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds card->atmdev->dev_data = card; 8951da177e4SLinus Torvalds card->atmdev->ci_range.vpi_bits = card->vpibits; 8961da177e4SLinus Torvalds card->atmdev->ci_range.vci_bits = card->vcibits; 8971da177e4SLinus Torvalds card->atmdev->link_rate = card->max_pcr; 8981da177e4SLinus Torvalds card->atmdev->phy = NULL; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds #ifdef CONFIG_ATM_NICSTAR_USE_SUNI 9011da177e4SLinus Torvalds if (card->max_pcr == ATM_OC3_PCR) 9021da177e4SLinus Torvalds suni_init(card->atmdev); 9031da177e4SLinus Torvalds #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 9061da177e4SLinus Torvalds if (card->max_pcr == ATM_25_PCR) 9071da177e4SLinus Torvalds idt77105_init(card->atmdev); 9081da177e4SLinus Torvalds #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds if (card->atmdev->phy && card->atmdev->phy->start) 9111da177e4SLinus Torvalds card->atmdev->phy->start(card->atmdev); 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds writel(NS_CFG_RXPATH | 9141da177e4SLinus Torvalds NS_CFG_SMBUFSIZE | 9151da177e4SLinus Torvalds NS_CFG_LGBUFSIZE | 9161da177e4SLinus Torvalds NS_CFG_EFBIE | 9171da177e4SLinus Torvalds NS_CFG_RSQSIZE | 9181da177e4SLinus Torvalds NS_CFG_VPIBITS | 9191da177e4SLinus Torvalds ns_cfg_rctsize | 9201da177e4SLinus Torvalds NS_CFG_RXINT_NODELAY | 9211da177e4SLinus Torvalds NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ 9221da177e4SLinus Torvalds NS_CFG_RSQAFIE | 9231da177e4SLinus Torvalds NS_CFG_TXEN | 9241da177e4SLinus Torvalds NS_CFG_TXIE | 9251da177e4SLinus Torvalds NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ 9261da177e4SLinus Torvalds NS_CFG_PHYIE, 9271da177e4SLinus Torvalds card->membase + CFG); 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds num_cards++; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds return error; 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds static void __devinit ns_init_card_error(ns_dev *card, int error) 9371da177e4SLinus Torvalds { 9381da177e4SLinus Torvalds if (error >= 17) 9391da177e4SLinus Torvalds { 9401da177e4SLinus Torvalds writel(0x00000000, card->membase + CFG); 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds if (error >= 16) 9431da177e4SLinus Torvalds { 9441da177e4SLinus Torvalds struct sk_buff *iovb; 9451da177e4SLinus Torvalds while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) 9461da177e4SLinus Torvalds dev_kfree_skb_any(iovb); 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds if (error >= 15) 9491da177e4SLinus Torvalds { 9501da177e4SLinus Torvalds struct sk_buff *sb; 9511da177e4SLinus Torvalds while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) 9521da177e4SLinus Torvalds dev_kfree_skb_any(sb); 9531da177e4SLinus Torvalds free_scq(card->scq0, NULL); 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds if (error >= 14) 9561da177e4SLinus Torvalds { 9571da177e4SLinus Torvalds struct sk_buff *lb; 9581da177e4SLinus Torvalds while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) 9591da177e4SLinus Torvalds dev_kfree_skb_any(lb); 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds if (error >= 13) 9621da177e4SLinus Torvalds { 9631da177e4SLinus Torvalds struct sk_buff *hb; 9641da177e4SLinus Torvalds while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) 9651da177e4SLinus Torvalds dev_kfree_skb_any(hb); 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds if (error >= 12) 9681da177e4SLinus Torvalds { 9691da177e4SLinus Torvalds kfree(card->rsq.org); 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds if (error >= 11) 9721da177e4SLinus Torvalds { 9731da177e4SLinus Torvalds kfree(card->tsq.org); 9741da177e4SLinus Torvalds } 9751da177e4SLinus Torvalds if (error >= 10) 9761da177e4SLinus Torvalds { 9771da177e4SLinus Torvalds free_irq(card->pcidev->irq, card); 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds if (error >= 4) 9801da177e4SLinus Torvalds { 9811da177e4SLinus Torvalds iounmap(card->membase); 9821da177e4SLinus Torvalds } 9831da177e4SLinus Torvalds if (error >= 3) 9841da177e4SLinus Torvalds { 9851da177e4SLinus Torvalds pci_disable_device(card->pcidev); 9861da177e4SLinus Torvalds kfree(card); 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds static scq_info *get_scq(int size, u32 scd) 9931da177e4SLinus Torvalds { 9941da177e4SLinus Torvalds scq_info *scq; 9951da177e4SLinus Torvalds int i; 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) 998a2c1aa54SJesper Juhl return NULL; 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); 1001a2c1aa54SJesper Juhl if (scq == NULL) 1002a2c1aa54SJesper Juhl return NULL; 10031da177e4SLinus Torvalds scq->org = kmalloc(2 * size, GFP_KERNEL); 10041da177e4SLinus Torvalds if (scq->org == NULL) 10051da177e4SLinus Torvalds { 10061da177e4SLinus Torvalds kfree(scq); 1007a2c1aa54SJesper Juhl return NULL; 10081da177e4SLinus Torvalds } 10091da177e4SLinus Torvalds scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * 10101da177e4SLinus Torvalds (size / NS_SCQE_SIZE), GFP_KERNEL); 1011a2c1aa54SJesper Juhl if (scq->skb == NULL) 10121da177e4SLinus Torvalds { 10131da177e4SLinus Torvalds kfree(scq->org); 10141da177e4SLinus Torvalds kfree(scq); 1015a2c1aa54SJesper Juhl return NULL; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds scq->num_entries = size / NS_SCQE_SIZE; 10181da177e4SLinus Torvalds scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size); 10191da177e4SLinus Torvalds scq->next = scq->base; 10201da177e4SLinus Torvalds scq->last = scq->base + (scq->num_entries - 1); 10211da177e4SLinus Torvalds scq->tail = scq->last; 10221da177e4SLinus Torvalds scq->scd = scd; 10231da177e4SLinus Torvalds scq->num_entries = size / NS_SCQE_SIZE; 10241da177e4SLinus Torvalds scq->tbd_count = 0; 10251da177e4SLinus Torvalds init_waitqueue_head(&scq->scqfull_waitq); 10261da177e4SLinus Torvalds scq->full = 0; 10271da177e4SLinus Torvalds spin_lock_init(&scq->lock); 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds for (i = 0; i < scq->num_entries; i++) 10301da177e4SLinus Torvalds scq->skb[i] = NULL; 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds return scq; 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds /* For variable rate SCQ vcc must be NULL */ 10381da177e4SLinus Torvalds static void free_scq(scq_info *scq, struct atm_vcc *vcc) 10391da177e4SLinus Torvalds { 10401da177e4SLinus Torvalds int i; 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) 10431da177e4SLinus Torvalds for (i = 0; i < scq->num_entries; i++) 10441da177e4SLinus Torvalds { 10451da177e4SLinus Torvalds if (scq->skb[i] != NULL) 10461da177e4SLinus Torvalds { 10471da177e4SLinus Torvalds vcc = ATM_SKB(scq->skb[i])->vcc; 10481da177e4SLinus Torvalds if (vcc->pop != NULL) 10491da177e4SLinus Torvalds vcc->pop(vcc, scq->skb[i]); 10501da177e4SLinus Torvalds else 10511da177e4SLinus Torvalds dev_kfree_skb_any(scq->skb[i]); 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds else /* vcc must be != NULL */ 10551da177e4SLinus Torvalds { 10561da177e4SLinus Torvalds if (vcc == NULL) 10571da177e4SLinus Torvalds { 10581da177e4SLinus Torvalds printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); 10591da177e4SLinus Torvalds for (i = 0; i < scq->num_entries; i++) 10601da177e4SLinus Torvalds dev_kfree_skb_any(scq->skb[i]); 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds else 10631da177e4SLinus Torvalds for (i = 0; i < scq->num_entries; i++) 10641da177e4SLinus Torvalds { 10651da177e4SLinus Torvalds if (scq->skb[i] != NULL) 10661da177e4SLinus Torvalds { 10671da177e4SLinus Torvalds if (vcc->pop != NULL) 10681da177e4SLinus Torvalds vcc->pop(vcc, scq->skb[i]); 10691da177e4SLinus Torvalds else 10701da177e4SLinus Torvalds dev_kfree_skb_any(scq->skb[i]); 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds } 10741da177e4SLinus Torvalds kfree(scq->skb); 10751da177e4SLinus Torvalds kfree(scq->org); 10761da177e4SLinus Torvalds kfree(scq); 10771da177e4SLinus Torvalds } 10781da177e4SLinus Torvalds 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds /* The handles passed must be pointers to the sk_buff containing the small 10821da177e4SLinus Torvalds or large buffer(s) cast to u32. */ 10838728b834SDavid S. Miller static void push_rxbufs(ns_dev *card, struct sk_buff *skb) 10841da177e4SLinus Torvalds { 10858728b834SDavid S. Miller struct ns_skb_cb *cb = NS_SKB_CB(skb); 10868728b834SDavid S. Miller u32 handle1, addr1; 10878728b834SDavid S. Miller u32 handle2, addr2; 10881da177e4SLinus Torvalds u32 stat; 10891da177e4SLinus Torvalds unsigned long flags; 10901da177e4SLinus Torvalds 10918728b834SDavid S. Miller /* *BARF* */ 10928728b834SDavid S. Miller handle2 = addr2 = 0; 10938728b834SDavid S. Miller handle1 = (u32)skb; 10948728b834SDavid S. Miller addr1 = (u32)virt_to_bus(skb->data); 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds #ifdef GENERAL_DEBUG 10971da177e4SLinus Torvalds if (!addr1) 10981da177e4SLinus Torvalds printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index); 10991da177e4SLinus Torvalds #endif /* GENERAL_DEBUG */ 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds stat = readl(card->membase + STAT); 11021da177e4SLinus Torvalds card->sbfqc = ns_stat_sfbqc_get(stat); 11031da177e4SLinus Torvalds card->lbfqc = ns_stat_lfbqc_get(stat); 11048728b834SDavid S. Miller if (cb->buf_type == BUF_SM) 11051da177e4SLinus Torvalds { 11061da177e4SLinus Torvalds if (!addr2) 11071da177e4SLinus Torvalds { 11081da177e4SLinus Torvalds if (card->sm_addr) 11091da177e4SLinus Torvalds { 11101da177e4SLinus Torvalds addr2 = card->sm_addr; 11111da177e4SLinus Torvalds handle2 = card->sm_handle; 11121da177e4SLinus Torvalds card->sm_addr = 0x00000000; 11131da177e4SLinus Torvalds card->sm_handle = 0x00000000; 11141da177e4SLinus Torvalds } 11151da177e4SLinus Torvalds else /* (!sm_addr) */ 11161da177e4SLinus Torvalds { 11171da177e4SLinus Torvalds card->sm_addr = addr1; 11181da177e4SLinus Torvalds card->sm_handle = handle1; 11191da177e4SLinus Torvalds } 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds } 11228728b834SDavid S. Miller else /* buf_type == BUF_LG */ 11231da177e4SLinus Torvalds { 11241da177e4SLinus Torvalds if (!addr2) 11251da177e4SLinus Torvalds { 11261da177e4SLinus Torvalds if (card->lg_addr) 11271da177e4SLinus Torvalds { 11281da177e4SLinus Torvalds addr2 = card->lg_addr; 11291da177e4SLinus Torvalds handle2 = card->lg_handle; 11301da177e4SLinus Torvalds card->lg_addr = 0x00000000; 11311da177e4SLinus Torvalds card->lg_handle = 0x00000000; 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds else /* (!lg_addr) */ 11341da177e4SLinus Torvalds { 11351da177e4SLinus Torvalds card->lg_addr = addr1; 11361da177e4SLinus Torvalds card->lg_handle = handle1; 11371da177e4SLinus Torvalds } 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds } 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds if (addr2) 11421da177e4SLinus Torvalds { 11438728b834SDavid S. Miller if (cb->buf_type == BUF_SM) 11441da177e4SLinus Torvalds { 11451da177e4SLinus Torvalds if (card->sbfqc >= card->sbnr.max) 11461da177e4SLinus Torvalds { 11478728b834SDavid S. Miller skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue); 11481da177e4SLinus Torvalds dev_kfree_skb_any((struct sk_buff *) handle1); 11498728b834SDavid S. Miller skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue); 11501da177e4SLinus Torvalds dev_kfree_skb_any((struct sk_buff *) handle2); 11511da177e4SLinus Torvalds return; 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds else 11541da177e4SLinus Torvalds card->sbfqc += 2; 11551da177e4SLinus Torvalds } 11568728b834SDavid S. Miller else /* (buf_type == BUF_LG) */ 11571da177e4SLinus Torvalds { 11581da177e4SLinus Torvalds if (card->lbfqc >= card->lbnr.max) 11591da177e4SLinus Torvalds { 11608728b834SDavid S. Miller skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue); 11611da177e4SLinus Torvalds dev_kfree_skb_any((struct sk_buff *) handle1); 11628728b834SDavid S. Miller skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue); 11631da177e4SLinus Torvalds dev_kfree_skb_any((struct sk_buff *) handle2); 11641da177e4SLinus Torvalds return; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds else 11671da177e4SLinus Torvalds card->lbfqc += 2; 11681da177e4SLinus Torvalds } 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds while (CMD_BUSY(card)); 11731da177e4SLinus Torvalds writel(addr2, card->membase + DR3); 11741da177e4SLinus Torvalds writel(handle2, card->membase + DR2); 11751da177e4SLinus Torvalds writel(addr1, card->membase + DR1); 11761da177e4SLinus Torvalds writel(handle1, card->membase + DR0); 11778728b834SDavid S. Miller writel(NS_CMD_WRITE_FREEBUFQ | cb->buf_type, card->membase + CMD); 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index, 11828728b834SDavid S. Miller (cb->buf_type == BUF_SM ? "small" : "large"), addr1, addr2); 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds if (!card->efbie && card->sbfqc >= card->sbnr.min && 11861da177e4SLinus Torvalds card->lbfqc >= card->lbnr.min) 11871da177e4SLinus Torvalds { 11881da177e4SLinus Torvalds card->efbie = 1; 11891da177e4SLinus Torvalds writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG); 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds 11921da177e4SLinus Torvalds return; 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds 11977d12e780SDavid Howells static irqreturn_t ns_irq_handler(int irq, void *dev_id) 11981da177e4SLinus Torvalds { 11991da177e4SLinus Torvalds u32 stat_r; 12001da177e4SLinus Torvalds ns_dev *card; 12011da177e4SLinus Torvalds struct atm_dev *dev; 12021da177e4SLinus Torvalds unsigned long flags; 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds card = (ns_dev *) dev_id; 12051da177e4SLinus Torvalds dev = card->atmdev; 12061da177e4SLinus Torvalds card->intcnt++; 12071da177e4SLinus Torvalds 12081da177e4SLinus Torvalds PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 12111da177e4SLinus Torvalds 12121da177e4SLinus Torvalds stat_r = readl(card->membase + STAT); 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds /* Transmit Status Indicator has been written to T. S. Queue */ 12151da177e4SLinus Torvalds if (stat_r & NS_STAT_TSIF) 12161da177e4SLinus Torvalds { 12171da177e4SLinus Torvalds TXPRINTK("nicstar%d: TSI interrupt\n", card->index); 12181da177e4SLinus Torvalds process_tsq(card); 12191da177e4SLinus Torvalds writel(NS_STAT_TSIF, card->membase + STAT); 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds /* Incomplete CS-PDU has been transmitted */ 12231da177e4SLinus Torvalds if (stat_r & NS_STAT_TXICP) 12241da177e4SLinus Torvalds { 12251da177e4SLinus Torvalds writel(NS_STAT_TXICP, card->membase + STAT); 12261da177e4SLinus Torvalds TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", 12271da177e4SLinus Torvalds card->index); 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds /* Transmit Status Queue 7/8 full */ 12311da177e4SLinus Torvalds if (stat_r & NS_STAT_TSQF) 12321da177e4SLinus Torvalds { 12331da177e4SLinus Torvalds writel(NS_STAT_TSQF, card->membase + STAT); 12341da177e4SLinus Torvalds PRINTK("nicstar%d: TSQ full.\n", card->index); 12351da177e4SLinus Torvalds process_tsq(card); 12361da177e4SLinus Torvalds } 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds /* Timer overflow */ 12391da177e4SLinus Torvalds if (stat_r & NS_STAT_TMROF) 12401da177e4SLinus Torvalds { 12411da177e4SLinus Torvalds writel(NS_STAT_TMROF, card->membase + STAT); 12421da177e4SLinus Torvalds PRINTK("nicstar%d: Timer overflow.\n", card->index); 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds 12451da177e4SLinus Torvalds /* PHY device interrupt signal active */ 12461da177e4SLinus Torvalds if (stat_r & NS_STAT_PHYI) 12471da177e4SLinus Torvalds { 12481da177e4SLinus Torvalds writel(NS_STAT_PHYI, card->membase + STAT); 12491da177e4SLinus Torvalds PRINTK("nicstar%d: PHY interrupt.\n", card->index); 12501da177e4SLinus Torvalds if (dev->phy && dev->phy->interrupt) { 12511da177e4SLinus Torvalds dev->phy->interrupt(dev); 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds } 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds /* Small Buffer Queue is full */ 12561da177e4SLinus Torvalds if (stat_r & NS_STAT_SFBQF) 12571da177e4SLinus Torvalds { 12581da177e4SLinus Torvalds writel(NS_STAT_SFBQF, card->membase + STAT); 12591da177e4SLinus Torvalds printk("nicstar%d: Small free buffer queue is full.\n", card->index); 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds /* Large Buffer Queue is full */ 12631da177e4SLinus Torvalds if (stat_r & NS_STAT_LFBQF) 12641da177e4SLinus Torvalds { 12651da177e4SLinus Torvalds writel(NS_STAT_LFBQF, card->membase + STAT); 12661da177e4SLinus Torvalds printk("nicstar%d: Large free buffer queue is full.\n", card->index); 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds /* Receive Status Queue is full */ 12701da177e4SLinus Torvalds if (stat_r & NS_STAT_RSQF) 12711da177e4SLinus Torvalds { 12721da177e4SLinus Torvalds writel(NS_STAT_RSQF, card->membase + STAT); 12731da177e4SLinus Torvalds printk("nicstar%d: RSQ full.\n", card->index); 12741da177e4SLinus Torvalds process_rsq(card); 12751da177e4SLinus Torvalds } 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds /* Complete CS-PDU received */ 12781da177e4SLinus Torvalds if (stat_r & NS_STAT_EOPDU) 12791da177e4SLinus Torvalds { 12801da177e4SLinus Torvalds RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); 12811da177e4SLinus Torvalds process_rsq(card); 12821da177e4SLinus Torvalds writel(NS_STAT_EOPDU, card->membase + STAT); 12831da177e4SLinus Torvalds } 12841da177e4SLinus Torvalds 12851da177e4SLinus Torvalds /* Raw cell received */ 12861da177e4SLinus Torvalds if (stat_r & NS_STAT_RAWCF) 12871da177e4SLinus Torvalds { 12881da177e4SLinus Torvalds writel(NS_STAT_RAWCF, card->membase + STAT); 12891da177e4SLinus Torvalds #ifndef RCQ_SUPPORT 12901da177e4SLinus Torvalds printk("nicstar%d: Raw cell received and no support yet...\n", 12911da177e4SLinus Torvalds card->index); 12921da177e4SLinus Torvalds #endif /* RCQ_SUPPORT */ 12931da177e4SLinus Torvalds /* NOTE: the following procedure may keep a raw cell pending until the 12941da177e4SLinus Torvalds next interrupt. As this preliminary support is only meant to 12951da177e4SLinus Torvalds avoid buffer leakage, this is not an issue. */ 12961da177e4SLinus Torvalds while (readl(card->membase + RAWCT) != card->rawch) 12971da177e4SLinus Torvalds { 12981da177e4SLinus Torvalds ns_rcqe *rawcell; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds rawcell = (ns_rcqe *) bus_to_virt(card->rawch); 13011da177e4SLinus Torvalds if (ns_rcqe_islast(rawcell)) 13021da177e4SLinus Torvalds { 13031da177e4SLinus Torvalds struct sk_buff *oldbuf; 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds oldbuf = card->rcbuf; 13061da177e4SLinus Torvalds card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell); 13071da177e4SLinus Torvalds card->rawch = (u32) virt_to_bus(card->rcbuf->data); 13081da177e4SLinus Torvalds recycle_rx_buf(card, oldbuf); 13091da177e4SLinus Torvalds } 13101da177e4SLinus Torvalds else 13111da177e4SLinus Torvalds card->rawch += NS_RCQE_SIZE; 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds } 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds /* Small buffer queue is empty */ 13161da177e4SLinus Torvalds if (stat_r & NS_STAT_SFBQE) 13171da177e4SLinus Torvalds { 13181da177e4SLinus Torvalds int i; 13191da177e4SLinus Torvalds struct sk_buff *sb; 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds writel(NS_STAT_SFBQE, card->membase + STAT); 13221da177e4SLinus Torvalds printk("nicstar%d: Small free buffer queue empty.\n", 13231da177e4SLinus Torvalds card->index); 13241da177e4SLinus Torvalds for (i = 0; i < card->sbnr.min; i++) 13251da177e4SLinus Torvalds { 13261da177e4SLinus Torvalds sb = dev_alloc_skb(NS_SMSKBSIZE); 13271da177e4SLinus Torvalds if (sb == NULL) 13281da177e4SLinus Torvalds { 13291da177e4SLinus Torvalds writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); 13301da177e4SLinus Torvalds card->efbie = 0; 13311da177e4SLinus Torvalds break; 13321da177e4SLinus Torvalds } 13338728b834SDavid S. Miller NS_SKB_CB(sb)->buf_type = BUF_SM; 13341da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, sb); 13351da177e4SLinus Torvalds skb_reserve(sb, NS_AAL0_HEADER); 13368728b834SDavid S. Miller push_rxbufs(card, sb); 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds card->sbfqc = i; 13391da177e4SLinus Torvalds process_rsq(card); 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds /* Large buffer queue empty */ 13431da177e4SLinus Torvalds if (stat_r & NS_STAT_LFBQE) 13441da177e4SLinus Torvalds { 13451da177e4SLinus Torvalds int i; 13461da177e4SLinus Torvalds struct sk_buff *lb; 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds writel(NS_STAT_LFBQE, card->membase + STAT); 13491da177e4SLinus Torvalds printk("nicstar%d: Large free buffer queue empty.\n", 13501da177e4SLinus Torvalds card->index); 13511da177e4SLinus Torvalds for (i = 0; i < card->lbnr.min; i++) 13521da177e4SLinus Torvalds { 13531da177e4SLinus Torvalds lb = dev_alloc_skb(NS_LGSKBSIZE); 13541da177e4SLinus Torvalds if (lb == NULL) 13551da177e4SLinus Torvalds { 13561da177e4SLinus Torvalds writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); 13571da177e4SLinus Torvalds card->efbie = 0; 13581da177e4SLinus Torvalds break; 13591da177e4SLinus Torvalds } 13608728b834SDavid S. Miller NS_SKB_CB(lb)->buf_type = BUF_LG; 13611da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, lb); 13621da177e4SLinus Torvalds skb_reserve(lb, NS_SMBUFSIZE); 13638728b834SDavid S. Miller push_rxbufs(card, lb); 13641da177e4SLinus Torvalds } 13651da177e4SLinus Torvalds card->lbfqc = i; 13661da177e4SLinus Torvalds process_rsq(card); 13671da177e4SLinus Torvalds } 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds /* Receive Status Queue is 7/8 full */ 13701da177e4SLinus Torvalds if (stat_r & NS_STAT_RSQAF) 13711da177e4SLinus Torvalds { 13721da177e4SLinus Torvalds writel(NS_STAT_RSQAF, card->membase + STAT); 13731da177e4SLinus Torvalds RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); 13741da177e4SLinus Torvalds process_rsq(card); 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 13781da177e4SLinus Torvalds PRINTK("nicstar%d: end of interrupt service\n", card->index); 13791da177e4SLinus Torvalds return IRQ_HANDLED; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds static int ns_open(struct atm_vcc *vcc) 13851da177e4SLinus Torvalds { 13861da177e4SLinus Torvalds ns_dev *card; 13871da177e4SLinus Torvalds vc_map *vc; 13881da177e4SLinus Torvalds unsigned long tmpl, modl; 13891da177e4SLinus Torvalds int tcr, tcra; /* target cell rate, and absolute value */ 13901da177e4SLinus Torvalds int n = 0; /* Number of entries in the TST. Initialized to remove 13911da177e4SLinus Torvalds the compiler warning. */ 13921da177e4SLinus Torvalds u32 u32d[4]; 13931da177e4SLinus Torvalds int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler 13941da177e4SLinus Torvalds warning. How I wish compilers were clever enough to 13951da177e4SLinus Torvalds tell which variables can truly be used 13961da177e4SLinus Torvalds uninitialized... */ 13971da177e4SLinus Torvalds int inuse; /* tx or rx vc already in use by another vcc */ 13981da177e4SLinus Torvalds short vpi = vcc->vpi; 13991da177e4SLinus Torvalds int vci = vcc->vci; 14001da177e4SLinus Torvalds 14011da177e4SLinus Torvalds card = (ns_dev *) vcc->dev->dev_data; 14021da177e4SLinus Torvalds PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci); 14031da177e4SLinus Torvalds if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) 14041da177e4SLinus Torvalds { 14051da177e4SLinus Torvalds PRINTK("nicstar%d: unsupported AAL.\n", card->index); 14061da177e4SLinus Torvalds return -EINVAL; 14071da177e4SLinus Torvalds } 14081da177e4SLinus Torvalds 14091da177e4SLinus Torvalds vc = &(card->vcmap[vpi << card->vcibits | vci]); 14101da177e4SLinus Torvalds vcc->dev_data = vc; 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds inuse = 0; 14131da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) 14141da177e4SLinus Torvalds inuse = 1; 14151da177e4SLinus Torvalds if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) 14161da177e4SLinus Torvalds inuse += 2; 14171da177e4SLinus Torvalds if (inuse) 14181da177e4SLinus Torvalds { 14191da177e4SLinus Torvalds printk("nicstar%d: %s vci already in use.\n", card->index, 14201da177e4SLinus Torvalds inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); 14211da177e4SLinus Torvalds return -EINVAL; 14221da177e4SLinus Torvalds } 14231da177e4SLinus Torvalds 14241da177e4SLinus Torvalds set_bit(ATM_VF_ADDR,&vcc->flags); 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds /* NOTE: You are not allowed to modify an open connection's QOS. To change 14271da177e4SLinus Torvalds that, remove the ATM_VF_PARTIAL flag checking. There may be other changes 14281da177e4SLinus Torvalds needed to do that. */ 14291da177e4SLinus Torvalds if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) 14301da177e4SLinus Torvalds { 14311da177e4SLinus Torvalds scq_info *scq; 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds set_bit(ATM_VF_PARTIAL,&vcc->flags); 14341da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class == ATM_CBR) 14351da177e4SLinus Torvalds { 14361da177e4SLinus Torvalds /* Check requested cell rate and availability of SCD */ 14371da177e4SLinus Torvalds if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 && 14381da177e4SLinus Torvalds vcc->qos.txtp.min_pcr == 0) 14391da177e4SLinus Torvalds { 14401da177e4SLinus Torvalds PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", 14411da177e4SLinus Torvalds card->index); 14421da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 14431da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 14441da177e4SLinus Torvalds return -EINVAL; 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds tcr = atm_pcr_goal(&(vcc->qos.txtp)); 14481da177e4SLinus Torvalds tcra = tcr >= 0 ? tcr : -tcr; 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds PRINTK("nicstar%d: target cell rate = %d.\n", card->index, 14511da177e4SLinus Torvalds vcc->qos.txtp.max_pcr); 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES; 14541da177e4SLinus Torvalds modl = tmpl % card->max_pcr; 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds n = (int)(tmpl / card->max_pcr); 14571da177e4SLinus Torvalds if (tcr > 0) 14581da177e4SLinus Torvalds { 14591da177e4SLinus Torvalds if (modl > 0) n++; 14601da177e4SLinus Torvalds } 14611da177e4SLinus Torvalds else if (tcr == 0) 14621da177e4SLinus Torvalds { 14631da177e4SLinus Torvalds if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) 14641da177e4SLinus Torvalds { 14651da177e4SLinus Torvalds PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); 14661da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 14671da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 14681da177e4SLinus Torvalds return -EINVAL; 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds } 14711da177e4SLinus Torvalds 14721da177e4SLinus Torvalds if (n == 0) 14731da177e4SLinus Torvalds { 14741da177e4SLinus Torvalds printk("nicstar%d: selected bandwidth < granularity.\n", card->index); 14751da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 14761da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 14771da177e4SLinus Torvalds return -EINVAL; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds if (n > (card->tst_free_entries - NS_TST_RESERVED)) 14811da177e4SLinus Torvalds { 14821da177e4SLinus Torvalds PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); 14831da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 14841da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 14851da177e4SLinus Torvalds return -EINVAL; 14861da177e4SLinus Torvalds } 14871da177e4SLinus Torvalds else 14881da177e4SLinus Torvalds card->tst_free_entries -= n; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n); 14911da177e4SLinus Torvalds for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) 14921da177e4SLinus Torvalds { 14931da177e4SLinus Torvalds if (card->scd2vc[frscdi] == NULL) 14941da177e4SLinus Torvalds { 14951da177e4SLinus Torvalds card->scd2vc[frscdi] = vc; 14961da177e4SLinus Torvalds break; 14971da177e4SLinus Torvalds } 14981da177e4SLinus Torvalds } 14991da177e4SLinus Torvalds if (frscdi == NS_FRSCD_NUM) 15001da177e4SLinus Torvalds { 15011da177e4SLinus Torvalds PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); 15021da177e4SLinus Torvalds card->tst_free_entries += n; 15031da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 15041da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 15051da177e4SLinus Torvalds return -EBUSY; 15061da177e4SLinus Torvalds } 15071da177e4SLinus Torvalds 15081da177e4SLinus Torvalds vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; 15091da177e4SLinus Torvalds 15101da177e4SLinus Torvalds scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); 1511a2c1aa54SJesper Juhl if (scq == NULL) 15121da177e4SLinus Torvalds { 15131da177e4SLinus Torvalds PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); 15141da177e4SLinus Torvalds card->scd2vc[frscdi] = NULL; 15151da177e4SLinus Torvalds card->tst_free_entries += n; 15161da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 15171da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 15181da177e4SLinus Torvalds return -ENOMEM; 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds vc->scq = scq; 15211da177e4SLinus Torvalds u32d[0] = (u32) virt_to_bus(scq->base); 15221da177e4SLinus Torvalds u32d[1] = (u32) 0x00000000; 15231da177e4SLinus Torvalds u32d[2] = (u32) 0xffffffff; 15241da177e4SLinus Torvalds u32d[3] = (u32) 0x00000000; 15251da177e4SLinus Torvalds ns_write_sram(card, vc->cbr_scd, u32d, 4); 15261da177e4SLinus Torvalds 15271da177e4SLinus Torvalds fill_tst(card, n, vc); 15281da177e4SLinus Torvalds } 15291da177e4SLinus Torvalds else if (vcc->qos.txtp.traffic_class == ATM_UBR) 15301da177e4SLinus Torvalds { 15311da177e4SLinus Torvalds vc->cbr_scd = 0x00000000; 15321da177e4SLinus Torvalds vc->scq = card->scq0; 15331da177e4SLinus Torvalds } 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class != ATM_NONE) 15361da177e4SLinus Torvalds { 15371da177e4SLinus Torvalds vc->tx = 1; 15381da177e4SLinus Torvalds vc->tx_vcc = vcc; 15391da177e4SLinus Torvalds vc->tbd_count = 0; 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds if (vcc->qos.rxtp.traffic_class != ATM_NONE) 15421da177e4SLinus Torvalds { 15431da177e4SLinus Torvalds u32 status; 15441da177e4SLinus Torvalds 15451da177e4SLinus Torvalds vc->rx = 1; 15461da177e4SLinus Torvalds vc->rx_vcc = vcc; 15471da177e4SLinus Torvalds vc->rx_iov = NULL; 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds /* Open the connection in hardware */ 15501da177e4SLinus Torvalds if (vcc->qos.aal == ATM_AAL5) 15511da177e4SLinus Torvalds status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; 15521da177e4SLinus Torvalds else /* vcc->qos.aal == ATM_AAL0 */ 15531da177e4SLinus Torvalds status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; 15541da177e4SLinus Torvalds #ifdef RCQ_SUPPORT 15551da177e4SLinus Torvalds status |= NS_RCTE_RAWCELLINTEN; 15561da177e4SLinus Torvalds #endif /* RCQ_SUPPORT */ 15571da177e4SLinus Torvalds ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) * 15581da177e4SLinus Torvalds NS_RCT_ENTRY_SIZE, &status, 1); 15591da177e4SLinus Torvalds } 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds 15631da177e4SLinus Torvalds set_bit(ATM_VF_READY,&vcc->flags); 15641da177e4SLinus Torvalds return 0; 15651da177e4SLinus Torvalds } 15661da177e4SLinus Torvalds 15671da177e4SLinus Torvalds 15681da177e4SLinus Torvalds 15691da177e4SLinus Torvalds static void ns_close(struct atm_vcc *vcc) 15701da177e4SLinus Torvalds { 15711da177e4SLinus Torvalds vc_map *vc; 15721da177e4SLinus Torvalds ns_dev *card; 15731da177e4SLinus Torvalds u32 data; 15741da177e4SLinus Torvalds int i; 15751da177e4SLinus Torvalds 15761da177e4SLinus Torvalds vc = vcc->dev_data; 15771da177e4SLinus Torvalds card = vcc->dev->dev_data; 15781da177e4SLinus Torvalds PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, 15791da177e4SLinus Torvalds (int) vcc->vpi, vcc->vci); 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds clear_bit(ATM_VF_READY,&vcc->flags); 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds if (vcc->qos.rxtp.traffic_class != ATM_NONE) 15841da177e4SLinus Torvalds { 15851da177e4SLinus Torvalds u32 addr; 15861da177e4SLinus Torvalds unsigned long flags; 15871da177e4SLinus Torvalds 15881da177e4SLinus Torvalds addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; 15891da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 15901da177e4SLinus Torvalds while(CMD_BUSY(card)); 15911da177e4SLinus Torvalds writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD); 15921da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds vc->rx = 0; 15951da177e4SLinus Torvalds if (vc->rx_iov != NULL) 15961da177e4SLinus Torvalds { 15971da177e4SLinus Torvalds struct sk_buff *iovb; 15981da177e4SLinus Torvalds u32 stat; 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds stat = readl(card->membase + STAT); 16011da177e4SLinus Torvalds card->sbfqc = ns_stat_sfbqc_get(stat); 16021da177e4SLinus Torvalds card->lbfqc = ns_stat_lfbqc_get(stat); 16031da177e4SLinus Torvalds 16041da177e4SLinus Torvalds PRINTK("nicstar%d: closing a VC with pending rx buffers.\n", 16051da177e4SLinus Torvalds card->index); 16061da177e4SLinus Torvalds iovb = vc->rx_iov; 16071da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, 16081da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt); 16091da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt = 0; 16101da177e4SLinus Torvalds NS_SKB(iovb)->vcc = NULL; 16111da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 16121da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 16131da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 16141da177e4SLinus Torvalds vc->rx_iov = NULL; 16151da177e4SLinus Torvalds } 16161da177e4SLinus Torvalds } 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class != ATM_NONE) 16191da177e4SLinus Torvalds { 16201da177e4SLinus Torvalds vc->tx = 0; 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class == ATM_CBR) 16241da177e4SLinus Torvalds { 16251da177e4SLinus Torvalds unsigned long flags; 16261da177e4SLinus Torvalds ns_scqe *scqep; 16271da177e4SLinus Torvalds scq_info *scq; 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds scq = vc->scq; 16301da177e4SLinus Torvalds 16311da177e4SLinus Torvalds for (;;) 16321da177e4SLinus Torvalds { 16331da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 16341da177e4SLinus Torvalds scqep = scq->next; 16351da177e4SLinus Torvalds if (scqep == scq->base) 16361da177e4SLinus Torvalds scqep = scq->last; 16371da177e4SLinus Torvalds else 16381da177e4SLinus Torvalds scqep--; 16391da177e4SLinus Torvalds if (scqep == scq->tail) 16401da177e4SLinus Torvalds { 16411da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 16421da177e4SLinus Torvalds break; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds /* If the last entry is not a TSR, place one in the SCQ in order to 16451da177e4SLinus Torvalds be able to completely drain it and then close. */ 16461da177e4SLinus Torvalds if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) 16471da177e4SLinus Torvalds { 16481da177e4SLinus Torvalds ns_scqe tsr; 16491da177e4SLinus Torvalds u32 scdi, scqi; 16501da177e4SLinus Torvalds u32 data; 16511da177e4SLinus Torvalds int index; 16521da177e4SLinus Torvalds 16531da177e4SLinus Torvalds tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 16541da177e4SLinus Torvalds scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 16551da177e4SLinus Torvalds scqi = scq->next - scq->base; 16561da177e4SLinus Torvalds tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 16571da177e4SLinus Torvalds tsr.word_3 = 0x00000000; 16581da177e4SLinus Torvalds tsr.word_4 = 0x00000000; 16591da177e4SLinus Torvalds *scq->next = tsr; 16601da177e4SLinus Torvalds index = (int) scqi; 16611da177e4SLinus Torvalds scq->skb[index] = NULL; 16621da177e4SLinus Torvalds if (scq->next == scq->last) 16631da177e4SLinus Torvalds scq->next = scq->base; 16641da177e4SLinus Torvalds else 16651da177e4SLinus Torvalds scq->next++; 16661da177e4SLinus Torvalds data = (u32) virt_to_bus(scq->next); 16671da177e4SLinus Torvalds ns_write_sram(card, scq->scd, &data, 1); 16681da177e4SLinus Torvalds } 16691da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 16701da177e4SLinus Torvalds schedule(); 16711da177e4SLinus Torvalds } 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds /* Free all TST entries */ 16741da177e4SLinus Torvalds data = NS_TST_OPCODE_VARIABLE; 16751da177e4SLinus Torvalds for (i = 0; i < NS_TST_NUM_ENTRIES; i++) 16761da177e4SLinus Torvalds { 16771da177e4SLinus Torvalds if (card->tste2vc[i] == vc) 16781da177e4SLinus Torvalds { 16791da177e4SLinus Torvalds ns_write_sram(card, card->tst_addr + i, &data, 1); 16801da177e4SLinus Torvalds card->tste2vc[i] = NULL; 16811da177e4SLinus Torvalds card->tst_free_entries++; 16821da177e4SLinus Torvalds } 16831da177e4SLinus Torvalds } 16841da177e4SLinus Torvalds 16851da177e4SLinus Torvalds card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; 16861da177e4SLinus Torvalds free_scq(vc->scq, vcc); 16871da177e4SLinus Torvalds } 16881da177e4SLinus Torvalds 16891da177e4SLinus Torvalds /* remove all references to vcc before deleting it */ 16901da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class != ATM_NONE) 16911da177e4SLinus Torvalds { 16921da177e4SLinus Torvalds unsigned long flags; 16931da177e4SLinus Torvalds scq_info *scq = card->scq0; 16941da177e4SLinus Torvalds 16951da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 16961da177e4SLinus Torvalds 16971da177e4SLinus Torvalds for(i = 0; i < scq->num_entries; i++) { 16981da177e4SLinus Torvalds if(scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) { 16991da177e4SLinus Torvalds ATM_SKB(scq->skb[i])->vcc = NULL; 17001da177e4SLinus Torvalds atm_return(vcc, scq->skb[i]->truesize); 17011da177e4SLinus Torvalds PRINTK("nicstar: deleted pending vcc mapping\n"); 17021da177e4SLinus Torvalds } 17031da177e4SLinus Torvalds } 17041da177e4SLinus Torvalds 17051da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 17061da177e4SLinus Torvalds } 17071da177e4SLinus Torvalds 17081da177e4SLinus Torvalds vcc->dev_data = NULL; 17091da177e4SLinus Torvalds clear_bit(ATM_VF_PARTIAL,&vcc->flags); 17101da177e4SLinus Torvalds clear_bit(ATM_VF_ADDR,&vcc->flags); 17111da177e4SLinus Torvalds 17121da177e4SLinus Torvalds #ifdef RX_DEBUG 17131da177e4SLinus Torvalds { 17141da177e4SLinus Torvalds u32 stat, cfg; 17151da177e4SLinus Torvalds stat = readl(card->membase + STAT); 17161da177e4SLinus Torvalds cfg = readl(card->membase + CFG); 17171da177e4SLinus Torvalds printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); 17181da177e4SLinus Torvalds printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n", 17191da177e4SLinus Torvalds (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last, 17201da177e4SLinus Torvalds readl(card->membase + TSQT)); 17211da177e4SLinus Torvalds printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n", 17221da177e4SLinus Torvalds (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last, 17231da177e4SLinus Torvalds readl(card->membase + RSQT)); 17241da177e4SLinus Torvalds printk("Empty free buffer queue interrupt %s \n", 17251da177e4SLinus Torvalds card->efbie ? "enabled" : "disabled"); 17261da177e4SLinus Torvalds printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", 17271da177e4SLinus Torvalds ns_stat_sfbqc_get(stat), card->sbpool.count, 17281da177e4SLinus Torvalds ns_stat_lfbqc_get(stat), card->lbpool.count); 17291da177e4SLinus Torvalds printk("hbpool.count = %d iovpool.count = %d \n", 17301da177e4SLinus Torvalds card->hbpool.count, card->iovpool.count); 17311da177e4SLinus Torvalds } 17321da177e4SLinus Torvalds #endif /* RX_DEBUG */ 17331da177e4SLinus Torvalds } 17341da177e4SLinus Torvalds 17351da177e4SLinus Torvalds 17361da177e4SLinus Torvalds 17371da177e4SLinus Torvalds static void fill_tst(ns_dev *card, int n, vc_map *vc) 17381da177e4SLinus Torvalds { 17391da177e4SLinus Torvalds u32 new_tst; 17401da177e4SLinus Torvalds unsigned long cl; 17411da177e4SLinus Torvalds int e, r; 17421da177e4SLinus Torvalds u32 data; 17431da177e4SLinus Torvalds 17441da177e4SLinus Torvalds /* It would be very complicated to keep the two TSTs synchronized while 17451da177e4SLinus Torvalds assuring that writes are only made to the inactive TST. So, for now I 17461da177e4SLinus Torvalds will use only one TST. If problems occur, I will change this again */ 17471da177e4SLinus Torvalds 17481da177e4SLinus Torvalds new_tst = card->tst_addr; 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds /* Fill procedure */ 17511da177e4SLinus Torvalds 17521da177e4SLinus Torvalds for (e = 0; e < NS_TST_NUM_ENTRIES; e++) 17531da177e4SLinus Torvalds { 17541da177e4SLinus Torvalds if (card->tste2vc[e] == NULL) 17551da177e4SLinus Torvalds break; 17561da177e4SLinus Torvalds } 17571da177e4SLinus Torvalds if (e == NS_TST_NUM_ENTRIES) { 17581da177e4SLinus Torvalds printk("nicstar%d: No free TST entries found. \n", card->index); 17591da177e4SLinus Torvalds return; 17601da177e4SLinus Torvalds } 17611da177e4SLinus Torvalds 17621da177e4SLinus Torvalds r = n; 17631da177e4SLinus Torvalds cl = NS_TST_NUM_ENTRIES; 17641da177e4SLinus Torvalds data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds while (r > 0) 17671da177e4SLinus Torvalds { 17681da177e4SLinus Torvalds if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) 17691da177e4SLinus Torvalds { 17701da177e4SLinus Torvalds card->tste2vc[e] = vc; 17711da177e4SLinus Torvalds ns_write_sram(card, new_tst + e, &data, 1); 17721da177e4SLinus Torvalds cl -= NS_TST_NUM_ENTRIES; 17731da177e4SLinus Torvalds r--; 17741da177e4SLinus Torvalds } 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds if (++e == NS_TST_NUM_ENTRIES) { 17771da177e4SLinus Torvalds e = 0; 17781da177e4SLinus Torvalds } 17791da177e4SLinus Torvalds cl += n; 17801da177e4SLinus Torvalds } 17811da177e4SLinus Torvalds 17821da177e4SLinus Torvalds /* End of fill procedure */ 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds data = ns_tste_make(NS_TST_OPCODE_END, new_tst); 17851da177e4SLinus Torvalds ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); 17861da177e4SLinus Torvalds ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); 17871da177e4SLinus Torvalds card->tst_addr = new_tst; 17881da177e4SLinus Torvalds } 17891da177e4SLinus Torvalds 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) 17931da177e4SLinus Torvalds { 17941da177e4SLinus Torvalds ns_dev *card; 17951da177e4SLinus Torvalds vc_map *vc; 17961da177e4SLinus Torvalds scq_info *scq; 17971da177e4SLinus Torvalds unsigned long buflen; 17981da177e4SLinus Torvalds ns_scqe scqe; 17991da177e4SLinus Torvalds u32 flags; /* TBD flags, not CPU flags */ 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds card = vcc->dev->dev_data; 18021da177e4SLinus Torvalds TXPRINTK("nicstar%d: ns_send() called.\n", card->index); 18031da177e4SLinus Torvalds if ((vc = (vc_map *) vcc->dev_data) == NULL) 18041da177e4SLinus Torvalds { 18051da177e4SLinus Torvalds printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); 18061da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx_err); 18071da177e4SLinus Torvalds dev_kfree_skb_any(skb); 18081da177e4SLinus Torvalds return -EINVAL; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds if (!vc->tx) 18121da177e4SLinus Torvalds { 18131da177e4SLinus Torvalds printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); 18141da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx_err); 18151da177e4SLinus Torvalds dev_kfree_skb_any(skb); 18161da177e4SLinus Torvalds return -EINVAL; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) 18201da177e4SLinus Torvalds { 18211da177e4SLinus Torvalds printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); 18221da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx_err); 18231da177e4SLinus Torvalds dev_kfree_skb_any(skb); 18241da177e4SLinus Torvalds return -EINVAL; 18251da177e4SLinus Torvalds } 18261da177e4SLinus Torvalds 18271da177e4SLinus Torvalds if (skb_shinfo(skb)->nr_frags != 0) 18281da177e4SLinus Torvalds { 18291da177e4SLinus Torvalds printk("nicstar%d: No scatter-gather yet.\n", card->index); 18301da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx_err); 18311da177e4SLinus Torvalds dev_kfree_skb_any(skb); 18321da177e4SLinus Torvalds return -EINVAL; 18331da177e4SLinus Torvalds } 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds ATM_SKB(skb)->vcc = vcc; 18361da177e4SLinus Torvalds 18371da177e4SLinus Torvalds if (vcc->qos.aal == ATM_AAL5) 18381da177e4SLinus Torvalds { 18391da177e4SLinus Torvalds buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ 18401da177e4SLinus Torvalds flags = NS_TBD_AAL5; 18411da177e4SLinus Torvalds scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data)); 18421da177e4SLinus Torvalds scqe.word_3 = cpu_to_le32((u32) skb->len); 18431da177e4SLinus Torvalds scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, 18441da177e4SLinus Torvalds ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0); 18451da177e4SLinus Torvalds flags |= NS_TBD_EOPDU; 18461da177e4SLinus Torvalds } 18471da177e4SLinus Torvalds else /* (vcc->qos.aal == ATM_AAL0) */ 18481da177e4SLinus Torvalds { 18491da177e4SLinus Torvalds buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ 18501da177e4SLinus Torvalds flags = NS_TBD_AAL0; 18511da177e4SLinus Torvalds scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER); 18521da177e4SLinus Torvalds scqe.word_3 = cpu_to_le32(0x00000000); 18531da177e4SLinus Torvalds if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ 18541da177e4SLinus Torvalds flags |= NS_TBD_EOPDU; 18551da177e4SLinus Torvalds scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); 18561da177e4SLinus Torvalds /* Force the VPI/VCI to be the same as in VCC struct */ 18571da177e4SLinus Torvalds scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | 18581da177e4SLinus Torvalds ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & 18591da177e4SLinus Torvalds NS_TBD_VC_MASK); 18601da177e4SLinus Torvalds } 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds if (vcc->qos.txtp.traffic_class == ATM_CBR) 18631da177e4SLinus Torvalds { 18641da177e4SLinus Torvalds scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); 18651da177e4SLinus Torvalds scq = ((vc_map *) vcc->dev_data)->scq; 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds else 18681da177e4SLinus Torvalds { 18691da177e4SLinus Torvalds scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); 18701da177e4SLinus Torvalds scq = card->scq0; 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds 18731da177e4SLinus Torvalds if (push_scqe(card, vc, scq, &scqe, skb) != 0) 18741da177e4SLinus Torvalds { 18751da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx_err); 18761da177e4SLinus Torvalds dev_kfree_skb_any(skb); 18771da177e4SLinus Torvalds return -EIO; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds atomic_inc(&vcc->stats->tx); 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds return 0; 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds 18851da177e4SLinus Torvalds 18861da177e4SLinus Torvalds static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, 18871da177e4SLinus Torvalds struct sk_buff *skb) 18881da177e4SLinus Torvalds { 18891da177e4SLinus Torvalds unsigned long flags; 18901da177e4SLinus Torvalds ns_scqe tsr; 18911da177e4SLinus Torvalds u32 scdi, scqi; 18921da177e4SLinus Torvalds int scq_is_vbr; 18931da177e4SLinus Torvalds u32 data; 18941da177e4SLinus Torvalds int index; 18951da177e4SLinus Torvalds 18961da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 18971da177e4SLinus Torvalds while (scq->tail == scq->next) 18981da177e4SLinus Torvalds { 18991da177e4SLinus Torvalds if (in_interrupt()) { 19001da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19011da177e4SLinus Torvalds printk("nicstar%d: Error pushing TBD.\n", card->index); 19021da177e4SLinus Torvalds return 1; 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds scq->full = 1; 19061da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19071da177e4SLinus Torvalds interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); 19081da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 19091da177e4SLinus Torvalds 19101da177e4SLinus Torvalds if (scq->full) { 19111da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19121da177e4SLinus Torvalds printk("nicstar%d: Timeout pushing TBD.\n", card->index); 19131da177e4SLinus Torvalds return 1; 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds *scq->next = *tbd; 19171da177e4SLinus Torvalds index = (int) (scq->next - scq->base); 19181da177e4SLinus Torvalds scq->skb[index] = skb; 19191da177e4SLinus Torvalds XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n", 19201da177e4SLinus Torvalds card->index, (u32) skb, index); 19211da177e4SLinus Torvalds XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", 19221da177e4SLinus Torvalds card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), 19231da177e4SLinus Torvalds le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), 19241da177e4SLinus Torvalds (u32) scq->next); 19251da177e4SLinus Torvalds if (scq->next == scq->last) 19261da177e4SLinus Torvalds scq->next = scq->base; 19271da177e4SLinus Torvalds else 19281da177e4SLinus Torvalds scq->next++; 19291da177e4SLinus Torvalds 19301da177e4SLinus Torvalds vc->tbd_count++; 19311da177e4SLinus Torvalds if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) 19321da177e4SLinus Torvalds { 19331da177e4SLinus Torvalds scq->tbd_count++; 19341da177e4SLinus Torvalds scq_is_vbr = 1; 19351da177e4SLinus Torvalds } 19361da177e4SLinus Torvalds else 19371da177e4SLinus Torvalds scq_is_vbr = 0; 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ) 19401da177e4SLinus Torvalds { 19411da177e4SLinus Torvalds int has_run = 0; 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds while (scq->tail == scq->next) 19441da177e4SLinus Torvalds { 19451da177e4SLinus Torvalds if (in_interrupt()) { 19461da177e4SLinus Torvalds data = (u32) virt_to_bus(scq->next); 19471da177e4SLinus Torvalds ns_write_sram(card, scq->scd, &data, 1); 19481da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19491da177e4SLinus Torvalds printk("nicstar%d: Error pushing TSR.\n", card->index); 19501da177e4SLinus Torvalds return 0; 19511da177e4SLinus Torvalds } 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds scq->full = 1; 19541da177e4SLinus Torvalds if (has_run++) break; 19551da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19561da177e4SLinus Torvalds interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); 19571da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds if (!scq->full) 19611da177e4SLinus Torvalds { 19621da177e4SLinus Torvalds tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); 19631da177e4SLinus Torvalds if (scq_is_vbr) 19641da177e4SLinus Torvalds scdi = NS_TSR_SCDISVBR; 19651da177e4SLinus Torvalds else 19661da177e4SLinus Torvalds scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; 19671da177e4SLinus Torvalds scqi = scq->next - scq->base; 19681da177e4SLinus Torvalds tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); 19691da177e4SLinus Torvalds tsr.word_3 = 0x00000000; 19701da177e4SLinus Torvalds tsr.word_4 = 0x00000000; 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds *scq->next = tsr; 19731da177e4SLinus Torvalds index = (int) scqi; 19741da177e4SLinus Torvalds scq->skb[index] = NULL; 19751da177e4SLinus Torvalds XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", 19761da177e4SLinus Torvalds card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2), 19771da177e4SLinus Torvalds le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4), 19781da177e4SLinus Torvalds (u32) scq->next); 19791da177e4SLinus Torvalds if (scq->next == scq->last) 19801da177e4SLinus Torvalds scq->next = scq->base; 19811da177e4SLinus Torvalds else 19821da177e4SLinus Torvalds scq->next++; 19831da177e4SLinus Torvalds vc->tbd_count = 0; 19841da177e4SLinus Torvalds scq->tbd_count = 0; 19851da177e4SLinus Torvalds } 19861da177e4SLinus Torvalds else 19871da177e4SLinus Torvalds PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index); 19881da177e4SLinus Torvalds } 19891da177e4SLinus Torvalds data = (u32) virt_to_bus(scq->next); 19901da177e4SLinus Torvalds ns_write_sram(card, scq->scd, &data, 1); 19911da177e4SLinus Torvalds 19921da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds return 0; 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds 19971da177e4SLinus Torvalds 19981da177e4SLinus Torvalds 19991da177e4SLinus Torvalds static void process_tsq(ns_dev *card) 20001da177e4SLinus Torvalds { 20011da177e4SLinus Torvalds u32 scdi; 20021da177e4SLinus Torvalds scq_info *scq; 20031da177e4SLinus Torvalds ns_tsi *previous = NULL, *one_ahead, *two_ahead; 20041da177e4SLinus Torvalds int serviced_entries; /* flag indicating at least on entry was serviced */ 20051da177e4SLinus Torvalds 20061da177e4SLinus Torvalds serviced_entries = 0; 20071da177e4SLinus Torvalds 20081da177e4SLinus Torvalds if (card->tsq.next == card->tsq.last) 20091da177e4SLinus Torvalds one_ahead = card->tsq.base; 20101da177e4SLinus Torvalds else 20111da177e4SLinus Torvalds one_ahead = card->tsq.next + 1; 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds if (one_ahead == card->tsq.last) 20141da177e4SLinus Torvalds two_ahead = card->tsq.base; 20151da177e4SLinus Torvalds else 20161da177e4SLinus Torvalds two_ahead = one_ahead + 1; 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || 20191da177e4SLinus Torvalds !ns_tsi_isempty(two_ahead)) 20201da177e4SLinus Torvalds /* At most two empty, as stated in the 77201 errata */ 20211da177e4SLinus Torvalds { 20221da177e4SLinus Torvalds serviced_entries = 1; 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds /* Skip the one or two possible empty entries */ 20251da177e4SLinus Torvalds while (ns_tsi_isempty(card->tsq.next)) { 20261da177e4SLinus Torvalds if (card->tsq.next == card->tsq.last) 20271da177e4SLinus Torvalds card->tsq.next = card->tsq.base; 20281da177e4SLinus Torvalds else 20291da177e4SLinus Torvalds card->tsq.next++; 20301da177e4SLinus Torvalds } 20311da177e4SLinus Torvalds 20321da177e4SLinus Torvalds if (!ns_tsi_tmrof(card->tsq.next)) 20331da177e4SLinus Torvalds { 20341da177e4SLinus Torvalds scdi = ns_tsi_getscdindex(card->tsq.next); 20351da177e4SLinus Torvalds if (scdi == NS_TSI_SCDISVBR) 20361da177e4SLinus Torvalds scq = card->scq0; 20371da177e4SLinus Torvalds else 20381da177e4SLinus Torvalds { 20391da177e4SLinus Torvalds if (card->scd2vc[scdi] == NULL) 20401da177e4SLinus Torvalds { 20411da177e4SLinus Torvalds printk("nicstar%d: could not find VC from SCD index.\n", 20421da177e4SLinus Torvalds card->index); 20431da177e4SLinus Torvalds ns_tsi_init(card->tsq.next); 20441da177e4SLinus Torvalds return; 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds scq = card->scd2vc[scdi]->scq; 20471da177e4SLinus Torvalds } 20481da177e4SLinus Torvalds drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); 20491da177e4SLinus Torvalds scq->full = 0; 20501da177e4SLinus Torvalds wake_up_interruptible(&(scq->scqfull_waitq)); 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds ns_tsi_init(card->tsq.next); 20541da177e4SLinus Torvalds previous = card->tsq.next; 20551da177e4SLinus Torvalds if (card->tsq.next == card->tsq.last) 20561da177e4SLinus Torvalds card->tsq.next = card->tsq.base; 20571da177e4SLinus Torvalds else 20581da177e4SLinus Torvalds card->tsq.next++; 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds if (card->tsq.next == card->tsq.last) 20611da177e4SLinus Torvalds one_ahead = card->tsq.base; 20621da177e4SLinus Torvalds else 20631da177e4SLinus Torvalds one_ahead = card->tsq.next + 1; 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds if (one_ahead == card->tsq.last) 20661da177e4SLinus Torvalds two_ahead = card->tsq.base; 20671da177e4SLinus Torvalds else 20681da177e4SLinus Torvalds two_ahead = one_ahead + 1; 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds if (serviced_entries) { 20721da177e4SLinus Torvalds writel((((u32) previous) - ((u32) card->tsq.base)), 20731da177e4SLinus Torvalds card->membase + TSQH); 20741da177e4SLinus Torvalds } 20751da177e4SLinus Torvalds } 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds 20781da177e4SLinus Torvalds 20791da177e4SLinus Torvalds static void drain_scq(ns_dev *card, scq_info *scq, int pos) 20801da177e4SLinus Torvalds { 20811da177e4SLinus Torvalds struct atm_vcc *vcc; 20821da177e4SLinus Torvalds struct sk_buff *skb; 20831da177e4SLinus Torvalds int i; 20841da177e4SLinus Torvalds unsigned long flags; 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n", 20871da177e4SLinus Torvalds card->index, (u32) scq, pos); 20881da177e4SLinus Torvalds if (pos >= scq->num_entries) 20891da177e4SLinus Torvalds { 20901da177e4SLinus Torvalds printk("nicstar%d: Bad index on drain_scq().\n", card->index); 20911da177e4SLinus Torvalds return; 20921da177e4SLinus Torvalds } 20931da177e4SLinus Torvalds 20941da177e4SLinus Torvalds ns_grab_scq_lock(card, scq, flags); 20951da177e4SLinus Torvalds i = (int) (scq->tail - scq->base); 20961da177e4SLinus Torvalds if (++i == scq->num_entries) 20971da177e4SLinus Torvalds i = 0; 20981da177e4SLinus Torvalds while (i != pos) 20991da177e4SLinus Torvalds { 21001da177e4SLinus Torvalds skb = scq->skb[i]; 21011da177e4SLinus Torvalds XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n", 21021da177e4SLinus Torvalds card->index, (u32) skb, i); 21031da177e4SLinus Torvalds if (skb != NULL) 21041da177e4SLinus Torvalds { 21051da177e4SLinus Torvalds vcc = ATM_SKB(skb)->vcc; 21061da177e4SLinus Torvalds if (vcc && vcc->pop != NULL) { 21071da177e4SLinus Torvalds vcc->pop(vcc, skb); 21081da177e4SLinus Torvalds } else { 21091da177e4SLinus Torvalds dev_kfree_skb_irq(skb); 21101da177e4SLinus Torvalds } 21111da177e4SLinus Torvalds scq->skb[i] = NULL; 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds if (++i == scq->num_entries) 21141da177e4SLinus Torvalds i = 0; 21151da177e4SLinus Torvalds } 21161da177e4SLinus Torvalds scq->tail = scq->base + pos; 21171da177e4SLinus Torvalds spin_unlock_irqrestore(&scq->lock, flags); 21181da177e4SLinus Torvalds } 21191da177e4SLinus Torvalds 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds 21221da177e4SLinus Torvalds static void process_rsq(ns_dev *card) 21231da177e4SLinus Torvalds { 21241da177e4SLinus Torvalds ns_rsqe *previous; 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds if (!ns_rsqe_valid(card->rsq.next)) 21271da177e4SLinus Torvalds return; 21282087ff3eSDavid Howells do { 21291da177e4SLinus Torvalds dequeue_rx(card, card->rsq.next); 21301da177e4SLinus Torvalds ns_rsqe_init(card->rsq.next); 21311da177e4SLinus Torvalds previous = card->rsq.next; 21321da177e4SLinus Torvalds if (card->rsq.next == card->rsq.last) 21331da177e4SLinus Torvalds card->rsq.next = card->rsq.base; 21341da177e4SLinus Torvalds else 21351da177e4SLinus Torvalds card->rsq.next++; 21362087ff3eSDavid Howells } while (ns_rsqe_valid(card->rsq.next)); 21371da177e4SLinus Torvalds writel((((u32) previous) - ((u32) card->rsq.base)), 21381da177e4SLinus Torvalds card->membase + RSQH); 21391da177e4SLinus Torvalds } 21401da177e4SLinus Torvalds 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds 21431da177e4SLinus Torvalds static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) 21441da177e4SLinus Torvalds { 21451da177e4SLinus Torvalds u32 vpi, vci; 21461da177e4SLinus Torvalds vc_map *vc; 21471da177e4SLinus Torvalds struct sk_buff *iovb; 21481da177e4SLinus Torvalds struct iovec *iov; 21491da177e4SLinus Torvalds struct atm_vcc *vcc; 21501da177e4SLinus Torvalds struct sk_buff *skb; 21511da177e4SLinus Torvalds unsigned short aal5_len; 21521da177e4SLinus Torvalds int len; 21531da177e4SLinus Torvalds u32 stat; 21541da177e4SLinus Torvalds 21551da177e4SLinus Torvalds stat = readl(card->membase + STAT); 21561da177e4SLinus Torvalds card->sbfqc = ns_stat_sfbqc_get(stat); 21571da177e4SLinus Torvalds card->lbfqc = ns_stat_lfbqc_get(stat); 21581da177e4SLinus Torvalds 21591da177e4SLinus Torvalds skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle); 21601da177e4SLinus Torvalds vpi = ns_rsqe_vpi(rsqe); 21611da177e4SLinus Torvalds vci = ns_rsqe_vci(rsqe); 21621da177e4SLinus Torvalds if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) 21631da177e4SLinus Torvalds { 21641da177e4SLinus Torvalds printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", 21651da177e4SLinus Torvalds card->index, vpi, vci); 21661da177e4SLinus Torvalds recycle_rx_buf(card, skb); 21671da177e4SLinus Torvalds return; 21681da177e4SLinus Torvalds } 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds vc = &(card->vcmap[vpi << card->vcibits | vci]); 21711da177e4SLinus Torvalds if (!vc->rx) 21721da177e4SLinus Torvalds { 21731da177e4SLinus Torvalds RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", 21741da177e4SLinus Torvalds card->index, vpi, vci); 21751da177e4SLinus Torvalds recycle_rx_buf(card, skb); 21761da177e4SLinus Torvalds return; 21771da177e4SLinus Torvalds } 21781da177e4SLinus Torvalds 21791da177e4SLinus Torvalds vcc = vc->rx_vcc; 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds if (vcc->qos.aal == ATM_AAL0) 21821da177e4SLinus Torvalds { 21831da177e4SLinus Torvalds struct sk_buff *sb; 21841da177e4SLinus Torvalds unsigned char *cell; 21851da177e4SLinus Torvalds int i; 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds cell = skb->data; 21881da177e4SLinus Torvalds for (i = ns_rsqe_cellcount(rsqe); i; i--) 21891da177e4SLinus Torvalds { 21901da177e4SLinus Torvalds if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL) 21911da177e4SLinus Torvalds { 21921da177e4SLinus Torvalds printk("nicstar%d: Can't allocate buffers for aal0.\n", 21931da177e4SLinus Torvalds card->index); 21941da177e4SLinus Torvalds atomic_add(i,&vcc->stats->rx_drop); 21951da177e4SLinus Torvalds break; 21961da177e4SLinus Torvalds } 21971da177e4SLinus Torvalds if (!atm_charge(vcc, sb->truesize)) 21981da177e4SLinus Torvalds { 21991da177e4SLinus Torvalds RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n", 22001da177e4SLinus Torvalds card->index); 22011da177e4SLinus Torvalds atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */ 22021da177e4SLinus Torvalds dev_kfree_skb_any(sb); 22031da177e4SLinus Torvalds break; 22041da177e4SLinus Torvalds } 22051da177e4SLinus Torvalds /* Rebuild the header */ 22061da177e4SLinus Torvalds *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 | 22071da177e4SLinus Torvalds (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); 22081da177e4SLinus Torvalds if (i == 1 && ns_rsqe_eopdu(rsqe)) 22091da177e4SLinus Torvalds *((u32 *) sb->data) |= 0x00000002; 22101da177e4SLinus Torvalds skb_put(sb, NS_AAL0_HEADER); 22111da177e4SLinus Torvalds memcpy(sb->tail, cell, ATM_CELL_PAYLOAD); 22121da177e4SLinus Torvalds skb_put(sb, ATM_CELL_PAYLOAD); 22131da177e4SLinus Torvalds ATM_SKB(sb)->vcc = vcc; 2214a61bbcf2SPatrick McHardy __net_timestamp(sb); 22151da177e4SLinus Torvalds vcc->push(vcc, sb); 22161da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx); 22171da177e4SLinus Torvalds cell += ATM_CELL_PAYLOAD; 22181da177e4SLinus Torvalds } 22191da177e4SLinus Torvalds 22201da177e4SLinus Torvalds recycle_rx_buf(card, skb); 22211da177e4SLinus Torvalds return; 22221da177e4SLinus Torvalds } 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds /* To reach this point, the AAL layer can only be AAL5 */ 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds if ((iovb = vc->rx_iov) == NULL) 22271da177e4SLinus Torvalds { 22281da177e4SLinus Torvalds iovb = skb_dequeue(&(card->iovpool.queue)); 22291da177e4SLinus Torvalds if (iovb == NULL) /* No buffers in the queue */ 22301da177e4SLinus Torvalds { 22311da177e4SLinus Torvalds iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); 22321da177e4SLinus Torvalds if (iovb == NULL) 22331da177e4SLinus Torvalds { 22341da177e4SLinus Torvalds printk("nicstar%d: Out of iovec buffers.\n", card->index); 22351da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 22361da177e4SLinus Torvalds recycle_rx_buf(card, skb); 22371da177e4SLinus Torvalds return; 22381da177e4SLinus Torvalds } 22398728b834SDavid S. Miller NS_SKB_CB(iovb)->buf_type = BUF_NONE; 22401da177e4SLinus Torvalds } 22411da177e4SLinus Torvalds else 22421da177e4SLinus Torvalds if (--card->iovpool.count < card->iovnr.min) 22431da177e4SLinus Torvalds { 22441da177e4SLinus Torvalds struct sk_buff *new_iovb; 22451da177e4SLinus Torvalds if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) 22461da177e4SLinus Torvalds { 22478728b834SDavid S. Miller NS_SKB_CB(iovb)->buf_type = BUF_NONE; 22481da177e4SLinus Torvalds skb_queue_tail(&card->iovpool.queue, new_iovb); 22491da177e4SLinus Torvalds card->iovpool.count++; 22501da177e4SLinus Torvalds } 22511da177e4SLinus Torvalds } 22521da177e4SLinus Torvalds vc->rx_iov = iovb; 22531da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt = 0; 22541da177e4SLinus Torvalds iovb->len = 0; 22551da177e4SLinus Torvalds iovb->tail = iovb->data = iovb->head; 22561da177e4SLinus Torvalds NS_SKB(iovb)->vcc = vcc; 22571da177e4SLinus Torvalds /* IMPORTANT: a pointer to the sk_buff containing the small or large 22581da177e4SLinus Torvalds buffer is stored as iovec base, NOT a pointer to the 22591da177e4SLinus Torvalds small or large buffer itself. */ 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) 22621da177e4SLinus Torvalds { 22631da177e4SLinus Torvalds printk("nicstar%d: received too big AAL5 SDU.\n", card->index); 22641da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_err); 22651da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); 22661da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt = 0; 22671da177e4SLinus Torvalds iovb->len = 0; 22681da177e4SLinus Torvalds iovb->tail = iovb->data = iovb->head; 22691da177e4SLinus Torvalds NS_SKB(iovb)->vcc = vcc; 22701da177e4SLinus Torvalds } 22711da177e4SLinus Torvalds iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++]; 22721da177e4SLinus Torvalds iov->iov_base = (void *) skb; 22731da177e4SLinus Torvalds iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; 22741da177e4SLinus Torvalds iovb->len += iov->iov_len; 22751da177e4SLinus Torvalds 22761da177e4SLinus Torvalds if (NS_SKB(iovb)->iovcnt == 1) 22771da177e4SLinus Torvalds { 22788728b834SDavid S. Miller if (NS_SKB_CB(skb)->buf_type != BUF_SM) 22791da177e4SLinus Torvalds { 22801da177e4SLinus Torvalds printk("nicstar%d: Expected a small buffer, and this is not one.\n", 22811da177e4SLinus Torvalds card->index); 22821da177e4SLinus Torvalds which_list(card, skb); 22831da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_err); 22841da177e4SLinus Torvalds recycle_rx_buf(card, skb); 22851da177e4SLinus Torvalds vc->rx_iov = NULL; 22861da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 22871da177e4SLinus Torvalds return; 22881da177e4SLinus Torvalds } 22891da177e4SLinus Torvalds } 22901da177e4SLinus Torvalds else /* NS_SKB(iovb)->iovcnt >= 2 */ 22911da177e4SLinus Torvalds { 22928728b834SDavid S. Miller if (NS_SKB_CB(skb)->buf_type != BUF_LG) 22931da177e4SLinus Torvalds { 22941da177e4SLinus Torvalds printk("nicstar%d: Expected a large buffer, and this is not one.\n", 22951da177e4SLinus Torvalds card->index); 22961da177e4SLinus Torvalds which_list(card, skb); 22971da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_err); 22981da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, 22991da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt); 23001da177e4SLinus Torvalds vc->rx_iov = NULL; 23011da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 23021da177e4SLinus Torvalds return; 23031da177e4SLinus Torvalds } 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds if (ns_rsqe_eopdu(rsqe)) 23071da177e4SLinus Torvalds { 23081da177e4SLinus Torvalds /* This works correctly regardless of the endianness of the host */ 23091da177e4SLinus Torvalds unsigned char *L1L2 = (unsigned char *)((u32)skb->data + 23101da177e4SLinus Torvalds iov->iov_len - 6); 23111da177e4SLinus Torvalds aal5_len = L1L2[0] << 8 | L1L2[1]; 23121da177e4SLinus Torvalds len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; 23131da177e4SLinus Torvalds if (ns_rsqe_crcerr(rsqe) || 23141da177e4SLinus Torvalds len + 8 > iovb->len || len + (47 + 8) < iovb->len) 23151da177e4SLinus Torvalds { 23161da177e4SLinus Torvalds printk("nicstar%d: AAL5 CRC error", card->index); 23171da177e4SLinus Torvalds if (len + 8 > iovb->len || len + (47 + 8) < iovb->len) 23181da177e4SLinus Torvalds printk(" - PDU size mismatch.\n"); 23191da177e4SLinus Torvalds else 23201da177e4SLinus Torvalds printk(".\n"); 23211da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_err); 23221da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, 23231da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt); 23241da177e4SLinus Torvalds vc->rx_iov = NULL; 23251da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 23261da177e4SLinus Torvalds return; 23271da177e4SLinus Torvalds } 23281da177e4SLinus Torvalds 23291da177e4SLinus Torvalds /* By this point we (hopefully) have a complete SDU without errors. */ 23301da177e4SLinus Torvalds 23311da177e4SLinus Torvalds if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ 23321da177e4SLinus Torvalds { 23331da177e4SLinus Torvalds /* skb points to a small buffer */ 23341da177e4SLinus Torvalds if (!atm_charge(vcc, skb->truesize)) 23351da177e4SLinus Torvalds { 23368728b834SDavid S. Miller push_rxbufs(card, skb); 23371da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds else 23401da177e4SLinus Torvalds { 23411da177e4SLinus Torvalds skb_put(skb, len); 23421da177e4SLinus Torvalds dequeue_sm_buf(card, skb); 23431da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 23441da177e4SLinus Torvalds skb->destructor = ns_sb_destructor; 23451da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 23461da177e4SLinus Torvalds ATM_SKB(skb)->vcc = vcc; 2347a61bbcf2SPatrick McHardy __net_timestamp(skb); 23481da177e4SLinus Torvalds vcc->push(vcc, skb); 23491da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx); 23501da177e4SLinus Torvalds } 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ 23531da177e4SLinus Torvalds { 23541da177e4SLinus Torvalds struct sk_buff *sb; 23551da177e4SLinus Torvalds 23561da177e4SLinus Torvalds sb = (struct sk_buff *) (iov - 1)->iov_base; 23571da177e4SLinus Torvalds /* skb points to a large buffer */ 23581da177e4SLinus Torvalds 23591da177e4SLinus Torvalds if (len <= NS_SMBUFSIZE) 23601da177e4SLinus Torvalds { 23611da177e4SLinus Torvalds if (!atm_charge(vcc, sb->truesize)) 23621da177e4SLinus Torvalds { 23638728b834SDavid S. Miller push_rxbufs(card, sb); 23641da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 23651da177e4SLinus Torvalds } 23661da177e4SLinus Torvalds else 23671da177e4SLinus Torvalds { 23681da177e4SLinus Torvalds skb_put(sb, len); 23691da177e4SLinus Torvalds dequeue_sm_buf(card, sb); 23701da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 23711da177e4SLinus Torvalds sb->destructor = ns_sb_destructor; 23721da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 23731da177e4SLinus Torvalds ATM_SKB(sb)->vcc = vcc; 2374a61bbcf2SPatrick McHardy __net_timestamp(sb); 23751da177e4SLinus Torvalds vcc->push(vcc, sb); 23761da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx); 23771da177e4SLinus Torvalds } 23781da177e4SLinus Torvalds 23798728b834SDavid S. Miller push_rxbufs(card, skb); 23801da177e4SLinus Torvalds 23811da177e4SLinus Torvalds } 23821da177e4SLinus Torvalds else /* len > NS_SMBUFSIZE, the usual case */ 23831da177e4SLinus Torvalds { 23841da177e4SLinus Torvalds if (!atm_charge(vcc, skb->truesize)) 23851da177e4SLinus Torvalds { 23868728b834SDavid S. Miller push_rxbufs(card, skb); 23871da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds else 23901da177e4SLinus Torvalds { 23911da177e4SLinus Torvalds dequeue_lg_buf(card, skb); 23921da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 23931da177e4SLinus Torvalds skb->destructor = ns_lb_destructor; 23941da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 23951da177e4SLinus Torvalds skb_push(skb, NS_SMBUFSIZE); 23961da177e4SLinus Torvalds memcpy(skb->data, sb->data, NS_SMBUFSIZE); 23971da177e4SLinus Torvalds skb_put(skb, len - NS_SMBUFSIZE); 23981da177e4SLinus Torvalds ATM_SKB(skb)->vcc = vcc; 2399a61bbcf2SPatrick McHardy __net_timestamp(skb); 24001da177e4SLinus Torvalds vcc->push(vcc, skb); 24011da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx); 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds 24048728b834SDavid S. Miller push_rxbufs(card, sb); 24051da177e4SLinus Torvalds 24061da177e4SLinus Torvalds } 24071da177e4SLinus Torvalds 24081da177e4SLinus Torvalds } 24091da177e4SLinus Torvalds else /* Must push a huge buffer */ 24101da177e4SLinus Torvalds { 24111da177e4SLinus Torvalds struct sk_buff *hb, *sb, *lb; 24121da177e4SLinus Torvalds int remaining, tocopy; 24131da177e4SLinus Torvalds int j; 24141da177e4SLinus Torvalds 24151da177e4SLinus Torvalds hb = skb_dequeue(&(card->hbpool.queue)); 24161da177e4SLinus Torvalds if (hb == NULL) /* No buffers in the queue */ 24171da177e4SLinus Torvalds { 24181da177e4SLinus Torvalds 24191da177e4SLinus Torvalds hb = dev_alloc_skb(NS_HBUFSIZE); 24201da177e4SLinus Torvalds if (hb == NULL) 24211da177e4SLinus Torvalds { 24221da177e4SLinus Torvalds printk("nicstar%d: Out of huge buffers.\n", card->index); 24231da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 24241da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, 24251da177e4SLinus Torvalds NS_SKB(iovb)->iovcnt); 24261da177e4SLinus Torvalds vc->rx_iov = NULL; 24271da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 24281da177e4SLinus Torvalds return; 24291da177e4SLinus Torvalds } 24301da177e4SLinus Torvalds else if (card->hbpool.count < card->hbnr.min) 24311da177e4SLinus Torvalds { 24321da177e4SLinus Torvalds struct sk_buff *new_hb; 24331da177e4SLinus Torvalds if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) 24341da177e4SLinus Torvalds { 24351da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, new_hb); 24361da177e4SLinus Torvalds card->hbpool.count++; 24371da177e4SLinus Torvalds } 24381da177e4SLinus Torvalds } 24398728b834SDavid S. Miller NS_SKB_CB(hb)->buf_type = BUF_NONE; 24401da177e4SLinus Torvalds } 24411da177e4SLinus Torvalds else 24421da177e4SLinus Torvalds if (--card->hbpool.count < card->hbnr.min) 24431da177e4SLinus Torvalds { 24441da177e4SLinus Torvalds struct sk_buff *new_hb; 24451da177e4SLinus Torvalds if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) 24461da177e4SLinus Torvalds { 24478728b834SDavid S. Miller NS_SKB_CB(new_hb)->buf_type = BUF_NONE; 24481da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, new_hb); 24491da177e4SLinus Torvalds card->hbpool.count++; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds if (card->hbpool.count < card->hbnr.min) 24521da177e4SLinus Torvalds { 24531da177e4SLinus Torvalds if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) 24541da177e4SLinus Torvalds { 24558728b834SDavid S. Miller NS_SKB_CB(new_hb)->buf_type = BUF_NONE; 24561da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, new_hb); 24571da177e4SLinus Torvalds card->hbpool.count++; 24581da177e4SLinus Torvalds } 24591da177e4SLinus Torvalds } 24601da177e4SLinus Torvalds } 24611da177e4SLinus Torvalds 24621da177e4SLinus Torvalds iov = (struct iovec *) iovb->data; 24631da177e4SLinus Torvalds 24641da177e4SLinus Torvalds if (!atm_charge(vcc, hb->truesize)) 24651da177e4SLinus Torvalds { 24661da177e4SLinus Torvalds recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt); 24671da177e4SLinus Torvalds if (card->hbpool.count < card->hbnr.max) 24681da177e4SLinus Torvalds { 24691da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, hb); 24701da177e4SLinus Torvalds card->hbpool.count++; 24711da177e4SLinus Torvalds } 24721da177e4SLinus Torvalds else 24731da177e4SLinus Torvalds dev_kfree_skb_any(hb); 24741da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx_drop); 24751da177e4SLinus Torvalds } 24761da177e4SLinus Torvalds else 24771da177e4SLinus Torvalds { 24781da177e4SLinus Torvalds /* Copy the small buffer to the huge buffer */ 24791da177e4SLinus Torvalds sb = (struct sk_buff *) iov->iov_base; 24801da177e4SLinus Torvalds memcpy(hb->data, sb->data, iov->iov_len); 24811da177e4SLinus Torvalds skb_put(hb, iov->iov_len); 24821da177e4SLinus Torvalds remaining = len - iov->iov_len; 24831da177e4SLinus Torvalds iov++; 24841da177e4SLinus Torvalds /* Free the small buffer */ 24858728b834SDavid S. Miller push_rxbufs(card, sb); 24861da177e4SLinus Torvalds 24871da177e4SLinus Torvalds /* Copy all large buffers to the huge buffer and free them */ 24881da177e4SLinus Torvalds for (j = 1; j < NS_SKB(iovb)->iovcnt; j++) 24891da177e4SLinus Torvalds { 24901da177e4SLinus Torvalds lb = (struct sk_buff *) iov->iov_base; 24911da177e4SLinus Torvalds tocopy = min_t(int, remaining, iov->iov_len); 24921da177e4SLinus Torvalds memcpy(hb->tail, lb->data, tocopy); 24931da177e4SLinus Torvalds skb_put(hb, tocopy); 24941da177e4SLinus Torvalds iov++; 24951da177e4SLinus Torvalds remaining -= tocopy; 24968728b834SDavid S. Miller push_rxbufs(card, lb); 24971da177e4SLinus Torvalds } 24981da177e4SLinus Torvalds #ifdef EXTRA_DEBUG 24991da177e4SLinus Torvalds if (remaining != 0 || hb->len != len) 25001da177e4SLinus Torvalds printk("nicstar%d: Huge buffer len mismatch.\n", card->index); 25011da177e4SLinus Torvalds #endif /* EXTRA_DEBUG */ 25021da177e4SLinus Torvalds ATM_SKB(hb)->vcc = vcc; 25031da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 25041da177e4SLinus Torvalds hb->destructor = ns_hb_destructor; 25051da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 2506a61bbcf2SPatrick McHardy __net_timestamp(hb); 25071da177e4SLinus Torvalds vcc->push(vcc, hb); 25081da177e4SLinus Torvalds atomic_inc(&vcc->stats->rx); 25091da177e4SLinus Torvalds } 25101da177e4SLinus Torvalds } 25111da177e4SLinus Torvalds 25121da177e4SLinus Torvalds vc->rx_iov = NULL; 25131da177e4SLinus Torvalds recycle_iov_buf(card, iovb); 25141da177e4SLinus Torvalds } 25151da177e4SLinus Torvalds 25161da177e4SLinus Torvalds } 25171da177e4SLinus Torvalds 25181da177e4SLinus Torvalds 25191da177e4SLinus Torvalds 25201da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 25211da177e4SLinus Torvalds 25221da177e4SLinus Torvalds static void ns_sb_destructor(struct sk_buff *sb) 25231da177e4SLinus Torvalds { 25241da177e4SLinus Torvalds ns_dev *card; 25251da177e4SLinus Torvalds u32 stat; 25261da177e4SLinus Torvalds 25271da177e4SLinus Torvalds card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data; 25281da177e4SLinus Torvalds stat = readl(card->membase + STAT); 25291da177e4SLinus Torvalds card->sbfqc = ns_stat_sfbqc_get(stat); 25301da177e4SLinus Torvalds card->lbfqc = ns_stat_lfbqc_get(stat); 25311da177e4SLinus Torvalds 25321da177e4SLinus Torvalds do 25331da177e4SLinus Torvalds { 25341da177e4SLinus Torvalds sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 25351da177e4SLinus Torvalds if (sb == NULL) 25361da177e4SLinus Torvalds break; 25378728b834SDavid S. Miller NS_SKB_CB(sb)->buf_type = BUF_SM; 25381da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, sb); 25391da177e4SLinus Torvalds skb_reserve(sb, NS_AAL0_HEADER); 25408728b834SDavid S. Miller push_rxbufs(card, sb); 25411da177e4SLinus Torvalds } while (card->sbfqc < card->sbnr.min); 25421da177e4SLinus Torvalds } 25431da177e4SLinus Torvalds 25441da177e4SLinus Torvalds 25451da177e4SLinus Torvalds 25461da177e4SLinus Torvalds static void ns_lb_destructor(struct sk_buff *lb) 25471da177e4SLinus Torvalds { 25481da177e4SLinus Torvalds ns_dev *card; 25491da177e4SLinus Torvalds u32 stat; 25501da177e4SLinus Torvalds 25511da177e4SLinus Torvalds card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data; 25521da177e4SLinus Torvalds stat = readl(card->membase + STAT); 25531da177e4SLinus Torvalds card->sbfqc = ns_stat_sfbqc_get(stat); 25541da177e4SLinus Torvalds card->lbfqc = ns_stat_lfbqc_get(stat); 25551da177e4SLinus Torvalds 25561da177e4SLinus Torvalds do 25571da177e4SLinus Torvalds { 25581da177e4SLinus Torvalds lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 25591da177e4SLinus Torvalds if (lb == NULL) 25601da177e4SLinus Torvalds break; 25618728b834SDavid S. Miller NS_SKB_CB(lb)->buf_type = BUF_LG; 25621da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, lb); 25631da177e4SLinus Torvalds skb_reserve(lb, NS_SMBUFSIZE); 25648728b834SDavid S. Miller push_rxbufs(card, lb); 25651da177e4SLinus Torvalds } while (card->lbfqc < card->lbnr.min); 25661da177e4SLinus Torvalds } 25671da177e4SLinus Torvalds 25681da177e4SLinus Torvalds 25691da177e4SLinus Torvalds 25701da177e4SLinus Torvalds static void ns_hb_destructor(struct sk_buff *hb) 25711da177e4SLinus Torvalds { 25721da177e4SLinus Torvalds ns_dev *card; 25731da177e4SLinus Torvalds 25741da177e4SLinus Torvalds card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data; 25751da177e4SLinus Torvalds 25761da177e4SLinus Torvalds while (card->hbpool.count < card->hbnr.init) 25771da177e4SLinus Torvalds { 25781da177e4SLinus Torvalds hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 25791da177e4SLinus Torvalds if (hb == NULL) 25801da177e4SLinus Torvalds break; 25818728b834SDavid S. Miller NS_SKB_CB(hb)->buf_type = BUF_NONE; 25821da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, hb); 25831da177e4SLinus Torvalds card->hbpool.count++; 25841da177e4SLinus Torvalds } 25851da177e4SLinus Torvalds } 25861da177e4SLinus Torvalds 25871da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 25881da177e4SLinus Torvalds 25891da177e4SLinus Torvalds 25901da177e4SLinus Torvalds static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb) 25911da177e4SLinus Torvalds { 25928728b834SDavid S. Miller struct ns_skb_cb *cb = NS_SKB_CB(skb); 25938728b834SDavid S. Miller 25948728b834SDavid S. Miller if (unlikely(cb->buf_type == BUF_NONE)) { 25951da177e4SLinus Torvalds printk("nicstar%d: What kind of rx buffer is this?\n", card->index); 25961da177e4SLinus Torvalds dev_kfree_skb_any(skb); 25978728b834SDavid S. Miller } else 25988728b834SDavid S. Miller push_rxbufs(card, skb); 25991da177e4SLinus Torvalds } 26001da177e4SLinus Torvalds 26011da177e4SLinus Torvalds 26021da177e4SLinus Torvalds static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count) 26031da177e4SLinus Torvalds { 26048728b834SDavid S. Miller while (count-- > 0) 26058728b834SDavid S. Miller recycle_rx_buf(card, (struct sk_buff *) (iov++)->iov_base); 26061da177e4SLinus Torvalds } 26071da177e4SLinus Torvalds 26081da177e4SLinus Torvalds 26091da177e4SLinus Torvalds static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb) 26101da177e4SLinus Torvalds { 26111da177e4SLinus Torvalds if (card->iovpool.count < card->iovnr.max) 26121da177e4SLinus Torvalds { 26131da177e4SLinus Torvalds skb_queue_tail(&card->iovpool.queue, iovb); 26141da177e4SLinus Torvalds card->iovpool.count++; 26151da177e4SLinus Torvalds } 26161da177e4SLinus Torvalds else 26171da177e4SLinus Torvalds dev_kfree_skb_any(iovb); 26181da177e4SLinus Torvalds } 26191da177e4SLinus Torvalds 26201da177e4SLinus Torvalds 26211da177e4SLinus Torvalds 26221da177e4SLinus Torvalds static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb) 26231da177e4SLinus Torvalds { 26248728b834SDavid S. Miller skb_unlink(sb, &card->sbpool.queue); 26251da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 26261da177e4SLinus Torvalds if (card->sbfqc < card->sbnr.min) 26271da177e4SLinus Torvalds #else 26281da177e4SLinus Torvalds if (card->sbfqc < card->sbnr.init) 26291da177e4SLinus Torvalds { 26301da177e4SLinus Torvalds struct sk_buff *new_sb; 26311da177e4SLinus Torvalds if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) 26321da177e4SLinus Torvalds { 26338728b834SDavid S. Miller NS_SKB_CB(new_sb)->buf_type = BUF_SM; 26341da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, new_sb); 26351da177e4SLinus Torvalds skb_reserve(new_sb, NS_AAL0_HEADER); 26368728b834SDavid S. Miller push_rxbufs(card, new_sb); 26371da177e4SLinus Torvalds } 26381da177e4SLinus Torvalds } 26391da177e4SLinus Torvalds if (card->sbfqc < card->sbnr.init) 26401da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 26411da177e4SLinus Torvalds { 26421da177e4SLinus Torvalds struct sk_buff *new_sb; 26431da177e4SLinus Torvalds if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) 26441da177e4SLinus Torvalds { 26458728b834SDavid S. Miller NS_SKB_CB(new_sb)->buf_type = BUF_SM; 26461da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, new_sb); 26471da177e4SLinus Torvalds skb_reserve(new_sb, NS_AAL0_HEADER); 26488728b834SDavid S. Miller push_rxbufs(card, new_sb); 26491da177e4SLinus Torvalds } 26501da177e4SLinus Torvalds } 26511da177e4SLinus Torvalds } 26521da177e4SLinus Torvalds 26531da177e4SLinus Torvalds 26541da177e4SLinus Torvalds 26551da177e4SLinus Torvalds static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb) 26561da177e4SLinus Torvalds { 26578728b834SDavid S. Miller skb_unlink(lb, &card->lbpool.queue); 26581da177e4SLinus Torvalds #ifdef NS_USE_DESTRUCTORS 26591da177e4SLinus Torvalds if (card->lbfqc < card->lbnr.min) 26601da177e4SLinus Torvalds #else 26611da177e4SLinus Torvalds if (card->lbfqc < card->lbnr.init) 26621da177e4SLinus Torvalds { 26631da177e4SLinus Torvalds struct sk_buff *new_lb; 26641da177e4SLinus Torvalds if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) 26651da177e4SLinus Torvalds { 26668728b834SDavid S. Miller NS_SKB_CB(new_lb)->buf_type = BUF_LG; 26671da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, new_lb); 26681da177e4SLinus Torvalds skb_reserve(new_lb, NS_SMBUFSIZE); 26698728b834SDavid S. Miller push_rxbufs(card, new_lb); 26701da177e4SLinus Torvalds } 26711da177e4SLinus Torvalds } 26721da177e4SLinus Torvalds if (card->lbfqc < card->lbnr.init) 26731da177e4SLinus Torvalds #endif /* NS_USE_DESTRUCTORS */ 26741da177e4SLinus Torvalds { 26751da177e4SLinus Torvalds struct sk_buff *new_lb; 26761da177e4SLinus Torvalds if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) 26771da177e4SLinus Torvalds { 26788728b834SDavid S. Miller NS_SKB_CB(new_lb)->buf_type = BUF_LG; 26791da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, new_lb); 26801da177e4SLinus Torvalds skb_reserve(new_lb, NS_SMBUFSIZE); 26818728b834SDavid S. Miller push_rxbufs(card, new_lb); 26821da177e4SLinus Torvalds } 26831da177e4SLinus Torvalds } 26841da177e4SLinus Torvalds } 26851da177e4SLinus Torvalds 26861da177e4SLinus Torvalds 26871da177e4SLinus Torvalds 26881da177e4SLinus Torvalds static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page) 26891da177e4SLinus Torvalds { 26901da177e4SLinus Torvalds u32 stat; 26911da177e4SLinus Torvalds ns_dev *card; 26921da177e4SLinus Torvalds int left; 26931da177e4SLinus Torvalds 26941da177e4SLinus Torvalds left = (int) *pos; 26951da177e4SLinus Torvalds card = (ns_dev *) dev->dev_data; 26961da177e4SLinus Torvalds stat = readl(card->membase + STAT); 26971da177e4SLinus Torvalds if (!left--) 26981da177e4SLinus Torvalds return sprintf(page, "Pool count min init max \n"); 26991da177e4SLinus Torvalds if (!left--) 27001da177e4SLinus Torvalds return sprintf(page, "Small %5d %5d %5d %5d \n", 27011da177e4SLinus Torvalds ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init, 27021da177e4SLinus Torvalds card->sbnr.max); 27031da177e4SLinus Torvalds if (!left--) 27041da177e4SLinus Torvalds return sprintf(page, "Large %5d %5d %5d %5d \n", 27051da177e4SLinus Torvalds ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init, 27061da177e4SLinus Torvalds card->lbnr.max); 27071da177e4SLinus Torvalds if (!left--) 27081da177e4SLinus Torvalds return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count, 27091da177e4SLinus Torvalds card->hbnr.min, card->hbnr.init, card->hbnr.max); 27101da177e4SLinus Torvalds if (!left--) 27111da177e4SLinus Torvalds return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count, 27121da177e4SLinus Torvalds card->iovnr.min, card->iovnr.init, card->iovnr.max); 27131da177e4SLinus Torvalds if (!left--) 27141da177e4SLinus Torvalds { 27151da177e4SLinus Torvalds int retval; 27161da177e4SLinus Torvalds retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt); 27171da177e4SLinus Torvalds card->intcnt = 0; 27181da177e4SLinus Torvalds return retval; 27191da177e4SLinus Torvalds } 27201da177e4SLinus Torvalds #if 0 27211da177e4SLinus Torvalds /* Dump 25.6 Mbps PHY registers */ 27221da177e4SLinus Torvalds /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it 27231da177e4SLinus Torvalds here just in case it's needed for debugging. */ 27241da177e4SLinus Torvalds if (card->max_pcr == ATM_25_PCR && !left--) 27251da177e4SLinus Torvalds { 27261da177e4SLinus Torvalds u32 phy_regs[4]; 27271da177e4SLinus Torvalds u32 i; 27281da177e4SLinus Torvalds 27291da177e4SLinus Torvalds for (i = 0; i < 4; i++) 27301da177e4SLinus Torvalds { 27311da177e4SLinus Torvalds while (CMD_BUSY(card)); 27321da177e4SLinus Torvalds writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD); 27331da177e4SLinus Torvalds while (CMD_BUSY(card)); 27341da177e4SLinus Torvalds phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; 27351da177e4SLinus Torvalds } 27361da177e4SLinus Torvalds 27371da177e4SLinus Torvalds return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", 27381da177e4SLinus Torvalds phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]); 27391da177e4SLinus Torvalds } 27401da177e4SLinus Torvalds #endif /* 0 - Dump 25.6 Mbps PHY registers */ 27411da177e4SLinus Torvalds #if 0 27421da177e4SLinus Torvalds /* Dump TST */ 27431da177e4SLinus Torvalds if (left-- < NS_TST_NUM_ENTRIES) 27441da177e4SLinus Torvalds { 27451da177e4SLinus Torvalds if (card->tste2vc[left + 1] == NULL) 27461da177e4SLinus Torvalds return sprintf(page, "%5d - VBR/UBR \n", left + 1); 27471da177e4SLinus Torvalds else 27481da177e4SLinus Torvalds return sprintf(page, "%5d - %d %d \n", left + 1, 27491da177e4SLinus Torvalds card->tste2vc[left + 1]->tx_vcc->vpi, 27501da177e4SLinus Torvalds card->tste2vc[left + 1]->tx_vcc->vci); 27511da177e4SLinus Torvalds } 27521da177e4SLinus Torvalds #endif /* 0 */ 27531da177e4SLinus Torvalds return 0; 27541da177e4SLinus Torvalds } 27551da177e4SLinus Torvalds 27561da177e4SLinus Torvalds 27571da177e4SLinus Torvalds 27581da177e4SLinus Torvalds static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) 27591da177e4SLinus Torvalds { 27601da177e4SLinus Torvalds ns_dev *card; 27611da177e4SLinus Torvalds pool_levels pl; 27621da177e4SLinus Torvalds int btype; 27631da177e4SLinus Torvalds unsigned long flags; 27641da177e4SLinus Torvalds 27651da177e4SLinus Torvalds card = dev->dev_data; 27661da177e4SLinus Torvalds switch (cmd) 27671da177e4SLinus Torvalds { 27681da177e4SLinus Torvalds case NS_GETPSTAT: 27691da177e4SLinus Torvalds if (get_user(pl.buftype, &((pool_levels __user *) arg)->buftype)) 27701da177e4SLinus Torvalds return -EFAULT; 27711da177e4SLinus Torvalds switch (pl.buftype) 27721da177e4SLinus Torvalds { 27731da177e4SLinus Torvalds case NS_BUFTYPE_SMALL: 27741da177e4SLinus Torvalds pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT)); 27751da177e4SLinus Torvalds pl.level.min = card->sbnr.min; 27761da177e4SLinus Torvalds pl.level.init = card->sbnr.init; 27771da177e4SLinus Torvalds pl.level.max = card->sbnr.max; 27781da177e4SLinus Torvalds break; 27791da177e4SLinus Torvalds 27801da177e4SLinus Torvalds case NS_BUFTYPE_LARGE: 27811da177e4SLinus Torvalds pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT)); 27821da177e4SLinus Torvalds pl.level.min = card->lbnr.min; 27831da177e4SLinus Torvalds pl.level.init = card->lbnr.init; 27841da177e4SLinus Torvalds pl.level.max = card->lbnr.max; 27851da177e4SLinus Torvalds break; 27861da177e4SLinus Torvalds 27871da177e4SLinus Torvalds case NS_BUFTYPE_HUGE: 27881da177e4SLinus Torvalds pl.count = card->hbpool.count; 27891da177e4SLinus Torvalds pl.level.min = card->hbnr.min; 27901da177e4SLinus Torvalds pl.level.init = card->hbnr.init; 27911da177e4SLinus Torvalds pl.level.max = card->hbnr.max; 27921da177e4SLinus Torvalds break; 27931da177e4SLinus Torvalds 27941da177e4SLinus Torvalds case NS_BUFTYPE_IOVEC: 27951da177e4SLinus Torvalds pl.count = card->iovpool.count; 27961da177e4SLinus Torvalds pl.level.min = card->iovnr.min; 27971da177e4SLinus Torvalds pl.level.init = card->iovnr.init; 27981da177e4SLinus Torvalds pl.level.max = card->iovnr.max; 27991da177e4SLinus Torvalds break; 28001da177e4SLinus Torvalds 28011da177e4SLinus Torvalds default: 28021da177e4SLinus Torvalds return -ENOIOCTLCMD; 28031da177e4SLinus Torvalds 28041da177e4SLinus Torvalds } 28051da177e4SLinus Torvalds if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl))) 28061da177e4SLinus Torvalds return (sizeof(pl)); 28071da177e4SLinus Torvalds else 28081da177e4SLinus Torvalds return -EFAULT; 28091da177e4SLinus Torvalds 28101da177e4SLinus Torvalds case NS_SETBUFLEV: 28111da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 28121da177e4SLinus Torvalds return -EPERM; 28131da177e4SLinus Torvalds if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl))) 28141da177e4SLinus Torvalds return -EFAULT; 28151da177e4SLinus Torvalds if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max) 28161da177e4SLinus Torvalds return -EINVAL; 28171da177e4SLinus Torvalds if (pl.level.min == 0) 28181da177e4SLinus Torvalds return -EINVAL; 28191da177e4SLinus Torvalds switch (pl.buftype) 28201da177e4SLinus Torvalds { 28211da177e4SLinus Torvalds case NS_BUFTYPE_SMALL: 28221da177e4SLinus Torvalds if (pl.level.max > TOP_SB) 28231da177e4SLinus Torvalds return -EINVAL; 28241da177e4SLinus Torvalds card->sbnr.min = pl.level.min; 28251da177e4SLinus Torvalds card->sbnr.init = pl.level.init; 28261da177e4SLinus Torvalds card->sbnr.max = pl.level.max; 28271da177e4SLinus Torvalds break; 28281da177e4SLinus Torvalds 28291da177e4SLinus Torvalds case NS_BUFTYPE_LARGE: 28301da177e4SLinus Torvalds if (pl.level.max > TOP_LB) 28311da177e4SLinus Torvalds return -EINVAL; 28321da177e4SLinus Torvalds card->lbnr.min = pl.level.min; 28331da177e4SLinus Torvalds card->lbnr.init = pl.level.init; 28341da177e4SLinus Torvalds card->lbnr.max = pl.level.max; 28351da177e4SLinus Torvalds break; 28361da177e4SLinus Torvalds 28371da177e4SLinus Torvalds case NS_BUFTYPE_HUGE: 28381da177e4SLinus Torvalds if (pl.level.max > TOP_HB) 28391da177e4SLinus Torvalds return -EINVAL; 28401da177e4SLinus Torvalds card->hbnr.min = pl.level.min; 28411da177e4SLinus Torvalds card->hbnr.init = pl.level.init; 28421da177e4SLinus Torvalds card->hbnr.max = pl.level.max; 28431da177e4SLinus Torvalds break; 28441da177e4SLinus Torvalds 28451da177e4SLinus Torvalds case NS_BUFTYPE_IOVEC: 28461da177e4SLinus Torvalds if (pl.level.max > TOP_IOVB) 28471da177e4SLinus Torvalds return -EINVAL; 28481da177e4SLinus Torvalds card->iovnr.min = pl.level.min; 28491da177e4SLinus Torvalds card->iovnr.init = pl.level.init; 28501da177e4SLinus Torvalds card->iovnr.max = pl.level.max; 28511da177e4SLinus Torvalds break; 28521da177e4SLinus Torvalds 28531da177e4SLinus Torvalds default: 28541da177e4SLinus Torvalds return -EINVAL; 28551da177e4SLinus Torvalds 28561da177e4SLinus Torvalds } 28571da177e4SLinus Torvalds return 0; 28581da177e4SLinus Torvalds 28591da177e4SLinus Torvalds case NS_ADJBUFLEV: 28601da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 28611da177e4SLinus Torvalds return -EPERM; 28621da177e4SLinus Torvalds btype = (int) arg; /* an int is the same size as a pointer */ 28631da177e4SLinus Torvalds switch (btype) 28641da177e4SLinus Torvalds { 28651da177e4SLinus Torvalds case NS_BUFTYPE_SMALL: 28661da177e4SLinus Torvalds while (card->sbfqc < card->sbnr.init) 28671da177e4SLinus Torvalds { 28681da177e4SLinus Torvalds struct sk_buff *sb; 28691da177e4SLinus Torvalds 28701da177e4SLinus Torvalds sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); 28711da177e4SLinus Torvalds if (sb == NULL) 28721da177e4SLinus Torvalds return -ENOMEM; 28738728b834SDavid S. Miller NS_SKB_CB(sb)->buf_type = BUF_SM; 28741da177e4SLinus Torvalds skb_queue_tail(&card->sbpool.queue, sb); 28751da177e4SLinus Torvalds skb_reserve(sb, NS_AAL0_HEADER); 28768728b834SDavid S. Miller push_rxbufs(card, sb); 28771da177e4SLinus Torvalds } 28781da177e4SLinus Torvalds break; 28791da177e4SLinus Torvalds 28801da177e4SLinus Torvalds case NS_BUFTYPE_LARGE: 28811da177e4SLinus Torvalds while (card->lbfqc < card->lbnr.init) 28821da177e4SLinus Torvalds { 28831da177e4SLinus Torvalds struct sk_buff *lb; 28841da177e4SLinus Torvalds 28851da177e4SLinus Torvalds lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); 28861da177e4SLinus Torvalds if (lb == NULL) 28871da177e4SLinus Torvalds return -ENOMEM; 28888728b834SDavid S. Miller NS_SKB_CB(lb)->buf_type = BUF_LG; 28891da177e4SLinus Torvalds skb_queue_tail(&card->lbpool.queue, lb); 28901da177e4SLinus Torvalds skb_reserve(lb, NS_SMBUFSIZE); 28918728b834SDavid S. Miller push_rxbufs(card, lb); 28921da177e4SLinus Torvalds } 28931da177e4SLinus Torvalds break; 28941da177e4SLinus Torvalds 28951da177e4SLinus Torvalds case NS_BUFTYPE_HUGE: 28961da177e4SLinus Torvalds while (card->hbpool.count > card->hbnr.init) 28971da177e4SLinus Torvalds { 28981da177e4SLinus Torvalds struct sk_buff *hb; 28991da177e4SLinus Torvalds 29001da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 29011da177e4SLinus Torvalds hb = skb_dequeue(&card->hbpool.queue); 29021da177e4SLinus Torvalds card->hbpool.count--; 29031da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 29041da177e4SLinus Torvalds if (hb == NULL) 29051da177e4SLinus Torvalds printk("nicstar%d: huge buffer count inconsistent.\n", 29061da177e4SLinus Torvalds card->index); 29071da177e4SLinus Torvalds else 29081da177e4SLinus Torvalds dev_kfree_skb_any(hb); 29091da177e4SLinus Torvalds 29101da177e4SLinus Torvalds } 29111da177e4SLinus Torvalds while (card->hbpool.count < card->hbnr.init) 29121da177e4SLinus Torvalds { 29131da177e4SLinus Torvalds struct sk_buff *hb; 29141da177e4SLinus Torvalds 29151da177e4SLinus Torvalds hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); 29161da177e4SLinus Torvalds if (hb == NULL) 29171da177e4SLinus Torvalds return -ENOMEM; 29188728b834SDavid S. Miller NS_SKB_CB(hb)->buf_type = BUF_NONE; 29191da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 29201da177e4SLinus Torvalds skb_queue_tail(&card->hbpool.queue, hb); 29211da177e4SLinus Torvalds card->hbpool.count++; 29221da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 29231da177e4SLinus Torvalds } 29241da177e4SLinus Torvalds break; 29251da177e4SLinus Torvalds 29261da177e4SLinus Torvalds case NS_BUFTYPE_IOVEC: 29271da177e4SLinus Torvalds while (card->iovpool.count > card->iovnr.init) 29281da177e4SLinus Torvalds { 29291da177e4SLinus Torvalds struct sk_buff *iovb; 29301da177e4SLinus Torvalds 29311da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 29321da177e4SLinus Torvalds iovb = skb_dequeue(&card->iovpool.queue); 29331da177e4SLinus Torvalds card->iovpool.count--; 29341da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 29351da177e4SLinus Torvalds if (iovb == NULL) 29361da177e4SLinus Torvalds printk("nicstar%d: iovec buffer count inconsistent.\n", 29371da177e4SLinus Torvalds card->index); 29381da177e4SLinus Torvalds else 29391da177e4SLinus Torvalds dev_kfree_skb_any(iovb); 29401da177e4SLinus Torvalds 29411da177e4SLinus Torvalds } 29421da177e4SLinus Torvalds while (card->iovpool.count < card->iovnr.init) 29431da177e4SLinus Torvalds { 29441da177e4SLinus Torvalds struct sk_buff *iovb; 29451da177e4SLinus Torvalds 29461da177e4SLinus Torvalds iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); 29471da177e4SLinus Torvalds if (iovb == NULL) 29481da177e4SLinus Torvalds return -ENOMEM; 29498728b834SDavid S. Miller NS_SKB_CB(iovb)->buf_type = BUF_NONE; 29501da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 29511da177e4SLinus Torvalds skb_queue_tail(&card->iovpool.queue, iovb); 29521da177e4SLinus Torvalds card->iovpool.count++; 29531da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 29541da177e4SLinus Torvalds } 29551da177e4SLinus Torvalds break; 29561da177e4SLinus Torvalds 29571da177e4SLinus Torvalds default: 29581da177e4SLinus Torvalds return -EINVAL; 29591da177e4SLinus Torvalds 29601da177e4SLinus Torvalds } 29611da177e4SLinus Torvalds return 0; 29621da177e4SLinus Torvalds 29631da177e4SLinus Torvalds default: 29641da177e4SLinus Torvalds if (dev->phy && dev->phy->ioctl) { 29651da177e4SLinus Torvalds return dev->phy->ioctl(dev, cmd, arg); 29661da177e4SLinus Torvalds } 29671da177e4SLinus Torvalds else { 29681da177e4SLinus Torvalds printk("nicstar%d: %s == NULL \n", card->index, 29691da177e4SLinus Torvalds dev->phy ? "dev->phy->ioctl" : "dev->phy"); 29701da177e4SLinus Torvalds return -ENOIOCTLCMD; 29711da177e4SLinus Torvalds } 29721da177e4SLinus Torvalds } 29731da177e4SLinus Torvalds } 29741da177e4SLinus Torvalds 29751da177e4SLinus Torvalds 29761da177e4SLinus Torvalds static void which_list(ns_dev *card, struct sk_buff *skb) 29771da177e4SLinus Torvalds { 29788728b834SDavid S. Miller printk("skb buf_type: 0x%08x\n", NS_SKB_CB(skb)->buf_type); 29791da177e4SLinus Torvalds } 29801da177e4SLinus Torvalds 29811da177e4SLinus Torvalds 29821da177e4SLinus Torvalds static void ns_poll(unsigned long arg) 29831da177e4SLinus Torvalds { 29841da177e4SLinus Torvalds int i; 29851da177e4SLinus Torvalds ns_dev *card; 29861da177e4SLinus Torvalds unsigned long flags; 29871da177e4SLinus Torvalds u32 stat_r, stat_w; 29881da177e4SLinus Torvalds 29891da177e4SLinus Torvalds PRINTK("nicstar: Entering ns_poll().\n"); 29901da177e4SLinus Torvalds for (i = 0; i < num_cards; i++) 29911da177e4SLinus Torvalds { 29921da177e4SLinus Torvalds card = cards[i]; 29931da177e4SLinus Torvalds if (spin_is_locked(&card->int_lock)) { 29941da177e4SLinus Torvalds /* Probably it isn't worth spinning */ 29951da177e4SLinus Torvalds continue; 29961da177e4SLinus Torvalds } 29971da177e4SLinus Torvalds ns_grab_int_lock(card, flags); 29981da177e4SLinus Torvalds 29991da177e4SLinus Torvalds stat_w = 0; 30001da177e4SLinus Torvalds stat_r = readl(card->membase + STAT); 30011da177e4SLinus Torvalds if (stat_r & NS_STAT_TSIF) 30021da177e4SLinus Torvalds stat_w |= NS_STAT_TSIF; 30031da177e4SLinus Torvalds if (stat_r & NS_STAT_EOPDU) 30041da177e4SLinus Torvalds stat_w |= NS_STAT_EOPDU; 30051da177e4SLinus Torvalds 30061da177e4SLinus Torvalds process_tsq(card); 30071da177e4SLinus Torvalds process_rsq(card); 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds writel(stat_w, card->membase + STAT); 30101da177e4SLinus Torvalds spin_unlock_irqrestore(&card->int_lock, flags); 30111da177e4SLinus Torvalds } 30121da177e4SLinus Torvalds mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); 30131da177e4SLinus Torvalds PRINTK("nicstar: Leaving ns_poll().\n"); 30141da177e4SLinus Torvalds } 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds 30171da177e4SLinus Torvalds 30181da177e4SLinus Torvalds static int ns_parse_mac(char *mac, unsigned char *esi) 30191da177e4SLinus Torvalds { 30201da177e4SLinus Torvalds int i, j; 30211da177e4SLinus Torvalds short byte1, byte0; 30221da177e4SLinus Torvalds 30231da177e4SLinus Torvalds if (mac == NULL || esi == NULL) 30241da177e4SLinus Torvalds return -1; 30251da177e4SLinus Torvalds j = 0; 30261da177e4SLinus Torvalds for (i = 0; i < 6; i++) 30271da177e4SLinus Torvalds { 30281da177e4SLinus Torvalds if ((byte1 = ns_h2i(mac[j++])) < 0) 30291da177e4SLinus Torvalds return -1; 30301da177e4SLinus Torvalds if ((byte0 = ns_h2i(mac[j++])) < 0) 30311da177e4SLinus Torvalds return -1; 30321da177e4SLinus Torvalds esi[i] = (unsigned char) (byte1 * 16 + byte0); 30331da177e4SLinus Torvalds if (i < 5) 30341da177e4SLinus Torvalds { 30351da177e4SLinus Torvalds if (mac[j++] != ':') 30361da177e4SLinus Torvalds return -1; 30371da177e4SLinus Torvalds } 30381da177e4SLinus Torvalds } 30391da177e4SLinus Torvalds return 0; 30401da177e4SLinus Torvalds } 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds 30431da177e4SLinus Torvalds 30441da177e4SLinus Torvalds static short ns_h2i(char c) 30451da177e4SLinus Torvalds { 30461da177e4SLinus Torvalds if (c >= '0' && c <= '9') 30471da177e4SLinus Torvalds return (short) (c - '0'); 30481da177e4SLinus Torvalds if (c >= 'A' && c <= 'F') 30491da177e4SLinus Torvalds return (short) (c - 'A' + 10); 30501da177e4SLinus Torvalds if (c >= 'a' && c <= 'f') 30511da177e4SLinus Torvalds return (short) (c - 'a' + 10); 30521da177e4SLinus Torvalds return -1; 30531da177e4SLinus Torvalds } 30541da177e4SLinus Torvalds 30551da177e4SLinus Torvalds 30561da177e4SLinus Torvalds 30571da177e4SLinus Torvalds static void ns_phy_put(struct atm_dev *dev, unsigned char value, 30581da177e4SLinus Torvalds unsigned long addr) 30591da177e4SLinus Torvalds { 30601da177e4SLinus Torvalds ns_dev *card; 30611da177e4SLinus Torvalds unsigned long flags; 30621da177e4SLinus Torvalds 30631da177e4SLinus Torvalds card = dev->dev_data; 30641da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 30651da177e4SLinus Torvalds while(CMD_BUSY(card)); 30661da177e4SLinus Torvalds writel((unsigned long) value, card->membase + DR0); 30671da177e4SLinus Torvalds writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF), 30681da177e4SLinus Torvalds card->membase + CMD); 30691da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 30701da177e4SLinus Torvalds } 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds 30731da177e4SLinus Torvalds 30741da177e4SLinus Torvalds static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr) 30751da177e4SLinus Torvalds { 30761da177e4SLinus Torvalds ns_dev *card; 30771da177e4SLinus Torvalds unsigned long flags; 30781da177e4SLinus Torvalds unsigned long data; 30791da177e4SLinus Torvalds 30801da177e4SLinus Torvalds card = dev->dev_data; 30811da177e4SLinus Torvalds ns_grab_res_lock(card, flags); 30821da177e4SLinus Torvalds while(CMD_BUSY(card)); 30831da177e4SLinus Torvalds writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF), 30841da177e4SLinus Torvalds card->membase + CMD); 30851da177e4SLinus Torvalds while(CMD_BUSY(card)); 30861da177e4SLinus Torvalds data = readl(card->membase + DR0) & 0x000000FF; 30871da177e4SLinus Torvalds spin_unlock_irqrestore(&card->res_lock, flags); 30881da177e4SLinus Torvalds return (unsigned char) data; 30891da177e4SLinus Torvalds } 30901da177e4SLinus Torvalds 30911da177e4SLinus Torvalds 30921da177e4SLinus Torvalds 30931da177e4SLinus Torvalds module_init(nicstar_init); 30941da177e4SLinus Torvalds module_exit(nicstar_cleanup); 3095