From 529c593ece216e4aaffd36bd940cb94f1fa63129 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 23 Feb 2000 00:40:54 +0000 Subject: Merge with 2.3.43. I did ignore all modifications to the qlogicisp.c driver due to the Origin A64 hacks. --- arch/sparc/config.in | 18 +- arch/sparc/defconfig | 5 +- arch/sparc/kernel/ioport.c | 482 ++++++++++++++++++++++++++++++---------- arch/sparc/kernel/irq.c | 40 +--- arch/sparc/kernel/rtrap.S | 16 +- arch/sparc/kernel/sparc_ksyms.c | 4 +- arch/sparc/kernel/sys_sparc.c | 3 +- arch/sparc/kernel/time.c | 6 +- arch/sparc/mm/init.c | 7 +- arch/sparc/mm/io-unit.c | 17 +- arch/sparc/mm/iommu.c | 29 ++- arch/sparc/mm/loadmmu.c | 5 +- arch/sparc/mm/srmmu.c | 4 +- arch/sparc/mm/sun4c.c | 20 +- arch/sparc/prom/bootstr.c | 3 +- arch/sparc/prom/console.c | 3 +- arch/sparc/prom/printf.c | 3 +- arch/sparc/vmlinux.lds | 1 + 18 files changed, 472 insertions(+), 194 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/config.in b/arch/sparc/config.in index a983b9a6d..ebaa64806 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.84 2000/01/31 21:10:04 davem Exp $ +# $Id: config.in,v 1.86 2000/02/10 02:51:10 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -21,7 +21,7 @@ bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_S bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 if [ "$CONFIG_SUN4" != "y" ]; then - bool ' Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI source drivers/pci/Config.in fi @@ -118,11 +118,24 @@ if [ "$CONFIG_SCSI" != "n" ]; then comment 'SCSI support type (disk, tape, CDrom)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 + fi + dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi + dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' @@ -130,6 +143,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + bool ' SCSI logging facility' CONFIG_SCSI_LOGGING mainmenu_option next_comment comment 'SCSI low-level drivers' diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 536d0c5f6..6db042563 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -175,9 +175,12 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CDrom) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=m # @@ -185,6 +188,7 @@ CONFIG_CHR_DEV_SG=m # CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -245,7 +249,6 @@ CONFIG_AUTOFS4_FS=m CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_BFS_FS_WRITE is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 61a51f103..336ae208f 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,10 +1,28 @@ -/* $Id: ioport.c,v 1.30 2000/01/28 13:41:55 jj Exp $ +/* $Id: ioport.c,v 1.31 2000/02/06 22:55:32 zaitcev Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * * 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev. + * + * 2000/01/29 + * zait: as long as pci_alloc_consistent produces something addressable, + * things are ok. + * rth: no, it is relevant, because get_free_pages returns you a + * pointer into the big page mapping + * zait: so what? + * zait: remap_it_my_way(virt_to_phys(get_free_page())) + * Hmm + * Suppose I did this remap_it_my_way(virt_to_phys(get_free_page())). + * So far so good. + * Now, driver calls pci_free_consistent(with result of + * remap_it_my_way()). + * How do you find the address to pass to free_pages()? + * zait: walk the page tables? It's only two or three level after all. + * zait: you have to walk them anyway to remove the mapping. + * Hmm + * Sounds reasonable */ #include @@ -15,6 +33,8 @@ #include #include #include +#include /* struct pci_dev */ +#include #include #include @@ -23,8 +43,8 @@ #include #include -struct resource *sparc_find_resource_bystart(struct resource *, unsigned long); -struct resource *sparc_find_resource_by_hit(struct resource *, unsigned long); +struct resource *_sparc_find_resource(struct resource *r, unsigned long); +int _sparc_len2order(unsigned long len); static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, @@ -32,14 +52,21 @@ static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, static void _sparc_free_io(struct resource *res); /* This points to the next to use virtual memory for DVMA mappings */ -static struct resource sparc_dvma = { +static struct resource _sparc_dvma = { "sparc_dvma", DVMA_VADDR, DVMA_VADDR + DVMA_LEN - 1 }; /* This points to the start of I/O mappings, cluable from outside. */ - struct resource sparc_iomap = { +/*ext*/ struct resource sparc_iomap = { "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 @@ -76,55 +103,6 @@ static void xres_free(struct xresource *xrp) { xrp->xflag = 0; } -/* - */ -extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); -extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); - -static void mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus, int rdonly) -{ - switch(sparc_cpu_model) { - case sun4c: - case sun4: - sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - default: - printk("mapioaddr: Trying to map IO space for unsupported machine.\n"); - printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model); - printk("mapioaddr: Halting...\n"); - halt(); - }; - return; -} - -extern void srmmu_unmapioaddr(unsigned long virt); -extern void sun4c_unmapioaddr(unsigned long virt); - -static void unmapioaddr(unsigned long virt_addr) -{ - switch(sparc_cpu_model) { - case sun4c: - case sun4: - sun4c_unmapioaddr(virt_addr); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_unmapioaddr(virt_addr); - break; - default: - printk("unmapioaddr: sparc_cpu_model = %d, halt...\n", sparc_cpu_model); - halt(); - }; - return; -} - /* * These are typically used in PCI drivers * which are trying to be cross-platform. @@ -147,7 +125,7 @@ void iounmap(void *virtual) unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; struct resource *res; - if ((res = sparc_find_resource_bystart(&sparc_iomap, vaddr)) == NULL) { + if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) { printk("free_io/iounmap: cannot free %lx\n", vaddr); return; } @@ -161,7 +139,6 @@ void iounmap(void *virtual) } /* - * Davem's version of sbus_ioremap. */ unsigned long sbus_ioremap(struct resource *phyres, unsigned long offset, unsigned long size, char *name) @@ -218,8 +195,6 @@ static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, } /* - * This is called from _sparc_alloc_io only, we left it separate - * in case Davem changes his mind about interface to sbus_ioremap(). */ static void * _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) @@ -240,7 +215,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) va = res->start; pa &= PAGE_MASK; for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { - mapioaddr(pa, va, bus, 0); + (*_sparc_mapioaddr)(pa, va, bus, 0); va += PAGE_SIZE; pa += PAGE_SIZE; } @@ -270,7 +245,7 @@ static void _sparc_free_io(struct resource *res) plen = res->end - res->start + 1; while (plen != 0) { plen -= PAGE_SIZE; - unmapioaddr(res->start + plen); + (*_sparc_unmapioaddr)(res->start + plen); } release_resource(res); @@ -305,9 +280,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) return NULL; } - for (order = 0; order < 6; order++) /* 2^6 pages == 256K */ - if ((1 << (order + PAGE_SHIFT)) >= len_total) - break; + order = _sparc_len2order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { /* @@ -324,25 +297,17 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) } 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) { + 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; } - *dma_addrp = res->start; mmu_map_dma_area(va, res->start, len_total); - /* - * "Official" or "natural" address of pages we got is va. - * We want to return uncached range. We could make va[len] - * uncached but it's difficult to make cached back [P3: hmm] - * We use the artefact of sun4c, replicated everywhere else, - * that CPU can use bus addresses to access the same memory. - */ - res->name = (void *)va; /* XXX Ouch.. we got to hide it somewhere */ + *dma_addrp = res->start; return (void *)res->start; } @@ -350,9 +315,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) { struct resource *res; unsigned long pgp; - int order; - if ((res = sparc_find_resource_bystart(&sparc_dvma, + if ((res = _sparc_find_resource(&_sparc_dvma, (unsigned long)p)) == NULL) { printk("sbus_free_consistent: cannot free %p\n", p); return; @@ -370,17 +334,14 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) return; } - mmu_inval_dma_area((unsigned long)res->name, n); /* XXX Ouch */ - mmu_unmap_dma_area(ba, n); release_resource(res); + kfree(res); - pgp = (unsigned long) res->name; /* XXX Ouch */ - for (order = 0; order < 6; order++) - if ((1 << (order + PAGE_SHIFT)) >= n) - break; - free_pages(pgp, order); + /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ + pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + mmu_unmap_dma_area(ba, n); - kfree(res); + free_pages(pgp, _sparc_len2order(n)); } /* @@ -408,10 +369,10 @@ u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) return 0; } memset((char*)res, 0, sizeof(struct resource)); - res->name = va; + res->name = va; /* XXX */ - if (allocate_resource(&sparc_dvma, res, len_total, - sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) { + 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; @@ -431,7 +392,6 @@ u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) if (len > 256*1024) { /* __get_free_pages() limit */ return 0; } -/* BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) */ return mmu_get_scsi_one(va, len, sdev->bus); #endif } @@ -442,7 +402,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) struct resource *res; unsigned long va; - if ((res = sparc_find_resource_bystart(&sparc_dvma, ba)) == NULL) { + if ((res = _sparc_find_resource(&_sparc_dvma, ba)) == NULL) { printk("sbus_unmap_single: cannot find %08x\n", (unsigned)ba); return; } @@ -461,14 +421,12 @@ void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) kfree(res); #endif #if 1 /* "trampoline" version */ -/* BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) */ mmu_release_scsi_one(ba, n, sdev->bus); #endif } int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { -/* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_get_scsi_sgl(sg, n, sdev->bus); /* @@ -480,65 +438,351 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { -/* BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_release_scsi_sgl(sg, n, sdev->bus); } -#endif /* - * P3: I think a partial flush is permitted... - * We are not too efficient at doing it though. - * - * If only DaveM understood a concept of an allocation cookie, - * we could avoid find_resource_by_hit() here and a major - * performance hit. */ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) { unsigned long va; struct resource *res; - res = sparc_find_resource_by_hit(&sparc_dvma, ba); + /* We do not need the resource, just print a message if invalid. */ + res = _sparc_find_resource(&_sparc_dvma, ba); if (res == NULL) panic("sbus_dma_sync_single: 0x%x\n", ba); - va = (unsigned long) res->name; - /* if (va == 0) */ - - mmu_inval_dma_area(va, (res->end - res->start) + 1); + va = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); } void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { - printk("dma_sync_sg: not implemented yet\n"); + printk("sbus_dma_sync_sg: not implemented yet\n"); +} +#endif /* CONFIG_SBUS */ + +#ifdef CONFIG_PCI + +/* Allocate and map kernel buffer using consistent mode DMA for a device. + * hwdev should be valid struct pci_dev pointer for PCI devices. + */ +void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) +{ + unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; + unsigned long va; + struct resource *res; + int order; + + if (len == 0) { + return NULL; + } + if (len > 256*1024) { /* __get_free_pages() limit */ + return NULL; + } + + order = _sparc_len2order(len_total); + va = __get_free_pages(GFP_KERNEL, order); + if (va == 0) { + printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); + return NULL; + } + + if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { + free_pages(va, order); + printk("sbus_alloc_consistent: no core\n"); + return NULL; + } + 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("pci_alloc_consistent: cannot occupy 0x%lx", len_total); + free_pages(va, order); + kfree(res); + return NULL; + } + + mmu_inval_dma_area(va, len_total); + +#if 1 +/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\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; + } + } + + *pba = virt_to_bus(va); + return (void *) res->start; } +/* Free and unmap a consistent DMA buffer. + * cpu_addr is what was returned from pci_alloc_consistent, + * size must be the same as what as passed into pci_alloc_consistent, + * and likewise dma_addr must be the same as what *dma_addrp was set to. + * + * References to the memory and mappings assosciated with cpu_addr/dma_addr + * past this call are illegal. + */ +void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) +{ + struct resource *res; + unsigned long pgp; + + if ((res = _sparc_find_resource(&_sparc_dvma, + (unsigned long)p)) == NULL) { + printk("sbus_free_consistent: cannot free %p\n", p); + return; + } + + if (((unsigned long)p & (PAGE_MASK-1)) != 0) { + printk("sbus_free_consistent: unaligned va %p\n", p); + return; + } + + n = (n + PAGE_SIZE-1) & PAGE_MASK; + if ((res->end-res->start)+1 != n) { + printk("sbus_free_consistent: region 0x%lx asked 0x%lx\n", + (long)((res->end-res->start)+1), (long)n); + return; + } + + pgp = (unsigned long) bus_to_virt(ba); + mmu_inval_dma_area(pgp, n); + { + int x; + for (x = 0; x < n; x += PAGE_SIZE) { + (*_sparc_unmapioaddr)(p + n); + } + } + + release_resource(res); + kfree(res); + + free_pages(pgp, _sparc_len2order(n)); +} + +/* Map a single buffer of the indicated size for DMA in streaming mode. + * The 32-bit bus address to use is returned. + * + * Once the device is given the dma address, the device owns this memory + * until either pci_unmap_single or pci_dma_sync_single is performed. + */ +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) +{ + return virt_to_bus(ptr); +} + +/* Unmap a single streaming mode DMA translation. The dma_addr and size + * must match what was provided for in a previous pci_map_single call. All + * other usages are undefined. + * + * After this call, reads by the cpu to the buffer are guarenteed to see + * whatever the device wrote there. + */ +void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +{ + /* Nothing to do... */ +} + +/* Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +{ + int n; + for (n = 0; n < nents; n++) { + sg->dvma_address = virt_to_bus(sg->address); + sg->dvma_length = sg->length; + sg++; + } + return nents; +} + +/* Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents) +{ + /* Nothing to do... */ +} + +/* Make physical memory consistent for a single + * streaming mode DMA translation after a transfer. + * + * If you perform a pci_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the PCI dma + * mapping, you must call this function before doing so. At the + * next point you give the PCI dma address back to the card, the + * device again owns the buffer. + */ +void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size) +{ + mmu_inval_dma_area((unsigned long)bus_to_virt(ba), + (size + PAGE_SIZE-1) & PAGE_MASK); +} + +/* Make physical memory consistent for a set of streaming + * mode DMA translations after a transfer. + * + * The same as pci_dma_sync_single but for a scatter-gather list, + * same rules and usage. + */ +void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +{ + while (nents) { + --nents; + mmu_inval_dma_area((unsigned long)sg->address, + (sg->dvma_length + PAGE_SIZE-1) & PAGE_MASK); + sg++; + } +} +#endif CONFIG_PCI + +#ifdef CONFIG_PROC_FS + +static int +_sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof, + void *data) +{ + char *p = buf, *e = buf + length; + struct resource *r; + const char *nm; + + for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { + if (p + 32 >= e) /* Better than nothing */ + break; + if ((nm = r->name) == 0) nm = "???"; + p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm); + } + + return p-buf; +} + +static struct proc_dir_entry _sparc_iomap_proc_entry = { + 0, /* Inode number - dynamic */ + 6, /* Length of the file name */ + "io_map", /* The file name */ + S_IFREG | S_IRUGO, /* File mode */ + 1, /* Number of links */ + 0, 0, /* The uid and gid for the file */ + 0, /* The size of the file reported by ls. */ + NULL, /* struct inode_operations * ops */ + NULL, /* get_info: backward compatibility */ + NULL, /* owner */ + NULL, NULL, NULL, /* linkage */ + &sparc_iomap, + _sparc_io_get_info, /* The read function for this file */ + NULL, + /* and more stuff */ +}; + +static struct proc_dir_entry _sparc_dvma_proc_entry = { + 0, /* Inode number - dynamic */ + 8, /* Length of the file name */ + "dvma_map", /* The file name */ + S_IFREG | S_IRUGO, /* File mode */ + 1, /* Number of links */ + 0, 0, /* The uid and gid for the file */ + 0, /* The size of the file reported by ls. */ + NULL, /* struct inode_operations * ops */ + NULL, /* get_info: backward compatibility */ + NULL, /* owner */ + NULL, NULL, NULL, /* linkage */ + &_sparc_dvma, + _sparc_io_get_info, + NULL, + /* some more stuff */ +}; + +#endif CONFIG_PROC_FS + /* * This is a version of find_resource and it belongs to kernel/resource.c. * Until we have agreement with Linus and Martin, it lingers here. * - * "same start" is more strict than "hit into" + * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case. + * This probably warrants some sort of hashing. */ struct resource * -sparc_find_resource_bystart(struct resource *root, unsigned long start) +_sparc_find_resource(struct resource *root, unsigned long hit) { struct resource *tmp; - for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { - if (tmp->start == start) + for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { + if (tmp->start <= hit && tmp->end >= hit) return tmp; - } - return NULL; + } + return NULL; } -struct resource * -sparc_find_resource_by_hit(struct resource *root, unsigned long hit) +int +_sparc_len2order(unsigned long len) { - struct resource *tmp; + int order; - for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { - if (tmp->start <= hit && tmp->end >= hit) - return tmp; - } - return NULL; + for (order = 0; order < 7; order++) /* 2^6 pages == 256K */ + if ((1 << (order + PAGE_SHIFT)) >= len) + return order; + printk("len2order: from %p: len %lu(0x%lx) yields order >=7.\n", + __builtin_return_address(0), len, len); + return 1; +} + +/* + * 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); + halt(); + }; + +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &_sparc_iomap_proc_entry); + proc_register(&proc_root, &_sparc_dvma_proc_entry); +#endif } diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 8e8fab320..471929a01 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.100 2000/01/29 01:38:04 anton Exp $ +/* $Id: irq.c,v 1.101 2000/02/09 11:15:03 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -205,9 +205,6 @@ unsigned int local_irq_count; unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -atomic_t global_bh_lock = ATOMIC_INIT(0); -spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; - /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -217,9 +214,6 @@ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -/* This protects BH software state (masks, things like that). */ -spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED; - void smp_show_backtrace_all_cpus(void); void show_backtrace(void); @@ -239,7 +233,7 @@ static void show(char * str) } printk("]\n"); - printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0)); + printk("bh: %d [ ", (spin_is_locked(&global_bh_lock) ? 1 : 0)); for (i = 0; i < NR_CPUS; i++) { printk("%d ", local_bh_count[cpu]); @@ -253,18 +247,6 @@ static void show(char * str) #endif } -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if(!--count) { - show("wait_on_bh"); - count = 0; - } - barrier(); - } while(spin_is_locked(&global_bh_count)); -} - /* * We have to allow irqs to arrive between __sti and __cli */ @@ -281,7 +263,7 @@ static inline void wait_on_irq(int cpu) * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count)) + if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock)) break; } @@ -300,7 +282,7 @@ static inline void wait_on_irq(int cpu) continue; if (spin_is_locked (&global_irq_lock)) continue; - if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count)) + if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock)) continue; if (spin_trylock(&global_irq_lock)) break; @@ -308,20 +290,6 @@ static inline void wait_on_irq(int cpu) } } -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void synchronize_bh(void) -{ - if (spin_is_locked (&global_bh_count) && !in_interrupt()) - wait_on_bh(); -} - /* * This is called when we want to synchronize with * interrupts. We may for example tell a device to diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index 7b056b47a..dcfc2dc78 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.53 2000/01/08 16:38:18 anton Exp $ +/* $Id: rtrap.S,v 1.54 2000/02/09 11:15:03 davem Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -48,16 +48,18 @@ rtrap_7win_patch5: and %g1, 0x7f, %g1 .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 .globl C_LABEL(ret_trap_lockless_ipi) ret_trap_entry: - sethi %hi(C_LABEL(bh_active)), %l3 - sethi %hi(C_LABEL(bh_mask)), %l4 - ld [%l4 + %lo(C_LABEL(bh_mask))], %g5 - ld [%l3 + %lo(C_LABEL(bh_active))], %g4 + ld [%curptr + AOFF_task_processor], %l3 + sll %l3, 5, %l3 + sethi %hi(C_LABEL(softirq_state)), %l4 + add %l4, %l3, %l4 + ld [%l4 + %lo(C_LABEL(softirq_state))], %g5 + ld [%l4 + %lo(C_LABEL(softirq_state) + 4)], %g4 andcc %g4, %g5, %g0 be C_LABEL(ret_trap_lockless_ipi) nop - call C_LABEL(do_bottom_half) + call C_LABEL(do_softirq) nop - + C_LABEL(ret_trap_lockless_ipi): andcc %t_psr, PSR_PS, %g0 be 1f diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 8df494f2d..d1b3eca63 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.88 2000/01/28 13:41:55 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.89 2000/02/09 11:15:03 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,8 +11,10 @@ #include #include +#include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 3815cae1b..fde9bccfd 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.59 2000/01/29 07:40:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.60 2000/02/08 20:24:18 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 3e52fef95..5a03e646b 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.51 2000/01/29 01:08:59 anton Exp $ +/* $Id: time.c,v 1.53 2000/02/09 21:11:04 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -429,12 +429,14 @@ void __init time_init(void) extern __inline__ unsigned long do_gettimeoffset(void) { + struct tasklet_struct *t; unsigned long offset = 0; unsigned int count; count = (*master_l10_counter >> 10) & 0x1fffff; - if(test_bit(TIMER_BH, &bh_active)) + t = &bh_task_vec[TIMER_BH]; + if (test_bit(TASKLET_STATE_SCHED, &t->state)) offset = 1000000; return offset + count; diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 9e9a225a5..6736dc9d3 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.79 2000/01/29 01:09:06 anton Exp $ +/* $Id: init.c,v 1.80 2000/02/09 21:11:06 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,8 +33,6 @@ #include #include -extern void show_net_buffers(void); - unsigned long *sparc_valid_addr_bitmap; unsigned long phys_base; @@ -89,9 +87,6 @@ void show_mem(void) printk("%ld entries in page dir cache\n",pgd_cache_size); #endif show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } extern pgprot_t protection_map[16]; diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 90b4aee69..a370ea2d4 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.20 2000/01/15 00:51:27 anton Exp $ +/* $Id: io-unit.c,v 1.21 2000/02/06 22:55:45 zaitcev Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -210,6 +210,20 @@ static void iounit_map_dma_area(unsigned long va, __u32 addr, int len) static void iounit_unmap_dma_area(unsigned long addr, int len) { + /* XXX Somebody please fill this in */ +} + +/* XXX We do not pass sbus device here, bad. */ +static unsigned long 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; + int i; + iopte_t *iopte; + + i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); + iopte = (iopte_t *)(iounit->page_table + i); + return (iopte_val(*iopte) & 0xFFFFFFF0) << 4; /* XXX sun4d guru, help */ } #endif @@ -237,6 +251,7 @@ void __init ld_mmu_iounit(void) #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM); #endif } diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 5a8cc8c5b..5fde9a52a 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.18 2000/01/15 00:51:27 anton Exp $ +/* $Id: iommu.c,v 1.19 2000/02/06 22:55:45 zaitcev Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -289,8 +289,32 @@ static void iommu_map_dma_area(unsigned long va, __u32 addr, int len) iommu_invalidate(iommu->regs); } -static void iommu_unmap_dma_area(unsigned long addr, int len) +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; + + iopte += ((busa - iommu->start) >> PAGE_SHIFT); + end = PAGE_ALIGN((busa + len)); + while (busa < end) { + iopte_val(*iopte++) = 0; + busa += PAGE_SIZE; + } + flush_tlb_all(); /* P3: Hmm... it would not hurt. */ + iommu_invalidate(iommu->regs); +} + +static unsigned long 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; } #endif @@ -327,5 +351,6 @@ void __init ld_mmu_iommu(void) #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 } diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c index ce0885679..e388c31f5 100644 --- a/arch/sparc/mm/loadmmu.c +++ b/arch/sparc/mm/loadmmu.c @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.54 2000/01/29 01:09:07 anton Exp $ +/* $Id: loadmmu.c,v 1.56 2000/02/08 20:24:21 davem Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -27,6 +26,7 @@ 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,4 +44,5 @@ 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 10990f3ea..d46b45378 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.205 2000/01/21 17:59:46 anton Exp $ +/* $Id: srmmu.c,v 1.206 2000/02/08 07:45:59 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1304,7 +1304,7 @@ void __init srmmu_paging_init(void) sparc_context_init(num_contexts); { - unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index e0bd738d6..715bdb864 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.185 2000/01/15 00:51:32 anton Exp $ +/* $Id: sun4c.c,v 1.187 2000/02/08 07:46:01 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -584,15 +584,24 @@ static void sun4c_map_dma_area(unsigned long va, u32 addr, int len) } } -static void sun4c_unmap_dma_area(unsigned long addr, int len) +static unsigned long 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; } -static void sun4c_inval_dma_area(unsigned long addr, int len) +static unsigned long sun4c_unmap_dma_area(unsigned long busa, int len) { + /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ + /* XXX Implement this */ } -static void sun4c_flush_dma_area(unsigned long addr, int len) +static void sun4c_inval_dma_area(unsigned long virt, int len) +{ +} + +static void sun4c_flush_dma_area(unsigned long virt, int len) { } @@ -2574,7 +2583,7 @@ void __init sun4c_paging_init(void) sparc_context_init(num_contexts); { - unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); @@ -2721,6 +2730,7 @@ void __init ld_mmu_sun4c(void) BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM); diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c index a4a040ca2..1530c80c2 100644 --- a/arch/sparc/prom/bootstr.c +++ b/arch/sparc/prom/bootstr.c @@ -1,10 +1,9 @@ -/* $Id: bootstr.c,v 1.19 2000/01/29 01:09:11 anton Exp $ +/* $Id: bootstr.c,v 1.20 2000/02/08 20:24:23 davem Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -#include #include #include #include diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c index 2305dc858..c2b857459 100644 --- a/arch/sparc/prom/console.c +++ b/arch/sparc/prom/console.c @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.21 2000/01/29 01:09:12 anton Exp $ +/* $Id: console.c,v 1.22 2000/02/08 20:24:23 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -6,7 +6,6 @@ * Copyright (C) 1998 Pete Zaitcev */ -#include #include #include #include diff --git a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c index 24ac381a8..331a2d00b 100644 --- a/arch/sparc/prom/printf.c +++ b/arch/sparc/prom/printf.c @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.6 2000/01/29 01:09:12 anton Exp $ +/* $Id: printf.c,v 1.7 2000/02/08 20:24:23 davem Exp $ * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,7 +8,6 @@ * about or use it! It's simple and smelly anyway.... */ -#include #include #include diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds index b3dfc253e..dbe55e5fe 100644 --- a/arch/sparc/vmlinux.lds +++ b/arch/sparc/vmlinux.lds @@ -73,4 +73,5 @@ SECTIONS .debug_pubnames 0 : { *(.debug_pubnames) } .debug_sfnames 0 : { *(.debug_sfnames) } .line 0 : { *(.line) } + /DISCARD/ : { *(.text.exit) *(.data.exit) } } -- cgit v1.2.3