nicstar.c

来自「linux 内核源代码」· C语言 代码 · 共 2,241 行 · 第 1/5 页

C
2,241
字号
/****************************************************************************** * * nicstar.c * * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. * * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. *            It was taken from the frle-0.22 device driver. *            As the file doesn't have a copyright notice, in the file *            nicstarmac.copyright I put the copyright notice from the *            frle-0.22 device driver. *            Some code is based on the nicstar driver by M. Welsh. * * Author: Rui Prior (rprior@inescn.pt) * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 * * * (C) INESC 1999 * * ******************************************************************************//**** IMPORTANT INFORMATION *************************************************** * * There are currently three types of spinlocks: * * 1 - Per card interrupt spinlock (to protect structures and such) * 2 - Per SCQ scq spinlock * 3 - Per card resource spinlock (to access registers, etc.) * * These must NEVER be grabbed in reverse order. * ******************************************************************************//* Header files ***************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/skbuff.h>#include <linux/atmdev.h>#include <linux/atm.h>#include <linux/pci.h>#include <linux/types.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/bitops.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include "nicstar.h"#ifdef CONFIG_ATM_NICSTAR_USE_SUNI#include "suni.h"#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105#include "idt77105.h"#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */#if BITS_PER_LONG != 32#  error FIXME: this driver requires a 32-bit platform#endif/* Additional code ************************************************************/#include "nicstarmac.c"/* Configurable parameters ****************************************************/#undef PHY_LOOPBACK#undef TX_DEBUG#undef RX_DEBUG#undef GENERAL_DEBUG#undef EXTRA_DEBUG#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know                             you're going to use only raw ATM *//* Do not touch these *********************************************************/#ifdef TX_DEBUG#define TXPRINTK(args...) printk(args)#else#define TXPRINTK(args...)#endif /* TX_DEBUG */#ifdef RX_DEBUG#define RXPRINTK(args...) printk(args)#else#define RXPRINTK(args...)#endif /* RX_DEBUG */#ifdef GENERAL_DEBUG#define PRINTK(args...) printk(args)#else#define PRINTK(args...)#endif /* GENERAL_DEBUG */#ifdef EXTRA_DEBUG#define XPRINTK(args...) printk(args)#else#define XPRINTK(args...)#endif /* EXTRA_DEBUG *//* Macros *********************************************************************/#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)#define NS_DELAY mdelay(1)#define ALIGN_BUS_ADDR(addr, alignment) \        ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1))#define ALIGN_ADDRESS(addr, alignment) \        bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment))#undef CEIL#ifndef ATM_SKB#define ATM_SKB(s) (&(s)->atm)#endif   /* Spinlock debugging stuff */#ifdef NS_DEBUG_SPINLOCKS /* See nicstar.h */#define ns_grab_int_lock(card,flags) \ do { \    unsigned long nsdsf, nsdsf2; \    local_irq_save(flags); \    save_flags(nsdsf); cli();\    if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \                                (flags)&(1<<9)?"en":"dis"); \    if (spin_is_locked(&(card)->int_lock) && \        (card)->cpu_int == smp_processor_id()) { \       printk("nicstar.c: line %d (cpu %d) int_lock already locked at line %d (cpu %d)\n", \              __LINE__, smp_processor_id(), (card)->has_int_lock, \              (card)->cpu_int); \       printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \    } \    if (spin_is_locked(&(card)->res_lock) && \        (card)->cpu_res == smp_processor_id()) { \       printk("nicstar.c: line %d (cpu %d) res_lock locked at line %d (cpu %d)(trying int)\n", \              __LINE__, smp_processor_id(), (card)->has_res_lock, \              (card)->cpu_res); \       printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \    } \    spin_lock_irq(&(card)->int_lock); \    (card)->has_int_lock = __LINE__; \    (card)->cpu_int = smp_processor_id(); \    restore_flags(nsdsf); } while (0)#define ns_grab_res_lock(card,flags) \ do { \    unsigned long nsdsf, nsdsf2; \    local_irq_save(flags); \    save_flags(nsdsf); cli();\    if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \                                (flags)&(1<<9)?"en":"dis"); \    if (spin_is_locked(&(card)->res_lock) && \        (card)->cpu_res == smp_processor_id()) { \       printk("nicstar.c: line %d (cpu %d) res_lock already locked at line %d (cpu %d)\n", \              __LINE__, smp_processor_id(), (card)->has_res_lock, \              (card)->cpu_res); \       printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \    } \    spin_lock_irq(&(card)->res_lock); \    (card)->has_res_lock = __LINE__; \    (card)->cpu_res = smp_processor_id(); \    restore_flags(nsdsf); } while (0)#define ns_grab_scq_lock(card,scq,flags) \ do { \    unsigned long nsdsf, nsdsf2; \    local_irq_save(flags); \    save_flags(nsdsf); cli();\    if (nsdsf & (1<<9)) printk ("nicstar.c: ints %sabled -> enabled.\n", \                                (flags)&(1<<9)?"en":"dis"); \    if (spin_is_locked(&(scq)->lock) && \        (scq)->cpu_lock == smp_processor_id()) { \       printk("nicstar.c: line %d (cpu %d) this scq_lock already locked at line %d (cpu %d)\n", \              __LINE__, smp_processor_id(), (scq)->has_lock, \              (scq)->cpu_lock); \       printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \    } \    if (spin_is_locked(&(card)->res_lock) && \        (card)->cpu_res == smp_processor_id()) { \       printk("nicstar.c: line %d (cpu %d) res_lock locked at line %d (cpu %d)(trying scq)\n", \              __LINE__, smp_processor_id(), (card)->has_res_lock, \              (card)->cpu_res); \       printk("nicstar.c: ints were %sabled.\n", ((flags)&(1<<9)?"en":"dis")); \    } \    spin_lock_irq(&(scq)->lock); \    (scq)->has_lock = __LINE__; \    (scq)->cpu_lock = smp_processor_id(); \    restore_flags(nsdsf); } while (0)#else /* !NS_DEBUG_SPINLOCKS */#define ns_grab_int_lock(card,flags) \        spin_lock_irqsave(&(card)->int_lock,(flags))#define ns_grab_res_lock(card,flags) \        spin_lock_irqsave(&(card)->res_lock,(flags))#define ns_grab_scq_lock(card,scq,flags) \        spin_lock_irqsave(&(scq)->lock,flags)#endif /* NS_DEBUG_SPINLOCKS *//* Function declarations ******************************************************/static u32 ns_read_sram(ns_dev *card, u32 sram_address);static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count);static int __devinit ns_init_card(int i, struct pci_dev *pcidev);static void __devinit ns_init_card_error(ns_dev *card, int error);static scq_info *get_scq(int size, u32 scd);static void free_scq(scq_info *scq, struct atm_vcc *vcc);static void push_rxbufs(ns_dev *, struct sk_buff *);static irqreturn_t ns_irq_handler(int irq, void *dev_id);static int ns_open(struct atm_vcc *vcc);static void ns_close(struct atm_vcc *vcc);static void fill_tst(ns_dev *card, int n, vc_map *vc);static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,                     struct sk_buff *skb);static void process_tsq(ns_dev *card);static void drain_scq(ns_dev *card, scq_info *scq, int pos);static void process_rsq(ns_dev *card);static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe);#ifdef NS_USE_DESTRUCTORSstatic void ns_sb_destructor(struct sk_buff *sb);static void ns_lb_destructor(struct sk_buff *lb);static void ns_hb_destructor(struct sk_buff *hb);#endif /* NS_USE_DESTRUCTORS */static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb);static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count);static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb);static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb);static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb);static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page);static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);static void which_list(ns_dev *card, struct sk_buff *skb);static void ns_poll(unsigned long arg);static int ns_parse_mac(char *mac, unsigned char *esi);static short ns_h2i(char c);static void ns_phy_put(struct atm_dev *dev, unsigned char value,                       unsigned long addr);static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr);/* Global variables ***********************************************************/static struct ns_dev *cards[NS_MAX_CARDS];static unsigned num_cards;static struct atmdev_ops atm_ops ={   .open	= ns_open,   .close	= ns_close,   .ioctl	= ns_ioctl,   .send	= ns_send,   .phy_put	= ns_phy_put,   .phy_get	= ns_phy_get,   .proc_read	= ns_proc_read,   .owner	= THIS_MODULE,};static struct timer_list ns_timer;static char *mac[NS_MAX_CARDS];module_param_array(mac, charp, NULL, 0);MODULE_LICENSE("GPL");/* Functions*******************************************************************/static int __devinit nicstar_init_one(struct pci_dev *pcidev,				      const struct pci_device_id *ent){   static int index = -1;   unsigned int error;   index++;   cards[index] = NULL;   error = ns_init_card(index, pcidev);   if (error) {      cards[index--] = NULL;	/* don't increment index */      goto err_out;   }   return 0;err_out:   return -ENODEV;}static void __devexit nicstar_remove_one(struct pci_dev *pcidev){   int i, j;   ns_dev *card = pci_get_drvdata(pcidev);   struct sk_buff *hb;   struct sk_buff *iovb;   struct sk_buff *lb;   struct sk_buff *sb;      i = card->index;   if (cards[i] == NULL)      return;   if (card->atmdev->phy && card->atmdev->phy->stop)      card->atmdev->phy->stop(card->atmdev);   /* Stop everything */   writel(0x00000000, card->membase + CFG);   /* De-register device */   atm_dev_deregister(card->atmdev);   /* Disable PCI device */   pci_disable_device(pcidev);      /* Free up resources */   j = 0;   PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);   while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)   {      dev_kfree_skb_any(hb);      j++;   }   PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);   j = 0;   PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);   while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)   {      dev_kfree_skb_any(iovb);      j++;   }   PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);   while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)      dev_kfree_skb_any(lb);   while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)      dev_kfree_skb_any(sb);   free_scq(card->scq0, NULL);   for (j = 0; j < NS_FRSCD_NUM; j++)   {      if (card->scd2vc[j] != NULL)         free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);   }   kfree(card->rsq.org);   kfree(card->tsq.org);   free_irq(card->pcidev->irq, card);   iounmap(card->membase);   kfree(card);}static struct pci_device_id nicstar_pci_tbl[] __devinitdata ={	{PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{0,}			/* terminate list */};MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);static struct pci_driver nicstar_driver = {	.name		= "nicstar",	.id_table	= nicstar_pci_tbl,	.probe		= nicstar_init_one,	.remove		= __devexit_p(nicstar_remove_one),};static int __init nicstar_init(void){   unsigned error = 0;	/* Initialized to remove compile warning */   XPRINTK("nicstar: nicstar_init() called.\n");   error = pci_register_driver(&nicstar_driver);      TXPRINTK("nicstar: TX debug enabled.\n");   RXPRINTK("nicstar: RX debug enabled.\n");   PRINTK("nicstar: General debug enabled.\n");#ifdef PHY_LOOPBACK   printk("nicstar: using PHY loopback.\n");#endif /* PHY_LOOPBACK */   XPRINTK("nicstar: nicstar_init() returned.\n");   if (!error) {      init_timer(&ns_timer);      ns_timer.expires = jiffies + NS_POLL_PERIOD;      ns_timer.data = 0UL;      ns_timer.function = ns_poll;      add_timer(&ns_timer);   }      return error;}static void __exit nicstar_cleanup(void){   XPRINTK("nicstar: nicstar_cleanup() called.\n");   del_timer(&ns_timer);   pci_unregister_driver(&nicstar_driver);   XPRINTK("nicstar: nicstar_cleanup() returned.\n");}static u32 ns_read_sram(ns_dev *card, u32 sram_address){   unsigned long flags;   u32 data;   sram_address <<= 2;   sram_address &= 0x0007FFFC;	/* address must be dword aligned */   sram_address |= 0x50000000;	/* SRAM read command */   ns_grab_res_lock(card, flags);   while (CMD_BUSY(card));   writel(sram_address, card->membase + CMD);   while (CMD_BUSY(card));   data = readl(card->membase + DR0);   spin_unlock_irqrestore(&card->res_lock, flags);   return data;}   static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count){   unsigned long flags;   int i, c;   count--;	/* count range now is 0..3 instead of 1..4 */   c = count;   c <<= 2;	/* to use increments of 4 */   ns_grab_res_lock(card, flags);   while (CMD_BUSY(card));   for (i = 0; i <= c; i += 4)      writel(*(value++), card->membase + i);   /* Note: DR# registers are the first 4 dwords in nicstar's memspace,            so card->membase + DR0 == card->membase */   sram_address <<= 2;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?