fore200e.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,369 行 · 第 1/5 页

C
2,369
字号
	    dma_addr, size, direction);    pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);}static voidfore200e_pca_dma_sync_for_cpu(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_for_cpu((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);}static voidfore200e_pca_dma_sync_for_device(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_for_device((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){    /* returned chunks are page-aligned */    chunk->alloc_size = size * nbr;    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;        return 0;}/* free a DMA consistent chunk of memory */static voidfore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk){    pci_free_consistent((struct pci_dev*)fore200e->bus_dev,			chunk->alloc_size,			chunk->alloc_addr,			chunk->dma_addr);}static intfore200e_pca_irq_check(struct fore200e* fore200e){    /* this is a 1 bit register */    int irq_posted = readl(fore200e->regs.pca.psr);#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG == 2)    if (irq_posted && (readl(fore200e->regs.pca.hcr) & PCA200E_HCR_OUTFULL)) {	DPRINTK(2,"FIFO OUT full, device %d\n", fore200e->atm_dev->number);    }#endif    return irq_posted;}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 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);    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, latency;    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 defined(__BIG_ENDIAN)	/* request the PCA board to convert the endianess of slave RAM accesses */	| PCA200E_CTRL_CONVERT_ENDIAN#endif#if 0        | PCA200E_CTRL_DIS_CACHE_RD        | PCA200E_CTRL_DIS_WRT_INVAL        | PCA200E_CTRL_ENA_CONT_REQ_MODE        | PCA200E_CTRL_2_CACHE_WRT_INVAL#endif	| PCA200E_CTRL_LARGE_PCI_BURSTS;        pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl);    /* raise latency from 32 (default) to 192, as this seems to prevent NIC       lockups (under heavy rx loads) due to continuous 'FIFO OUT full' condition.       this may impact the performances of other PCI devices on the same bus, though */    latency = 192;    pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);    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;        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);    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), DMA_FROM_DEVICE);    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), DMA_FROM_DEVICE);    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_for_cpu(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_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);}static voidfore200e_sba_dma_sync_for_device(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_for_device((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 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);    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 (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;    }    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;}static int __initfore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom){    struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;

⌨️ 快捷键说明

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