📄 iphase.c
字号:
/****************************************************************************** iphase.c: Device driver for Interphase ATM PCI adapter cards Author: Peter Wang <pwang@iphase.com> Interphase Corporation <www.iphase.com> Version: 1.0 ******************************************************************************* This software may be used and distributed according to the terms of the GNU Public License (GPL), incorporated herein by reference. Drivers based on this skeleton fall under the GPL and must retain the authorship (implicit copyright) notice. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Modified from an incomplete driver for Interphase 5575 1KVC 1M card which was originally written by Monalisa Agrawal at UNH. Now this driver supports a variety of varients of Interphase ATM PCI (i)Chip adapter card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) in terms of PHY type, the size of control memory and the size of packet memory. The followings are the change log and history: Bugfix the Mona's UBR driver. Modify the basic memory allocation and dma logic. Port the driver to the latest kernel from 2.0.46. Complete the ABR logic of the driver, and added the ABR work- around for the hardware anormalies. Add the CBR support. Add the flow control logic to the driver to allow rate-limit VC. Add 4K VC support to the board with 512K control memory. Add the support of all the variants of the Interphase ATM PCI (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 (25M UTP25) and x531 (DS3 and E3). Add SMP support. Support and updates available at: ftp://ftp.iphase.com/pub/atm*******************************************************************************/#ifdef IA_MODULE#define MODULE#endif#include <linux/version.h>#include <linux/module.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/pci.h> #include <linux/errno.h> #include <linux/atm.h> #include <linux/atmdev.h> #include <linux/sonet.h> #include <linux/skbuff.h> #include <linux/time.h> #include <linux/sched.h> /* for xtime */ #include <linux/delay.h> #include <linux/uio.h> #include <linux/init.h> #include <asm/system.h> #include <asm/io.h> #include <asm/atomic.h> #include <asm/uaccess.h> #include <asm/string.h> #include <asm/byteorder.h> #include <math.h> #include <linux/vmalloc.h> #include "iphase.h" #include "suni.h" #define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) struct suni_priv { struct k_sonet_stats sonet_stats; /* link diagnostics */ unsigned char loop_mode; /* loopback mode */ struct atm_dev *dev; /* device back-pointer */ struct suni_priv *next; /* next SUNI */}; #define PRIV(dev) ((struct suni_priv *) dev->phy_data)static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr);static IADEV *ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};static struct atm_dev *_ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};static int iadev_count = 0;static void ia_led_timer(unsigned long arg);static struct timer_list ia_timer = { function: ia_led_timer };struct atm_vcc *vcc_close_que[100];static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ;static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ;static u32 IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER |IF_IADBG_ABR | IF_IADBG_EVENT*/ 0; #ifdef MODULEMODULE_PARM(IA_TX_BUF, "i");MODULE_PARM(IA_TX_BUF_SZ, "i");MODULE_PARM(IA_RX_BUF, "i");MODULE_PARM(IA_RX_BUF_SZ, "i");MODULE_PARM(IADebugFlag, "i");#endif/**************************** IA_LIB **********************************/static void ia_init_rtn_q (IARTN_Q *que) { que->next = NULL; que->tail = NULL; }static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data) { data->next = NULL; if (que->next == NULL) que->next = que->tail = data; else { data->next = que->next; que->next = data; } return;}static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) { IARTN_Q *entry; entry = (IARTN_Q *)kmalloc(sizeof(IARTN_Q), GFP_KERNEL); if (!entry) return -1; entry->data = data; entry->next = NULL; if (que->next == NULL) que->next = que->tail = entry; else { que->tail->next = entry; que->tail = que->tail->next; } return 1;}static IARTN_Q * ia_deque_rtn_q (IARTN_Q *que) { IARTN_Q *tmpdata; if (que->next == NULL) return NULL; tmpdata = que->next; if ( que->next == que->tail) que->next = que->tail = NULL; else que->next = que->next->next; return tmpdata;}static void ia_hack_tcq(IADEV *dev) { u_short desc1; u_short tcq_wr; struct ia_vcc *iavcc_r = NULL; extern void desc_dbg(IADEV *iadev); tcq_wr = readl(dev->seg_reg+TCQ_WR_PTR) & 0xffff; while (dev->host_tcq_wr != tcq_wr) { desc1 = *(u_short *)(dev->seg_ram + dev->host_tcq_wr); if (!desc1) ; else if (!dev->desc_tbl[desc1 -1].timestamp) { IF_ABR(printk(" Desc %d is reset at %ld\n", desc1 -1, jiffies);) *(u_short *) (dev->seg_ram + dev->host_tcq_wr) = 0; } else if (dev->desc_tbl[desc1 -1].timestamp) { if (!(iavcc_r = dev->desc_tbl[desc1 -1].iavcc)) { printk("IA: Fatal err in get_desc\n"); continue; } iavcc_r->vc_desc_cnt--; dev->desc_tbl[desc1 -1].timestamp = 0; IF_EVENT(printk("ia_hack: return_q skb = 0x%x desc = %d\n", (u32)dev->desc_tbl[desc1 -1].txskb, desc1);) if (iavcc_r->pcr < dev->rate_limit) { IA_SKB_STATE (dev->desc_tbl[desc1-1].txskb) |= IA_TX_DONE; if (ia_enque_rtn_q(&dev->tx_return_q, dev->desc_tbl[desc1 -1]) < 0) printk("ia_hack_tcq: No memory available\n"); } dev->desc_tbl[desc1 -1].iavcc = NULL; dev->desc_tbl[desc1 -1].txskb = NULL; } dev->host_tcq_wr += 2; if (dev->host_tcq_wr > dev->ffL.tcq_ed) dev->host_tcq_wr = dev->ffL.tcq_st; }} /* ia_hack_tcq */static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) { u_short desc_num, i; struct sk_buff *skb; struct ia_vcc *iavcc_r = NULL; unsigned long delta; static unsigned long timer = 0; int ltimeout; extern void desc_dbg(IADEV *iadev); ia_hack_tcq (dev); if(((jiffies - timer)>50)||((dev->ffL.tcq_rd==dev->host_tcq_wr))){ timer = jiffies; i=0; while (i < dev->num_tx_desc) { if (!dev->desc_tbl[i].timestamp) { i++; continue; } ltimeout = dev->desc_tbl[i].iavcc->ltimeout; delta = jiffies - dev->desc_tbl[i].timestamp; if (delta >= ltimeout) { IF_ABR(printk("RECOVER run!! desc_tbl %d = %d delta = %ld, time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);) if (dev->ffL.tcq_rd == dev->ffL.tcq_st) dev->ffL.tcq_rd = dev->ffL.tcq_ed; else dev->ffL.tcq_rd -= 2; *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd) = i+1; if (!(skb = dev->desc_tbl[i].txskb) || !(iavcc_r = dev->desc_tbl[i].iavcc)) printk("Fatal err, desc table vcc or skb is NULL\n"); else iavcc_r->vc_desc_cnt--; dev->desc_tbl[i].timestamp = 0; dev->desc_tbl[i].iavcc = NULL; dev->desc_tbl[i].txskb = NULL; } i++; } /* while */ } if (dev->ffL.tcq_rd == dev->host_tcq_wr) return 0xFFFF; /* Get the next available descriptor number from TCQ */ desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) { dev->ffL.tcq_rd += 2; if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) dev->ffL.tcq_rd = dev->ffL.tcq_st; if (dev->ffL.tcq_rd == dev->host_tcq_wr) return 0xFFFF; desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); } /* get system time */ dev->desc_tbl[desc_num -1].timestamp = jiffies; return desc_num;}static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { u_char foundLockUp; vcstatus_t *vcstatus; u_short *shd_tbl; u_short tempCellSlot, tempFract; struct main_vc *abr_vc = (struct main_vc *)dev->MAIN_VC_TABLE_ADDR; struct ext_vc *eabr_vc = (struct ext_vc *)dev->EXT_VC_TABLE_ADDR; u_int i; if (vcc->qos.txtp.traffic_class == ATM_ABR) { vcstatus = (vcstatus_t *) &(dev->testTable[vcc->vci]->vc_status); vcstatus->cnt++; foundLockUp = 0; if( vcstatus->cnt == 0x05 ) { abr_vc += vcc->vci; eabr_vc += vcc->vci; if( eabr_vc->last_desc ) { if( (abr_vc->status & 0x07) == ABR_STATE /* 0x2 */ ) { /* Wait for 10 Micro sec */ udelay(10); if ((eabr_vc->last_desc)&&((abr_vc->status & 0x07)==ABR_STATE)) foundLockUp = 1; } else { tempCellSlot = abr_vc->last_cell_slot; tempFract = abr_vc->fraction; if((tempCellSlot == dev->testTable[vcc->vci]->lastTime) && (tempFract == dev->testTable[vcc->vci]->fract)) foundLockUp = 1; dev->testTable[vcc->vci]->lastTime = tempCellSlot; dev->testTable[vcc->vci]->fract = tempFract; } } /* last descriptor */ vcstatus->cnt = 0; } /* vcstatus->cnt */ if (foundLockUp) { IF_ABR(printk("LOCK UP found\n");) writew(0xFFFD, dev->seg_reg+MODE_REG_0); /* Wait for 10 Micro sec */ udelay(10); abr_vc->status &= 0xFFF8; abr_vc->status |= 0x0001; /* state is idle */ shd_tbl = (u_short *)dev->ABR_SCHED_TABLE_ADDR; for( i = 0; ((i < dev->num_vc) && (shd_tbl[i])); i++ ); if (i < dev->num_vc) shd_tbl[i] = vcc->vci; else IF_ERR(printk("ABR Seg. may not continue on VC %x\n",vcc->vci);) writew(T_ONLINE, dev->seg_reg+MODE_REG_0); writew(~(TRANSMIT_DONE|TCQ_NOT_EMPTY), dev->seg_reg+SEG_MASK_REG); writew(TRANSMIT_DONE, dev->seg_reg+SEG_INTR_STATUS_REG); vcstatus->cnt = 0; } /* foundLockUp */ } /* if an ABR VC */} /*** Conversion of 24-bit cellrate (cells/sec) to 16-bit floating point format.**** +----+----+------------------+-------------------------------+** | R | NZ | 5-bit exponent | 9-bit mantissa |** +----+----+------------------+-------------------------------+** ** R = reserverd (written as 0)** NZ = 0 if 0 cells/sec; 1 otherwise**** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec*/static u16cellrate_to_float(u32 cr){#define NZ 0x4000#define M_BITS 9 /* Number of bits in mantissa */#define E_BITS 5 /* Number of bits in exponent */#define M_MASK 0x1ff #define E_MASK 0x1f u16 flot; u32 tmp = cr & 0x00ffffff; int i = 0; if (cr == 0) return 0; while (tmp != 1) { tmp >>= 1; i++; } if (i == M_BITS) flot = NZ | (i << M_BITS) | (cr & M_MASK); else if (i < M_BITS) flot = NZ | (i << M_BITS) | ((cr << (M_BITS - i)) & M_MASK); else flot = NZ | (i << M_BITS) | ((cr >> (i - M_BITS)) & M_MASK); return flot;}#if 0/*** Conversion of 16-bit floating point format to 24-bit cellrate (cells/sec).*/static u32float_to_cellrate(u16 rate){ u32 exp, mantissa, cps; if ((rate & NZ) == 0) return 0; exp = (rate >> M_BITS) & E_MASK; mantissa = rate & M_MASK; if (exp == 0) return 1; cps = (1 << M_BITS) | mantissa; if (exp == M_BITS) cps = cps; else if (exp > M_BITS) cps <<= (exp - M_BITS); else cps >>= (M_BITS - exp); return cps;}#endif static void init_abr_vc (IADEV *dev, srv_cls_param_t *srv_p) { srv_p->class_type = ATM_ABR; srv_p->pcr = dev->LineRate; srv_p->mcr = 0; srv_p->icr = 0x055cb7; srv_p->tbe = 0xffffff; srv_p->frtt = 0x3a; srv_p->rif = 0xf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -