📄 firestream.c
字号:
fs_dprintk (FS_DEBUG_IRQ, " %s", irq_bitname[i]); fs_dprintk (FS_DEBUG_IRQ, "\n"); } if (status & ISR_RBRQ0_W) { fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (0)!!!!\n"); process_incoming (dev, &dev->rx_rq[0]); /* items mentioned on RBRQ0 are from FP 0 or 1. */ top_off_fp (dev, &dev->rx_fp[0], GFP_ATOMIC); top_off_fp (dev, &dev->rx_fp[1], GFP_ATOMIC); } if (status & ISR_RBRQ1_W) { fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (1)!!!!\n"); process_incoming (dev, &dev->rx_rq[1]); top_off_fp (dev, &dev->rx_fp[2], GFP_ATOMIC); top_off_fp (dev, &dev->rx_fp[3], GFP_ATOMIC); } if (status & ISR_RBRQ2_W) { fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (2)!!!!\n"); process_incoming (dev, &dev->rx_rq[2]); top_off_fp (dev, &dev->rx_fp[4], GFP_ATOMIC); top_off_fp (dev, &dev->rx_fp[5], GFP_ATOMIC); } if (status & ISR_RBRQ3_W) { fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (3)!!!!\n"); process_incoming (dev, &dev->rx_rq[3]); top_off_fp (dev, &dev->rx_fp[6], GFP_ATOMIC); top_off_fp (dev, &dev->rx_fp[7], GFP_ATOMIC); } if (status & ISR_CSQ_W) { fs_dprintk (FS_DEBUG_IRQ, "Command executed ok!\n"); process_return_queue (dev, &dev->st_q); } if (status & ISR_TBRQ_W) { fs_dprintk (FS_DEBUG_IRQ, "Data tramsitted!\n"); process_txdone_queue (dev, &dev->tx_relq); } func_exit ();}#ifdef FS_POLL_FREQstatic void fs_poll (unsigned long data){ struct fs_dev *dev = (struct fs_dev *) data; fs_irq (0, dev, NULL); dev->timer.expires = jiffies + FS_POLL_FREQ; add_timer (&dev->timer);}#endifstatic int __init fs_init (struct fs_dev *dev){ struct pci_dev *pci_dev; int isr, to; int i; func_enter (); pci_dev = dev->pci_dev; printk (KERN_INFO "found a FireStream %d card, base %08lx, irq%d.\n", IS_FS50(dev)?50:155, pci_resource_start(pci_dev, 0), dev->pci_dev->irq); if (fs_debug & FS_DEBUG_INIT) my_hd ((unsigned char *) dev, sizeof (*dev)); undocumented_pci_fix (pci_dev); dev->hw_base = pci_resource_start(pci_dev, 0); dev->base = (ulong) ioremap(dev->hw_base, 0x1000); reset_chip (dev); write_fs (dev, SARMODE0, 0 | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */ | (1 * SARMODE0_INTMODE_READCLEAR) | (1 * SARMODE0_CWRE) | IS_FS50(dev)?SARMODE0_PRPWT_FS50_5: SARMODE0_PRPWT_FS155_3 | (1 * SARMODE0_CALSUP_1) | IS_FS50 (dev)?(0 | SARMODE0_RXVCS_32 | SARMODE0_ABRVCS_32 | SARMODE0_TXVCS_32): (0 | SARMODE0_RXVCS_1k | SARMODE0_ABRVCS_1k | SARMODE0_TXVCS_1k)); /* 10ms * 100 is 1 second. That should be enough, as AN3:9 says it takes 1ms. */ to = 100; while (--to) { isr = read_fs (dev, ISR); /* This bit is documented as "RESERVED" */ if (isr & ISR_INIT_ERR) { printk (KERN_ERR "Error initializing the FS... \n"); return 1; } if (isr & ISR_INIT) { fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n"); break; } /* Try again after 10ms. */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout ((HZ+99)/100); } if (!to) { printk (KERN_ERR "timeout initializing the FS... \n"); return 1; } /* XXX fix for fs155 */ dev->channel_mask = 0x1f; dev->channo = 0; /* AN3: 10 */ write_fs (dev, SARMODE1, 0 | (0 * SARMODE1_DEFHEC) /* XXX PHY */ | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */ | (1 * SARMODE1_DCRM) | (1 * SARMODE1_DCOAM) | (0 * SARMODE1_OAMCRC) | (0 * SARMODE1_DUMPE) | (0 * SARMODE1_GPLEN) | (0 * SARMODE1_GNAM) | (0 * SARMODE1_GVAS) | (0 * SARMODE1_GPAS) | (1 * SARMODE1_GPRI) | (0 * SARMODE1_PMS) | (0 * SARMODE1_GFCR) | (1 * SARMODE1_HECM2) | (1 * SARMODE1_HECM1) | (1 * SARMODE1_HECM0) | (1 << 12) /* That's what hang's driver does. Program to 0 */ | (0 * 0xff) /* XXX FS155 */); /* Cal prescale etc */ /* AN3: 11 */ write_fs (dev, TMCONF, 0x0000000f); write_fs (dev, CALPRESCALE, 0x01010101 * num); write_fs (dev, 0x80, 0x000F00E4); /* AN3: 12 */ write_fs (dev, CELLOSCONF, 0 | ( 0 * CELLOSCONF_CEN) | ( CELLOSCONF_SC1) | (0x80 * CELLOSCONF_COBS) | (num * CELLOSCONF_COPK) /* Changed from 0xff to 0x5a */ | (num * CELLOSCONF_COST));/* after a hint from Hang. * performance jumped 50->70... */ /* Magic value by Hang */ write_fs (dev, CELLOSCONF_COST, 0x0B809191); if (IS_FS50 (dev)) { write_fs (dev, RAS0, RAS0_DCD_XHLT); dev->atm_dev->ci_range.vpi_bits = 12; dev->atm_dev->ci_range.vci_bits = 16; dev->nchannels = FS50_NR_CHANNELS; } else { write_fs (dev, RAS0, RAS0_DCD_XHLT | (((1 << FS155_VPI_BITS) - 1) * RAS0_VPSEL) | (((1 << FS155_VCI_BITS) - 1) * RAS0_VCSEL)); /* We can chose the split arbitarily. We might be able to support more. Whatever. This should do for now. */ dev->atm_dev->ci_range.vpi_bits = FS155_VPI_BITS; dev->atm_dev->ci_range.vci_bits = FS155_VCI_BITS; /* Address bits we can't use should be compared to 0. */ write_fs (dev, RAC, 0); /* Manual (AN9, page 6) says ASF1=0 means compare Utopia address * too. I can't find ASF1 anywhere. Anyway, we AND with just hte * other bits, then compare with 0, which is exactly what we * want. */ write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1); dev->nchannels = FS155_NR_CHANNELS; } dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *), GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%d)\n", dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *)); if (!dev->atm_vccs) { printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n"); /* XXX Clean up..... */ return 1; } memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *)); dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n", dev->atm_vccs, dev->nchannels / 8); if (!dev->tx_inuse) { printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n"); /* XXX Clean up..... */ return 1; } memset (dev->tx_inuse, 0, dev->nchannels / 8); /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */ /* -- RAS2 : FS50 only: Default is OK. */ /* DMAMODE, default should be OK. -- REW */ write_fs (dev, DMAMR, DMAMR_TX_MODE_FULL); init_q (dev, &dev->hp_txq, TX_PQ(TXQ_HP), TXQ_NENTRIES, 0); init_q (dev, &dev->lp_txq, TX_PQ(TXQ_LP), TXQ_NENTRIES, 0); init_q (dev, &dev->tx_relq, TXB_RQ, TXQ_NENTRIES, 1); init_q (dev, &dev->st_q, ST_Q, TXQ_NENTRIES, 1); for (i=0;i < FS_NR_FREE_POOLS;i++) { init_fp (dev, &dev->rx_fp[i], RXB_FP(i), rx_buf_sizes[i], rx_pool_sizes[i]); top_off_fp (dev, &dev->rx_fp[i], GFP_KERNEL); } for (i=0;i < FS_NR_RX_QUEUES;i++) init_q (dev, &dev->rx_rq[i], RXB_RQ(i), RXRQ_NENTRIES, 1); dev->irq = pci_dev->irq; if (request_irq (dev->irq, fs_irq, SA_SHIRQ, "firestream", dev)) { printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq); /* XXX undo all previous stuff... */ return 1; } fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev); /* We want to be notified of most things. Just the statistics count overflows are not interesting */ write_fs (dev, IMR, 0 | ISR_RBRQ0_W | ISR_RBRQ1_W | ISR_RBRQ2_W | ISR_RBRQ3_W | ISR_TBRQ_W | ISR_CSQ_W); write_fs (dev, SARMODE0, 0 | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */ | (1 * SARMODE0_GINT) | (1 * SARMODE0_INTMODE_READCLEAR) | (0 * SARMODE0_CWRE) | (IS_FS50(dev)?SARMODE0_PRPWT_FS50_5: SARMODE0_PRPWT_FS155_3) | (1 * SARMODE0_CALSUP_1) | (IS_FS50 (dev)?(0 | SARMODE0_RXVCS_32 | SARMODE0_ABRVCS_32 | SARMODE0_TXVCS_32): (0 | SARMODE0_RXVCS_1k | SARMODE0_ABRVCS_1k | SARMODE0_TXVCS_1k)) | (1 * SARMODE0_RUN)); init_phy (dev, PHY_NTC_INIT); if (loopback == 2) { write_phy (dev, 0x39, 0x000e); }#ifdef FS_POLL_FREQ init_timer (&dev->timer); dev->timer.data = (unsigned long) dev; dev->timer.function = fs_poll; dev->timer.expires = jiffies + FS_POLL_FREQ; add_timer (&dev->timer);#endif dev->atm_dev->dev_data = dev; func_exit (); return 0;}static int __init firestream_init_one (struct pci_dev *pci_dev, const struct pci_device_id *ent) { struct atm_dev *atm_dev; struct fs_dev *fs_dev; if (pci_enable_device(pci_dev)) goto err_out; fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL); fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%d)\n", fs_dev, sizeof (struct fs_dev)); if (!fs_dev) goto err_out; memset (fs_dev, 0, sizeof (struct fs_dev)); atm_dev = atm_dev_register("fs", &ops, -1, NULL); if (!atm_dev) goto err_out_free_fs_dev; fs_dev->pci_dev = pci_dev; fs_dev->atm_dev = atm_dev; fs_dev->flags = ent->driver_data; if (fs_init(fs_dev)) goto err_out_free_atm_dev; fs_dev->next = fs_boards; fs_boards = fs_dev; return 0; err_out_free_atm_dev: atm_dev_deregister(atm_dev); err_out_free_fs_dev: kfree(fs_dev); err_out: return -ENODEV;}void __devexit firestream_remove_one (struct pci_dev *pdev){ int i; struct fs_dev *dev, *nxtdev; struct fs_vcc *vcc; struct FS_BPENTRY *fp, *nxt; func_enter ();#if 0 printk ("hptxq:\n"); for (i=0;i<60;i++) { printk ("%d: %08x %08x %08x %08x \n", i, pq[qp].cmd, pq[qp].p0, pq[qp].p1, pq[qp].p2); qp++; if (qp >= 60) qp = 0; } printk ("descriptors:\n"); for (i=0;i<60;i++) { printk ("%d: %p: %08x %08x %p %p\n", i, da[qd], dq[qd].flags, dq[qd].bsa, dq[qd].skb, dq[qd].dev); qd++; if (qd >= 60) qd = 0; }#endif for (dev = fs_boards;dev != NULL;dev=nxtdev) { fs_dprintk (FS_DEBUG_CLEANUP, "Releasing resources for dev at %p.\n", dev); /* XXX Hit all the tx channels too! */ for (i=0;i < dev->nchannels;i++) { if (dev->atm_vccs[i]) { vcc = FS_VCC (dev->atm_vccs[i]); submit_command (dev, &dev->hp_txq, QE_CMD_TX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0); submit_command (dev, &dev->hp_txq, QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0); } } /* XXX Wait a while for the chip to release all buffers. */ for (i=0;i < FS_NR_FREE_POOLS;i++) { for (fp=bus_to_virt (read_fs (dev, FP_SA(dev->rx_fp[i].offset))); !(fp->flags & FP_FLAGS_EPI);fp = nxt) { fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb); dev_kfree_skb_any (fp->skb); nxt = bus_to_virt (fp->next); fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp); kfree (fp); } fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb); dev_kfree_skb_any (fp->skb); fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp); kfree (fp); } /* Hang the chip in "reset", prevent it clobbering memory that is no longer ours. */ reset_chip (dev); fs_dprintk (FS_DEBUG_CLEANUP, "Freeing irq%d.\n", dev->irq); free_irq (dev->irq, dev); del_timer (&dev->timer); atm_dev_deregister(dev->atm_dev); free_queue (dev, &dev->hp_txq); free_queue (dev, &dev->lp_txq); free_queue (dev, &dev->tx_relq); free_queue (dev, &dev->st_q); fs_dprintk (FS_DEBUG_ALLOC, "Free atmvccs: %p\n", dev->atm_vccs); kfree (dev->atm_vccs); for (i=0;i< FS_NR_FREE_POOLS;i++) free_freepool (dev, &dev->rx_fp[i]); for (i=0;i < FS_NR_RX_QUEUES;i++) free_queue (dev, &dev->rx_rq[i]); fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev); nxtdev = dev->next; kfree (dev); } func_exit ();}#if 0int __init fs_detect(void){ struct pci_dev *pci_dev; int devs = 0; func_enter (); pci_dev = NULL; while ((pci_dev = pci_find_device(PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50, pci_dev))) { if (fs_register_and_init (pci_dev, &fs_pci_tbl[0])) break; devs++; } while ((pci_dev = pci_find_device(PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155, pci_dev))) { if (fs_register_and_init (pci_dev, FS_IS155)) break; devs++; } func_exit (); return devs;}#else#if 0int __init init_PCI (void){ /* Begin init_PCI */ int pci_count; printk ("init_PCI\n"); /* memset (&firestream_driver, 0, sizeof (firestream_driver)); firestream_driver.name = "firestream"; firestream_driver.id_table = firestream_pci_tbl; firestream_driver.probe = fs_register_and_init; */ pci_count = pci_register_driver (&firestream_driver); if (pci_count <= 0) { pci_unregister_driver (&firestream_driver); pci_count = 0; } return(pci_count);} /* End init_PCI */#endif#endif/*#ifdef MODULE#define firestream_init init_module#endif */const static struct pci_device_id firestream_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50}, { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS155}, { 0, }};MODULE_DEVICE_TABLE(pci, firestream_pci_tbl);static struct pci_driver firestream_driver = { name: "firestream", id_table: firestream_pci_tbl, probe: firestream_init_one, remove: firestream_remove_one,};static int __init firestream_init_module (void){ int error; func_enter (); error = pci_module_init(&firestream_driver); func_exit (); return error;}static void __exit firestream_cleanup_module(void){ pci_unregister_driver(&firestream_driver);}module_init(firestream_init_module);module_exit(firestream_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -