xref: /openbmc/linux/drivers/atm/nicstar.c (revision 7d12e780)
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