Commit ad7ad57c authored by David S. Miller's avatar David S. Miller

[SPARC64]: Fix conflicts in SBUS/PCI/EBUS/ISA DMA handling.

Fully unify all of the DMA ops so that subordinate bus types to
the DMA operation providers (such as ebus, isa, of_device) can
work transparently.

Basically, we just make sure that for every system device we
create, the dev->archdata 'iommu' and 'stc' fields are filled
in.

Then we have two platform variants of the DMA ops, one for SUN4U which
actually programs the real hardware, and one for SUN4V which makes
hypervisor calls.

This also fixes the crashes in parport_pc on sparc64, reported by
Meelis Roos.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c7f439b9
......@@ -8,14 +8,14 @@ EXTRA_CFLAGS := -Werror
extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o setup.o cpu.o idprom.o \
traps.o auxio.o una_asm.o sysfs.o \
traps.o auxio.o una_asm.o sysfs.o iommu.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
......
......@@ -391,6 +391,8 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
sd = &dev->ofdev.dev.archdata;
sd->prom_node = dp;
sd->op = &dev->ofdev;
sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
......
......@@ -90,6 +90,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
sd = &isa_dev->ofdev.dev.archdata;
sd->prom_node = dp;
sd->op = &isa_dev->ofdev;
sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu;
sd->stc = isa_br->ofdev.dev.parent->archdata.stc;
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
......
......@@ -283,12 +283,6 @@ int __init pcic_present(void)
return pci_controller_scan(pci_is_controller);
}
const struct pci_iommu_ops *pci_iommu_ops;
EXPORT_SYMBOL(pci_iommu_ops);
extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
pci_sun4v_iommu_ops;
/* Find each controller in the system, attach and initialize
* software state structure for each and link into the
* pci_pbm_root. Setup the controller enough such
......@@ -296,11 +290,6 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
*/
static void __init pci_controller_probe(void)
{
if (tlb_type == hypervisor)
pci_iommu_ops = &pci_sun4v_iommu_ops;
else
pci_iommu_ops = &pci_sun4u_iommu_ops;
printk("PCI: Probing for controllers.\n");
pci_controller_scan(pci_controller_init);
......@@ -406,6 +395,10 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
sd->op = of_find_device_by_node(node);
sd->msi_num = 0xffffffff;
sd = &sd->op->dev.archdata;
sd->iommu = pbm->iommu;
sd->stc = &pbm->stc;
type = of_get_property(node, "device_type", NULL);
if (type == NULL)
type = "";
......@@ -1226,4 +1219,51 @@ struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
}
EXPORT_SYMBOL(pci_device_to_OF_node);
static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
{
struct pci_dev *ali_isa_bridge;
u8 val;
/* ALI sound chips generate 31-bits of DMA, a special register
* determines what bit 31 is emitted as.
*/
ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
PCI_DEVICE_ID_AL_M1533,
NULL);
pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
if (set_bit)
val |= 0x01;
else
val &= ~0x01;
pci_write_config_byte(ali_isa_bridge, 0x7e, val);
pci_dev_put(ali_isa_bridge);
}
int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
{
u64 dma_addr_mask;
if (pdev == NULL) {
dma_addr_mask = 0xffffffff;
} else {
struct iommu *iommu = pdev->dev.archdata.iommu;
dma_addr_mask = iommu->dma_addr_mask;
if (pdev->vendor == PCI_VENDOR_ID_AL &&
pdev->device == PCI_DEVICE_ID_AL_M5451 &&
device_mask == 0x7fffffff) {
ali_sound_dma_hack(pdev,
(dma_addr_mask & 0x80000000) != 0);
return 1;
}
}
if (device_mask >= (1UL << 32UL))
return 0;
return (device_mask & dma_addr_mask) == dma_addr_mask;
}
#endif /* !(CONFIG_PCI) */
......@@ -39,12 +39,12 @@ static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
#define FIRE_IOMMU_FLUSH 0x40100UL
#define FIRE_IOMMU_FLUSHINV 0x40108UL
static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
u32 vdma[2], dma_mask;
u64 control;
int tsbsize;
int tsbsize, err;
/* No virtual-dma property on these guys, use largest size. */
vdma[0] = 0xc0000000; /* base */
......@@ -68,7 +68,9 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
*/
fire_write(iommu->iommu_flushinv, ~(u64)0);
pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
if (err)
return err;
fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
......@@ -78,6 +80,8 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
0x00000002 /* Bypass enable */ |
0x00000001 /* Translation enable */);
fire_write(iommu->iommu_control, control);
return 0;
}
/* Based at pbm->controller_regs */
......@@ -167,8 +171,8 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
}
static void pci_fire_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid)
static int pci_fire_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
......@@ -203,7 +207,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
pci_get_pbm_props(pbm);
pci_fire_hw_init(pbm);
pci_fire_pbm_iommu_init(pbm);
return pci_fire_pbm_iommu_init(pbm);
}
static inline int portid_compare(u32 x, u32 y)
......@@ -222,7 +227,8 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid)) {
pci_fire_pbm_init(pbm->parent, dp, portid);
if (pci_fire_pbm_init(pbm->parent, dp, portid))
goto fatal_memory_error;
return;
}
}
......@@ -250,7 +256,9 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
pci_fire_pbm_init(p, dp, portid);
if (pci_fire_pbm_init(p, dp, portid))
goto fatal_memory_error;
return;
fatal_memory_error:
......
......@@ -813,16 +813,19 @@ static void psycho_scan_bus(struct pci_pbm_info *pbm)
psycho_register_error_handlers(pbm);
}
static void psycho_iommu_init(struct pci_pbm_info *pbm)
static int psycho_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
int err;
/* Register addresses. */
iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
/* PSYCHO's IOMMU lacks ctx flushing. */
iommu->iommu_ctxflush = 0;
......@@ -845,7 +848,9 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm)
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
if (err)
return err;
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
__pa(iommu->page_table));
......@@ -858,6 +863,8 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm)
/* If necessary, hook us up for starfire IRQ translations. */
if (this_is_starfire)
starfire_hookup(pbm->portid);
return 0;
}
#define PSYCHO_IRQ_RETRY 0x1a00UL
......@@ -1031,15 +1038,12 @@ void psycho_init(struct device_node *dp, char *model_name)
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) {
prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt();
}
if (!p)
goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu) {
prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt();
}
if (!iommu)
goto fatal_memory_error;
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
p->pbm_A.portid = upa_portid;
......@@ -1062,8 +1066,14 @@ void psycho_init(struct device_node *dp, char *model_name)
psycho_controller_hwinit(&p->pbm_A);
psycho_iommu_init(&p->pbm_A);
if (psycho_iommu_init(&p->pbm_A))
goto fatal_memory_error;
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, dp, is_pbm_a);
return;
fatal_memory_error:
prom_printf("PSYCHO: Fatal memory allocation error.\n");
prom_halt();
}
......@@ -672,18 +672,20 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm)
sabre_register_error_handlers(pbm);
}
static void sabre_iommu_init(struct pci_pbm_info *pbm,
int tsbsize, unsigned long dvma_offset,
u32 dma_mask)
static int sabre_iommu_init(struct pci_pbm_info *pbm,
int tsbsize, unsigned long dvma_offset,
u32 dma_mask)
{
struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
int err;
/* Register addresses. */
iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH;
iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
/* Sabre's IOMMU lacks ctx flushing. */
iommu->iommu_ctxflush = 0;
......@@ -701,7 +703,10 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm,
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
err = iommu_table_init(iommu, tsbsize * 1024 * 8,
dvma_offset, dma_mask);
if (err)
return err;
sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
__pa(iommu->page_table));
......@@ -722,6 +727,8 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm,
break;
}
sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
return 0;
}
static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
......@@ -775,16 +782,12 @@ void sabre_init(struct device_node *dp, char *model_name)
}
p = kzalloc(sizeof(*p), GFP_ATOMIC);
if (!p) {
prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n");
prom_halt();
}
if (!p)
goto fatal_memory_error;
iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
if (!iommu) {
prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
prom_halt();
}
if (!iommu)
goto fatal_memory_error;
pbm = &p->pbm_A;
pbm->iommu = iommu;
......@@ -847,10 +850,16 @@ void sabre_init(struct device_node *dp, char *model_name)
prom_halt();
}
sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
goto fatal_memory_error;
/*
* Look for APB underneath.
*/
sabre_pbm_init(p, pbm, dp);
return;
fatal_memory_error:
prom_printf("SABRE: Fatal memory allocation error.\n");
prom_halt();
}
......@@ -1148,14 +1148,14 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
#define SCHIZO_IOMMU_FLUSH (0x00210UL)
#define SCHIZO_IOMMU_CTXFLUSH (0x00218UL)
static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
int tsbsize, err;
u64 control;
int tsbsize;
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
......@@ -1195,6 +1195,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH;
iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH;
/* We use the main control/status register of SCHIZO as the write
......@@ -1219,7 +1220,9 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
if (err)
return err;
schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
......@@ -1236,6 +1239,8 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
control |= SCHIZO_IOMMU_CTRL_ENAB;
schizo_write(iommu->iommu_control, control);
return 0;
}
#define SCHIZO_PCI_IRQ_RETRY (0x1a00UL)
......@@ -1328,14 +1333,14 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
}
static void schizo_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid,
int chip_type)
static int schizo_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid,
int chip_type)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
const char *chipset_name;
int is_pbm_a;
int is_pbm_a, err;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
......@@ -1406,8 +1411,13 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pci_get_pbm_props(pbm);
schizo_pbm_iommu_init(pbm);
err = schizo_pbm_iommu_init(pbm);
if (err)
return err;
schizo_pbm_strbuf_init(pbm);
return 0;
}
static inline int portid_compare(u32 x, u32 y, int chip_type)
......@@ -1431,34 +1441,38 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid, chip_type)) {
schizo_pbm_init(pbm->parent, dp, portid, chip_type);
if (schizo_pbm_init(pbm->parent, dp,
portid, chip_type))
goto fatal_memory_error;
return;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
goto memfail;
goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto memfail;
goto fatal_memory_error;
p->pbm_A.iommu = iommu;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto memfail;
goto fatal_memory_error;
p->pbm_B.iommu = iommu;
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
schizo_pbm_init(p, dp, portid, chip_type);
if (schizo_pbm_init(p, dp, portid, chip_type))
goto fatal_memory_error;
return;
memfail:
fatal_memory_error:
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -210,6 +210,10 @@ static void __init walk_children(struct device_node *dp, struct sbus_dev *parent
sdev->bus = sbus;
sdev->parent = parent;
sdev->ofdev.dev.archdata.iommu =
sbus->ofdev.dev.archdata.iommu;
sdev->ofdev.dev.archdata.stc =
sbus->ofdev.dev.archdata.stc;
fill_sbus_device(dp, sdev);
......@@ -269,6 +273,11 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus)
sdev->bus = sbus;
sdev->parent = NULL;
sdev->ofdev.dev.archdata.iommu =
sbus->ofdev.dev.archdata.iommu;
sdev->ofdev.dev.archdata.stc =
sbus->ofdev.dev.archdata.stc;
fill_sbus_device(dev_dp, sdev);
walk_children(dev_dp, sdev, sbus);
......
......@@ -10,6 +10,10 @@ struct device_node;
struct of_device;
struct dev_archdata {
void *iommu;
void *stc;
void *host_controller;
struct device_node *prom_node;
struct of_device *op;
};
......
This diff is collapsed.
/* $Id: iommu.h,v 1.10 2001/03/08 09:55:56 davem Exp $
* iommu.h: Definitions for the sun5 IOMMU.
/* iommu.h: Definitions for the sun5 IOMMU.
*
* Copyright (C) 1996, 1999 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#ifndef _SPARC64_IOMMU_H
#define _SPARC64_IOMMU_H
......@@ -33,6 +32,7 @@ struct iommu {
unsigned long iommu_tsbbase;
unsigned long iommu_flush;
unsigned long iommu_flushinv;
unsigned long iommu_tags;
unsigned long iommu_ctxflush;
unsigned long write_complete_reg;
unsigned long dummy_page;
......@@ -54,4 +54,7 @@ struct strbuf {
volatile unsigned long __flushflag_buf[(64+(64-1)) / sizeof(long)];
};
#endif /* !(_SPARC_IOMMU_H) */
extern int iommu_table_init(struct iommu *iommu, int tsbsize,
u32 dma_offset, u32 dma_addr_mask);
#endif /* !(_SPARC64_IOMMU_H) */
......@@ -117,7 +117,7 @@ static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id
if (!strcmp(parent->name, "dma")) {
p = parport_pc_probe_port(base, base + 0x400,
op->irqs[0], PARPORT_DMA_NOFIFO,
op->dev.parent);
op->dev.parent->parent);
if (!p)
return -ENOMEM;
dev_set_drvdata(&op->dev, p);
......
......@@ -3,8 +3,7 @@
#ifdef __KERNEL__
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
/* Can be used to override the logic in pci_scan_bus for skipping
* already-configured bus numbers - to be used for buggy BIOSes
......@@ -30,80 +29,42 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
/* We don't do dynamic PCI IRQ allocation */
}
/* Dynamic DMA mapping stuff.
*/
/* The PCI address space does not equal the physical memory
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions.
*/
#define PCI_DMA_BUS_IS_PHYS (0)
#include <asm/scatterlist.h>
struct pci_dev;
struct pci_iommu_ops {
void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *, gfp_t);
void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t);
dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int);
void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int);
int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int);
void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int);
void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int);
void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
};
extern const struct pci_iommu_ops *pci_iommu_ops;
/* Allocate and map kernel buffer using consistent mode DMA for a device.
* hwdev should be valid struct pci_dev pointer for PCI devices.
*/
static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size,
dma_addr_t *dma_handle)
{
return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle, GFP_ATOMIC);
return dma_alloc_coherent(&pdev->dev, size, dma_handle, GFP_ATOMIC);
}
/* Free and unmap a consistent DMA buffer.
* cpu_addr is what was returned from pci_alloc_consistent,
* size must be the same as what as passed into pci_alloc_consistent,
* and likewise dma_addr must be the same as what *dma_addrp was set to.
*
* References to the memory and mappings associated with cpu_addr/dma_addr
* past this call are illegal.
*/
static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
static inline void pci_free_consistent(struct pci_dev *pdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle);
return dma_free_coherent(&pdev->dev, size, vaddr, dma_handle);
}
/* Map a single buffer of the indicated size for DMA in streaming mode.
* The 32-bit bus address to use is returned.
*
* Once the device is given the dma address, the device owns this memory
* until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
*/
static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
static inline dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr,
size_t size, int direction)
{
return pci_iommu_ops->map_single(hwdev, ptr, size, direction);
return dma_map_single(&pdev->dev, ptr, size,
(enum dma_data_direction) direction);
}
/* Unmap a single streaming mode DMA translation. The dma_addr and size
* must match what was provided for in a previous pci_map_single call. All
* other usages are undefined.
*
* After this call, reads by the cpu to the buffer are guaranteed to see
* whatever the device wrote there.
*/
static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr,
size_t size, int direction)
{
pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction);
dma_unmap_single(&pdev->dev, dma_addr, size,
(enum dma_data_direction) direction);
}
/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */
#define pci_map_page(dev, page, off, size, dir) \
pci_map_single(dev, (page_address(page) + (off)), size, dir)
#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
#define pci_unmap_page(dev,addr,sz,dir) \
pci_unmap_single(dev,addr,sz,dir)
/* pci_unmap_{single,page} is not a nop, thus... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
......@@ -119,75 +80,48 @@ static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
/* Map a set of buffers described by scatterlist in streaming
* mode for DMA. This is the scatter-gather version of the
* above pci_map_single interface. Here the scatter gather list
* elements are each tagged with the appropriate dma address
* and length. They are obtained via sg_dma_{address,length}(SG).
*
* NOTE: An implementation may be able to use a smaller number of
* DMA address/length pairs than there are SG table elements.
* (for example via virtual mapping capabilities)
* The routine returns the number of addr/length pairs actually
* used, at most nents.
*
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
static inline int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg,
int nents, int direction)
{
return pci_iommu_ops->map_sg(hwdev, sg, nents, direction);
return dma_map_sg(&pdev->dev, sg, nents,
(enum dma_data_direction) direction);
}
/* Unmap a set of streaming mode DMA translations.
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
static inline void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg,
int nents, int direction)
{
pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction);
dma_unmap_sg(&pdev->dev, sg, nents,
(enum dma_data_direction) direction);
}
/* Make physical memory consistent for a single
* streaming mode DMA translation after a transfer.
*
* If you perform a pci_map_single() but wish to interrogate the
* buffer using the cpu, yet do not wish to teardown the PCI dma
* mapping, you must call this function before doing so. At the
* next point you give the PCI dma address back to the card, you
* must first perform a pci_dma_sync_for_device, and then the
* device again owns the buffer.
*/
static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
static inline void pci_dma_sync_single_for_cpu(struct pci_dev *pdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction);
dma_sync_single_for_cpu(&pdev->dev, dma_handle, size,
(enum dma_data_direction) direction);
}
static inline void
pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
size_t size, int direction)
static inline void pci_dma_sync_single_for_device(struct pci_dev *pdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
/* No flushing needed to sync cpu writes to the device. */
BUG_ON(direction == PCI_DMA_NONE);
}
/* Make physical memory consistent for a set of streaming
* mode DMA translations after a transfer.
*
* The same as pci_dma_sync_single_* but for a scatter-gather list,
* same rules and usage.
*/
static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev,
struct scatterlist *sg,
int nents, int direction)
{
pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction);
dma_sync_sg_for_cpu(&pdev->dev, sg, nents,
(enum dma_data_direction) direction);
}
static inline void
pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
int nelems, int direction)
static inline void pci_dma_sync_sg_for_device(struct pci_dev *pdev,
struct scatterlist *sg,
int nelems, int direction)
{
/* No flushing needed to sync cpu writes to the device. */
BUG_ON(direction == PCI_DMA_NONE);
}
/* Return whether the given PCI device DMA address mask can
......@@ -206,11 +140,9 @@ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
#define PCI64_REQUIRED_MASK (~(dma64_addr_t)0)
#define PCI64_ADDR_BASE 0xfffc000000000000UL
#define PCI_DMA_ERROR_CODE (~(dma_addr_t)0x0)
static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
{
return (dma_addr == PCI_DMA_ERROR_CODE);
return dma_mapping_error(dma_addr);
}
#ifdef CONFIG_PCI
......
/* $Id: sbus.h,v 1.14 2000/02/18 13:50:55 davem Exp $
* sbus.h: Defines for the Sun SBus.
/* sbus.h: Defines for the Sun SBus.
*
* Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#ifndef _SPARC64_SBUS_H
......@@ -69,7 +68,6 @@ struct sbus_dev {
/* This struct describes the SBus(s) found on this machine. */
struct sbus_bus {
struct of_device ofdev;
void *iommu; /* Opaque IOMMU cookie */
struct sbus_dev *devices; /* Tree of SBUS devices */
struct sbus_bus *next; /* Next SBUS in system */
int prom_node; /* OBP node of SBUS */
......@@ -102,9 +100,18 @@ extern struct sbus_bus *sbus_root;
extern void sbus_set_sbus64(struct sbus_dev *, int);
extern void sbus_fill_device_irq(struct sbus_dev *);
/* These yield IOMMU mappings in consistent mode. */
extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp);
extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t);
static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
dma_addr_t *dma_handle)
{
return dma_alloc_coherent(&sdev->ofdev.dev, size,
dma_handle, GFP_ATOMIC);
}
static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
}
#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
......@@ -112,18 +119,67 @@ extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t);
#define SBUS_DMA_NONE DMA_NONE
/* All the rest use streaming mode mappings. */
extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
size_t size, int direction)
{
return dma_map_single(&sdev->ofdev.dev, ptr, size,
(enum dma_data_direction) direction);
}
static inline void sbus_unmap_single(struct sbus_dev *sdev,
dma_addr_t dma_addr, size_t size,
int direction)
{
dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
(enum dma_data_direction) direction);
}
static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
int nents, int direction)
{
return dma_map_sg(&sdev->ofdev.dev, sg, nents,
(enum dma_data_direction) direction);
}
static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
int nents, int direction)
{
dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
(enum dma_data_direction) direction);
}
/* Finally, allow explicit synchronization of streamable mappings. */
extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
(enum dma_data_direction) direction);
}
#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
/* No flushing needed to sync cpu writes to the device. */
}
static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
struct scatterlist *sg,
int nents, int direction)
{
dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
(enum dma_data_direction) direction);
}
#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
struct scatterlist *sg,
int nents, int direction)
{
/* No flushing needed to sync cpu writes to the device. */
}
extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment