pci_dma.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
- /*
- * 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) 2000 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Leo Dagum
- */
- #include <linux/config.h>
- #include <linux/types.h>
- #include <linux/mm.h>
- #include <linux/string.h>
- #include <linux/pci.h>
- #include <linux/slab.h>
- #include <linux/devfs_fs_kernel.h>
- #ifndef LANGUAGE_C
- #define LANGUAGE_C 99
- #endif
- #ifndef _LANGUAGE_C
- #define _LANGUAGE_C 99
- #endif
- #include <asm/io.h>
- #include <asm/sn/sgi.h>
- #include <asm/sn/invent.h>
- #include <asm/sn/hcl.h>
- #include <asm/sn/pci/pcibr.h>
- #include <asm/sn/pci/pcibr_private.h>
- #include <asm/sn/iobus.h>
- #include <asm/sn/types.h>
- #include <asm/sn/alenlist.h>
- #include <asm/sn/pci/pci_bus_cvlink.h>
- /*
- * this is REALLY ugly, blame it on gcc's lame inlining that we
- * have to put procedures in header files
- */
- #if LANGUAGE_C == 99
- #undef LANGUAGE_C
- #endif
- #if CONFIG_IA64_SGI_IO == 99
- #undef CONFIG_IA64_SGI_IO
- #endif
- pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t);
- struct sn1_dma_maps_s *find_sn1_dma_map(dma_addr_t, unsigned char);
- extern devfs_handle_t busnum_to_pcibr_vhdl[];
- extern nasid_t busnum_to_nid[];
- extern void * busnum_to_atedmamaps[];
- /*
- * Get a free pciio_dmamap_t entry.
- */
- pciio_dmamap_t
- get_free_pciio_dmamap(devfs_handle_t pci_bus)
- {
- int i;
- struct sn1_dma_maps_s *sn1_dma_map = NULL;
- /*
- * Darn, we need to get the maps allocated for this bus.
- */
- for (i=0; i<512; i++) {
- if (busnum_to_pcibr_vhdl[i] == pci_bus) {
- sn1_dma_map = busnum_to_atedmamaps[i];
- }
- }
- /*
- * Now get a free dmamap entry from this list.
- */
- for (i=0; i<512; i++, sn1_dma_map++) {
- if (!sn1_dma_map->dma_addr) {
- sn1_dma_map->dma_addr = -1;
- return( (pciio_dmamap_t) sn1_dma_map );
- }
- }
- printk("get_pciio_dmamap: Unable to find a free dmamapn");
- return(NULL);
- }
- struct sn1_dma_maps_s *
- find_sn1_dma_map(dma_addr_t dma_addr, unsigned char busnum)
- {
- struct sn1_dma_maps_s *sn1_dma_map = NULL;
- int i;
- sn1_dma_map = busnum_to_atedmamaps[busnum];
- for (i=0; i<512; i++, sn1_dma_map++) {
- if (sn1_dma_map->dma_addr == dma_addr) {
- return( sn1_dma_map );
- }
- }
- printk("find_pciio_dmamap: Unable find the corresponding dma mapn");
- return(NULL);
- }
- /*
- * sn1 platform specific pci_alloc_consistent()
- *
- * this interface is meant for "command" streams, i.e. called only
- * once for initializing a device, so we don't want prefetching or
- * write gathering turned on, hence the PCIIO_DMA_CMD flag
- */
- void *
- sn1_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
- {
- void *ret;
- int gfp = GFP_ATOMIC;
- devfs_handle_t vhdl;
- struct sn1_device_sysdata *device_sysdata;
- paddr_t temp_ptr;
- *dma_handle = (dma_addr_t) NULL;
- /*
- * get vertex for the device
- */
- device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata;
- vhdl = device_sysdata->vhdl;
- if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) {
- memset(ret, 0, size);
- } else {
- return(NULL);
- }
- temp_ptr = (paddr_t) __pa(ret);
- if (IS_PCIA64(hwdev)) {
- /*
- * This device supports 64bits DMA addresses.
- */
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD
- | PCIIO_DMA_A64 );
- return (ret);
- }
- /*
- * Devices that supports 32 Bits upto 63 Bits DMA Address gets
- * 32 Bits DMA addresses.
- *
- * First try to get 32 Bit Direct Map Support.
- */
- if (IS_PCI32G(hwdev)) {
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
- if (dma_handle) {
- return (ret);
- } else {
- /*
- * We need to map this request by using ATEs.
- */
- printk("sn1_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!");
- BUG();
- }
- }
- if (IS_PCI32L(hwdev)) {
- /*
- * SNIA64 cannot support DMA Addresses smaller than 32 bits.
- */
- return (NULL);
- }
- return NULL;
- }
- void
- sn1_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
- {
- free_pages((unsigned long) vaddr, get_order(size));
- }
- /*
- * On sn1 we use the orig_address entry of the scatterlist to store
- * the physical address corresponding to the given virtual address
- */
- int
- sn1_pci_map_sg (struct pci_dev *hwdev,
- struct scatterlist *sg, int nents, int direction)
- {
- int i;
- devfs_handle_t vhdl;
- dma_addr_t dma_addr;
- paddr_t temp_ptr;
- struct sn1_device_sysdata *device_sysdata;
- pciio_dmamap_t dma_map;
- if (direction == PCI_DMA_NONE)
- BUG();
- /*
- * Handle 64 bit cards.
- */
- device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata;
- vhdl = device_sysdata->vhdl;
- for (i = 0; i < nents; i++, sg++) {
- sg->orig_address = (char *)NULL;
- dma_addr = 0;
- temp_ptr = (paddr_t) __pa(sg->address);
- /*
- * Handle the most common case 64Bit cards.
- */
- if (IS_PCIA64(hwdev)) {
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM |
- PCIIO_DMA_CMD | PCIIO_DMA_A64 );
- sg->address = (char *)dma_addr;
- continue;
- }
- /*
- * Handle 32Bits and greater cards.
- */
- if (IS_PCI32G(hwdev)) {
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM |
- PCIIO_DMA_CMD);
- if (dma_addr) {
- sg->address = (char *)dma_addr;
- continue;
- }
- }
- /*
- * It is a 32bit card and we cannot do Direct mapping.
- * Let's 32Bit Page map the request.
- */
- dma_map = NULL;
- dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM |
- PCIIO_DMA_CMD);
- if (!dma_map) {
- printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.n");
- BUG();
- }
- dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length);
- /* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%pn", dma_map, temp_ptr, dma_addr); */
- sg->address = (char *)dma_addr;
- sg->orig_address = (char *)dma_map;
-
- }
- return nents;
- }
- /*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
- void
- sn1_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
- {
- int i;
- struct sn1_dma_maps_s *sn1_dma_map;
- if (direction == PCI_DMA_NONE)
- BUG();
- for (i = 0; i < nelems; i++, sg++)
- if (sg->orig_address) {
- /*
- * We maintain the DMA Map pointer in sg->orig_address if
- * it is ever allocated.
- */
- /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */
- /* sg->address = sg->orig_address; */
- sg->address = (char *)-1;
- sn1_dma_map = (struct sn1_dma_maps_s *)sg->orig_address;
- pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map);
- pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map);
- sn1_dma_map->dma_addr = 0;
- sg->orig_address = 0;
- }
- }
- /*
- * We map this to the one step pciio_dmamap_trans interface rather than
- * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have
- * no way of saving the dmamap handle from the alloc to later free
- * (which is pretty much unacceptable).
- *
- * TODO: simplify our interface;
- * get rid of dev_desc and vhdl (seems redundant given a pci_dev);
- * figure out how to save dmamap handle so can use two step.
- */
- dma_addr_t sn1_pci_map_single (struct pci_dev *hwdev,
- void *ptr, size_t size, int direction)
- {
- devfs_handle_t vhdl;
- dma_addr_t dma_addr;
- paddr_t temp_ptr;
- struct sn1_device_sysdata *device_sysdata;
- pciio_dmamap_t dma_map = NULL;
- struct sn1_dma_maps_s *sn1_dma_map;
- if (direction == PCI_DMA_NONE)
- BUG();
- /*
- * find vertex for the device
- */
- device_sysdata = (struct sn1_device_sysdata *)hwdev->sysdata;
- vhdl = device_sysdata->vhdl;
- /*
- * Call our dmamap interface
- */
- dma_addr = 0;
- temp_ptr = (paddr_t) __pa(ptr);
- if (IS_PCIA64(hwdev)) {
- /*
- * This device supports 64bits DMA addresses.
- */
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD
- | PCIIO_DMA_A64 );
- return (dma_addr);
- }
- /*
- * Devices that supports 32 Bits upto 63 Bits DMA Address gets
- * 32 Bits DMA addresses.
- *
- * First try to get 32 Bit Direct Map Support.
- */
- if (IS_PCI32G(hwdev)) {
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
- if (dma_addr) {
- return (dma_addr);
- }
- }
- if (IS_PCI32L(hwdev)) {
- /*
- * SNIA64 cannot support DMA Addresses smaller than 32 bits.
- */
- return ((dma_addr_t) NULL);
- }
- /*
- * It is a 32bit card and we cannot do Direct mapping.
- * Let's 32Bit Page map the request.
- */
- dma_map = NULL;
- dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIBR_BARRIER |
- PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
- if (!dma_map) {
- printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.n");
- BUG();
- }
- dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size);
- /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%pn", dma_map,
- temp_ptr, dma_addr); */
- sn1_dma_map = (struct sn1_dma_maps_s *)dma_map;
- sn1_dma_map->dma_addr = dma_addr;
- return ((dma_addr_t)dma_addr);
- }
- void
- sn1_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
- {
- struct sn1_dma_maps_s *sn1_dma_map = NULL;
- if (direction == PCI_DMA_NONE)
- BUG();
- /*
- * Get the sn1_dma_map entry.
- */
- if (IS_PCI32_MAPPED(dma_addr))
- sn1_dma_map = find_sn1_dma_map(dma_addr, hwdev->bus->number);
- if (sn1_dma_map) {
- pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map);
- pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map);
- sn1_dma_map->dma_addr = (dma_addr_t)NULL;
- }
- }
- void
- sn1_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
- {
-
- if (direction == PCI_DMA_NONE)
- BUG();
- /* Nothing to do */
- }
- void
- sn1_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
- {
- if (direction == PCI_DMA_NONE)
- BUG();
- /* Nothing to do */
- }
- unsigned long
- sn1_dma_address (struct scatterlist *sg)
- {
- return ((unsigned long)sg->address);
- }