From a8c505ffbe4b0820787119a0d7e9d539e8d6e393 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Apr 2003 10:58:15 -0700 Subject: [BRIDGE}: Change bridge forwarding table to use hlist. --- include/linux/list.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/list.h b/include/linux/list.h index a724f9bcbe4d..11b8674c14ff 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -437,6 +437,10 @@ static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node for (pos = (head)->first; pos; \ pos = pos->next) +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ + pos = n) + #else #warning "don't include kernel headers in userspace" #endif /* __KERNEL__ */ -- cgit v1.2.3 From b0ac3ca407d85d11e7e80d34222e52d83afe715d Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 29 Apr 2003 11:07:03 -0700 Subject: [SPARC]: The iommu rewrite. --- arch/sparc/kernel/ioport.c | 200 +++++--------------------- arch/sparc/lib/Makefile | 2 +- arch/sparc/lib/bitext.c | 114 +++++++++++++++ arch/sparc/mm/init.c | 2 - arch/sparc/mm/io-unit.c | 10 +- arch/sparc/mm/iommu.c | 338 ++++++++++++++++++++++++++++---------------- arch/sparc/mm/loadmmu.c | 2 - arch/sparc/mm/srmmu.c | 149 ++++++++----------- arch/sparc/mm/sun4c.c | 40 ++++-- include/asm-sparc/bitext.h | 24 ++++ include/asm-sparc/iommu.h | 9 +- include/asm-sparc/pgtable.h | 28 +++- include/asm-sparc/sbus.h | 2 +- 13 files changed, 517 insertions(+), 403 deletions(-) create mode 100644 arch/sparc/lib/bitext.c create mode 100644 include/asm-sparc/bitext.h (limited to 'include') diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 3066f0cbc83b..cf4c996c71d2 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -61,13 +61,6 @@ static struct resource _sparc_dvma = { "sparc_iomap", IOBASE_VADDR, IOBASE_END - 1 }; -/* - * BTFIXUP would do as well but it seems overkill for the case. - */ -static void (*_sparc_mapioaddr)(unsigned long pa, unsigned long va, - int bus, int ro); -static void (*_sparc_unmapioaddr)(unsigned long va); - /* * Our mini-allocator... * Boy this is gross! We need it because we must map I/O for @@ -201,8 +194,6 @@ static void * _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) { unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); - unsigned long va; - unsigned int psz; if (allocate_resource(&sparc_iomap, res, (offset + sz + PAGE_SIZE-1) & PAGE_MASK, @@ -213,27 +204,10 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) prom_halt(); } - va = res->start; pa &= PAGE_MASK; - for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { - (*_sparc_mapioaddr)(pa, va, bus, 0); - va += PAGE_SIZE; - pa += PAGE_SIZE; - } + sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1); - /* - * XXX Playing with implementation details here. - * On sparc64 Ebus has resources with precise boundaries. - * We share drivers with sparc64. Too clever drivers use - * start of a resource instead of a base address. - * - * XXX-2 This may be not valid anymore, clean when - * interface to sbus_ioremap() is resolved. - */ - res->start += offset; - res->end = res->start + sz - 1; /* not strictly necessary.. */ - - return (void *) res->start; + return (void *) (res->start + offset); } /* @@ -244,12 +218,8 @@ static void _sparc_free_io(struct resource *res) unsigned long plen; plen = res->end - res->start + 1; - plen = (plen + PAGE_SIZE-1) & PAGE_MASK; - while (plen != 0) { - plen -= PAGE_SIZE; - (*_sparc_unmapioaddr)(res->start + plen); - } - + if ((plen & (PAGE_SIZE-1)) != 0) BUG(); + sparc_unmapiorange(res->start, plen); release_resource(res); } @@ -283,40 +253,44 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) } order = get_order(len_total); - va = __get_free_pages(GFP_KERNEL, order); - if (va == 0) { - /* - * printk here may be flooding... Consider removal XXX. - */ - printk("sbus_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); - return NULL; - } + if ((va = __get_free_pages(GFP_KERNEL, order)) == 0) + goto err_nopages; - if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { - free_pages(va, order); - printk("sbus_alloc_consistent: no core\n"); - return NULL; - } + if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) + goto err_nomem; memset((char*)res, 0, sizeof(struct resource)); if (allocate_resource(&_sparc_dvma, res, len_total, _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { printk("sbus_alloc_consistent: cannot occupy 0x%lx", len_total); - free_pages(va, order); - kfree(res); - return NULL; + goto err_nova; } + mmu_inval_dma_area(va, len_total); + // XXX The mmu_map_dma_area does this for us below, see comments. + // sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); + /* + * XXX That's where sdev would be used. Currently we load + * all iommu tables with the same translations. + */ + if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0) + goto err_noiommu; - mmu_map_dma_area(va, res->start, len_total); - - *dma_addrp = res->start; return (void *)res->start; + +err_noiommu: + release_resource(res); +err_nova: + free_pages(va, order); +err_nomem: + kfree(res); +err_nopages: + return NULL; } void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) { struct resource *res; - unsigned long pgp; + struct page *pgv; if ((res = _sparc_find_resource(&_sparc_dvma, (unsigned long)p)) == NULL) { @@ -340,10 +314,10 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) kfree(res); /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ - pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + pgv = mmu_translate_dvma(ba); mmu_unmap_dma_area(ba, n); - free_pages(pgp, get_order(n)); + __free_pages(pgv, get_order(n)); } /* @@ -353,39 +327,6 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) */ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction) { -#if 0 /* This is the version that abuses consistent space */ - unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; - struct resource *res; - - /* XXX why are some lenghts signed, others unsigned? */ - if (len <= 0) { - return 0; - } - /* XXX So what is maxphys for us and how do drivers know it? */ - if (len > 256*1024) { /* __get_free_pages() limit */ - return 0; - } - - if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { - printk("sbus_map_single: no core\n"); - return 0; - } - memset((char*)res, 0, sizeof(struct resource)); - res->name = va; /* XXX */ - - if (allocate_resource(&_sparc_dvma, res, len_total, - _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE) != 0) { - printk("sbus_map_single: cannot occupy 0x%lx", len); - kfree(res); - return 0; - } - - mmu_map_dma_area(va, res->start, len_total); - mmu_flush_dma_area((unsigned long)va, len_total); /* in all contexts? */ - - return res->start; -#endif -#if 1 /* "trampoline" version */ /* XXX why are some lenghts signed, others unsigned? */ if (len <= 0) { return 0; @@ -395,36 +336,11 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire return 0; } return mmu_get_scsi_one(va, len, sdev->bus); -#endif } void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction) { -#if 0 /* This is the version that abuses consistent space */ - struct resource *res; - unsigned long va; - - if ((res = _sparc_find_resource(&_sparc_dvma, ba)) == NULL) { - printk("sbus_unmap_single: cannot find %08x\n", (unsigned)ba); - return; - } - - n = (n + PAGE_SIZE-1) & PAGE_MASK; - if ((res->end-res->start)+1 != n) { - printk("sbus_unmap_single: region 0x%lx asked 0x%lx\n", - (long)((res->end-res->start)+1), n); - return; - } - - va = (unsigned long) res->name; /* XXX Ouch */ - mmu_inval_dma_area(va, n); /* in all contexts, mm's?... */ - mmu_unmap_dma_area(ba, n); /* iounit cache flush is here */ - release_resource(res); - kfree(res); -#endif -#if 1 /* "trampoline" version */ mmu_release_scsi_one(ba, n, sdev->bus); -#endif } int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) @@ -456,7 +372,7 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int if (res == NULL) panic("sbus_dma_sync_single: 0x%x\n", ba); - va = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ /* * XXX This bogosity will be fixed with the iommu rewrite coming soon * to a kernel near you. - Anton @@ -511,24 +427,12 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) kfree(res); return NULL; } - mmu_inval_dma_area(va, len_total); - #if 0 -/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\n", +/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n", (long)va, (long)res->start, (long)virt_to_phys(va), len_total); #endif - { - unsigned long xva, xpa; - xva = res->start; - xpa = virt_to_phys(va); - while (len_total != 0) { - len_total -= PAGE_SIZE; - (*_sparc_mapioaddr)(xpa, xva, 0, 0); - xva += PAGE_SIZE; - xpa += PAGE_SIZE; - } - } + sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ return (void *) res->start; @@ -567,12 +471,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) pgp = (unsigned long) phys_to_virt(ba); /* bus_to_virt actually */ mmu_inval_dma_area(pgp, n); - { - int x; - for (x = 0; x < n; x += PAGE_SIZE) { - (*_sparc_unmapioaddr)((unsigned long)p + n); - } - } + sparc_unmapiorange((unsigned long)p, n); release_resource(res); kfree(res); @@ -751,37 +650,6 @@ _sparc_find_resource(struct resource *root, unsigned long hit) return NULL; } -/* - * Necessary boot time initializations. - */ - -void ioport_init(void) -{ - extern void sun4c_mapioaddr(unsigned long, unsigned long, int, int); - extern void srmmu_mapioaddr(unsigned long, unsigned long, int, int); - extern void sun4c_unmapioaddr(unsigned long); - extern void srmmu_unmapioaddr(unsigned long); - - switch(sparc_cpu_model) { - case sun4c: - case sun4: - case sun4e: - _sparc_mapioaddr = sun4c_mapioaddr; - _sparc_unmapioaddr = sun4c_unmapioaddr; - break; - case sun4m: - case sun4d: - _sparc_mapioaddr = srmmu_mapioaddr; - _sparc_unmapioaddr = srmmu_unmapioaddr; - break; - default: - printk("ioport_init: cpu type %d is unknown.\n", - sparc_cpu_model); - prom_halt(); - }; - -} - void register_proc_sparc_ioport(void) { #ifdef CONFIG_PROC_FS diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index f228a921b9f1..aefdebcd363c 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -10,4 +10,4 @@ obj-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ - ashldi3.o rwsem.o muldi3.o + ashldi3.o rwsem.o muldi3.o bitext.o diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c new file mode 100644 index 000000000000..9f9553b7ea8c --- /dev/null +++ b/arch/sparc/lib/bitext.c @@ -0,0 +1,114 @@ +/* + * bitext.c: kernel little helper (of bit shuffling variety). + * + * Copyright (C) 2002 Pete Zaitcev + * + * The algorithm to search a zero bit string is geared towards its application. + * We expect a couple of fixed sizes of requests, so a rotating counter, reset + * by align size, should provide fast enough search while maintaining low + * fragmentation. + */ + +#include + +#include +#include + +/** + * bit_map_string_get - find and set a bit string in bit map. + * @t: the bit map. + * @len: requested string length + * @align: requested alignment + * + * Returns offset in the map or -1 if out of space. + * + * Not safe to call from an interrupt (uses spin_lock). + */ +int bit_map_string_get(struct bit_map *t, int len, int align) +{ + int offset, count; /* siamese twins */ + int off_new; + int align1; + int i; + + if (align == 0) + align = 1; + align1 = align - 1; + if ((align & align1) != 0) + BUG(); + if (align < 0 || align >= t->size) + BUG(); + if (len <= 0 || len > t->size) + BUG(); + + spin_lock(&t->lock); + offset = t->last_off & ~align1; + count = 0; + for (;;) { + off_new = find_next_zero_bit(t->map, t->size, offset); + off_new = (off_new + align1) & ~align1; + count += off_new - offset; + offset = off_new; + if (offset >= t->size) + offset = 0; + if (count + len > t->size) { + spin_unlock(&t->lock); +/* P3 */ printk(KERN_ERR + "bitmap out: size %d used %d off %d len %d align %d count %d\n", + t->size, t->used, offset, len, align, count); + return -1; + } + + if (offset + len > t->size) { + offset = 0; + count += t->size - offset; + continue; + } + + i = 0; + while (test_bit(offset + i, t->map) == 0) { + i++; + if (i == len) { + for (i = 0; i < len; i++) + __set_bit(offset + i, t->map); + if ((t->last_off = offset + len) >= t->size) + t->last_off = 0; + t->used += len; + spin_unlock(&t->lock); + return offset; + } + } + count += i + 1; + if ((offset += i + 1) >= t->size) + offset = 0; + } +} + +void bit_map_clear(struct bit_map *t, int offset, int len) +{ + int i; + + if (t->used < len) + BUG(); /* Much too late to do any good, but alas... */ + spin_lock(&t->lock); + for (i = 0; i < len; i++) { + if (test_bit(offset + i, t->map) == 0) + BUG(); + __clear_bit(offset + i, t->map); + } + t->used -= len; + spin_unlock(&t->lock); +} + +void bit_map_init(struct bit_map *t, unsigned long *map, int size) +{ + + if ((size & 07) != 0) + BUG(); + memset(map, 0, size>>3); + + memset(t, 0, sizeof *t); + spin_lock_init(&t->lock); + t->map = map; + t->size = size; +} diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index b1692c1a21da..3274b90e4906 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -88,8 +88,6 @@ void show_mem(void) #endif } -extern pgprot_t protection_map[16]; - void __init sparc_context_init(int numctx) { int ctx; diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index f00e22b0087f..86ee494b7af4 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -176,13 +176,15 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_ } #ifdef CONFIG_SBUS -static void iounit_map_dma_area(unsigned long va, __u32 addr, int len) +static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len) { unsigned long page, end; pgprot_t dvma_prot; iopte_t *iopte; struct sbus_bus *sbus; + *pba = addr; + dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); end = PAGE_ALIGN((addr + len)); while(addr < end) { @@ -213,6 +215,8 @@ static void iounit_map_dma_area(unsigned long va, __u32 addr, int len) } flush_cache_all(); flush_tlb_all(); + + return 0; } static void iounit_unmap_dma_area(unsigned long addr, int len) @@ -221,7 +225,7 @@ static void iounit_unmap_dma_area(unsigned long addr, int len) } /* XXX We do not pass sbus device here, bad. */ -static unsigned long iounit_translate_dvma(unsigned long addr) +static struct page *iounit_translate_dvma(unsigned long addr) { struct sbus_bus *sbus = sbus_root; /* They are all the same */ struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; @@ -230,7 +234,7 @@ static unsigned long iounit_translate_dvma(unsigned long addr) i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); iopte = (iopte_t *)(iounit->page_table + i); - return (iopte_val(*iopte) & 0xFFFFFFF0) << 4; /* XXX sun4d guru, help */ + return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */ } #endif diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index ebcef957e453..487daf560f4e 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -23,6 +23,18 @@ #include #include #include +#include +#include + +/* + * This can be sized dynamically, but we will do this + * only when we have a guidance about actual I/O pressures. + */ +#define IOMMU_RNGE IOMMU_RNGE_256MB +#define IOMMU_START 0xF0000000 +#define IOMMU_WINSIZE (256*1024*1024U) +#define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 265KB */ +#define IOMMU_ORDER 6 /* 4096 * (1<<6) */ /* srmmu.c */ extern int viking_mxcc_present; @@ -34,34 +46,30 @@ static int viking_flush; extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); -#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) -#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ) - -static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu) -{ - unsigned long kern_end = (unsigned long) high_memory; - unsigned long first = PAGE_OFFSET; - unsigned long last = kern_end; - iopte_t *iopte = iommu->page_table; +/* + * Values precomputed according to CPU type. + */ +static unsigned int ioperm_noc; /* Consistent mapping iopte flags */ +static pgprot_t dvma_prot; /* Consistent mapping pte flags */ - iopte += ((first - iommu->start) >> PAGE_SHIFT); - while(first <= last) { - *iopte++ = __iopte(MKIOPTE(__pa(first))); - first += PAGE_SIZE; - } -} +#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) +#define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ) void __init iommu_init(int iommund, struct sbus_bus *sbus) { - unsigned int impl, vers, ptsize; + unsigned int impl, vers; unsigned long tmp; struct iommu_struct *iommu; struct linux_prom_registers iommu_promregs[PROMREG_MAX]; struct resource r; - int i; + unsigned long *bitmap; iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); + if (!iommu) { + prom_printf("Unable to allocate iommu structure\n"); + prom_halt(); + } prom_getproperty(iommund, "reg", (void *) iommu_promregs, sizeof(iommu_promregs)); memset(&r, 0, sizeof(r)); @@ -69,93 +77,129 @@ iommu_init(int iommund, struct sbus_bus *sbus) r.start = iommu_promregs[0].phys_addr; iommu->regs = (struct iommu_regs *) sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); - if(!iommu->regs) - panic("Cannot map IOMMU registers."); + if(!iommu->regs) { + prom_printf("Cannot map IOMMU registers\n"); + prom_halt(); + } impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; tmp = iommu->regs->control; tmp &= ~(IOMMU_CTRL_RNGE); - switch(PAGE_OFFSET & 0xf0000000) { - case 0xf0000000: - tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xf0000000; - break; - case 0xe0000000: - tmp |= (IOMMU_RNGE_512MB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xe0000000; - break; - case 0xd0000000: - case 0xc0000000: - tmp |= (IOMMU_RNGE_1GB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xc0000000; - break; - case 0xb0000000: - case 0xa0000000: - case 0x90000000: - case 0x80000000: - tmp |= (IOMMU_RNGE_2GB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0x80000000; - break; - } + tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); iommu->regs->control = tmp; iommu_invalidate(iommu->regs); + iommu->start = IOMMU_START; iommu->end = 0xffffffff; /* Allocate IOMMU page table */ - ptsize = iommu->end - iommu->start + 1; - ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t); - /* Stupid alignment constraints give me a headache. We need 256K or 512K or 1M or 2M area aligned to its size and current gfp will fortunately give it to us. */ - for (i = 6; i < 9; i++) - if ((1 << (i + PAGE_SHIFT)) == ptsize) - break; - tmp = __get_free_pages(GFP_KERNEL, i); + tmp = __get_free_pages(GFP_KERNEL, IOMMU_ORDER); if (!tmp) { - prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize); + prom_printf("Unable to allocate iommu table [0x%08x]\n", + IOMMU_NPTES*sizeof(iopte_t)); prom_halt(); } - iommu->lowest = iommu->page_table = (iopte_t *)tmp; + iommu->page_table = (iopte_t *)tmp; /* Initialize new table. */ + memset(iommu->page_table, 0, IOMMU_NPTES*sizeof(iopte_t)); flush_cache_all(); - memset(iommu->page_table, 0, ptsize); - iommu_map_dvma_pages_for_iommu(iommu); - if(viking_mxcc_present) { - unsigned long start = (unsigned long) iommu->page_table; - unsigned long end = (start + ptsize); + flush_tlb_all(); + iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; + iommu_invalidate(iommu->regs); + + bitmap = kmalloc(IOMMU_NPTES>>3, GFP_KERNEL); + if (!bitmap) { + prom_printf("Unable to allocate iommu bitmap [%d]\n", + (int)(IOMMU_NPTES>>3)); + prom_halt(); + } + bit_map_init(&iommu->usemap, bitmap, IOMMU_NPTES); + + printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", + impl, vers, iommu->page_table, + (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES); + + sbus->iommu = iommu; +} + +/* This begs to be btfixup-ed by srmmu. */ +static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte) +{ + unsigned long start; + unsigned long end; + + start = (unsigned long)iopte & PAGE_MASK; + end = PAGE_ALIGN(start + niopte*sizeof(iopte_t)); + if (viking_mxcc_present) { while(start < end) { viking_mxcc_flush_page(start); start += PAGE_SIZE; } } else if (viking_flush) { - unsigned long start = (unsigned long) iommu->page_table; - unsigned long end = (start + ptsize); while(start < end) { viking_flush_page(start); start += PAGE_SIZE; } } - flush_tlb_all(); - iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; - iommu_invalidate(iommu->regs); +} - sbus->iommu = iommu; - printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n", - impl, vers, iommu->page_table, ptsize); +static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) +{ + struct iommu_struct *iommu = sbus->iommu; + int ioptex; + iopte_t *iopte, *iopte0; + unsigned int busa, busa0; + int i; + + ioptex = bit_map_string_get(&iommu->usemap, npages, 1); + if (ioptex < 0) + panic("iommu out"); + busa0 = iommu->start + (ioptex << PAGE_SHIFT); + iopte0 = &iommu->page_table[ioptex]; + + busa = busa0; + iopte = iopte0; + for (i = 0; i < npages; i++) { + iopte_val(*iopte) = MKIOPTE(page_to_pfn(page), IOPERM); + iommu_invalidate_page(iommu->regs, busa); + busa += PAGE_SIZE; + iopte++; + page++; + } + + iommu_viking_flush_iotlb(iopte0, npages); + + return busa0; +} + +static u32 iommu_get_scsi_one(char *vaddr, unsigned int len, + struct sbus_bus *sbus) +{ + unsigned long off; + int npages; + struct page *page; + u32 busa; + + off = (unsigned long)vaddr & ~PAGE_MASK; + npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; + page = virt_to_page((unsigned long)vaddr & PAGE_MASK); + busa = iommu_get_one(page, npages, sbus); + return busa + off; } static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { - return (__u32)vaddr; + return iommu_get_scsi_one(vaddr, len, sbus); } static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { flush_page_for_dma(0); - return (__u32)vaddr; + return iommu_get_scsi_one(vaddr, len, sbus); } static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) @@ -166,75 +210,129 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb flush_page_for_dma(page); page += PAGE_SIZE; } - return (__u32)vaddr; + return iommu_get_scsi_one(vaddr, len, sbus); } static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { + int n; + while (sz != 0) { --sz; - sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset); - sg[sz].dvma_length = (__u32) (sg[sz].length); + n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; + sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_length = (__u32) sg->length; + sg++; } } static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { + int n; + flush_page_for_dma(0); while (sz != 0) { --sz; - sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset); - sg[sz].dvma_length = (__u32) (sg[sz].length); + n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; + sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_length = (__u32) sg->length; + sg++; } } static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { unsigned long page, oldpage = 0; + int n, i; while(sz != 0) { --sz; - page = (unsigned long) page_address(sg[sz].page); - if (oldpage == page) - page += PAGE_SIZE; /* We flushed that page already */ - while(page < (unsigned long)(page_address(sg[sz].page) + sg[sz].offset + sg[sz].length)) { - flush_page_for_dma(page); - page += PAGE_SIZE; + + n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; + + /* + * We expect unmapped highmem pages to be not in the cache. + * XXX Is this a good assumption? + * XXX What if someone else unmaps it here and races us? + */ + if ((page = (unsigned long) page_address(sg->page)) != 0) { + for (i = 0; i < n; i++) { + if (page != oldpage) { /* Already flushed? */ + flush_page_for_dma(page); + oldpage = page; + } + page += PAGE_SIZE; + } } - sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset); - sg[sz].dvma_length = (__u32) (sg[sz].length); - oldpage = page - PAGE_SIZE; + + sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset; + sg->dvma_length = (__u32) sg->length; + sg++; } } +static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus) +{ + struct iommu_struct *iommu = sbus->iommu; + int ioptex; + int i; + + if (busa < iommu->start) + BUG(); + ioptex = (busa - iommu->start) >> PAGE_SHIFT; + for (i = 0; i < npages; i++) { + iopte_val(iommu->page_table[ioptex + i]) = 0; + iommu_invalidate_page(iommu->regs, busa); + busa += PAGE_SIZE; + } + bit_map_clear(&iommu->usemap, ioptex, npages); +} + static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) { + unsigned long off; + int npages; + + off = vaddr & ~PAGE_MASK; + npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; + iommu_release_one(vaddr & PAGE_MASK, npages, sbus); } static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { + int n; + + while(sz != 0) { + --sz; + + n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; + iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus); + sg->dvma_address = 0x21212121; + sg++; + } } #ifdef CONFIG_SBUS -static void iommu_map_dma_area(unsigned long va, __u32 addr, int len) +static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, + unsigned long addr, int len) { - unsigned long page, end, ipte_cache; - pgprot_t dvma_prot; + unsigned long page, end; struct iommu_struct *iommu = sbus_root->iommu; iopte_t *iopte = iommu->page_table; iopte_t *first; + int ioptex; - if(viking_mxcc_present || srmmu_modtype == HyperSparc) { - dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); - ipte_cache = 1; - } else { - dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); - ipte_cache = 0; - } + if ((va & ~PAGE_MASK) != 0) BUG(); + if ((addr & ~PAGE_MASK) != 0) BUG(); + if ((len & ~PAGE_MASK) != 0) BUG(); + + ioptex = bit_map_string_get(&iommu->usemap, len >> PAGE_SHIFT, 1); + if (ioptex < 0) + panic("iommu out"); - iopte += ((addr - iommu->start) >> PAGE_SHIFT); + iopte += ioptex; first = iopte; - end = PAGE_ALIGN((addr + len)); + end = addr + len; while(addr < end) { page = va; { @@ -252,16 +350,11 @@ static void iommu_map_dma_area(unsigned long va, __u32 addr, int len) pgdp = pgd_offset(&init_mm, addr); pmdp = pmd_offset(pgdp, addr); ptep = pte_offset_map(pmdp, addr); - /* XXX What if we run out of atomic maps above */ set_pte(ptep, mk_pte(virt_to_page(page), dvma_prot)); - if (ipte_cache != 0) { - iopte_val(*iopte++) = MKIOPTE(__pa(page)); - } else { - iopte_val(*iopte++) = - MKIOPTE(__pa(page)) & ~IOPTE_CACHE; - } } + iopte_val(*iopte++) = + MKIOPTE(page_to_pfn(virt_to_page(page)), ioperm_noc); addr += PAGE_SIZE; va += PAGE_SIZE; } @@ -277,23 +370,12 @@ static void iommu_map_dma_area(unsigned long va, __u32 addr, int len) * to handle the latter case as well. */ flush_cache_all(); - if(viking_mxcc_present) { - unsigned long start = ((unsigned long) first) & PAGE_MASK; - unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); - while(start < end) { - viking_mxcc_flush_page(start); - start += PAGE_SIZE; - } - } else if(viking_flush) { - unsigned long start = ((unsigned long) first) & PAGE_MASK; - unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); - while(start < end) { - viking_flush_page(start); - start += PAGE_SIZE; - } - } + iommu_viking_flush_iotlb(first, len >> PAGE_SHIFT); flush_tlb_all(); iommu_invalidate(iommu->regs); + + *pba = iommu->start + (ioptex << PAGE_SHIFT); + return 0; } static void iommu_unmap_dma_area(unsigned long busa, int len) @@ -301,27 +383,29 @@ static void iommu_unmap_dma_area(unsigned long busa, int len) struct iommu_struct *iommu = sbus_root->iommu; iopte_t *iopte = iommu->page_table; unsigned long end; + int ioptex = (busa - iommu->start) >> PAGE_SHIFT; - iopte += ((busa - iommu->start) >> PAGE_SHIFT); - end = PAGE_ALIGN((busa + len)); + if ((busa & ~PAGE_MASK) != 0) BUG(); + if ((len & ~PAGE_MASK) != 0) BUG(); + + iopte += ioptex; + end = busa + len; while (busa < end) { iopte_val(*iopte++) = 0; busa += PAGE_SIZE; } - flush_tlb_all(); /* P3: Hmm... it would not hurt. */ + flush_tlb_all(); iommu_invalidate(iommu->regs); + bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT); } -static unsigned long iommu_translate_dvma(unsigned long busa) +static struct page *iommu_translate_dvma(unsigned long busa) { struct iommu_struct *iommu = sbus_root->iommu; iopte_t *iopte = iommu->page_table; - unsigned long pa; iopte += ((busa - iommu->start) >> PAGE_SHIFT); - pa = pte_val(*iopte); - pa = (pa & 0xFFFFFFF0) << 4; /* Loose higher bits of 36 */ - return pa + PAGE_OFFSET; + return pfn_to_page((pte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4)); } #endif @@ -352,12 +436,20 @@ void __init ld_mmu_iommu(void) BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_pflush, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_pflush, BTFIXUPCALL_NORM); } - BTFIXUPSET_CALL(mmu_release_scsi_one, iommu_release_scsi_one, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(mmu_release_scsi_sgl, iommu_release_scsi_sgl, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(mmu_release_scsi_one, iommu_release_scsi_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_release_scsi_sgl, iommu_release_scsi_sgl, BTFIXUPCALL_NORM); #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM); #endif + + if (viking_mxcc_present || srmmu_modtype == HyperSparc) { + dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); + ioperm_noc = IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID; + } else { + dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); + ioperm_noc = IOPTE_WRITE | IOPTE_VALID; + } } diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c index e388c31f55d9..e9f9571601ba 100644 --- a/arch/sparc/mm/loadmmu.c +++ b/arch/sparc/mm/loadmmu.c @@ -26,7 +26,6 @@ unsigned int pg_iobits; extern void ld_mmu_sun4c(void); extern void ld_mmu_srmmu(void); -extern void ioport_init(void); void __init load_mmu(void) { @@ -44,5 +43,4 @@ void __init load_mmu(void) prom_halt(); } btfixup(); - ioport_init(); } diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index ee0ae591e311..30ec1351efe3 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -137,29 +138,26 @@ static inline int srmmu_device_memory(unsigned long x) int srmmu_cache_pagetables; /* these will be initialized in srmmu_nocache_calcsize() */ -int srmmu_nocache_npages; unsigned long srmmu_nocache_size; unsigned long srmmu_nocache_end; unsigned long pkmap_base; unsigned long pkmap_base_end; -unsigned long srmmu_nocache_bitmap_size; extern unsigned long fix_kmap_begin; extern unsigned long fix_kmap_end; +/* 1 bit <=> 256 bytes of nocache <=> 64 PTEs */ #define SRMMU_NOCACHE_BITMAP_SHIFT (PAGE_SHIFT - 4) void *srmmu_nocache_pool; void *srmmu_nocache_bitmap; -int srmmu_nocache_low; -int srmmu_nocache_used; -static spinlock_t srmmu_nocache_spinlock = SPIN_LOCK_UNLOCKED; +static struct bit_map srmmu_nocache_map; /* This makes sense. Honest it does - Anton */ #define __nocache_pa(VADDR) (((unsigned long)VADDR) - SRMMU_NOCACHE_VADDR + __pa((unsigned long)srmmu_nocache_pool)) #define __nocache_va(PADDR) (__va((unsigned long)PADDR) - (unsigned long)srmmu_nocache_pool + SRMMU_NOCACHE_VADDR) #define __nocache_fix(VADDR) __va(__nocache_pa(VADDR)) -static inline unsigned long srmmu_pte_pfn(pte_t pte) +static unsigned long srmmu_pte_pfn(pte_t pte) { if (srmmu_device_memory(pte_val(pte))) { /* XXX Anton obviously had something in mind when he did this. @@ -219,15 +217,6 @@ static inline int srmmu_pgd_present(pgd_t pgd) static inline void srmmu_pgd_clear(pgd_t * pgdp) { srmmu_set_pte((pte_t *)pgdp, __pte(0)); } -static inline int srmmu_pte_write(pte_t pte) -{ return pte_val(pte) & SRMMU_WRITE; } - -static inline int srmmu_pte_dirty(pte_t pte) -{ return pte_val(pte) & SRMMU_DIRTY; } - -static inline int srmmu_pte_young(pte_t pte) -{ return pte_val(pte) & SRMMU_REF; } - static inline pte_t srmmu_pte_wrprotect(pte_t pte) { return __pte(pte_val(pte) & ~SRMMU_WRITE);} @@ -321,10 +310,7 @@ static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) */ static unsigned long __srmmu_get_nocache(int size, int align) { - int offset = srmmu_nocache_low; - int i; - unsigned long va_tmp, phys_tmp; - int lowest_failed = 0; + int offset; if (size < SRMMU_NOCACHE_BITMAP_SHIFT) { printk("Size 0x%x too small for nocache request\n", size); @@ -334,49 +320,20 @@ static unsigned long __srmmu_get_nocache(int size, int align) printk("Size 0x%x unaligned int nocache request\n", size); size += SRMMU_NOCACHE_BITMAP_SHIFT-1; } - size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; - - spin_lock(&srmmu_nocache_spinlock); - -repeat: - offset = find_next_zero_bit(srmmu_nocache_bitmap, srmmu_nocache_bitmap_size, offset); - - /* we align on physical address */ - if (align) { - va_tmp = (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); - phys_tmp = (__nocache_pa(va_tmp) + align - 1) & ~(align - 1); - va_tmp = (unsigned long)__nocache_va(phys_tmp); - offset = (va_tmp - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; - } - if ((srmmu_nocache_bitmap_size - offset) < size) { - printk("Run out of nocached RAM!\n"); - spin_unlock(&srmmu_nocache_spinlock); + offset = bit_map_string_get(&srmmu_nocache_map, + size >> SRMMU_NOCACHE_BITMAP_SHIFT, + align >> SRMMU_NOCACHE_BITMAP_SHIFT); +/* P3 */ /* printk("srmmu: get size %d align %d, got %d (0x%x)\n", + size >> SRMMU_NOCACHE_BITMAP_SHIFT, align >> SRMMU_NOCACHE_BITMAP_SHIFT, + offset, offset); */ + if (offset == -1) { + printk("srmmu: out of nocache %d: %d/%d\n", + size, (int) srmmu_nocache_size, + srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); return 0; } - i = 0; - while(i < size) { - if (test_bit(offset + i, srmmu_nocache_bitmap)) { - lowest_failed = 1; - offset = offset + i + 1; - goto repeat; - } - i++; - } - - i = 0; - while(i < size) { - set_bit(offset + i, srmmu_nocache_bitmap); - i++; - srmmu_nocache_used++; - } - - if (!lowest_failed && ((align >> SRMMU_NOCACHE_BITMAP_SHIFT) <= 1) && (offset > srmmu_nocache_low)) - srmmu_nocache_low = offset; - - spin_unlock(&srmmu_nocache_spinlock); - return (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); } @@ -422,63 +379,57 @@ void srmmu_free_nocache(unsigned long vaddr, int size) offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; - spin_lock(&srmmu_nocache_spinlock); - - while(size--) { - clear_bit(offset + size, srmmu_nocache_bitmap); - srmmu_nocache_used--; - } - - if (offset < srmmu_nocache_low) - srmmu_nocache_low = offset; - - spin_unlock(&srmmu_nocache_spinlock); +/* P3 */ /* printk("srmmu: free off %d (0x%x) size %d\n", offset, offset, size); */ + bit_map_clear(&srmmu_nocache_map, offset, size); } void srmmu_early_allocate_ptable_skeleton(unsigned long start, unsigned long end); extern unsigned long probe_memory(void); /* in fault.c */ -/* Reserve nocache dynamically proportionally to the amount of +/* + * Reserve nocache dynamically proportionally to the amount of * system RAM. -- Tomas Szepe , June 2002 */ void srmmu_nocache_calcsize(void) { unsigned long sysmemavail = probe_memory() / 1024; + int srmmu_nocache_npages; srmmu_nocache_npages = sysmemavail / SRMMU_NOCACHE_ALCRATIO / 1024 * 256; - if (sysmemavail % (SRMMU_NOCACHE_ALCRATIO * 1024)) - srmmu_nocache_npages += 256; + + /* P3 XXX The 4x overuse: corroborated by /proc/meminfo. */ + // if (srmmu_nocache_npages < 256) srmmu_nocache_npages = 256; + if (srmmu_nocache_npages < 550) srmmu_nocache_npages = 550; /* anything above 1280 blows up */ if (srmmu_nocache_npages > 1280) srmmu_nocache_npages = 1280; srmmu_nocache_size = srmmu_nocache_npages * PAGE_SIZE; - srmmu_nocache_bitmap_size = srmmu_nocache_npages * 16; srmmu_nocache_end = SRMMU_NOCACHE_VADDR + srmmu_nocache_size; fix_kmap_begin = srmmu_nocache_end; fix_kmap_end = fix_kmap_begin + (KM_TYPE_NR * NR_CPUS - 1) * PAGE_SIZE; pkmap_base = SRMMU_NOCACHE_VADDR + srmmu_nocache_size + 0x40000; pkmap_base_end = pkmap_base + LAST_PKMAP * PAGE_SIZE; - - /* printk("system memory available = %luk\nnocache ram size = %luk\n", - sysmemavail, srmmu_nocache_size / 1024); */ } void srmmu_nocache_init(void) { + unsigned int bitmap_bits; pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long paddr, vaddr; unsigned long pteval; + bitmap_bits = srmmu_nocache_size >> SRMMU_NOCACHE_BITMAP_SHIFT; + srmmu_nocache_pool = __alloc_bootmem(srmmu_nocache_size, PAGE_SIZE, 0UL); memset(srmmu_nocache_pool, 0, srmmu_nocache_size); - srmmu_nocache_bitmap = __alloc_bootmem(srmmu_nocache_bitmap_size, SMP_CACHE_BYTES, 0UL); - memset(srmmu_nocache_bitmap, 0, srmmu_nocache_bitmap_size); + srmmu_nocache_bitmap = __alloc_bootmem(bitmap_bits >> 3, SMP_CACHE_BYTES, 0UL); + bit_map_init(&srmmu_nocache_map, srmmu_nocache_bitmap, bitmap_bits); srmmu_swapper_pg_dir = (pgd_t *)__srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE); memset(__nocache_fix(srmmu_swapper_pg_dir), 0, SRMMU_PGD_TABLE_SIZE); @@ -486,11 +437,12 @@ void srmmu_nocache_init(void) srmmu_early_allocate_ptable_skeleton(SRMMU_NOCACHE_VADDR, srmmu_nocache_end); - spin_lock_init(&srmmu_nocache_spinlock); - paddr = __pa((unsigned long)srmmu_nocache_pool); vaddr = SRMMU_NOCACHE_VADDR; +/* P3 */ printk("srmmu: pool 0x%x vaddr 0x%x bitmap 0x%x bits %d (0x%x)\n", + (int)srmmu_nocache_pool, vaddr, srmmu_nocache_bitmap, bitmap_bits, bitmap_bits); + while (vaddr < srmmu_nocache_end) { pgd = pgd_offset_k(vaddr); pmd = srmmu_pmd_offset(__nocache_fix(pgd), vaddr); @@ -637,7 +589,8 @@ static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, } /* Low level IO area allocation on the SRMMU. */ -void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) +static inline void srmmu_mapioaddr(unsigned long physaddr, + unsigned long virt_addr, int bus_type) { pgd_t *pgdp; pmd_t *pmdp; @@ -656,16 +609,24 @@ void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_ty * 36-bit physical address on the I/O space lines... */ tmp |= (bus_type << 28); - if(rdonly) - tmp |= SRMMU_PRIV_RDONLY; - else - tmp |= SRMMU_PRIV; + tmp |= SRMMU_PRIV; __flush_page_to_ram(virt_addr); srmmu_set_pte(ptep, __pte(tmp)); +} + +static void srmmu_mapiorange(unsigned int bus, unsigned long xpa, + unsigned long xva, unsigned int len) +{ + while (len != 0) { + len -= PAGE_SIZE; + srmmu_mapioaddr(xpa, xva, bus); + xva += PAGE_SIZE; + xpa += PAGE_SIZE; + } flush_tlb_all(); } -void srmmu_unmapioaddr(unsigned long virt_addr) +static inline void srmmu_unmapioaddr(unsigned long virt_addr) { pgd_t *pgdp; pmd_t *pmdp; @@ -677,6 +638,15 @@ void srmmu_unmapioaddr(unsigned long virt_addr) /* No need to flush uncacheable page. */ srmmu_pte_clear(ptep); +} + +static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len) +{ + while (len != 0) { + len -= PAGE_SIZE; + srmmu_unmapioaddr(virt_addr); + virt_addr += PAGE_SIZE; + } flush_tlb_all(); } @@ -1398,7 +1368,7 @@ static void srmmu_mmu_info(struct seq_file *m) srmmu_name, num_contexts, srmmu_nocache_size, - (srmmu_nocache_used << SRMMU_NOCACHE_BITMAP_SHIFT)); + srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); } static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) @@ -2258,7 +2228,10 @@ void __init ld_mmu_srmmu(void) BTFIXUPSET_CALL(pte_mkyoung, srmmu_pte_mkyoung, BTFIXUPCALL_ORINT(SRMMU_REF)); BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(destroy_context, srmmu_destroy_context, BTFIXUPCALL_NORM); - + + BTFIXUPSET_CALL(sparc_mapiorange, srmmu_mapiorange, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sparc_unmapiorange, srmmu_unmapiorange, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(alloc_thread_info, srmmu_alloc_thread_info, BTFIXUPCALL_NORM); diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 2f28f983c86e..289a3f425831 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -534,10 +534,13 @@ static inline void sun4c_init_ss2_cache_bug(void) } /* Addr is always aligned on a page boundary for us already. */ -static void sun4c_map_dma_area(unsigned long va, u32 addr, int len) +static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va, + unsigned long addr, int len) { unsigned long page, end; + *pba = addr; + end = PAGE_ALIGN((addr + len)); while (addr < end) { page = va; @@ -550,13 +553,15 @@ static void sun4c_map_dma_area(unsigned long va, u32 addr, int len) addr += PAGE_SIZE; va += PAGE_SIZE; } + + return 0; } -static unsigned long sun4c_translate_dvma(unsigned long busa) +static struct page *sun4c_translate_dvma(unsigned long busa) { /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ unsigned long pte = sun4c_get_pte(busa); - return (pte << PAGE_SHIFT) + PAGE_OFFSET; + return pfn_to_page(pte & SUN4C_PFN_MASK); } static void sun4c_unmap_dma_area(unsigned long busa, int len) @@ -1578,21 +1583,33 @@ static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) } } -void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus_type, int rdonly) +static inline void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr) { unsigned long page_entry; page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK); page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT)); - if (rdonly) - page_entry &= ~_SUN4C_WRITEABLE; sun4c_put_pte(virt_addr, page_entry); } -void sun4c_unmapioaddr(unsigned long virt_addr) +static void sun4c_mapiorange(unsigned int bus, unsigned long xpa, + unsigned long xva, unsigned int len) { - sun4c_put_pte(virt_addr, 0); + while (len != 0) { + len -= PAGE_SIZE; + sun4c_mapioaddr(xpa, xva); + xva += PAGE_SIZE; + xpa += PAGE_SIZE; + } +} + +static void sun4c_unmapiorange(unsigned long virt_addr, unsigned int len) +{ + while (len != 0) { + len -= PAGE_SIZE; + sun4c_put_pte(virt_addr, 0); + virt_addr += PAGE_SIZE; + } } static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm) @@ -1783,7 +1800,7 @@ static pte_t sun4c_pte_mkyoung(pte_t pte) */ static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot) { - return __pte((page - mem_map) | pgprot_val(pgprot)); + return __pte(page_to_pfn(page) | pgprot_val(pgprot)); } static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot) @@ -2225,6 +2242,9 @@ void __init ld_mmu_sun4c(void) BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(alloc_thread_info, sun4c_alloc_thread_info, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(free_thread_info, sun4c_free_thread_info, BTFIXUPCALL_NORM); diff --git a/include/asm-sparc/bitext.h b/include/asm-sparc/bitext.h new file mode 100644 index 000000000000..88b1518834a8 --- /dev/null +++ b/include/asm-sparc/bitext.h @@ -0,0 +1,24 @@ +/* + * bitext.h: Bit string operations on the sparc, specific to architecture. + * + * Copyright 2002 Pete Zaitcev + */ + +#ifndef _SPARC_BITEXT_H +#define _SPARC_BITEXT_H + +#include + +struct bit_map { + spinlock_t lock; + unsigned long *map; + int size; + int used; + int last_off; +}; + +extern int bit_map_string_get(struct bit_map *t, int len, int align); +extern void bit_map_clear(struct bit_map *t, int offset, int len); +extern void bit_map_init(struct bit_map *t, unsigned long *map, int size); + +#endif /* defined(_SPARC_BITEXT_H) */ diff --git a/include/asm-sparc/iommu.h b/include/asm-sparc/iommu.h index cf1d5b794833..8171362d56b9 100644 --- a/include/asm-sparc/iommu.h +++ b/include/asm-sparc/iommu.h @@ -6,6 +6,7 @@ #define _SPARC_IOMMU_H #include +#include /* The iommu handles all virtual to physical address translations * that occur between the SBUS and physical memory. Access by @@ -100,11 +101,11 @@ struct iommu_regs { struct iommu_struct { struct iommu_regs *regs; iopte_t *page_table; - iopte_t *lowest; /* to speed up searches... */ - unsigned long plow; /* For convenience */ unsigned long start; /* First managed virtual address */ unsigned long end; /* Last managed virtual address */ + + struct bit_map usemap; }; extern __inline__ void iommu_invalidate(struct iommu_regs *regs) @@ -112,9 +113,9 @@ extern __inline__ void iommu_invalidate(struct iommu_regs *regs) regs->tlbflush = 0; } -extern __inline__ void iommu_invalidate_page(struct iommu_regs *regs, unsigned long page) +extern __inline__ void iommu_invalidate_page(struct iommu_regs *regs, unsigned long ba) { - regs->pageflush = (page & PAGE_MASK); + regs->pageflush = (ba & PAGE_MASK); } #endif /* !(_SPARC_IOMMU_H) */ diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index c25c0d4f7461..137421b5bdc4 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -27,6 +27,7 @@ #ifndef __ASSEMBLY__ struct vm_area_struct; +struct page; extern void load_mmu(void); extern unsigned long calc_highpages(void); @@ -51,15 +52,30 @@ BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct s /* * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep. + * + * The mmu_map_dma_area establishes two mappings in one go. + * These mappings point to pages normally mapped at 'va' (linear address). + * First mapping is for CPU visible address at 'a', uncached. + * This is an alias, but it works because it is an uncached mapping. + * Second mapping is for device visible address, or "bus" address. + * The bus address is returned at '*pba'. + * + * These functions seem distinct, but are hard to split. On sun4c, + * at least for now, 'a' is equal to bus address, and retured in *pba. + * On sun4m, page attributes depend on the CPU type, so we have to + * know if we are mapping RAM or I/O, so it has to be an additional argument + * to a separate mapping function for CPU visible mappings. */ -BTFIXUPDEF_CALL(void, mmu_map_dma_area, unsigned long va, __u32 addr, int len) -BTFIXUPDEF_CALL(unsigned long /*phys*/, mmu_translate_dvma, unsigned long busa) +BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len) +BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa) BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len) -#define mmu_map_dma_area(va, ba,len) BTFIXUP_CALL(mmu_map_dma_area)(va,ba,len) +#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len) #define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len) #define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba) +/* + */ BTFIXUPDEF_SIMM13(pmd_shift) BTFIXUPDEF_SETHI(pmd_size) BTFIXUPDEF_SETHI(pmd_mask) @@ -377,6 +393,12 @@ BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, #define update_mmu_cache(vma,addr,pte) BTFIXUP_CALL(update_mmu_cache)(vma,addr,pte) +BTFIXUPDEF_CALL(void, sparc_mapiorange, unsigned int, unsigned long, + unsigned long, unsigned int) +BTFIXUPDEF_CALL(void, sparc_unmapiorange, unsigned long, unsigned int) +#define sparc_mapiorange(bus,pa,va,len) BTFIXUP_CALL(sparc_mapiorange)(bus,pa,va,len) +#define sparc_unmapiorange(va,len) BTFIXUP_CALL(sparc_unmapiorange)(va,len) + extern int invalid_segment; /* Encode and de-code a swap entry */ diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h index bf09706e88ea..075c98e2bc56 100644 --- a/include/asm-sparc/sbus.h +++ b/include/asm-sparc/sbus.h @@ -10,7 +10,7 @@ #include #include -#include +/* #include */ /* Unused since we use opaque iommu (|io-unit) */ #include /* We scan which devices are on the SBus using the PROM node device -- cgit v1.2.3 From 67ac5b866bda838d9838faedad0435e3e84fb2bd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 29 Apr 2003 17:17:33 -0700 Subject: [PATCH] complete modinfo section Restores .modinfo section, and uses it to store license and vermagic. --- include/linux/module.h | 48 +++++++++++++++++----------- kernel/module.c | 87 ++++++++++++++++++++++++++++++++++---------------- scripts/modpost.c | 4 +-- 3 files changed, 90 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/include/linux/module.h b/include/linux/module.h index 657802c8af75..9511614b024a 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -20,10 +20,7 @@ #include /* Not Yet Implemented */ -#define MODULE_AUTHOR(name) -#define MODULE_DESCRIPTION(desc) #define MODULE_SUPPORTED_DEVICE(name) -#define MODULE_PARM_DESC(var,desc) #define print_modules() /* v850 toolchain uses a `_' prefix for all user symbols */ @@ -58,12 +55,11 @@ search_extable(const struct exception_table_entry *first, unsigned long value); #ifdef MODULE -#define ___module_cat(a,b) a ## b +#define ___module_cat(a,b) __mod_ ## a ## b #define __module_cat(a,b) ___module_cat(a,b) -/* For userspace: you can also call me... */ -#define MODULE_ALIAS(alias) \ - static const char __module_cat(__alias_,__LINE__)[] \ - __attribute__((section(".modinfo"),unused)) = "alias=" alias +#define __MODULE_INFO(tag, name, info) \ +static const char __module_cat(name,__LINE__)[] \ + __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info #define MODULE_GENERIC_TABLE(gtype,name) \ extern const struct gtype##_id __mod_##gtype##_table \ @@ -71,6 +67,19 @@ extern const struct gtype##_id __mod_##gtype##_table \ #define THIS_MODULE (&__this_module) +#else /* !MODULE */ + +#define MODULE_GENERIC_TABLE(gtype,name) +#define __MODULE_INFO(tag, name, info) +#define THIS_MODULE ((struct module *)0) +#endif + +/* Generic info of form tag = "info" */ +#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) + +/* For userspace: you can also call me... */ +#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) + /* * The following license idents are currently accepted as indicating free * software modules @@ -97,17 +106,18 @@ extern const struct gtype##_id __mod_##gtype##_table \ * 2. So the community can ignore bug reports including proprietary modules * 3. So vendors can do likewise based on their own policies */ -#define MODULE_LICENSE(license) \ - static const char __module_license[] \ - __attribute__((section(".init.license"), unused)) = license - -#else /* !MODULE */ - -#define MODULE_ALIAS(alias) -#define MODULE_GENERIC_TABLE(gtype,name) -#define THIS_MODULE ((struct module *)0) -#define MODULE_LICENSE(license) -#endif +#define MODULE_LICENSE(_license) MODULE_INFO(license, _license) + +/* Author, ideally of form NAME [, NAME ]*[ and NAME ] */ +#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) + +/* What your module does. */ +#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) + +/* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ +#define MODULE_PARM_DESC(_parm, desc) \ + __MODULE_INFO(parm, _parm, #_parm ":" desc) #define MODULE_DEVICE_TABLE(type,name) \ MODULE_GENERIC_TABLE(type##_device,name) diff --git a/kernel/module.c b/kernel/module.c index ccba086ce6bc..17e2884ce495 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -939,12 +939,12 @@ EXPORT_SYMBOL_GPL(__symbol_get); /* Change all symbols so that sh_value encodes the pointer directly. */ static int simplify_symbols(Elf_Shdr *sechdrs, unsigned int symindex, - unsigned int strindex, + const char *strtab, unsigned int versindex, struct module *mod) { Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; - const char *strtab = (char *)sechdrs[strindex].sh_addr; + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); int ret = 0; @@ -1063,13 +1063,9 @@ static inline int license_is_gpl_compatible(const char *license) || strcmp(license, "Dual MPL/GPL") == 0); } -static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx) +static void set_license(struct module *mod, const char *license) { - char *license; - - if (licenseidx) - license = (char *)sechdrs[licenseidx].sh_addr; - else + if (!license) license = "unspecified"; mod->license_gplok = license_is_gpl_compatible(license); @@ -1080,6 +1076,40 @@ static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx) } } +/* Parse tag=value strings from .modinfo section */ +static char *next_string(char *string, unsigned long *secsize) +{ + /* Skip non-zero chars */ + while (string[0]) { + string++; + if ((*secsize)-- <= 1) + return NULL; + } + + /* Skip any zero padding. */ + while (!string[0]) { + string++; + if ((*secsize)-- <= 1) + return NULL; + } + return string; +} + +static char *get_modinfo(Elf_Shdr *sechdrs, + unsigned int info, + const char *tag) +{ + char *p; + unsigned int taglen = strlen(tag); + unsigned long size = sechdrs[info].sh_size; + + for (p = (char *)sechdrs[info].sh_addr; p; p = next_string(p, &size)) { + if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') + return p + taglen + 1; + } + return NULL; +} + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, @@ -1088,9 +1118,9 @@ static struct module *load_module(void __user *umod, { Elf_Ehdr *hdr; Elf_Shdr *sechdrs; - char *secstrings, *args; - unsigned int i, symindex, exportindex, strindex, setupindex, exindex, - modindex, obsparmindex, licenseindex, gplindex, vmagindex, + char *secstrings, *args, *modmagic, *strtab = NULL; + unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, + exportindex, modindex, obsparmindex, infoindex, gplindex, crcindex, gplcrcindex, versindex; long arglen; struct module *mod; @@ -1124,6 +1154,7 @@ static struct module *load_module(void __user *umod, /* Convenience variables */ sechdrs = (void *)hdr + hdr->e_shoff; secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + sechdrs[0].sh_addr = 0; /* And these should exist, but gcc whinges if we don't init them */ symindex = strindex = 0; @@ -1137,6 +1168,7 @@ static struct module *load_module(void __user *umod, if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; strindex = sechdrs[i].sh_link; + strtab = (char *)hdr + sechdrs[strindex].sh_offset; } #ifndef CONFIG_MODULE_UNLOAD /* Don't load .exit sections */ @@ -1145,12 +1177,6 @@ static struct module *load_module(void __user *umod, #endif } -#ifdef CONFIG_KALLSYMS - /* Keep symbol and string tables for decoding later. */ - sechdrs[symindex].sh_flags |= SHF_ALLOC; - sechdrs[strindex].sh_flags |= SHF_ALLOC; -#endif - modindex = find_sec(hdr, sechdrs, secstrings, ".gnu.linkonce.this_module"); if (!modindex) { @@ -1168,9 +1194,16 @@ static struct module *load_module(void __user *umod, setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); - licenseindex = find_sec(hdr, sechdrs, secstrings, ".init.license"); - vmagindex = find_sec(hdr, sechdrs, secstrings, "__vermagic"); versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); + infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); + + /* Don't keep modinfo section */ + sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; +#ifdef CONFIG_KALLSYMS + /* Keep symbol and string tables for decoding later. */ + sechdrs[symindex].sh_flags |= SHF_ALLOC; + sechdrs[strindex].sh_flags |= SHF_ALLOC; +#endif /* Check module struct version now, before we try to use module. */ if (!check_modstruct_version(sechdrs, versindex, mod)) { @@ -1178,14 +1211,15 @@ static struct module *load_module(void __user *umod, goto free_hdr; } + modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); /* This is allowed: modprobe --force will invalidate it. */ - if (!vmagindex) { + if (!modmagic) { tainted |= TAINT_FORCED_MODULE; printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", mod->name); - } else if (!same_magic((char *)sechdrs[vmagindex].sh_addr, vermagic)) { + } else if (!same_magic(modmagic, vermagic)) { printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", - mod->name, (char*)sechdrs[vmagindex].sh_addr, vermagic); + mod->name, modmagic, vermagic); err = -ENOEXEC; goto free_hdr; } @@ -1265,11 +1299,11 @@ static struct module *load_module(void __user *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); - /* Set up license info based on contents of section */ - set_license(mod, sechdrs, licenseindex); + /* Set up license info based on the info section */ + set_license(mod, get_modinfo(sechdrs, infoindex, "license")); /* Fix up syms, so that st_value is a pointer to location. */ - err = simplify_symbols(sechdrs, symindex, strindex, versindex, mod); + err = simplify_symbols(sechdrs, symindex, strtab, versindex, mod); if (err < 0) goto cleanup; @@ -1300,8 +1334,7 @@ static struct module *load_module(void __user *umod, for (i = 1; i < hdr->e_shnum; i++) { const char *strtab = (char *)sechdrs[strindex].sh_addr; if (sechdrs[i].sh_type == SHT_REL) - err = apply_relocate(sechdrs, strtab, symindex, i, - mod); + err = apply_relocate(sechdrs, strtab, symindex, i,mod); else if (sechdrs[i].sh_type == SHT_RELA) err = apply_relocate_add(sechdrs, strtab, symindex, i, mod); diff --git a/scripts/modpost.c b/scripts/modpost.c index 1b94b2c73b28..13c33ccca090 100644 --- a/scripts/modpost.c +++ b/scripts/modpost.c @@ -404,9 +404,7 @@ add_header(struct buffer *b) buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); - buf_printf(b, "const char vermagic[]\n"); - buf_printf(b, "__attribute__((section(\"__vermagic\"))) =\n"); - buf_printf(b, "VERMAGIC_STRING;\n"); + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); } /* Record CRCs for unresolved symbols */ -- cgit v1.2.3 From fbf7eda6f4f1e3d5b9a26d82a6884755d34923b7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 29 Apr 2003 17:17:42 -0700 Subject: [PATCH] __module_get Introduces __module_get for places where we know we already hold a reference and ignoring the fact that the module is being "rmmod --wait"ed is simpler. --- fs/filesystems.c | 12 +----------- include/linux/module.h | 19 +++++++++++++++++++ kernel/module.c | 3 ++- 3 files changed, 22 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/fs/filesystems.c b/fs/filesystems.c index a87d637e168a..c4b467fb67dd 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -32,17 +32,7 @@ static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED; /* WARNING: This can be used only if we _already_ own a reference */ void get_filesystem(struct file_system_type *fs) { - if (!try_module_get(fs->owner)) { -#ifdef CONFIG_MODULE_UNLOAD - unsigned int cpu = get_cpu(); - local_inc(&fs->owner->ref[cpu].count); - put_cpu(); -#else - /* Getting filesystem while it's starting up? We're - already supposed to have a reference. */ - BUG(); -#endif - } + __module_get(fs->owner); } void put_filesystem(struct file_system_type *fs) diff --git a/include/linux/module.h b/include/linux/module.h index 9511614b024a..4ddc5edcd22f 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -265,6 +265,7 @@ struct module *module_text_address(unsigned long addr); #ifdef CONFIG_MODULE_UNLOAD +unsigned int module_refcount(struct module *mod); void __symbol_put(const char *symbol); #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) void symbol_put_addr(void *addr); @@ -275,6 +276,17 @@ void symbol_put_addr(void *addr); #define local_dec(x) atomic_dec(x) #endif +/* Sometimes we know we already have a refcount, and it's easier not + to handle the error case (which only happens with rmmod --wait). */ +static inline void __module_get(struct module *module) +{ + if (module) { + BUG_ON(module_refcount(module) == 0); + local_inc(&module->ref[get_cpu()].count); + put_cpu(); + } +} + static inline int try_module_get(struct module *module) { int ret = 1; @@ -310,6 +322,9 @@ static inline int try_module_get(struct module *module) static inline void module_put(struct module *module) { } +static inline void __module_get(struct module *module) +{ +} #define symbol_put(x) do { } while(0) #define symbol_put_addr(p) do { } while(0) @@ -367,6 +382,10 @@ static inline struct module *module_text_address(unsigned long addr) #define symbol_put(x) do { } while(0) #define symbol_put_addr(x) do { } while(0) +static inline void __module_get(struct module *module) +{ +} + static inline int try_module_get(struct module *module) { return 1; diff --git a/kernel/module.c b/kernel/module.c index 17e2884ce495..06ff9328b30b 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -431,7 +431,7 @@ static inline void restart_refcounts(void) } #endif -static unsigned int module_refcount(struct module *mod) +unsigned int module_refcount(struct module *mod) { unsigned int i, total = 0; @@ -439,6 +439,7 @@ static unsigned int module_refcount(struct module *mod) total += atomic_read(&mod->ref[i].count); return total; } +EXPORT_SYMBOL(module_refcount); /* This exists whether we can unload or not */ static void free_module(struct module *mod); -- cgit v1.2.3 From c007c1ed97d2b716e215567a95881e76ff58e1d9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 29 Apr 2003 17:31:14 -0700 Subject: [PATCH] irqs: IRDA Some IRQ udpates for IRDA which seemed to get lost. --- drivers/net/irda/ali-ircc.c | 9 +++++---- drivers/net/irda/donauboe.c | 7 ++++--- drivers/net/irda/nsc-ircc.c | 7 ++++--- drivers/net/irda/smc-ircc.c | 4 ++-- drivers/net/irda/toshoboe.c | 9 ++++----- drivers/net/irda/vlsi_ir.c | 8 +++++--- drivers/net/irda/w83977af_ir.c | 8 ++++---- include/net/irda/irport.h | 2 +- 8 files changed, 29 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index ed5b6d3a293c..46223bbbb7c3 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -95,7 +95,6 @@ static int ali_ircc_net_close(struct net_device *dev); static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); -static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void ali_ircc_suspend(struct ali_ircc_cb *self); static void ali_ircc_wakeup(struct ali_ircc_cb *self); static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev); @@ -632,7 +631,8 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info) * An interrupt from the chip has arrived. Time to do some work * */ -static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct ali_ircc_cb *self; @@ -641,7 +641,7 @@ static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!dev) { WARNING("%s: irq %d for unknown device.\n", driver_name, irq); - return; + return IRQ_NONE; } self = (struct ali_ircc_cb *) dev->priv; @@ -656,7 +656,8 @@ static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(&self->lock); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + return IRQ_HANDLED; } /* * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs) diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index b90bd7c27460..185035d28b17 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -745,20 +745,20 @@ STATIC int toshoboe_invalid_dev(int irq) return 1; } -STATIC void +STATIC irqreturn_t toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs) { struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; __u8 irqstat; if (self == NULL && toshoboe_invalid_dev(irq)) - return; + return IRQ_NONE; irqstat = INB (OBOE_ISR); /* was it us */ if (!(irqstat & OBOE_INT_MASK)) - return; + return IRQ_NONE; /* Ack all the interrupts */ OUTB (irqstat, OBOE_ISR); @@ -791,6 +791,7 @@ toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs) if (irqstat & OBOE_INT_SIP) { self->int_sip++; PROBE_DEBUG("I"); } + return IRQ_HANDLED; } STATIC int diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 850d08cfaff0..ada9a3feda69 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -131,7 +131,6 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); -static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self); static int nsc_ircc_read_dongle_id (int iobase); static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); @@ -1781,7 +1780,8 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, * An interrupt from the chip has arrived. Time to do some work * */ -static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct nsc_ircc_cb *self; @@ -1790,7 +1790,7 @@ static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!dev) { WARNING("%s: irq %d for unknown device.\n", driver_name, irq); - return; + return IRQ_NONE; } self = (struct nsc_ircc_cb *) dev->priv; @@ -1818,6 +1818,7 @@ static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) outb(bsr, iobase+BSR); /* Restore bank register */ spin_unlock(&self->lock); + return IRQ_HANDLED; } /* diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index 570f66981f67..f802455b8ada 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -992,9 +992,9 @@ static irqreturn_t ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } irport = (struct irport_cb *) dev->priv; - ASSERT(irport != NULL, return;); + ASSERT(irport != NULL, return IRQ_NONE;); self = (struct ircc_cb *) irport->priv; - ASSERT(self != NULL, return;); + ASSERT(self != NULL, return IRQ_NONE;); /* Check if we should use the SIR interrupt handler */ if (self->io->speed < 576000) { diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c index 6acd04de8d4a..04b1ee08bea2 100644 --- a/drivers/net/irda/toshoboe.c +++ b/drivers/net/irda/toshoboe.c @@ -349,7 +349,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) } /*interrupt handler */ -static void +static irqreturn_t toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; @@ -360,7 +360,7 @@ toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) { printk (KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); - return; + return IRQ_NONE; } IRDA_DEBUG (4, "%s()\n", __FUNCTION__ ); @@ -369,7 +369,7 @@ toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) /* woz it us */ if (!(irqstat & 0xf8)) - return; + return IRQ_NONE; outb_p (irqstat, OBOE_ISR); /*Acknologede it */ @@ -456,8 +456,7 @@ toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) self->stats.rx_errors++; } - - + return IRQ_HANDLED; } static int diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 73650d69ccd9..6624608c7195 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1570,7 +1570,8 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) /********************************************************/ -static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t vlsi_interrupt(int irq, void *dev_instance, + struct pt_regs *regs) { struct net_device *ndev = dev_instance; vlsi_irda_dev_t *idev = ndev->priv; @@ -1579,6 +1580,7 @@ static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs) int boguscount = 32; unsigned got_act; unsigned long flags; + int handled = 0; got_act = 0; iobase = ndev->base_addr; @@ -1591,7 +1593,7 @@ static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ break; - + handled = 1; if (irintr&IRINTR_RPKTINT) vlsi_rx_interrupt(ndev); @@ -1610,7 +1612,7 @@ static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (boguscount <= 0) printk(KERN_WARNING "%s: too much work in interrupt!\n", __FUNCTION__); - + return IRQ_RETVAL(handled); } /********************************************************/ diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 52df492072d8..3013e4e821ab 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -97,7 +97,6 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void w83977af_dma_write(struct w83977af_ir *self, int iobase); static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed); -static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int w83977af_is_receiving(struct w83977af_ir *self); static int w83977af_net_init(struct net_device *dev); @@ -1118,7 +1117,8 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) * An interrupt from the chip has arrived. Time to do some work * */ -static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t w83977af_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct w83977af_ir *self; @@ -1128,7 +1128,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!dev) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); - return; + return IRQ_NONE; } self = (struct w83977af_ir *) dev->priv; @@ -1153,7 +1153,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs) outb(icr, iobase+ICR); /* Restore (new) interrupts */ outb(set, iobase+SSR); /* Restore bank register */ - + return IRQ_HANDLED; } /* diff --git a/include/net/irda/irport.h b/include/net/irda/irport.h index e5877f66fab8..79b4d8904346 100644 --- a/include/net/irda/irport.h +++ b/include/net/irda/irport.h @@ -73,7 +73,7 @@ struct irport_cb { /* For piggyback drivers */ void *priv; void (*change_speed)(void *priv, __u32 speed); - void (*interrupt)(int irq, void *dev_id, struct pt_regs *regs); + int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs); }; struct irport_cb *irport_open(int i, unsigned int iobase, unsigned int irq); -- cgit v1.2.3 From e5ded0b1d26fceb4a59547fa4d1fcf3fb3983b5b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 29 Apr 2003 17:31:22 -0700 Subject: [PATCH] Fix slab-vs-gfp bitflag clash Fixes a bug spotted by Alexey Mahotkin : the slab-internal SLAB_NO_GROW bit clashes with __GFP_NORETRY. Fix that up so it won't happen again by moving the bit layout into gfp.h. --- include/linux/gfp.h | 1 + include/linux/slab.h | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index ade6d9e97475..be82baa340fa 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -31,6 +31,7 @@ #define __GFP_REPEAT 0x400 /* Retry the allocation. Might fail */ #define __GFP_NOFAIL 0x800 /* Retry for ever. Cannot fail */ #define __GFP_NORETRY 0x1000 /* Do not retry. Might fail */ +#define __GFP_NO_GROW 0x2000 /* Slab internal usage */ #define GFP_ATOMIC (__GFP_HIGH) #define GFP_NOIO (__GFP_WAIT) diff --git a/include/linux/slab.h b/include/linux/slab.h index 603748b9b349..49374df2d450 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -22,8 +22,11 @@ typedef struct kmem_cache_s kmem_cache_t; #define SLAB_KERNEL GFP_KERNEL #define SLAB_DMA GFP_DMA -#define SLAB_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS|__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|__GFP_NORETRY) -#define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */ +#define SLAB_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS|\ + __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT|\ + __GFP_NOFAIL|__GFP_NORETRY) + +#define SLAB_NO_GROW __GFP_NO_GROW /* don't grow a cache */ /* flags to pass to kmem_cache_create(). * The first 3 are only valid when the allocator as been build -- cgit v1.2.3 From a31a4dea7f948c13e24f84fa310cec3814401dfd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 29 Apr 2003 17:32:05 -0700 Subject: [PATCH] Update alt_instr to handle SSE2 prefetch and better nops --- arch/i386/Kconfig | 19 ++++------ arch/i386/kernel/cpu/amd.c | 9 +++++ arch/i386/kernel/cpu/intel.c | 5 +++ arch/i386/kernel/setup.c | 88 +++++++++++++++++++++++++++++++++---------- arch/i386/vmlinux.lds.S | 1 + include/asm-i386/cpufeature.h | 5 +++ include/asm-i386/processor.h | 88 ++++++++++++++++++++++++++++++++++++------- include/asm-i386/system.h | 40 +++++++++++++++++--- 8 files changed, 207 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 234e92cbf4ba..729fab09cd2b 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -273,6 +273,13 @@ config MVIAC3_2 endchoice +config X86_GENERIC + bool "Generic x86 support" + help + Including some tuning for non selected x86 CPUs too. + when it has moderate overhead. This is intended for generic + distributions kernels. + # # Define implied options from the CPU selection here # @@ -288,10 +295,10 @@ config X86_XADD config X86_L1_CACHE_SHIFT int + default "7" if MPENTIUM4 || X86_GENERIC default "4" if MELAN || M486 || M386 default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 default "6" if MK7 || MK8 - default "7" if MPENTIUM4 config RWSEM_GENERIC_SPINLOCK bool @@ -363,16 +370,6 @@ config X86_OOSTORE depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 default y -config X86_PREFETCH - bool - depends on MPENTIUMIII || MPENTIUM4 || MVIAC3_2 - default y - -config X86_SSE2 - bool - depends on MK8 || MPENTIUM4 - default y - config HUGETLB_PAGE bool "Huge TLB Page Support" help diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index ff810509b8fe..091b98ae93b6 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -178,6 +178,15 @@ static void __init init_amd(struct cpuinfo_x86 *c) break; } + switch (c->x86) { + case 15: + set_bit(X86_FEATURE_K8, c->x86_capability); + break; + case 6: + set_bit(X86_FEATURE_K7, c->x86_capability); + break; + } + display_cacheinfo(c); } diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index 69aa8304f797..1736d1a2115b 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -353,6 +353,11 @@ too_many_siblings: break; } #endif + + if (c->x86 == 15) + set_bit(X86_FEATURE_P4, c->x86_capability); + if (c->x86 == 6) + set_bit(X86_FEATURE_P3, c->x86_capability); } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 9c20d88208ae..26efeeb167c2 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -795,41 +795,91 @@ static void __init register_memory(unsigned long max_low_pfn) pci_mem_start = low_mem_size; } +/* Use inline assembly to define this because the nops are defined + as inline assembly strings in the include files and we cannot + get them easily into strings. */ +asm("intelnops: " + GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 + GENERIC_NOP7 GENERIC_NOP8); +asm("k8nops: " + K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 + K8_NOP7 K8_NOP8); +asm("k7nops: " + K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 + K7_NOP7 K7_NOP8); + +extern unsigned char intelnops[], k8nops[], k7nops[]; +static unsigned char *intel_nops[ASM_NOP_MAX+1] = { + NULL, + intelnops, + intelnops + 1, + intelnops + 1 + 2, + intelnops + 1 + 2 + 3, + intelnops + 1 + 2 + 3 + 4, + intelnops + 1 + 2 + 3 + 4 + 5, + intelnops + 1 + 2 + 3 + 4 + 5 + 6, + intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, +}; +static unsigned char *k8_nops[ASM_NOP_MAX+1] = { + NULL, + k8nops, + k8nops + 1, + k8nops + 1 + 2, + k8nops + 1 + 2 + 3, + k8nops + 1 + 2 + 3 + 4, + k8nops + 1 + 2 + 3 + 4 + 5, + k8nops + 1 + 2 + 3 + 4 + 5 + 6, + k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, +}; +static unsigned char *k7_nops[ASM_NOP_MAX+1] = { + NULL, + k7nops, + k7nops + 1, + k7nops + 1 + 2, + k7nops + 1 + 2 + 3, + k7nops + 1 + 2 + 3 + 4, + k7nops + 1 + 2 + 3 + 4 + 5, + k7nops + 1 + 2 + 3 + 4 + 5 + 6, + k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, +}; +static struct nop { + int cpuid; + unsigned char **noptable; +} noptypes[] = { + { X86_FEATURE_K8, k8_nops }, + { X86_FEATURE_K7, k7_nops }, + { -1, 0 } +}; + /* Replace instructions with better alternatives for this CPU type. This runs before SMP is initialized to avoid SMP problems with self modifying code. This implies that assymetric systems where APs have less capabilities than the boot processor are not handled. - In this case boot with "noreplacement". */ void apply_alternatives(void *start, void *end) { struct alt_instr *a; int diff, i, k; - - for (a = start; a < (struct alt_instr *)end; - a = (void *)ALIGN((unsigned long)(a + 1) + a->instrlen, 4)) { + unsigned char **noptable = intel_nops; + for (i = 0; noptypes[i].cpuid >= 0; i++) { + if (boot_cpu_has(noptypes[i].cpuid)) { + noptable = noptypes[i].noptable; + break; + } + } + for (a = start; (void *)a < end; a++) { if (!boot_cpu_has(a->cpuid)) continue; BUG_ON(a->replacementlen > a->instrlen); memcpy(a->instr, a->replacement, a->replacementlen); diff = a->instrlen - a->replacementlen; + /* Pad the rest with nops */ for (i = a->replacementlen; diff > 0; diff -= k, i += k) { - static const char *nops[] = { - 0, - "\x90", -#if CONFIG_MK7 || CONFIG_MK8 - "\x66\x90", - "\x66\x66\x90", - "\x66\x66\x66\x90", -#else - "\x89\xf6", - "\x8d\x76\x00", - "\x8d\x74\x26\x00", -#endif - }; - k = min_t(int, diff, ARRAY_SIZE(nops)); - memcpy(a->instr + i, nops[k], k); + k = diff; + if (k > ASM_NOP_MAX) + k = ASM_NOP_MAX; + memcpy(a->instr + i, noptable[k], k); } } } diff --git a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S index b6a3f2de1bcf..56401363b4f6 100644 --- a/arch/i386/vmlinux.lds.S +++ b/arch/i386/vmlinux.lds.S @@ -85,6 +85,7 @@ SECTIONS __alt_instructions = .; .altinstructions : { *(.altinstructions) } __alt_instructions_end = .; + .altinstr_replacement : { *(.altinstr_replacement) } . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index 46a85b395db8..040e1f66ea48 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -63,6 +63,11 @@ #define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */ #define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */ #define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ +/* cpu types for specific tunings: */ +#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */ +#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */ +#define X86_FEATURE_P3 (3*32+ 6) /* P3 */ +#define X86_FEATURE_P4 (3*32+ 7) /* P4 */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index bc47e152108d..d69cc46d5866 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -495,32 +496,93 @@ static inline void rep_nop(void) #define cpu_relax() rep_nop() -/* Prefetch instructions for Pentium III and AMD Athlon */ -#ifdef CONFIG_X86_PREFETCH +/* generic versions from gas */ +#define GENERIC_NOP1 ".byte 0x90\n" +#define GENERIC_NOP2 ".byte 0x89,0xf6\n" +#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" +#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" +#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 +#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" +#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" +#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 + +/* Opteron nops */ +#define K8_NOP1 GENERIC_NOP1 +#define K8_NOP2 ".byte 0x66,0x90\n" +#define K8_NOP3 ".byte 0x66,0x66,0x90\n" +#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" +#define K8_NOP5 K8_NOP3 K8_NOP2 +#define K8_NOP6 K8_NOP3 K8_NOP3 +#define K8_NOP7 K8_NOP4 K8_NOP3 +#define K8_NOP8 K8_NOP4 K8_NOP4 + +/* K7 nops */ +/* uses eax dependencies (arbitary choice) */ +#define K7_NOP1 GENERIC_NOP1 +#define K7_NOP2 ".byte 0x8b,0xc0\n" +#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" +#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" +#define K7_NOP5 K7_NOP4 ASM_NOP1 +#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" +#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" +#define K7_NOP8 K7_NOP7 ASM_NOP1 + +#ifdef CONFIG_MK8 +#define ASM_NOP1 K8_NOP1 +#define ASM_NOP2 K8_NOP2 +#define ASM_NOP3 K8_NOP3 +#define ASM_NOP4 K8_NOP4 +#define ASM_NOP5 K8_NOP5 +#define ASM_NOP6 K8_NOP6 +#define ASM_NOP7 K8_NOP7 +#define ASM_NOP8 K8_NOP8 +#elif CONFIG_MK7 +#define ASM_NOP1 K7_NOP1 +#define ASM_NOP2 K7_NOP2 +#define ASM_NOP3 K7_NOP3 +#define ASM_NOP4 K7_NOP4 +#define ASM_NOP5 K7_NOP5 +#define ASM_NOP6 K7_NOP6 +#define ASM_NOP7 K7_NOP7 +#define ASM_NOP8 K7_NOP8 +#else +#define ASM_NOP1 GENERIC_NOP1 +#define ASM_NOP2 GENERIC_NOP2 +#define ASM_NOP3 GENERIC_NOP3 +#define ASM_NOP4 GENERIC_NOP4 +#define ASM_NOP5 GENERIC_NOP5 +#define ASM_NOP6 GENERIC_NOP6 +#define ASM_NOP7 GENERIC_NOP7 +#define ASM_NOP8 GENERIC_NOP8 +#endif +#define ASM_NOP_MAX 8 + +/* Prefetch instructions for Pentium III and AMD Athlon */ +/* It's not worth to care about 3dnow! prefetches for the K6 + because they are microcoded there and very slow. */ #define ARCH_HAS_PREFETCH extern inline void prefetch(const void *x) { - __asm__ __volatile__ ("prefetchnta (%0)" : : "r"(x)); + alternative_input(ASM_NOP3, + "prefetchnta (%1)", + X86_FEATURE_XMM, + "r" (x)); } -#elif defined CONFIG_X86_USE_3DNOW - #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW #define ARCH_HAS_SPINLOCK_PREFETCH -extern inline void prefetch(const void *x) -{ - __asm__ __volatile__ ("prefetch (%0)" : : "r"(x)); -} - +/* 3dnow! prefetch to get an exclusive cache line. Useful for + spinlocks to avoid one state transition in the cache coherency protocol. */ extern inline void prefetchw(const void *x) { - __asm__ __volatile__ ("prefetchw (%0)" : : "r"(x)); + alternative_input(ASM_NOP3, + "prefetchw (%1)", + X86_FEATURE_3DNOW, + "r" (x)); } #define spin_lock_prefetch(x) prefetchw(x) -#endif - #endif /* __ASM_I386_PROCESSOR_H */ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 5831f6d34ad7..71b9dd77ed04 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -277,13 +277,16 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, /* Compiling for a 386 proper. Is it worth implementing via cli/sti? */ #endif +#ifdef __KERNEL__ struct alt_instr { - u8 *instr; /* original instruction */ - u8 cpuid; /* cpuid bit set for replacement */ - u8 instrlen; /* length of original instruction */ - u8 replacementlen; /* length of new instruction, <= instrlen */ - u8 replacement[0]; /* new instruction */ + __u8 *instr; /* original instruction */ + __u8 *replacement; + __u8 cpuid; /* cpuid bit set for replacement */ + __u8 instrlen; /* length of original instruction */ + __u8 replacementlen; /* length of new instruction, <= instrlen */ + __u8 pad; }; +#endif /* * Alternative instructions for different CPU types or capabilities. @@ -302,12 +305,39 @@ struct alt_instr { ".section .altinstructions,\"a\"\n" \ " .align 4\n" \ " .long 661b\n" /* label */ \ + " .long 663f\n" /* new instruction */ \ " .byte %c0\n" /* feature bit */ \ " .byte 662b-661b\n" /* sourcelen */ \ " .byte 664f-663f\n" /* replacementlen */ \ + ".previous\n" \ + ".section .altinstr_replacement,\"ax\"\n" \ "663:\n\t" newinstr "\n664:\n" /* replacement */ \ ".previous" :: "i" (feature) : "memory") +/* + * Alternative inline assembly with input. + * + * Pecularities: + * No memory clobber here. + * Argument numbers start with 1. + * Best is to use constraints that are fixed size (like (%1) ... "r") + * If you use variable sized constraints like "m" or "g" in the + * replacement maake sure to pad to the worst case length. + */ +#define alternative_input(oldinstr, newinstr, feature, input) \ + asm volatile ("661:\n\t" oldinstr "\n662:\n" \ + ".section .altinstructions,\"a\"\n" \ + " .align 4\n" \ + " .long 661b\n" /* label */ \ + " .long 663f\n" /* new instruction */ \ + " .byte %c0\n" /* feature bit */ \ + " .byte 662b-661b\n" /* sourcelen */ \ + " .byte 664f-663f\n" /* replacementlen */ \ + ".previous\n" \ + ".section .altinstr_replacement,\"ax\"\n" \ + "663:\n\t" newinstr "\n664:\n" /* replacement */ \ + ".previous" :: "i" (feature), input) + /* * Force strict CPU ordering. * And yes, this is required on UP too when we're talking -- cgit v1.2.3 From 0948aa6d1967d2b3a6e07eb9176a579187bae1e2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 29 Apr 2003 17:32:40 -0700 Subject: [PATCH] improved bdevname --- fs/partitions/check.c | 21 ++++++++++++++------- fs/partitions/check.h | 2 +- include/linux/fs.h | 5 +---- kernel/ksyms.c | 1 + 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/fs/partitions/check.c b/fs/partitions/check.c index a8530c42211f..591123911467 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -99,25 +99,32 @@ char *disk_name(struct gendisk *hd, int part, char *buf) #ifdef CONFIG_DEVFS_FS if (hd->devfs_name[0] != '\0') { if (part) - sprintf(buf, "%s/part%d", hd->devfs_name, part); + snprintf(buf, BDEVNAME_SIZE, "%s/part%d", + hd->devfs_name, part); else if (hd->minors != 1) - sprintf(buf, "%s/disc", hd->devfs_name); + snprintf(buf, BDEVNAME_SIZE, "%s/disc", hd->devfs_name); else - sprintf(buf, "%s", hd->devfs_name); + snprintf(buf, BDEVNAME_SIZE, "%s", hd->devfs_name); return buf; } #endif if (!part) - sprintf(buf, "%s", hd->disk_name); + snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) - sprintf(buf, "%sp%d", hd->disk_name, part); + snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part); else - sprintf(buf, "%s%d", hd->disk_name, part); + snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part); return buf; } +const char *bdevname(struct block_device *bdev, char *buf) +{ + int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor; + return disk_name(bdev->bd_disk, part, buf); +} + static struct parsed_partitions * check_partition(struct gendisk *hd, struct block_device *bdev) { @@ -417,7 +424,7 @@ void del_gendisk(struct gendisk *disk) struct dev_name { struct list_head list; dev_t dev; - char namebuf[64]; + char namebuf[BDEVNAME_SIZE]; char *name; }; diff --git a/fs/partitions/check.h b/fs/partitions/check.h index 882980c55720..43adcc68e471 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h @@ -8,7 +8,7 @@ enum { MAX_PART = 256 }; struct parsed_partitions { - char name[40]; + char name[BDEVNAME_SIZE]; struct { sector_t from; sector_t size; diff --git a/include/linux/fs.h b/include/linux/fs.h index 572b92e6f443..b9b2cf5b69e8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1068,10 +1068,7 @@ extern int chrdev_open(struct inode *, struct file *); /* fs/block_dev.c */ #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ extern const char *__bdevname(dev_t, char *buffer); -extern inline const char *bdevname(struct block_device *bdev, char *buffer) -{ - return __bdevname(bdev->bd_dev, buffer); -} +extern const char *bdevname(struct block_device *bdev, char *buffer); extern struct block_device *lookup_bdev(const char *); extern struct block_device *open_bdev_excl(const char *, int, int, void *); extern void close_bdev_excl(struct block_device *, int); diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 8c8cff48895d..c8ca8a9fa5e1 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -515,6 +515,7 @@ EXPORT_SYMBOL(vsprintf); EXPORT_SYMBOL(vsnprintf); EXPORT_SYMBOL(vsscanf); EXPORT_SYMBOL(__bdevname); +EXPORT_SYMBOL(bdevname); EXPORT_SYMBOL(cdevname); EXPORT_SYMBOL(simple_strtoull); EXPORT_SYMBOL(simple_strtoul); -- cgit v1.2.3 From efa428ef2cafff1c31730f04147244d1e2def76f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 29 Apr 2003 17:33:47 -0700 Subject: [PATCH] percpu counters cause UML compilation errors in with SMP The percpu counters break UML SMP compilation (in current 2.5.58 bk snapshot) (first NR_CPUS undeclared in header, then dereference of incomplete structure in .c file) --- include/linux/percpu_counter.h | 2 +- lib/percpu_counter.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h index 69d0a66b662e..53c52176c391 100644 --- a/include/linux/percpu_counter.h +++ b/include/linux/percpu_counter.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #ifdef CONFIG_SMP diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c index 73f99d99f9ac..a9afaec00bdd 100644 --- a/lib/percpu_counter.c +++ b/lib/percpu_counter.c @@ -1,5 +1,6 @@ #include +#include void percpu_counter_mod(struct percpu_counter *fbc, long amount) { -- cgit v1.2.3