pcibr_dvr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,108 行 · 第 1/5 页
C
2,108 行
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */#include <linux/module.h>#include <linux/string.h>#include <linux/interrupt.h>#include <asm/sn/sgi.h>#include <asm/sn/sn_sal.h>#include <asm/sn/iograph.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/pci/pci_defs.h>#include <asm/sn/prio.h> #include <asm/sn/sn_private.h>/* * global variables to toggle the different levels of pcibr debugging. * -pcibr_debug_mask is the mask of the different types of debugging * you want to enable. See sys/PCI/pcibr_private.h * -pcibr_debug_module is the module you want to trace. By default * all modules are trace. The format is something like "001c10". * -pcibr_debug_widget is the widget you want to trace. For TIO * based bricks use the corelet id. * -pcibr_debug_slot is the pci slot you want to trace. */uint32_t pcibr_debug_mask; /* 0x00000000 to disable */static char *pcibr_debug_module = "all"; /* 'all' for all modules */static int pcibr_debug_widget = -1; /* '-1' for all widgets */static int pcibr_debug_slot = -1; /* '-1' for all slots */#if PCIBR_SOFT_LISTpcibr_list_p pcibr_list;#endifextern char *pci_space[];/* ===================================================================== * Function Table of Contents * * The order of functions in this file has stopped * making much sense. We might want to take a look * at it some time and bring back some sanity, or * perhaps bust this file into smaller chunks. */extern void do_pcibr_rrb_free_all(pcibr_soft_t, pciio_slot_t);extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);extern void pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, int slot, int vchan, int more_rrbs);extern int pcibr_wrb_flush(vertex_hdl_t);extern int pcibr_rrb_alloc(vertex_hdl_t, int *, int *);void pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int);extern void pcibr_rrb_flush(vertex_hdl_t);static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, uint64_t);void pcibr_release_device(pcibr_soft_t, pciio_slot_t, uint64_t);extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int);extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen);int pcibr_detach(vertex_hdl_t);void pcibr_directmap_init(pcibr_soft_t);int pcibr_pcix_rbars_calc(pcibr_soft_t);extern int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *);extern void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *);extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t);extern void free_pciio_dmamap(pcibr_dmamap_t);extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl);extern void ate_write(pcibr_soft_t, int, int, bridge_ate_t);pcibr_info_t pcibr_info_get(vertex_hdl_t);static iopaddr_t pcibr_addr_pci_to_xio(vertex_hdl_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);void pcibr_piomap_free(pcibr_piomap_t);caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t);void pcibr_piomap_done(pcibr_piomap_t);caddr_t pcibr_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);iopaddr_t pcibr_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t);void pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t);static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t);extern bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned);pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned);void pcibr_dmamap_free(pcibr_dmamap_t);extern bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int);static iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t);iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t);void pcibr_dmamap_done(pcibr_dmamap_t);cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t);iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned);void pcibr_dmamap_drain(pcibr_dmamap_t);void pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t);iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t);void pcibr_provider_startup(vertex_hdl_t);void pcibr_provider_shutdown(vertex_hdl_t);int pcibr_reset(vertex_hdl_t);pciio_endian_t pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t);int pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t);extern int pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t);extern int pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int, char *, int *);pciio_businfo_t pcibr_businfo_get(vertex_hdl_t);/* ===================================================================== * Device(x) register management *//* pcibr_try_set_device: attempt to modify Device(x) * for the specified slot on the specified bridge * as requested in flags, limited to the specified * bits. Returns which BRIDGE bits were in conflict, * or ZERO if everything went OK. * * Caller MUST hold pcibr_lock when calling this function. */static intpcibr_try_set_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, unsigned flags, uint64_t mask){ pcibr_soft_slot_t slotp; uint64_t old; uint64_t new; uint64_t chg; uint64_t bad; uint64_t badpmu; uint64_t badd32; uint64_t badd64; uint64_t fix; unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; s = pcibr_lock(pcibr_soft); old = slotp->bss_device; /* figure out what the desired * Device(x) bits are based on * the flags specified. */ new = old; /* Currently, we inherit anything that * the new caller has not specified in * one way or another, unless we take * action here to not inherit. * * This is needed for the "swap" stuff, * since it could have been set via * pcibr_endian_set -- altho note that * any explicit PCIBR_BYTE_STREAM or * PCIBR_WORD_VALUES will freely override * the effect of that call (and vice * versa, no protection either way). * * I want to get rid of pcibr_endian_set * in favor of tracking DMA endianness * using the flags specified when DMA * channels are created. */#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN)#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) /* Do not use Barrier, Write Gather, * or Prefetch unless asked. * Leave everything else as it * was from the last time. */ new = new & ~BRIDGE_DEV_BARRIER & ~BRIDGE_DEV_WRGA_BITS & ~BRIDGE_DEV_PREF ; /* Generic macro flags */ if (flags & PCIIO_DMA_DATA) { new = (new & ~BRIDGE_DEV_BARRIER) /* barrier off */ | BRIDGE_DEV_PREF; /* prefetch on */ } if (flags & PCIIO_DMA_CMD) { new = ((new & ~BRIDGE_DEV_PREF) /* prefetch off */ & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ | BRIDGE_DEV_BARRIER; /* barrier on */ } /* Generic detail flags */ if (flags & PCIIO_WRITE_GATHER) new |= BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_NOWRITE_GATHER) new &= ~BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_PREFETCH) new |= BRIDGE_DEV_PREF; if (flags & PCIIO_NOPREFETCH) new &= ~BRIDGE_DEV_PREF; if (flags & PCIBR_WRITE_GATHER) new |= BRIDGE_DEV_WRGA_BITS; if (flags & PCIBR_NOWRITE_GATHER) new &= ~BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_BYTE_STREAM) new |= BRIDGE_DEV_SWAP_DIR; if (flags & PCIIO_WORD_VALUES) new &= ~BRIDGE_DEV_SWAP_DIR; /* Provider-specific flags */ if (flags & PCIBR_PREFETCH) new |= BRIDGE_DEV_PREF; if (flags & PCIBR_NOPREFETCH) new &= ~BRIDGE_DEV_PREF; if (flags & PCIBR_PRECISE) new |= BRIDGE_DEV_PRECISE; if (flags & PCIBR_NOPRECISE) new &= ~BRIDGE_DEV_PRECISE; if (flags & PCIBR_BARRIER) new |= BRIDGE_DEV_BARRIER; if (flags & PCIBR_NOBARRIER) new &= ~BRIDGE_DEV_BARRIER; if (flags & PCIBR_64BIT) new |= BRIDGE_DEV_DEV_SIZE; if (flags & PCIBR_NO64BIT) new &= ~BRIDGE_DEV_DEV_SIZE; /* * PIC BRINGUP WAR (PV# 855271): * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit * device. The bit is only intended for 64-bit devices and, on * PIC, can cause problems for 32-bit devices. */ if (mask == BRIDGE_DEV_D64_BITS && PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { if (flags & PCIBR_VCHAN1) { new |= BRIDGE_DEV_VIRTUAL_EN; mask |= BRIDGE_DEV_VIRTUAL_EN; } } /* PIC BRINGUP WAR (PV# 878674): Don't allow 64bit PIO accesses */ if ((flags & PCIBR_64BIT) && PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) { new &= ~(1ull << 22); } chg = old ^ new; /* what are we changing, */ chg &= mask; /* of the interesting bits */ if (chg) { badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; bad = badpmu | badd32 | badd64; if (bad) { /* some conflicts can be resolved by * forcing the bit on. this may cause * some performance degredation in * the stream(s) that want the bit off, * but the alternative is not allowing * the new stream at all. */ if ( (fix = bad & (BRIDGE_DEV_PRECISE | BRIDGE_DEV_BARRIER)) ) { bad &= ~fix; /* don't change these bits if * they are already set in "old" */ chg &= ~(fix & old); } /* some conflicts can be resolved by * forcing the bit off. this may cause * some performance degredation in * the stream(s) that want the bit on, * but the alternative is not allowing * the new stream at all. */ if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | BRIDGE_DEV_PREF)) ) { bad &= ~fix; /* don't change these bits if * we wanted to turn them on. */ chg &= ~(fix & new); } /* conflicts in other bits mean * we can not establish this DMA * channel while the other(s) are * still present. */ if (bad) { pcibr_unlock(pcibr_soft, s); PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, "pcibr_try_set_device: mod blocked by 0x%x\n", bad)); return bad; } } } if (mask == BRIDGE_DEV_PMU_BITS) slotp->bss_pmu_uctr++; if (mask == BRIDGE_DEV_D32_BITS) slotp->bss_d32_uctr++; if (mask == BRIDGE_DEV_D64_BITS) slotp->bss_d64_uctr++; /* the value we want to write is the * original value, with the bits for * our selected changes flipped, and * with any disabled features turned off. */ new = old ^ chg; /* only change what we want to change */ if (slotp->bss_device == new) { pcibr_unlock(pcibr_soft, s); return 0; } pcireg_device_set(pcibr_soft, slot, new); slotp->bss_device = new; pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, "pcibr_try_set_device: Device(%d): 0x%x\n", slot, new)); return 0;}voidpcibr_release_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, uint64_t mask){ pcibr_soft_slot_t slotp; unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; s = pcibr_lock(pcibr_soft); if (mask == BRIDGE_DEV_PMU_BITS) slotp->bss_pmu_uctr--; if (mask == BRIDGE_DEV_D32_BITS) slotp->bss_d32_uctr--; if (mask == BRIDGE_DEV_D64_BITS) slotp->bss_d64_uctr--; pcibr_unlock(pcibr_soft, s);}/* ===================================================================== * Bridge (pcibr) "Device Driver" entry points */static intpcibr_mmap(struct file * file, struct vm_area_struct * vma){ vertex_hdl_t pcibr_vhdl = file->f_dentry->d_fsdata; pcibr_soft_t pcibr_soft; void *bridge; unsigned long phys_addr; int error = 0; pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED | VM_IO; error = io_remap_page_range(vma, phys_addr, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); return error;}/* * This is the file operation table for the pcibr driver. * As each of the functions are implemented, put the * appropriate function name below. */static int pcibr_mmap(struct file * file, struct vm_area_struct * vma);struct file_operations pcibr_fops = { .owner = THIS_MODULE, .mmap = pcibr_mmap,};/* This is special case code used by grio. There are plans to make * this a bit more general in the future, but till then this should
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?