📄 nicstar.c
字号:
/****************************************************************************** * * 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/config.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"#include "nicstarmac.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 *//* 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 MAX(a,b) ((a) > (b) ? (a) : (b))#define MIN(a,b) ((a) < (b) ? (a) : (b))#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(d)#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 *//* Version definition *********************************************************//*#include <linux/version.h>char kernel_version[] = UTS_RELEASE;*//* 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 ns_init_card(int i, struct pci_dev *pcidev);static void 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 *card, u32 type, u32 handle1, u32 addr1, u32 handle2, u32 addr2);static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs);static int ns_open(struct atm_vcc *vcc, short vpi, int vci);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 *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_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s");/* Functions*******************************************************************/#ifdef MODULEint init_module(void){ int i; unsigned error = 0; /* Initialized to remove compile warning */ struct pci_dev *pcidev; XPRINTK("nicstar: init_module() called.\n"); if(!pci_present()) { printk("nicstar: no PCI subsystem found.\n"); return -EIO; } for(i = 0; i < NS_MAX_CARDS; i++) cards[i] = NULL; pcidev = NULL; for(i = 0; i < NS_MAX_CARDS; i++) { if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201, pcidev)) == NULL) break; error = ns_init_card(i, pcidev); if (error) cards[i--] = NULL; /* Try to find another card but don't increment index */ } if (i == 0) { if (!error) { printk("nicstar: no cards found.\n"); return -ENXIO; } else return -EIO; } 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: init_module() returned.\n"); 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 0;}void cleanup_module(void){ int i, j; unsigned short pci_command; ns_dev *card; struct sk_buff *hb; struct sk_buff *iovb; struct sk_buff *lb; struct sk_buff *sb; XPRINTK("nicstar: cleanup_module() called.\n"); if (MOD_IN_USE) printk("nicstar: module in use, remove delayed.\n"); del_timer(&ns_timer); for (i = 0; i < NS_MAX_CARDS; i++) { if (cards[i] == NULL) continue; card = cards[i];#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 if (card->max_pcr == ATM_25_PCR) { idt77105_stop(card->atmdev); }#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ /* Stop everything */ writel(0x00000000, card->membase + CFG); /* De-register device */ atm_dev_deregister(card->atmdev); /* Disable memory mapping and busmastering */ if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command) != 0) { printk("nicstar%d: can't read PCI_COMMAND.\n", i); } pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command) != 0) { printk("nicstar%d: can't write PCI_COMMAND.\n", i); } /* 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((void *) card->membase); kfree(card); } XPRINTK("nicstar: cleanup_module() returned.\n");}#elseint __init nicstar_detect(void){ int i; unsigned error = 0; /* Initialized to remove compile warning */ struct pci_dev *pcidev; if(!pci_present()) { printk("nicstar: no PCI subsystem found.\n"); return -EIO; } for(i = 0; i < NS_MAX_CARDS; i++) cards[i] = NULL; pcidev = NULL; for(i = 0; i < NS_MAX_CARDS; i++) { if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -