Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

This commit is contained in:
Steve French 2005-06-02 14:42:23 -07:00
commit 467ca22d33
14 changed files with 184 additions and 88 deletions

View File

@ -2427,7 +2427,7 @@ sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents,
{ {
struct epoll_event *events64 = NULL; struct epoll_event *events64 = NULL;
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
int error, numevents, size; int numevents, size;
int evt_idx; int evt_idx;
int do_free_pages = 0; int do_free_pages = 0;

View File

@ -1103,8 +1103,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#endif /* CONFIG_ACPI */
/* /*
* ia64_mca_cpe_poll * ia64_mca_cpe_poll
* *
@ -1122,6 +1120,8 @@ ia64_mca_cpe_poll (unsigned long dummy)
platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
} }
#endif /* CONFIG_ACPI */
/* /*
* C portion of the OS INIT handler * C portion of the OS INIT handler
* *

View File

@ -211,13 +211,23 @@ struct {
*/ */
#define ADDR(x) (u32) ((unsigned long)(x) - offset) #define ADDR(x) (u32) ((unsigned long)(x) - offset)
/*
* Error results ... some OF calls will return "-1" on error, some
* will return 0, some will return either. To simplify, here are
* macros to use with any ihandle or phandle return value to check if
* it is valid
*/
#define PROM_ERROR (-1u)
#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR)
#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR)
/* This is the one and *ONLY* place where we actually call open /* This is the one and *ONLY* place where we actually call open
* firmware from, since we need to make sure we're running in 32b * firmware from, since we need to make sure we're running in 32b
* mode when we do. We switch back to 64b mode upon return. * mode when we do. We switch back to 64b mode upon return.
*/ */
#define PROM_ERROR (-1)
static int __init call_prom(const char *service, int nargs, int nret, ...) static int __init call_prom(const char *service, int nargs, int nret, ...)
{ {
int i; int i;
@ -587,14 +597,13 @@ static void __init prom_send_capabilities(void)
{ {
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
ihandle elfloader; ihandle elfloader;
int ret;
elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
if (elfloader == 0) { if (elfloader == 0) {
prom_printf("couldn't open /packages/elf-loader\n"); prom_printf("couldn't open /packages/elf-loader\n");
return; return;
} }
ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), call_prom("call-method", 3, 1, ADDR("process-elf-header"),
elfloader, ADDR(&fake_elf)); elfloader, ADDR(&fake_elf));
call_prom("close", 1, 0, elfloader); call_prom("close", 1, 0, elfloader);
} }
@ -646,7 +655,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
base = _ALIGN_UP(base + 0x100000, align)) { base = _ALIGN_UP(base + 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base); prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0); addr = (unsigned long)prom_claim(base, size, 0);
if ((int)addr != PROM_ERROR) if (addr != PROM_ERROR)
break; break;
addr = 0; addr = 0;
if (align == 0) if (align == 0)
@ -708,7 +717,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base); prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0); addr = (unsigned long)prom_claim(base, size, 0);
if ((int)addr != PROM_ERROR) if (addr != PROM_ERROR)
break; break;
addr = 0; addr = 0;
} }
@ -902,18 +911,19 @@ static void __init prom_instantiate_rtas(void)
{ {
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
struct prom_t *_prom = PTRRELOC(&prom); struct prom_t *_prom = PTRRELOC(&prom);
phandle prom_rtas, rtas_node; phandle rtas_node;
ihandle rtas_inst;
u32 base, entry = 0; u32 base, entry = 0;
u32 size = 0; u32 size = 0;
prom_debug("prom_instantiate_rtas: start...\n"); prom_debug("prom_instantiate_rtas: start...\n");
prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
prom_debug("prom_rtas: %x\n", prom_rtas); prom_debug("rtas_node: %x\n", rtas_node);
if (prom_rtas == (phandle) -1) if (!PHANDLE_VALID(rtas_node))
return; return;
prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); prom_getprop(rtas_node, "rtas-size", &size, sizeof(size));
if (size == 0) if (size == 0)
return; return;
@ -922,14 +932,18 @@ static void __init prom_instantiate_rtas(void)
prom_printf("RTAS allocation failed !\n"); prom_printf("RTAS allocation failed !\n");
return; return;
} }
prom_printf("instantiating rtas at 0x%x", base);
rtas_node = call_prom("open", 1, 1, ADDR("/rtas")); rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
prom_printf("..."); if (!IHANDLE_VALID(rtas_inst)) {
prom_printf("opening rtas package failed");
return;
}
prom_printf("instantiating rtas at 0x%x ...", base);
if (call_prom("call-method", 3, 2, if (call_prom("call-method", 3, 2,
ADDR("instantiate-rtas"), ADDR("instantiate-rtas"),
rtas_node, base) != PROM_ERROR) { rtas_inst, base) != PROM_ERROR) {
entry = (long)_prom->args.rets[1]; entry = (long)_prom->args.rets[1];
} }
if (entry == 0) { if (entry == 0) {
@ -940,8 +954,8 @@ static void __init prom_instantiate_rtas(void)
reserve_mem(base, size); reserve_mem(base, size);
prom_setprop(prom_rtas, "linux,rtas-base", &base, sizeof(base)); prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
prom_setprop(prom_rtas, "linux,rtas-entry", &entry, sizeof(entry)); prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas base = 0x%x\n", base);
prom_debug("rtas entry = 0x%x\n", entry); prom_debug("rtas entry = 0x%x\n", entry);
@ -1062,7 +1076,7 @@ static void __init prom_initialize_tce_table(void)
prom_printf("opening PHB %s", path); prom_printf("opening PHB %s", path);
phb_node = call_prom("open", 1, 1, path); phb_node = call_prom("open", 1, 1, path);
if ( (long)phb_node <= 0) if (phb_node == 0)
prom_printf("... failed\n"); prom_printf("... failed\n");
else else
prom_printf("... done\n"); prom_printf("... done\n");
@ -1279,12 +1293,12 @@ static void __init prom_init_client_services(unsigned long pp)
/* get a handle for the stdout device */ /* get a handle for the stdout device */
_prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
if ((long)_prom->chosen <= 0) if (!PHANDLE_VALID(_prom->chosen))
prom_panic("cannot find chosen"); /* msg won't be printed :( */ prom_panic("cannot find chosen"); /* msg won't be printed :( */
/* get device tree root */ /* get device tree root */
_prom->root = call_prom("finddevice", 1, 1, ADDR("/")); _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
if ((long)_prom->root <= 0) if (!PHANDLE_VALID(_prom->root))
prom_panic("cannot find device tree root"); /* msg won't be printed :( */ prom_panic("cannot find device tree root"); /* msg won't be printed :( */
} }
@ -1356,9 +1370,8 @@ static int __init prom_find_machine_type(void)
} }
/* Default to pSeries. We need to know if we are running LPAR */ /* Default to pSeries. We need to know if we are running LPAR */
rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
if (rtas != (phandle) -1) { if (!PHANDLE_VALID(rtas)) {
unsigned long x; int x = prom_getproplen(rtas, "ibm,hypertas-functions");
x = prom_getproplen(rtas, "ibm,hypertas-functions");
if (x != PROM_ERROR) { if (x != PROM_ERROR) {
prom_printf("Hypertas detected, assuming LPAR !\n"); prom_printf("Hypertas detected, assuming LPAR !\n");
return PLATFORM_PSERIES_LPAR; return PLATFORM_PSERIES_LPAR;
@ -1426,12 +1439,13 @@ static void __init prom_check_displays(void)
* leave some room at the end of the path for appending extra * leave some room at the end of the path for appending extra
* arguments * arguments
*/ */
if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) if (call_prom("package-to-path", 3, 1, node, path,
PROM_SCRATCH_SIZE-10) == PROM_ERROR)
continue; continue;
prom_printf("found display : %s, opening ... ", path); prom_printf("found display : %s, opening ... ", path);
ih = call_prom("open", 1, 1, path); ih = call_prom("open", 1, 1, path);
if (ih == (ihandle)0 || ih == (ihandle)-1) { if (ih == 0) {
prom_printf("failed\n"); prom_printf("failed\n");
continue; continue;
} }
@ -1514,6 +1528,12 @@ static unsigned long __init dt_find_string(char *str)
return 0; return 0;
} }
/*
* The Open Firmware 1275 specification states properties must be 31 bytes or
* less, however not all firmwares obey this. Make it 64 bytes to be safe.
*/
#define MAX_PROPERTY_NAME 64
static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
@ -1527,10 +1547,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* get and store all property names */ /* get and store all property names */
prev_name = RELOC(""); prev_name = RELOC("");
for (;;) { for (;;) {
int rc;
/* 32 is max len of name including nul. */
namep = make_room(mem_start, mem_end, 32, 1); /* 64 is max len of name including nul. */
if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
rc = call_prom("nextprop", 3, 1, node, prev_name, namep);
if (rc != 1) {
/* No more nodes: unwind alloc */ /* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep; *mem_start = (unsigned long)namep;
break; break;
@ -1555,12 +1577,6 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
} }
} }
/*
* The Open Firmware 1275 specification states properties must be 31 bytes or
* less, however not all firmwares obey this. Make it 64 bytes to be safe.
*/
#define MAX_PROPERTY_NAME 64
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
@ -1607,7 +1623,10 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prev_name = RELOC(""); prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start); sstart = (char *)RELOC(dt_string_start);
for (;;) { for (;;) {
if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) int rc;
rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
if (rc != 1)
break; break;
/* find string offset */ /* find string offset */
@ -1623,7 +1642,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
l = call_prom("getproplen", 2, 1, node, pname); l = call_prom("getproplen", 2, 1, node, pname);
/* sanity checks */ /* sanity checks */
if (l < 0) if (l == PROM_ERROR)
continue; continue;
if (l > MAX_PROPERTY_LENGTH) { if (l > MAX_PROPERTY_LENGTH) {
prom_printf("WARNING: ignoring large property "); prom_printf("WARNING: ignoring large property ");
@ -1771,17 +1790,18 @@ static void __init fixup_device_tree(void)
/* Some G5s have a missing interrupt definition, fix it up here */ /* Some G5s have a missing interrupt definition, fix it up here */
u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
if ((long)u3 <= 0) if (!PHANDLE_VALID(u3))
return; return;
i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
if ((long)i2c <= 0) if (!PHANDLE_VALID(i2c))
return; return;
mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
if ((long)mpic <= 0) if (!PHANDLE_VALID(mpic))
return; return;
/* check if proper rev of u3 */ /* check if proper rev of u3 */
if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
== PROM_ERROR)
return; return;
if (u3_rev != 0x35) if (u3_rev != 0x35)
return; return;

View File

@ -196,6 +196,34 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long
return NULL; return NULL;
} }
static int iommu_alloc_ctx(struct pci_iommu *iommu)
{
int lowest = iommu->ctx_lowest_free;
int sz = IOMMU_NUM_CTXS - lowest;
int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
if (unlikely(n == sz)) {
n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
if (unlikely(n == lowest)) {
printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
n = 0;
}
}
if (n)
__set_bit(n, iommu->ctx_bitmap);
return n;
}
static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
{
if (likely(ctx)) {
__clear_bit(ctx, iommu->ctx_bitmap);
if (ctx < iommu->ctx_lowest_free)
iommu->ctx_lowest_free = ctx;
}
}
/* Allocate and map kernel buffer of size SIZE using consistent mode /* Allocate and map kernel buffer of size SIZE using consistent mode
* DMA for PCI device PDEV. Return non-NULL cpu-side address if * DMA for PCI device PDEV. Return non-NULL cpu-side address if
* successful and set *DMA_ADDRP to the PCI side dma address. * successful and set *DMA_ADDRP to the PCI side dma address.
@ -236,7 +264,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
npages = size >> IO_PAGE_SHIFT; npages = size >> IO_PAGE_SHIFT;
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
first_page = __pa(first_page); first_page = __pa(first_page);
while (npages--) { while (npages--) {
iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) |
@ -317,6 +345,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
} }
} }
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
order = get_order(size); order = get_order(size);
@ -360,7 +390,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct
base_paddr = __pa(oaddr & IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK);
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
iopte_protection = IOPTE_STREAMING(ctx); iopte_protection = IOPTE_STREAMING(ctx);
else else
@ -380,39 +410,53 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct
return PCI_DMA_ERROR_CODE; return PCI_DMA_ERROR_CODE;
} }
static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages) static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
{ {
int limit; int limit;
PCI_STC_FLUSHFLAG_INIT(strbuf);
if (strbuf->strbuf_ctxflush && if (strbuf->strbuf_ctxflush &&
iommu->iommu_ctxflush) { iommu->iommu_ctxflush) {
unsigned long matchreg, flushreg; unsigned long matchreg, flushreg;
u64 val;
flushreg = strbuf->strbuf_ctxflush; flushreg = strbuf->strbuf_ctxflush;
matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
limit = 100000;
pci_iommu_write(flushreg, ctx); pci_iommu_write(flushreg, ctx);
for(;;) { val = pci_iommu_read(matchreg);
if (((long)pci_iommu_read(matchreg)) >= 0L) val &= 0xffff;
break; if (!val)
limit--; goto do_flush_sync;
if (!limit)
break; while (val) {
udelay(1); if (val & 0x1)
pci_iommu_write(flushreg, ctx);
val >>= 1;
} }
if (!limit) val = pci_iommu_read(matchreg);
if (unlikely(val)) {
printk(KERN_WARNING "pci_strbuf_flush: ctx flush " printk(KERN_WARNING "pci_strbuf_flush: ctx flush "
"timeout vaddr[%08x] ctx[%lx]\n", "timeout matchreg[%lx] ctx[%lx]\n",
vaddr, ctx); val, ctx);
goto do_page_flush;
}
} else { } else {
unsigned long i; unsigned long i;
do_page_flush:
for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
pci_iommu_write(strbuf->strbuf_pflush, vaddr); pci_iommu_write(strbuf->strbuf_pflush, vaddr);
} }
do_flush_sync:
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
if (direction == PCI_DMA_TODEVICE)
return;
PCI_STC_FLUSHFLAG_INIT(strbuf);
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg); (void) pci_iommu_read(iommu->write_complete_reg);
@ -466,7 +510,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
/* Step 1: Kick data out of streaming buffers if necessary. */ /* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
/* Step 2: Clear out first TSB entry. */ /* Step 2: Clear out first TSB entry. */
iopte_make_dummy(iommu, base); iopte_make_dummy(iommu, base);
@ -474,6 +518,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
npages, ctx); npages, ctx);
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -613,7 +659,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int
/* Step 4: Choose a context if necessary. */ /* Step 4: Choose a context if necessary. */
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
/* Step 5: Create the mappings. */ /* Step 5: Create the mappings. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
@ -678,7 +724,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
/* Step 1: Kick data out of streaming buffers if necessary. */ /* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
/* Step 2: Clear out first TSB entry. */ /* Step 2: Clear out first TSB entry. */
iopte_make_dummy(iommu, base); iopte_make_dummy(iommu, base);
@ -686,6 +732,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
npages, ctx); npages, ctx);
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -724,7 +772,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size
} }
/* Step 2: Kick data out of streaming buffers. */ /* Step 2: Kick data out of streaming buffers. */
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -768,7 +816,7 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i
i--; i--;
npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
- bus_addr) >> IO_PAGE_SHIFT; - bus_addr) >> IO_PAGE_SHIFT;
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }

View File

@ -1212,7 +1212,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p)
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses. */ /* Register addresses. */
iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;

View File

@ -1265,7 +1265,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses. */ /* Register addresses. */
iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;

View File

@ -1753,7 +1753,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses, SCHIZO has iommu ctx flushing. */ /* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;

View File

@ -117,17 +117,25 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages
#define STRBUF_TAG_VALID 0x02UL #define STRBUF_TAG_VALID 0x02UL
static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction)
{ {
unsigned long n; unsigned long n;
int limit; int limit;
iommu->strbuf_flushflag = 0UL;
n = npages; n = npages;
while (n--) while (n--)
upa_writeq(base + (n << IO_PAGE_SHIFT), upa_writeq(base + (n << IO_PAGE_SHIFT),
iommu->strbuf_regs + STRBUF_PFLUSH); iommu->strbuf_regs + STRBUF_PFLUSH);
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
if (direction == SBUS_DMA_TODEVICE)
return;
iommu->strbuf_flushflag = 0UL;
/* Whoopee cushion! */ /* Whoopee cushion! */
upa_writeq(__pa(&iommu->strbuf_flushflag), upa_writeq(__pa(&iommu->strbuf_flushflag),
iommu->strbuf_regs + STRBUF_FSYNC); iommu->strbuf_regs + STRBUF_FSYNC);
@ -421,7 +429,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size,
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT); free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);
sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -584,7 +592,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int
iommu = sdev->bus->iommu; iommu = sdev->bus->iommu;
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);
sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -596,7 +604,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t
size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
@ -620,7 +628,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int
size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }

View File

@ -16,4 +16,6 @@
#define IOPTE_CACHE 0x0000000000000010UL /* Cached (in UPA E-cache) */ #define IOPTE_CACHE 0x0000000000000010UL /* Cached (in UPA E-cache) */
#define IOPTE_WRITE 0x0000000000000002UL /* Writeable */ #define IOPTE_WRITE 0x0000000000000002UL /* Writeable */
#define IOMMU_NUM_CTXS 4096
#endif /* !(_SPARC_IOMMU_H) */ #endif /* !(_SPARC_IOMMU_H) */

View File

@ -15,6 +15,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/iommu.h>
/* The abstraction used here is that there are PCI controllers, /* The abstraction used here is that there are PCI controllers,
* each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
@ -40,9 +41,6 @@ struct pci_iommu {
*/ */
spinlock_t lock; spinlock_t lock;
/* Context allocator. */
unsigned int iommu_cur_ctx;
/* IOMMU page table, a linear array of ioptes. */ /* IOMMU page table, a linear array of ioptes. */
iopte_t *page_table; /* The page table itself. */ iopte_t *page_table; /* The page table itself. */
int page_table_sz_bits; /* log2 of ow many pages does it map? */ int page_table_sz_bits; /* log2 of ow many pages does it map? */
@ -87,6 +85,10 @@ struct pci_iommu {
u16 flush; u16 flush;
} alloc_info[PBM_NCLUSTERS]; } alloc_info[PBM_NCLUSTERS];
/* CTX allocation. */
unsigned long ctx_lowest_free;
unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)];
/* Here a PCI controller driver describes the areas of /* Here a PCI controller driver describes the areas of
* PCI memory space where DMA to/from physical memory * PCI memory space where DMA to/from physical memory
* are addressed. Drivers interrogate the PCI layer * are addressed. Drivers interrogate the PCI layer

View File

@ -478,7 +478,7 @@ static int __init esp4_init(void)
{ {
struct xfrm_decap_state decap; struct xfrm_decap_state decap;
if (sizeof(struct esp_decap_data) < if (sizeof(struct esp_decap_data) >
sizeof(decap.decap_data)) { sizeof(decap.decap_data)) {
extern void decap_data_too_small(void); extern void decap_data_too_small(void);

View File

@ -3,6 +3,7 @@
* communicating with userspace via netlink. * communicating with userspace via netlink.
* *
* (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
* (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -17,6 +18,7 @@
* 2005-01-10: Added /proc counter for dropped packets; fixed so * 2005-01-10: Added /proc counter for dropped packets; fixed so
* packets aren't delivered to user space if they're going * packets aren't delivered to user space if they're going
* to be dropped. * to be dropped.
* 2005-05-26: local_bh_{disable,enable} around nf_reinject (Harald Welte)
* *
*/ */
#include <linux/module.h> #include <linux/module.h>
@ -71,7 +73,15 @@ static DECLARE_MUTEX(ipqnl_sem);
static void static void
ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
{ {
/* TCP input path (and probably other bits) assume to be called
* from softirq context, not from syscall, like ipq_issue_verdict is
* called. TCP input path deadlocks with locks taken from timer
* softirq, e.g. We therefore emulate this by local_bh_disable() */
local_bh_disable();
nf_reinject(entry->skb, entry->info, verdict); nf_reinject(entry->skb, entry->info, verdict);
local_bh_enable();
kfree(entry); kfree(entry);
} }

View File

@ -738,7 +738,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
unsigned long amount; unsigned long amount;
amount = 0; amount = 0;
spin_lock_irq(&sk->sk_receive_queue.lock); spin_lock_bh(&sk->sk_receive_queue.lock);
skb = skb_peek(&sk->sk_receive_queue); skb = skb_peek(&sk->sk_receive_queue);
if (skb != NULL) { if (skb != NULL) {
/* /*
@ -748,7 +748,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
*/ */
amount = skb->len - sizeof(struct udphdr); amount = skb->len - sizeof(struct udphdr);
} }
spin_unlock_irq(&sk->sk_receive_queue.lock); spin_unlock_bh(&sk->sk_receive_queue.lock);
return put_user(amount, (int __user *)arg); return put_user(amount, (int __user *)arg);
} }
@ -848,12 +848,12 @@ static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
/* Clear queue. */ /* Clear queue. */
if (flags&MSG_PEEK) { if (flags&MSG_PEEK) {
int clear = 0; int clear = 0;
spin_lock_irq(&sk->sk_receive_queue.lock); spin_lock_bh(&sk->sk_receive_queue.lock);
if (skb == skb_peek(&sk->sk_receive_queue)) { if (skb == skb_peek(&sk->sk_receive_queue)) {
__skb_unlink(skb, &sk->sk_receive_queue); __skb_unlink(skb, &sk->sk_receive_queue);
clear = 1; clear = 1;
} }
spin_unlock_irq(&sk->sk_receive_queue.lock); spin_unlock_bh(&sk->sk_receive_queue.lock);
if (clear) if (clear)
kfree_skb(skb); kfree_skb(skb);
} }
@ -1334,7 +1334,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
struct sk_buff_head *rcvq = &sk->sk_receive_queue; struct sk_buff_head *rcvq = &sk->sk_receive_queue;
struct sk_buff *skb; struct sk_buff *skb;
spin_lock_irq(&rcvq->lock); spin_lock_bh(&rcvq->lock);
while ((skb = skb_peek(rcvq)) != NULL) { while ((skb = skb_peek(rcvq)) != NULL) {
if (udp_checksum_complete(skb)) { if (udp_checksum_complete(skb)) {
UDP_INC_STATS_BH(UDP_MIB_INERRORS); UDP_INC_STATS_BH(UDP_MIB_INERRORS);
@ -1345,7 +1345,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
break; break;
} }
} }
spin_unlock_irq(&rcvq->lock); spin_unlock_bh(&rcvq->lock);
/* nothing to see, move along */ /* nothing to see, move along */
if (skb == NULL) if (skb == NULL)

View File

@ -18,7 +18,7 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#if 1 /* control */ #if 0 /* control */
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else #else
#define DPRINTK(format,args...) #define DPRINTK(format,args...)
@ -73,8 +73,13 @@ static int dsmark_graft(struct Qdisc *sch,unsigned long arg,
DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new, DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new,
old); old);
if (!new)
new = &noop_qdisc; if (new == NULL) {
new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
if (new == NULL)
new = &noop_qdisc;
}
sch_tree_lock(sch); sch_tree_lock(sch);
*old = xchg(&p->q,new); *old = xchg(&p->q,new);
if (*old) if (*old)
@ -163,14 +168,15 @@ static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker)
return; return;
for (i = 0; i < p->indices; i++) { for (i = 0; i < p->indices; i++) {
if (p->mask[i] == 0xff && !p->value[i]) if (p->mask[i] == 0xff && !p->value[i])
continue; goto ignore;
if (walker->count >= walker->skip) { if (walker->count >= walker->skip) {
if (walker->fn(sch, i+1, walker) < 0) { if (walker->fn(sch, i+1, walker) < 0) {
walker->stop = 1; walker->stop = 1;
break; break;
} }
} }
walker->count++; ignore:
walker->count++;
} }
} }