📄 fore200e.c
字号:
static voidfore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction){ DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);}static voidfore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction){ DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);}/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */static intfore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment){#if defined(__sparc_v9__) /* returned chunks are page-aligned */ chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, chunk->alloc_size, &chunk->dma_addr); if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) return -ENOMEM; chunk->align_addr = chunk->alloc_addr;#else if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0) return -ENOMEM;#endif return 0;}/* free a DMA consistent chunk of memory */static voidfore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk){#if defined(__sparc_v9__) pci_free_consistent((struct pci_dev*)fore200e->bus_dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr);#else fore200e_chunk_free(fore200e, chunk);#endif}static intfore200e_pca_irq_check(struct fore200e* fore200e){ /* this is a 1 bit register */ return readl(fore200e->regs.pca.psr);}static voidfore200e_pca_irq_ack(struct fore200e* fore200e){ writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr);}static voidfore200e_pca_reset(struct fore200e* fore200e){ writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); fore200e_spin(10); writel(0, fore200e->regs.pca.hcr);}static int __initfore200e_pca_map(struct fore200e* fore200e){ DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); if (fore200e->virt_base == NULL) { printk(FORE200E "can't map device %s\n", fore200e->name); return -EFAULT; } DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); /* gain access to the PCA-200E specific registers */ fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); fore200e->state = FORE200E_STATE_MAP; return 0;}static voidfore200e_pca_unmap(struct fore200e* fore200e){ DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), this leads to a kernel panic if the module is loaded and unloaded several times */ if (fore200e->virt_base != NULL) iounmap(fore200e->virt_base);}static int __initfore200e_pca_configure(struct fore200e* fore200e){ struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; u8 master_ctrl; DPRINTK(2, "device %s being configured\n", fore200e->name); if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) { printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); return -EIO; } pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); master_ctrl = master_ctrl#if 0 | PCA200E_CTRL_DIS_CACHE_RD | PCA200E_CTRL_DIS_WRT_INVAL#endif#if defined(__BIG_ENDIAN) /* request the PCA board to convert the endianess of slave RAM accesses */ | PCA200E_CTRL_CONVERT_ENDIAN#endif | PCA200E_CTRL_LARGE_PCI_BURSTS; pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); fore200e->state = FORE200E_STATE_CONFIGURE; return 0;}static struct fore200e* __initfore200e_pca_detect(const struct fore200e_bus* bus, int index){ struct fore200e* fore200e; struct pci_dev* pci_dev = NULL; int count = index; if (pci_present() == 0) { printk(FORE200E "no PCI subsystem\n"); return NULL; } do { pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev); if (pci_dev == NULL) return NULL; } while (count--); if (pci_enable_device(pci_dev)) return NULL; fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) return NULL; fore200e->bus = bus; fore200e->bus_dev = pci_dev; fore200e->irq = pci_dev->irq; fore200e->phys_base = pci_resource_start (pci_dev, 0);#if defined(__powerpc__) fore200e->phys_base += KERNELBASE;#endif sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); pci_set_master(pci_dev); return fore200e;}static int __initfore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; struct prom_opcode opcode; int ok; u32 prom_dma; FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); opcode.opcode = OPCODE_GET_PROM; opcode.pad = 0; prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode); ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); *entry->status = STATUS_FREE; fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); return -EIO; }#if defined(__BIG_ENDIAN) #define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) /* MAC address is stored as little-endian */ swap_here(&prom->mac_addr[0]); swap_here(&prom->mac_addr[4]);#endif return 0;}static intfore200e_pca_proc_read(struct fore200e* fore200e, char *page){ struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));}#endif /* CONFIG_ATM_FORE200E_PCA */#ifdef CONFIG_ATM_FORE200E_SBAstatic u32fore200e_sba_read(volatile u32* addr){ return sbus_readl(addr);}static voidfore200e_sba_write(u32 val, volatile u32* addr){ sbus_writel(val, addr);}static u32fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction){ u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction); DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", virt_addr, size, direction, dma_addr); return dma_addr;}static voidfore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction){ DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction); sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);}static voidfore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction){ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);}/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */static intfore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment){ chunk->alloc_size = chunk->align_size = size * nbr; /* returned chunks are page-aligned */ chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, chunk->alloc_size, &chunk->dma_addr); if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) return -ENOMEM; chunk->align_addr = chunk->alloc_addr; return 0;}/* free a DVMA consistent chunk of memory */static voidfore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk){ sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr);}static voidfore200e_sba_irq_enable(struct fore200e* fore200e){ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);}static intfore200e_sba_irq_check(struct fore200e* fore200e){ return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;}static voidfore200e_sba_irq_ack(struct fore200e* fore200e){ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);}static voidfore200e_sba_reset(struct fore200e* fore200e){ fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); fore200e_spin(10); fore200e->bus->write(0, fore200e->regs.sba.hcr);}static int __initfore200e_sba_map(struct fore200e* fore200e){ struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; unsigned int bursts; /* gain access to the SBA-200E specific registers */ fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); fore200e->virt_base = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); if (fore200e->virt_base == NULL) { printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); return -EFAULT; } DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ /* get the supported DVMA burst sizes */ bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); if (sbus_can_dma_64bit(sbus_dev)) sbus_set_sbus64(sbus_dev, bursts);#if 0 if (bursts & DMA_BURST16) fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr); else if (bursts & DMA_BURST8) fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr); else if (bursts & DMA_BURST4) fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr);#endif fore200e->state = FORE200E_STATE_MAP; return 0;}static voidfore200e_sba_unmap(struct fore200e* fore200e){ sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); sbus_iounmap((ulong)fore200e->virt_base, SBA200E_RAM_LENGTH);}static int __initfore200e_sba_configure(struct fore200e* fore200e){ fore200e->state = FORE200E_STATE_CONFIGURE; return 0;}static struct fore200e* __initfore200e_sba_detect(const struct fore200e_bus* bus, int index){ struct fore200e* fore200e; struct sbus_bus* sbus_bus; struct sbus_dev* sbus_dev = NULL; unsigned int count = 0; for_each_sbus (sbus_bus) { for_each_sbusdev (sbus_dev, sbus_bus) { if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { if (count >= index) goto found; count++; } } } return NULL; found:#if 1 if (sbus_dev->num_registers != 4) { printk(FORE200E "this %s device has %d instead of 4 registers\n", bus->model_name, sbus_dev->num_registers); return NULL; }#endif fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) return NULL; fore200e->bus = bus; fore200e->bus_dev = sbus_dev; fore200e->irq = sbus_dev->irqs[ 0 ]; fore200e->phys_base = (unsigned long)sbus_dev; sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); return fore200e;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -