patch-2.4.20 linux-2.4.20/arch/ia64/sn/io/pci_dma.c
Next file: linux-2.4.20/arch/ia64/sn/kernel/llsc4.c
Previous file: linux-2.4.20/arch/ia64/sn/io/efi-rtc.c
Back to the patch index
Back to the overall index
- Lines: 836
- Date:
Thu Nov 28 15:53:09 2002
- Orig file:
linux-2.4.19/arch/ia64/sn/io/pci_dma.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/ia64/sn/io/pci_dma.c linux-2.4.20/arch/ia64/sn/io/pci_dma.c
@@ -4,6 +4,9 @@
* for more details.
*
* Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for
+ * a description of how these routines should be used.
*/
#include <linux/types.h>
@@ -12,6 +15,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
#include <asm/delay.h>
#include <asm/io.h>
@@ -27,15 +31,38 @@
#include <asm/sn/pci/pci_bus_cvlink.h>
#include <asm/sn/nag.h>
+/* DMA, PIO, and memory allocation flags */
+#ifdef CONFIG_IA64_SGI_SN1
+#define DMA_DATA_FLAGS ( PCIIO_BYTE_STREAM | PCIIO_DMA_DATA )
+#define DMA_CONTROL_FLAGS ( PCIIO_BYTE_STREAM | PCIBR_BARRIER | \
+ PCIIO_DMA_CMD )
+#elif defined(CONFIG_IA64_SGI_SN2)
+#define DMA_DATA_FLAGS ( PCIIO_DMA_DATA )
+#define DMA_CONTROL_FLAGS ( PCIBR_BARRIER | PCIIO_DMA_CMD )
+#else
+#error need to define DMA mapping flags for this platform
+#endif
+
+/*
+ * For ATE allocations
+ */
pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t);
void free_pciio_dmamap(pcibr_dmamap_t);
-struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char);
+static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char);
+
+/*
+ * Toplogy stuff
+ */
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.
+/**
+ * get_free_pciio_dmamap - find and allocate an ATE
+ * @pci_bus: PCI bus to get an entry for
+ *
+ * Finds and allocates an ATE on the PCI bus specified
+ * by @pci_bus.
*/
pciio_dmamap_t
get_free_pciio_dmamap(devfs_handle_t pci_bus)
@@ -46,7 +73,7 @@
/*
* Darn, we need to get the maps allocated for this bus.
*/
- for (i=0; i<MAX_PCI_XWIDGET; i++) {
+ for (i = 0; i < MAX_PCI_XWIDGET; i++) {
if (busnum_to_pcibr_vhdl[i] == pci_bus) {
sn_dma_map = busnum_to_atedmamaps[i];
}
@@ -55,19 +82,21 @@
/*
* Now get a free dmamap entry from this list.
*/
- for (i=0; i<MAX_ATE_MAPS; i++, sn_dma_map++) {
+ for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) {
if (!sn_dma_map->dma_addr) {
sn_dma_map->dma_addr = -1;
return( (pciio_dmamap_t) sn_dma_map );
}
}
- return(NULL);
-
+ return NULL;
}
-/*
- * Free pciio_dmamap_t entry.
+/**
+ * free_pciio_dmamap - free an ATE
+ * @dma_map: ATE to free
+ *
+ * Frees the ATE specified by @dma_map.
*/
void
free_pciio_dmamap(pcibr_dmamap_t dma_map)
@@ -76,177 +105,229 @@
sn_dma_map = (struct sn_dma_maps_s *) dma_map;
sn_dma_map->dma_addr = 0;
+}
+
+/**
+ * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum
+ * @dma_addr: DMA address to look for
+ * @busnum: PCI bus to look on
+ *
+ * Finds the ATE associated with @dma_addr and @busnum.
+ */
+static struct sn_dma_maps_s *
+find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum)
+{
+
+ struct sn_dma_maps_s *sn_dma_map = NULL;
+ int i;
+
+ sn_dma_map = busnum_to_atedmamaps[busnum];
+
+ for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) {
+ if (sn_dma_map->dma_addr == dma_addr) {
+ return sn_dma_map;
+ }
+ }
+ printk(KERN_WARNING "find_sn_dma_map: Unable find the corresponding "
+ "dma map\n");
+
+ return NULL;
}
-/*
- * sn_dma_sync: This routine flushes all DMA buffers for the device into the II.
- * This does not mean that the data is in the "Coherence Domain". But it
- * is very close.
+/**
+ * sn_dma_sync - try to flush DMA buffers into the coherence domain
+ * @hwdev: device to flush
+ *
+ * This routine flushes all DMA buffers for the device into the II of
+ * the destination hub.
+ *
+ * NOTE!: this does not mean that the data is in the "coherence domain",
+ * but it is very close. In other words, this routine *does not work*
+ * as advertised due to hardware bugs. That said, it should be good enough for
+ * most situations.
*/
void
-sn_dma_sync( struct pci_dev *hwdev )
+sn_dma_sync(struct pci_dev *hwdev)
{
struct sn_device_sysdata *device_sysdata;
volatile unsigned long dummy;
/*
- * It is expected that on IA64 platform, a DMA sync ensures that all
- * the DMA (dma_handle) are complete and coherent.
- * 1. Flush Write Buffers from Bridge.
- * 2. Flush Xbow Port.
+ * It is expected that on an IA64 platform, a DMA sync ensures that
+ * all the DMA from a particular device is complete and coherent. We
+ * try to do this by
+ * 1. flushing the write wuffers from Bridge
+ * 2. flushing the Xbow port.
+ * Unfortunately, this only gets the DMA transactions 'very close' to
+ * the coherence domain, but not quite in it.
*/
device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata;
dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync;
/*
- * For the Xbow Port flush, we maybe denied the request because
- * someone else may be flushing the Port .. try again.
+ * For the Xbow port flush, we maybe denied the request because
+ * someone else may be flushing the port .. try again.
*/
while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) {
udelay(2);
}
}
-
-struct sn_dma_maps_s *
-find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum)
-{
-
- struct sn_dma_maps_s *sn_dma_map = NULL;
- int i;
-
- sn_dma_map = busnum_to_atedmamaps[busnum];
-
- for (i=0; i<MAX_ATE_MAPS; i++, sn_dma_map++) {
- if (sn_dma_map->dma_addr == dma_addr) {
- return( sn_dma_map );
- }
- }
-
-printk("find_pciio_dmamap: Unable find the corresponding dma map\n");
-
- return(NULL);
-
-}
-
-/*
- * sn1 platform specific pci_alloc_consistent()
+/**
+ * sn_pci_alloc_consistent - allocate memory for coherent DMA
+ * @hwdev: device to allocate for
+ * @size: size of the region
+ * @dma_handle: DMA (bus) address
+ *
+ * pci_alloc_consistent() returns a pointer to a memory region suitable for
+ * coherent DMA traffic to/from a PCI device. On SN platforms, this means
+ * that @dma_handle will have the PCIBR_BARRIER and PCIIO_DMA_CMD flags
+ * set.
*
- * 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
+ * This interface is usually used for "command" streams (e.g. the command
+ * queue for a SCSI controller). See Documentation/DMA-mapping.txt for
+ * more information. Note that this routine should always put a 32 bit
+ * DMA address into @dma_handle. This is because most other platforms
+ * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_
+ * DMAs, and unfortunately this interface has to cater to the LCD. Oh well.
+ *
+ * Also known as platform_pci_alloc_consistent() by the IA64 machvec code.
*/
void *
-sn_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+sn_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;
+ void *cpuaddr;
+ devfs_handle_t vhdl;
struct sn_device_sysdata *device_sysdata;
- paddr_t temp_ptr;
+ unsigned long phys_addr;
+ pciio_dmamap_t dma_map = 0;
+ struct sn_dma_maps_s *sn_dma_map;
- *dma_handle = (dma_addr_t) NULL;
+ *dma_handle = 0;
+
+ /* We can't easily support < 32 bit devices */
+ if (IS_PCI32L(hwdev))
+ return NULL;
/*
- * get vertex for the device
+ * Get hwgraph vertex for the device
*/
device_sysdata = (struct sn_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)) {
+ /*
+ * Allocate the memory. FIXME: if we're allocating for
+ * two devices on the same bus, we should at least try to
+ * allocate memory in the same 2 GB window to avoid using
+ * ATEs for the translation. See the comment above about the
+ * 32 bit requirement for this function.
+ */
+ if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size))))
+ return NULL;
- /*
- * This device supports 64bits DMA addresses.
- */
-#ifdef CONFIG_IA64_SGI_SN1
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD
- | PCIIO_DMA_A64 );
-#else /* SN2 */
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_DMA_CMD | PCIIO_DMA_A64 );
-#endif
+ memset(cpuaddr, 0, size); /* have to zero it out */
- return (ret);
- }
+ /* physical addr. of the memory we just got */
+ phys_addr = __pa(cpuaddr);
+ *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+ DMA_CONTROL_FLAGS);
/*
- * Devices that supports 32 Bits upto 63 Bits DMA Address gets
- * 32 Bits DMA addresses.
- *
- * First try to get 32 Bit Direct Map Support.
+ * It is a 32 bit card and we cannot do direct mapping,
+ * so we use an ATE.
*/
- if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
-#else /* SN2 */
- *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
- PCIBR_BARRIER | PCIIO_DMA_CMD);
-#endif
-
- if (dma_handle) {
- return (ret);
- } else {
- /*
- * We need to map this request by using ATEs.
- */
- printk("sn_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!");
+ if (!(*dma_handle)) {
+ dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
+ DMA_CONTROL_FLAGS | PCIIO_FIXED);
+ if (!dma_map) {
+ printk(KERN_ERR "sn_pci_alloc_consistent: Unable to "
+ "allocate anymore 32 bit page map entries.\n");
BUG();
}
- }
-
- if (IS_PCI32L(hwdev)) {
- /*
- * SNIA64 cannot support DMA Addresses smaller than 32 bits.
- */
- return (NULL);
- }
+ *dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr,
+ size);
+ sn_dma_map = (struct sn_dma_maps_s *)dma_map;
+ sn_dma_map->dma_addr = *dma_handle;
+ printk(KERN_INFO "%s: PMU mapping: %p\n", __FUNCTION__,
+ (void *)*dma_handle);
+ }
+ else
+ printk(KERN_INFO "%s: direct mapping: %p\n", __FUNCTION__,
+ (void *)*dma_handle);
+
- return NULL;
+ return cpuaddr;
}
+/**
+ * sn_pci_free_consistent - free memory associated with coherent DMAable region
+ * @hwdev: device to free for
+ * @size: size to free
+ * @vaddr: kernel virtual address to free
+ * @dma_handle: DMA address associated with this region
+ *
+ * Frees the memory allocated by pci_alloc_consistent(). Also known
+ * as platform_pci_free_consistent() by the IA64 machvec code.
+ */
void
sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
{
+ struct sn_dma_maps_s *sn_dma_map = NULL;
+
+ /*
+ * Get the sn_dma_map entry.
+ */
+ if (IS_PCI32_MAPPED(dma_handle))
+ sn_dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number);
+
+ /*
+ * and free it if necessary...
+ */
+ if (sn_dma_map) {
+ pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
+ pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
+ sn_dma_map->dma_addr = (dma_addr_t)NULL;
+ }
free_pages((unsigned long) vaddr, get_order(size));
}
-/*
- * On sn1 we use the page entry of the scatterlist to store
- * the physical address corresponding to the given virtual address
+/**
+ * sn_pci_map_sg - map a scatter-gather list for DMA
+ * @hwdev: device to map for
+ * @sg: scatterlist to map
+ * @nents: number of entries
+ * @direction: direction of the DMA transaction
+ *
+ * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the
+ * IA64 machvec code.
*/
int
-sn_pci_map_sg (struct pci_dev *hwdev,
- struct scatterlist *sg, int nents, int direction)
+sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
int i;
- devfs_handle_t vhdl;
+ devfs_handle_t vhdl;
dma_addr_t dma_addr;
- paddr_t temp_ptr;
+ unsigned long phys_addr;
struct sn_device_sysdata *device_sysdata;
pciio_dmamap_t dma_map;
-
-
+ /* can't go anywhere w/o a direction in life */
if (direction == PCI_DMA_NONE)
BUG();
/*
- * Handle 64 bit cards.
+ * Get the hwgraph vertex for the device
*/
device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata;
vhdl = device_sysdata->vhdl;
+
+ /*
+ * Setup a DMA address for each entry in the
+ * scatterlist.
+ */
for (i = 0; i < nents; i++, sg++) {
/* this catches incorrectly written drivers that
attempt to map scatterlists that they have
@@ -262,50 +343,37 @@
"%p - this is currently being worked around.\n",
hwdev->slot_name, (void *)sg->address);
#endif
- temp_ptr = (u64)sg->address & TO_PHYS_MASK;
+ phys_addr = (u64)sg->address & TO_PHYS_MASK;
break;
- case 0xe: /* a good address, we now map it. */
- temp_ptr = (paddr_t) __pa(sg->address);
+ default: /* not previously mapped, get the phys. addr */
+ phys_addr = __pa(sg->address);
break;
- default:
- printk(KERN_ERR
- "Very bad address (%p) passed to sn_pci_map_sg\n",
- (void *)sg->address);
- BUG();
}
- sg->page = (char *)NULL;
+ sg->page = NULL;
dma_addr = 0;
/*
- * Handle the most common case 64Bit cards.
+ * Handle the most common case: 64 bit cards. This
+ * call should always succeed.
*/
if (IS_PCIA64(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length,
- PCIIO_BYTE_STREAM | PCIIO_DMA_DATA |
- PCIIO_DMA_A64 );
-#else
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length,
- PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#endif
+ dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+ sg->length,
+ DMA_DATA_FLAGS | PCIIO_DMA_A64 );
sg->address = (char *)dma_addr;
continue;
}
/*
- * Handle 32Bits and greater cards.
+ * Handle 32-63 bit cards via direct mapping
*/
if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length,
- PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, sg->length, PCIIO_DMA_DATA);
-#endif
+ dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+ sg->length,
+ DMA_DATA_FLAGS);
+ /*
+ * See if we got a direct map entry
+ */
if (dma_addr) {
sg->address = (char *)dma_addr;
continue;
@@ -314,22 +382,18 @@
}
/*
- * It is a 32bit card and we cannot do Direct mapping.
- * Let's 32Bit Page map the request.
+ * It is a 32 bit card and we cannot do direct mapping,
+ * so we use an ATE.
*/
- dma_map = NULL;
-#ifdef CONFIG_IA64_SGI_SN1
- dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
- PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
- dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, PCIIO_DMA_DATA);
-#endif
+ dma_map = 0;
+ dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
+ DMA_DATA_FLAGS);
if (!dma_map) {
- printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n");
+ printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
+ "anymore 32 bit 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%p\n", dma_map, temp_ptr, dma_addr); */
+ dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
sg->address = (char *)dma_addr;
sg->page = (char *)dma_map;
@@ -339,30 +403,34 @@
}
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
+/**
+ * sn_pci_unmap_sg - unmap a scatter-gather list
+ * @hwdev: device to unmap
+ * @sg: scatterlist to unmap
+ * @nents: number of scatterlist entries
+ * @direction: DMA direction
+ *
+ * Unmap a set of streaming mode DMA translations. Again, cpu read rules
+ * concerning calls here are the same as for pci_unmap_single() below. Also
+ * known as sn_pci_unmap_sg() by the IA64 machvec code.
*/
void
-sn_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
int i;
struct sn_dma_maps_s *sn_dma_map;
-
+ /* can't go anywhere w/o a direction in life */
if (direction == PCI_DMA_NONE)
BUG();
- for (i = 0; i < nelems; i++, sg++)
+ for (i = 0; i < nents; i++, sg++)
if (sg->page) {
/*
* We maintain the DMA Map pointer in sg->page if
* it is ever allocated.
*/
- /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */
- /* sg->address = sg->page; */
- sg->address = (char *)-1;
+ sg->address = 0;
sn_dma_map = (struct sn_dma_maps_s *)sg->page;
pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
@@ -372,7 +440,17 @@
}
-/*
+/**
+ * sn_pci_map_single - map a single region for DMA
+ * @hwdev: device to map for
+ * @ptr: kernel virtual address of the region to map
+ * @size: size of the region
+ * @direction: DMA direction
+ *
+ * Map the region pointed to by @ptr for DMA and return the
+ * DMA address. Also known as platform_pci_map_single() by
+ * the IA64 machvec code.
+ *
* 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
@@ -382,20 +460,21 @@
* 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 sn_pci_map_single (struct pci_dev *hwdev,
- void *ptr, size_t size, int direction)
+dma_addr_t
+sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
- devfs_handle_t vhdl;
+ devfs_handle_t vhdl;
dma_addr_t dma_addr;
- paddr_t temp_ptr;
+ unsigned long phys_addr;
struct sn_device_sysdata *device_sysdata;
pciio_dmamap_t dma_map = NULL;
struct sn_dma_maps_s *sn_dma_map;
-
if (direction == PCI_DMA_NONE)
BUG();
+ /* SN cannot support DMA addresses smaller than 32 bits. */
+ if (IS_PCI32L(hwdev)) return 0;
/*
* find vertex for the device
@@ -407,79 +486,63 @@
* Call our dmamap interface
*/
dma_addr = 0;
- temp_ptr = (paddr_t) __pa(ptr);
+ phys_addr = __pa(ptr);
if (IS_PCIA64(hwdev)) {
/*
- * This device supports 64bits DMA addresses.
+ * This device supports 64 bit DMA addresses.
*/
-#ifdef CONFIG_IA64_SGI_SN1
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size,
- PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#else
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size, PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#endif
- return (dma_addr);
+ dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+ DMA_DATA_FLAGS | PCIIO_DMA_A64);
+ return dma_addr;
}
/*
- * Devices that supports 32 Bits upto 63 Bits DMA Address gets
- * 32 Bits DMA addresses.
+ * Devices that supports 32 bit to 63 bit DMA addresses get
+ * 32 bit DMA addresses.
*
- * First try to get 32 Bit Direct Map Support.
+ * First try to get a 32 bit direct map register.
*/
if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size,
- PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
- dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
- temp_ptr, size, PCIIO_DMA_DATA);
-#endif
- if (dma_addr) {
- return (dma_addr);
- }
+ dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+ DMA_DATA_FLAGS);
+ 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.
+ * It's a 32 bit card and we cannot do direct mapping so
+ * let's use the PMU instead.
*/
dma_map = NULL;
-#ifdef CONFIG_IA64_SGI_SN1
- dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM |
- PCIIO_DMA_DATA);
-#else
- dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA);
-#endif
+ dma_map = pciio_dmamap_alloc(vhdl, NULL, size, DMA_DATA_FLAGS);
+
if (!dma_map) {
- printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n");
+ printk(KERN_ERR "pci_map_single: Unable to allocate anymore "
+ "32 bits 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%p\n", dma_map,
- temp_ptr, dma_addr); */
+ dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size);
sn_dma_map = (struct sn_dma_maps_s *)dma_map;
sn_dma_map->dma_addr = dma_addr;
return ((dma_addr_t)dma_addr);
}
+/**
+ * sn_pci_unmap_single - unmap a region used for DMA
+ * @hwdev: device to unmap
+ * @dma_addr: DMA address to unmap
+ * @size: size of region
+ * @direction: DMA direction
+ *
+ * Unmaps the region pointed to by @dma_addr. Also known as
+ * platform_pci_unmap_single() by the IA64 machvec code.
+ */
void
-sn_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
+sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
{
-
struct sn_dma_maps_s *sn_dma_map = NULL;
if (direction == PCI_DMA_NONE)
@@ -491,37 +554,97 @@
if (IS_PCI32_MAPPED(dma_addr))
sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number);
+ /*
+ * and free it if necessary...
+ */
if (sn_dma_map) {
pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
sn_dma_map->dma_addr = (dma_addr_t)NULL;
}
-
}
+/**
+ * sn_pci_dma_sync_single - make sure all DMAs have completed
+ * @hwdev: device to sync
+ * @dma_handle: DMA address to sync
+ * @size: size of region
+ * @direction: DMA direction
+ *
+ * This routine is supposed to sync the DMA region specified
+ * by @dma_handle into the 'coherence domain'. See sn_dma_sync()
+ * above for more information. Also known as
+ * platform_pci_dma_sync_single() by the IA64 machvec code.
+ */
void
-sn_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
+sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
{
-
- if (direction == PCI_DMA_NONE)
+ if (direction == PCI_DMA_NONE)
BUG();
sn_dma_sync(hwdev);
-
}
+/**
+ * sn_pci_dma_sync_sg - make sure all DMAs have completed
+ * @hwdev: device to sync
+ * @sg: scatterlist to sync
+ * @nents: number of entries in the scatterlist
+ * @direction: DMA direction
+ *
+ * This routine is supposed to sync the DMA regions specified
+ * by @sg into the 'coherence domain'. See sn_dma_sync()
+ * above for more information. Also known as
+ * platform_pci_dma_sync_sg() by the IA64 machvec code.
+ */
void
-sn_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
if (direction == PCI_DMA_NONE)
BUG();
sn_dma_sync(hwdev);
-
}
+/**
+ * sn_dma_address - get the DMA address for the first entry of a scatterlist
+ * @sg: sg to look at
+ *
+ * Gets the DMA address for the scatterlist @sg. Also known as
+ * platform_dma_address() by the IA64 machvec code.
+ */
unsigned long
-sn_dma_address (struct scatterlist *sg)
+sn_dma_address(struct scatterlist *sg)
{
return ((unsigned long)sg->address);
}
+
+/**
+ * sn_dma_supported - test a DMA mask
+ * @hwdev: device to test
+ * @mask: DMA mask to test
+ *
+ * Return whether the given PCI device DMA address mask can be supported
+ * properly. For example, if your device can only drive the low 24-bits
+ * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
+ * this function. Of course, SN only supports devices that have 32 or more
+ * address bits.
+ */
+int
+sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+{
+ if (mask < 0xffffffff)
+ return 0;
+ return 1;
+}
+
+EXPORT_SYMBOL(sn_pci_unmap_single);
+EXPORT_SYMBOL(sn_pci_map_single);
+EXPORT_SYMBOL(sn_pci_dma_sync_single);
+EXPORT_SYMBOL(sn_pci_map_sg);
+EXPORT_SYMBOL(sn_pci_unmap_sg);
+EXPORT_SYMBOL(sn_pci_alloc_consistent);
+EXPORT_SYMBOL(sn_pci_free_consistent);
+EXPORT_SYMBOL(sn_dma_address);
+EXPORT_SYMBOL(sn_pci_dma_supported);
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)