diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- /opt/kernel/linux-2.4.10/Documentation/DMA-mapping.txt Wed Aug 15 10:54:44 2001 +++ linux/Documentation/DMA-mapping.txt Sun Sep 16 23:31:44 2001 @@ -6,14 +6,15 @@ Jakub Jelinek Most of the 64bit platforms have special hardware that translates bus -addresses (DMA addresses) to physical addresses similarly to how page -tables and/or TLB translate virtual addresses to physical addresses. -This is needed so that e.g. PCI devices can access with a Single Address -Cycle (32bit DMA address) any page in the 64bit physical address space. -Previously in Linux those 64bit platforms had to set artificial limits on -the maximum RAM size in the system, so that the virt_to_bus() static scheme -works (the DMA address translation tables were simply filled on bootup -to map each bus address to the physical page __pa(bus_to_virt())). +addresses (DMA addresses) into physical addresses. This is similar to +how page tables and/or a TLB translates virtual addresses to physical +addresses on a cpu. This is needed so that e.g. PCI devices can +access with a Single Address Cycle (32bit DMA address) any page in the +64bit physical address space. Previously in Linux those 64bit +platforms had to set artificial limits on the maximum RAM size in the +system, so that the virt_to_bus() static scheme works (the DMA address +translation tables were simply filled on bootup to map each bus +address to the physical page __pa(bus_to_virt())). So that Linux can use the dynamic DMA mapping, it needs some help from the drivers, namely it has to take into account that DMA addresses should be @@ -28,9 +29,10 @@ #include -is in your driver. This file will obtain for you the definition of -the dma_addr_t type which should be used everywhere you hold a DMA -(bus) address returned from the DMA mapping functions. +is in your driver. This file will obtain for you the definition of the +dma_addr_t (which can hold any valid DMA address for the platform) +type which should be used everywhere you hold a DMA (bus) address +returned from the DMA mapping functions. What memory is DMA'able? @@ -49,7 +51,8 @@ _underlying_ memory mapped into a vmalloc() area, but this requires walking page tables to get the physical addresses, and then translating each of those pages back to a kernel address using -something like __va(). +something like __va(). [ EDIT: Update this when we integrate +Gerd Knorr's generic code which does this. ] This rule also means that you may not use kernel image addresses (ie. items in the kernel's data/text/bss segment, or your driver's) @@ -65,60 +68,96 @@ Does your device have any DMA addressing limitations? For example, is your device only capable of driving the low order 24-bits of address -on the PCI bus for DMA transfers? If your device can handle any PCI -dma address fully, then please skip to the next section, the rest of -this section does not concern your device. +on the PCI bus for SAC DMA transfers? If so, you need to inform the +PCI layer of this fact. + +By default, the kernel assumes that your device can address the full +32-bits in a SAC cycle. For a 64-bit DAC capable device, this needs +to be increased. And for a device with limitations, as discussed in +the previous paragraph, it needs to be decreased. For correct operation, you must interrogate the PCI layer in your device probe routine to see if the PCI controller on the machine can -properly support the DMA addressing limitation your device has. This -query is performed via a call to pci_dma_supported(): +properly support the DMA addressing limitation your device has. It is +good style to do this even if your device holds the default setting, +because this shows that you did think about these issues wrt. your +device. + +The query is performed via a call to pci_set_dma_mask(): - int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask) + int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask); Here, pdev is a pointer to the PCI device struct of your device, and device_mask is a bit mask describing which bits of a PCI address your -device supports. It returns non-zero if your card can perform DMA -properly on the machine. If it returns zero, your device can not -perform DMA properly on this platform, and attempting to do so will -result in undefined behavior. +device supports. It returns zero if your card can perform DMA +properly on the machine given the address mask you provided. -In the failure case, you have two options: - -1) Use some non-DMA mode for data transfer, if possible. -2) Ignore this device and do not initialize it. +If it returns non-zero, your device can not perform DMA properly on +this platform, and attempting to do so will result in undefined +behavior. You must either use a different mask, or not use DMA. + +This means that in the failure case, you have three options: + +1) Use another DMA mask, if possible (see below). +2) Use some non-DMA mode for data transfer, if possible. +3) Ignore this device and do not initialize it. It is recommended that your driver print a kernel KERN_WARNING message -when you do one of these two things. In this manner, if a user of -your driver reports that performance is bad or that the device is not -even detected, you can ask him for the kernel messages to find out +when you end up performing either #2 or #2. In this manner, if a user +of your driver reports that performance is bad or that the device is not +even detected, you can ask them for the kernel messages to find out exactly why. -So if, for example, you device can only drive the low 24-bits of -address during PCI bus mastering you might do something like: +The standard 32-bit addressing PCI device would do something like +this: - if (! pci_dma_supported(pdev, 0x00ffffff)) + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_WARNING + "mydev: No suitable DMA available.\n"); goto ignore_this_device; + } -When DMA is possible for a given mask, the PCI layer must be informed of the -mask for later allocation operations on the device. This is achieved by -setting the dma_mask member of the pci_dev structure, like so: - -#define MY_HW_DMA_MASK 0x00ffffff - - if (! pci_dma_supported(pdev, MY_HW_DMA_MASK)) +Another common scenario is a 64-bit capable device. The approach +here is to try for 64-bit DAC addressing, but back down to a +32-bit mask should that fail. The PCI platform code may fail the +64-bit mask not because the platform is not capable of 64-bit +addressing. Rather, it may fail in this case simply because +32-bit SAC addressing is done more efficiently than DAC addressing. +Sparc64 is one platform which behaves in this way. + +Here is how you would handle a 64-bit capable device which can drive +all 64-bits during a DAC cycle: + + int using_dac; + + if (!pci_set_dma_mask(pdev, 0xffffffffffffffff)) { + using_dac = 1; + } else if (!pci_set_dma_mask(pdev, 0xffffffff)) { + using_dac = 0; + } else { + printk(KERN_WARNING + "mydev: No suitable DMA available.\n"); goto ignore_this_device; + } - pdev->dma_mask = MY_HW_DMA_MASK; +If your 64-bit device is going to be an enormous consumer of DMA +mappings, this can be problematic since the DMA mappings are a +finite resource on many platforms. Please see the "DAC Addressing +for Address Space Hungry Devices" setion near the end of this +document for how to handle this case. -A helper function is provided which performs this common code sequence: +Finally, if your device can only drive the low 24-bits of +address during PCI bus mastering you might do something like: - int pci_set_dma_mask(struct pci_dev *pdev, dma_addr_t device_mask) + if (pci_set_dma_mask(pdev, 0x00ffffff)) { + printk(KERN_WARNING + "mydev: 24-bit DMA addressing not available.\n"); + goto ignore_this_device; + } -Unlike pci_dma_supported(), this returns -EIO when the PCI layer will not be -able to DMA with addresses restricted by that mask, and returns 0 when DMA -transfers are possible. If the call succeeds, the dma_mask will have been -updated so that your driver need not worry about it. +When pci_set_dma_mask() is successful, and returns zero, the PCI layer +saves away this mask you have provided. The PCI layer will use this +information later when you make DMA mappings. There is a case which we are aware of at this time, which is worth mentioning in this documentation. If your device supports multiple @@ -169,6 +208,10 @@ Think of "consistent" as "synchronous" or "coherent". + Consistent DMA mappings are always SAC addressable. That is + to say, consistent DMA addresses given to the driver will always + be in the low 32-bits of the PCI bus space. + Good examples of what to use consistent mappings for are: - Network card DMA ring descriptors. @@ -230,15 +273,26 @@ specific (and often is private to the bus which the device is attached to). -Size is the length of the region you want to allocate. +Size is the length of the region you want to allocate, in bytes. This routine will allocate RAM for that region, so it acts similarly to __get_free_pages (but takes size instead of a page order). If your driver needs regions sized smaller than a page, you may prefer using the pci_pool interface, described below. -It returns two values: the virtual address which you can use to access -it from the CPU and dma_handle which you pass to the card. +The consistent DMA mapping interfaces, for non-NULL dev, will always +return a DMA address which is SAC (Single Address Cycle) addressible. +Even if the device indicates (via PCI dma mask) that it may address +the upper 32-bits and thus perform DAC cycles, consistent allocation +will still only return 32-bit PCI addresses for DMA. This is true +of the pci_pool interface as well. + +In fact, as mentioned above, all consistent memory provided by the +kernel DMA APIs are always SAC addressable. + +pci_alloc_consistent returns two values: the virtual address which you +can use to access it from the CPU and dma_handle which you pass to the +card. The cpu return address and the DMA bus master address are both guaranteed to be aligned to the smallest PAGE_SIZE order which @@ -270,14 +324,15 @@ The "name" is for diagnostics (like a kmem_cache name); dev and size are as above. The device's hardware alignment requirement for this -type of data is "align" (a power of two). The flags are SLAB_ flags -as you'd pass to kmem_cache_create. Not all flags are understood, but -SLAB_POISON may help you find driver bugs. If you call this in a non- -sleeping context (f.e. in_interrupt is true or while holding SMP -locks), pass SLAB_ATOMIC. If your device has no boundary crossing -restrictions, pass 0 for alloc; passing 4096 says memory allocated -from this pool must not cross 4KByte boundaries (but at that time it -may be better to go for pci_alloc_consistent directly instead). +type of data is "align" (which is expressed in bytes, and must be a +power of two). The flags are SLAB_ flags as you'd pass to +kmem_cache_create. Not all flags are understood, but SLAB_POISON may +help you find driver bugs. If you call this in a non- sleeping +context (f.e. in_interrupt is true or while holding SMP locks), pass +SLAB_ATOMIC. If your device has no boundary crossing restrictions, +pass 0 for alloc; passing 4096 says memory allocated from this pool +must not cross 4KByte boundaries (but at that time it may be better to +go for pci_alloc_consistent directly instead). Allocate memory from a pci pool like this: @@ -318,6 +373,8 @@ PCI_DMA_TODEVICE means "from main memory to the PCI device" PCI_DMA_FROMDEVICE means "from the PCI device to main memory" +It is the direction in which the data moves during the DMA +transfer. You are _strongly_ encouraged to specify this as precisely as you possibly can. @@ -333,13 +390,13 @@ precise direction, and this will help catch cases where your direction tracking logic has failed to set things up properly. -Another advantage of specifying this value precisely (outside -of potential platform-specific optimizations of such) is for -debugging. Some platforms actually have a write permission -boolean which DMA mappings can be marked with, much like page -protections in a user program can have. Such platforms can -and do report errors in the kernel logs when the PCI controller -hardware detects violation of the permission setting. +Another advantage of specifying this value precisely (outside of +potential platform-specific optimizations of such) is for debugging. +Some platforms actually have a write permission boolean which DMA +mappings can be marked with, much like page protections in the user +program address space. Such platforms can and do report errors in the +kernel logs when the PCI controller hardware detects violation of the +permission setting. Only streaming mappings specify a direction, consistent mappings implicitly have a direction attribute setting of @@ -362,13 +419,17 @@ Using Streaming DMA mappings -The streaming DMA mapping routines can be called from interrupt context. -There are two versions of each map/unmap, one which map/unmap a single -memory region, one which map/unmap a scatterlist. +The streaming DMA mapping routines can be called from interrupt +context. There are two versions of each map/unmap, one which will +map/unmap a single memory region, and one which will map/unmap a +scatterlist. To map a single region, you do: + struct pci_dev *pdev = mydev->pdev; dma_addr_t dma_handle; + void *addr = buffer->ptr; + size_t size = buffer->len; dma_handle = pci_map_single(dev, addr, size, direction); @@ -377,9 +438,29 @@ pci_unmap_single(dev, dma_handle, size, direction); You should call pci_unmap_single when the DMA activity is finished, e.g. -from interrupt which told you the DMA transfer is done. +from the interrupt which told you that the DMA transfer is done. -Similarly with scatterlists, you map a region gathered from several regions by: +Using cpu pointers like this for single mappings has a disadvantage, +you cannot reference HIGHMEM memory in this way. Thus, there is a +map/unmap interface pair akin to pci_{map,unmap}_single. These +interfaces deal with page/offset pairs instead of cpu pointers. +Specifically: + + struct pci_dev *pdev = mydev->pdev; + dma_addr_t dma_handle; + struct page *page = buffer->page; + unsigned long offset = buffer->offset; + size_t size = buffer->len; + + dma_handle = pci_map_page(dev, page, offset, size, direction); + + ... + + pci_unmap_page(dev, dma_handle, size, direction); + +Here, "offset" means byte offset within the given page. + +With scatterlists, you map a region gathered from several regions by: int i, count = pci_map_sg(dev, sglist, nents, direction); struct scatterlist *sg; @@ -407,7 +488,7 @@ pci_unmap_sg(dev, sglist, nents, direction); -Again, make sure DMA activity finished. +Again, make sure DMA activity has already finished. PLEASE NOTE: The 'nents' argument to the pci_unmap_sg call must be the _same_ one you passed into the pci_map_sg call, @@ -421,8 +502,8 @@ all bus addresses. If you need to use the same streaming DMA region multiple times and touch -the data in between the DMA transfers, just map it -with pci_map_{single,sg}, after each DMA transfer call either: +the data in between the DMA transfers, just map it with +pci_map_{single,sg}, and after each DMA transfer call either: pci_dma_sync_single(dev, dma_handle, size, direction); @@ -430,9 +511,11 @@ pci_dma_sync_sg(dev, sglist, nents, direction); -and after the last DMA transfer call one of the DMA unmap routines +as appropriate. + +After the last DMA transfer call one of the DMA unmap routines pci_unmap_{single,sg}. If you don't touch the data from the first pci_map_* -call till pci_unmap_*, then you don't have to call the pci_sync_* +call till pci_unmap_*, then you don't have to call the pci_dma_sync_* routines at all. Here is pseudo code which shows a situation in which you would need @@ -492,6 +575,119 @@ supports dynamic DMA mapping in hardware) in your driver structures and/or in the card registers. +All PCI drivers should be using these interfaces with no exceptions. +It is planned to completely remove virt_to_bus() and bus_to_virt() as +they are entirely deprecated. Some ports already do not provide these +as it is impossible to correctly support them. + + 64-bit DMA and DAC cycle support + +Do you understand all of the text above? Great, then you already +know how to use 64-bit DMA addressing under Linux. Simply make +the appropriate pci_set_dma_mask() calls based upon your cards +capabilities, then use the mapping APIs above. + +It is that simple. + +Well, not for some odd devices. See the next section for information +about that. + + DAC Addressing for Address Space Hungry Devices + +There exists a class of devices which do not mesh well with the PCI +DMA mapping API. By definition these "mappings" are a finite +resource. The number of total available mappings per bus is platform +specific, but there will always be a reasonable amount. + +What is "reasonable"? Reasonable means that networking and block I/O +devices need not worry about using too many mappings. + +As an example of a problematic device, consider compute cluster cards. +They can potentially need to access gigabytes of memory at once via +DMA. Dynamic mappings are unsuitable for this kind of access pattern. + +To this end we've provided a small API by which a device driver +may use DAC cycles to directly address all of physical memory. +Not all platforms support this, but most do. It is easy to determine +whether the platform will work properly at probe time. + +First, understand that there may be a SEVERE performance penalty for +using these interfaces on some platforms. Therefore, you MUST only +use these interfaces if it is absolutely required. %99 of devices can +use the normal APIs without any problems. + +Note that for streaming type mappings you must either use these +interfaces, or the dynamic mapping interfaces above. You may not mix +usage of both for the same device. Such an act is illegal and is +guarenteed to put a banana in your tailpipe. + +However, consistent mappings may in fact be used in conjunction with +these interfaces. Remember that, as defined, consistent mappings are +always going to be SAC addressable. + +The first thing your driver needs to do is query the PCI platform +layer with your devices DAC addressing capabilities: + + int pci_dac_set_dma_mask(struct pci_dev *pdev, u64 mask); + +This routine behaves identically to pci_set_dma_mask. You may not +use the following interfaces if this routine fails. + +Next, DMA addresses using this API are kept track of using the +dma64_addr_t type. It is guarenteed to be big enough to hold any +DAC address the platform layer will give to you from the following +routines. If you have consistent mappings as well, you still +use plain dma_addr_t to keep track of those. + +All mappings obtained here will be direct. The mappings are not +translated, and this is the purpose of this dialect of the DMA API. + +All routines work with page/offset pairs. This is the _ONLY_ way to +portably refer to any piece of memory. If you have a cpu pointer +(which may be validly DMA'd too) you may easily obtain the page +and offset using something like this: + + struct page *page = virt_to_page(ptr); + unsigned long offset = ((unsigned long)ptr & ~PAGE_MASK); + +Here are the interfaces: + + dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, + struct page *page, + unsigned long offset, + int direction); + +The DAC address for the tuple PAGE/OFFSET are returned. The direction +argument is the same as for pci_{map,unmap}_single(). The same rules +for cpu/device access apply here as for the streaming mapping +interfaces. To reiterate: + + The cpu may touch the buffer before pci_dac_page_to_dma. + The device may touch the buffer after pci_dac_page_to_dma + is made, but the cpu may NOT. + +When the DMA transfer is complete, invoke: + + void pci_dac_dma_sync_single(struct pci_dev *pdev, + dma64_addr_t dma_addr, + size_t len, int direction); + +This must be done before the CPU looks at the buffer again. +This interface behaves identically to pci_dma_sync_{single,sg}(). + +If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t +the following interfaces are provided: + + struct page *pci_dac_dma_to_page(struct pci_dev *pdev, + dma64_addr_t dma_addr); + unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, + dma64_addr_t dma_addr); + +This is possible with the DAC interfaces purely because they are +not translated in any way. + + Closing + This document, and the API itself, would not be in it's current form without the feedback and suggestions from numerous individuals. We would like to specifically mention, in no particular order, the @@ -503,3 +699,6 @@ Grant Grundler Jay Estabrook Thomas Sailer + Andrea Arcangeli + Jens Axboe + David Mosberger-Tang diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/alpha_ksyms.c Fri Sep 14 00:21:32 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Sun Sep 16 23:31:44 2001 @@ -127,10 +127,16 @@ EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); +EXPORT_SYMBOL(pci_map_page); EXPORT_SYMBOL(pci_unmap_single); +EXPORT_SYMBOL(pci_unmap_page); EXPORT_SYMBOL(pci_map_sg); EXPORT_SYMBOL(pci_unmap_sg); EXPORT_SYMBOL(pci_dma_supported); +EXPORT_SYMBOL(pci_dac_dma_supported); +EXPORT_SYMBOL(pci_dac_page_to_dma); +EXPORT_SYMBOL(pci_dac_dma_to_page); +EXPORT_SYMBOL(pci_dac_dma_to_offset); #endif EXPORT_SYMBOL(dump_thread); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_cia.c Fri Sep 14 00:21:32 2001 +++ linux/arch/alpha/kernel/core_cia.c Sun Sep 16 23:31:44 2001 @@ -321,7 +321,7 @@ * be purged to make room for the new entries coming in for the garbage page. */ -#define CIA_BROKEN_TBIA_BASE 0xE0000000 +#define CIA_BROKEN_TBIA_BASE 0x30000000 #define CIA_BROKEN_TBIA_SIZE 1024 /* Always called with interrupts disabled */ @@ -382,10 +382,10 @@ for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i) ppte[i] = pte; - *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBIA_BASE | 3; - *(vip)CIA_IOC_PCI_W3_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1) + *(vip)CIA_IOC_PCI_W1_BASE = CIA_BROKEN_TBIA_BASE | 3; + *(vip)CIA_IOC_PCI_W1_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2; + *(vip)CIA_IOC_PCI_T1_BASE = virt_to_phys(ppte) >> 2; } static void __init @@ -595,6 +595,8 @@ failed: printk("pci: disabling sg translation window\n"); *(vip)CIA_IOC_PCI_W0_BASE = 0; + *(vip)CIA_IOC_PCI_W1_BASE = 0; + pci_isa_hose->sg_isa = NULL; alpha_mv.mv_pci_tbi = NULL; goto exit; } @@ -682,13 +684,9 @@ * Set up the PCI to main memory translation windows. * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is direct access 1GB at 1GB - * Window 2 is direct access 1GB at 2GB - * - * We must actually use 2 windows to direct-map the 2GB space, - * because of an idiot-syncrasy of the CYPRESS chip used on - * many PYXIS systems. It may respond to a PCI bus address in - * the last 1MB of the 4GB address range. + * Window 1 is scatter-gather 1MB at 768MB (for tbia) + * Window 2 is direct access 2GB at 2GB + * Window 3 is DAC access 4GB at 8GB * * ??? NetBSD hints that page tables must be aligned to 32K, * possibly due to a hardware bug. This is over-aligned @@ -698,20 +696,35 @@ hose->sg_pci = NULL; hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768); - __direct_map_base = 0x40000000; + __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; *(vip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3; *(vip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; *(vip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; - *(vip)CIA_IOC_PCI_W1_BASE = 0x40000000 | 1; - *(vip)CIA_IOC_PCI_W1_MASK = (0x40000000 - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T1_BASE = 0 >> 2; - - *(vip)CIA_IOC_PCI_W2_BASE = 0x80000000 | 1; - *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2; + *(vip)CIA_IOC_PCI_W2_BASE = __direct_map_base | 1; + *(vip)CIA_IOC_PCI_W2_MASK = (__direct_map_size - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_T2_BASE = 0 >> 2; + + /* On PYXIS we have the monster window, selected by bit 40, so + there is no need for window3 to be enabled. + + On CIA, we don't have true arbitrary addressing -- bits <39:32> + are compared against W_DAC. We can, however, directly map 4GB, + which is better than before. However, due to assumptions made + elsewhere, we should not claim that we support DAC unless that + 4GB covers all of physical memory. */ + if (is_pyxis || max_low_pfn > (0x100000000 >> PAGE_SHIFT)) { + *(vip)CIA_IOC_PCI_W3_BASE = 0; + } else { + *(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8; + *(vip)CIA_IOC_PCI_W3_MASK = 0xfff00000; + *(vip)CIA_IOC_PCI_T3_BASE = 0 >> 2; + + alpha_mv.pci_dac_offset = 0x200000000; + *(vip)CIA_IOC_PCI_W_DAC = alpha_mv.pci_dac_offset >> 32; + } /* Prepare workaround for apparently broken tbia. */ cia_prepare_tbia_workaround(); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_mcpcia.c Fri Mar 2 20:12:07 2001 +++ linux/arch/alpha/kernel/core_mcpcia.c Sun Sep 16 23:31:44 2001 @@ -406,12 +406,12 @@ * Set up the PCI->physical memory translation windows. * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is scatter-gather 128MB at 1GB + * Window 1 is scatter-gather (up to) 1GB at 1GB (for pci) * Window 2 is direct access 2GB at 2GB - * ??? We ought to scale window 1 with memory. */ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); - hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); + hose->sg_pci = iommu_arena_new(hose, 0x40000000, + size_for_memory(0x40000000), 0); __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_titan.c linux/arch/alpha/kernel/core_titan.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_titan.c Fri Mar 2 20:12:07 2001 +++ linux/arch/alpha/kernel/core_titan.c Sun Sep 16 23:31:44 2001 @@ -20,6 +20,8 @@ #include #undef __EXTERN_INLINE +#include + #include "proto.h" #include "pci_impl.h" @@ -277,6 +279,7 @@ titan_init_one_pachip_port(titan_pachip_port *port, int index) { struct pci_controller *hose; + unsigned long sg_size; hose = alloc_pci_controller(); if (index == 0) @@ -342,40 +345,35 @@ * Note: Window 3 on Titan is Scatter-Gather ONLY * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is direct access 1GB at 1GB - * Window 2 is direct access 1GB at 2GB - * Window 3 is scatter-gather 128MB at 3GB - * ??? We ought to scale window 3 memory. - * - * We must actually use 2 windows to direct-map the 2GB space, - * because of an idiot-syncrasy of the CYPRESS chip. It may - * respond to a PCI bus address in the last 1MB of the 4GB - * address range. + * Window 1 is scatter-gather (up to) 1GB at 1GB + * Window 2 is direct access 2GB at 2GB */ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); hose->sg_isa->align_entry = 8; /* 64KB for ISA */ - hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + hose->sg_pci = iommu_arena_new(hose, 0x40000000, + size_for_memory(0x40000000), 0); hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */ - __direct_map_base = 0x40000000; + __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; port->wsba[0].csr = hose->sg_isa->dma_base | 3; port->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; port->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); - port->wsba[1].csr = 0x40000000 | 1; - port->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; - port->tba[1].csr = 0; + port->wsba[1].csr = hose->sg_pci->dma_base | 3; + port->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000; + port->tba[1].csr = virt_to_phys(hose->sg_pci->ptes); port->wsba[2].csr = 0x80000000 | 1; - port->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; - port->tba[2].csr = 0x40000000; + port->wsm[2].csr = (0x80000000 - 1) & 0xfff00000; + port->tba[2].csr = 0x80000000; + + port->wsba[3].csr = 0; - port->wsba[3].csr = hose->sg_pci->dma_base | 3; - port->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; - port->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); + /* Enable the Monster Window to make DAC pci64 possible. */ + port->pctl.csr |= pctl_m_mwin; titan_pci_tbi(hose, 0, -1); } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/core_tsunami.c Tue Jun 12 04:15:27 2001 +++ linux/arch/alpha/kernel/core_tsunami.c Sun Sep 16 23:31:44 2001 @@ -279,16 +279,6 @@ #define FN __FUNCTION__ static void __init -tsunami_monster_window_enable(tsunami_pchip * pchip) -{ - volatile unsigned long * csr = &pchip->pctl.csr; - - *csr |= pctl_m_mwin; - mb(); - *csr; -} - -static void __init tsunami_init_one_pchip(tsunami_pchip *pchip, int index) { struct pci_controller *hose; @@ -358,47 +348,34 @@ * Note: Window 3 is scatter-gather only * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is direct access 1GB at 1GB - * Window 2 is direct access 1GB at 2GB - * Window 3 is scatter-gather 128MB at 3GB - * ??? We ought to scale window 3 memory. - * - * We must actually use 2 windows to direct-map the 2GB space, - * because of an idiot-syncrasy of the CYPRESS chip. It may - * respond to a PCI bus address in the last 1MB of the 4GB - * address range. + * Window 1 is scatter-gather (up to) 1GB at 1GB + * Window 2 is direct access 2GB at 2GB */ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); - { - unsigned long size = 0x08000000; - if (max_low_pfn > (0x80000000 >> PAGE_SHIFT)) - size = 0x40000000; - hose->sg_pci = iommu_arena_new(hose, 0xc0000000, size, 0); - } - - __direct_map_base = 0x40000000; + hose->sg_pci = iommu_arena_new(hose, 0x40000000, + size_for_memory(0x40000000), 0); + + __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; pchip->wsba[0].csr = hose->sg_isa->dma_base | 3; pchip->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; pchip->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); - pchip->wsba[1].csr = 0x40000000 | 1; - pchip->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[1].csr = 0; + pchip->wsba[1].csr = hose->sg_pci->dma_base | 3; + pchip->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000; + pchip->tba[1].csr = virt_to_phys(hose->sg_pci->ptes); pchip->wsba[2].csr = 0x80000000 | 1; - pchip->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[2].csr = 0x40000000; + pchip->wsm[2].csr = (0x80000000 - 1) & 0xfff00000; + pchip->tba[2].csr = 0x80000000; - pchip->wsba[3].csr = hose->sg_pci->dma_base | 3; - pchip->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; - pchip->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); - - tsunami_pci_tbi(hose, 0, -1); + pchip->wsba[3].csr = 0; /* Enable the Monster Window to make DAC pci64 possible. */ - tsunami_monster_window_enable(pchip); + pchip->pctl.csr |= pctl_m_mwin; + + tsunami_pci_tbi(hose, 0, -1); } void __init diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/pci_impl.h Fri Sep 14 00:21:32 2001 +++ linux/arch/alpha/kernel/pci_impl.h Sun Sep 16 23:28:44 2001 @@ -168,4 +168,4 @@ extern int iommu_bind(struct pci_iommu_arena *, long, long, unsigned long *); extern int iommu_unbind(struct pci_iommu_arena *, long, long); - +extern unsigned long size_for_memory(unsigned long max); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/pci_iommu.c Fri Sep 14 00:21:32 2001 +++ linux/arch/alpha/kernel/pci_iommu.c Sun Sep 16 23:31:44 2001 @@ -17,17 +17,18 @@ #define DEBUG_ALLOC 0 #if DEBUG_ALLOC > 0 -# define DBGA(args...) printk(KERN_DEBUG ##args) +# define DBGA(args...) printk(KERN_DEBUG args) #else # define DBGA(args...) #endif #if DEBUG_ALLOC > 1 -# define DBGA2(args...) printk(KERN_DEBUG ##args) +# define DBGA2(args...) printk(KERN_DEBUG args) #else # define DBGA2(args...) #endif #define DEBUG_NODIRECT 0 +#define DEBUG_FORCEDAC 0 static inline unsigned long @@ -43,6 +44,19 @@ } +/* Return the minimum of MAX or the first power of two larger + than main memory. */ + +unsigned long +size_for_memory(unsigned long max) +{ + unsigned long mem = max_low_pfn << PAGE_SHIFT; + if (mem < max) + max = 1UL << ceil_log2(mem); + return max; +} + + struct pci_iommu_arena * iommu_arena_new(struct pci_controller *hose, dma_addr_t base, unsigned long window_size, unsigned long align) @@ -163,8 +177,9 @@ 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 *pdev, void *cpu_addr, long size, int direction) +static dma_addr_t +pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size, + int dac_allowed) { struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; @@ -173,10 +188,7 @@ unsigned long paddr; dma_addr_t ret; - if (direction == PCI_DMA_NONE) - BUG(); - - paddr = virt_to_phys(cpu_addr); + paddr = __pa(cpu_addr); #if !DEBUG_NODIRECT /* First check to see if we can use the direct map window. */ @@ -184,13 +196,23 @@ && paddr + size <= __direct_map_size) { ret = paddr + __direct_map_base; - DBGA2("pci_map_single: [%p,%lx] -> direct %x from %p\n", + DBGA2("pci_map_single: [%p,%lx] -> direct %lx from %p\n", cpu_addr, size, ret, __builtin_return_address(0)); return ret; } #endif + /* Next, use DAC if selected earlier. */ + if (dac_allowed) { + ret = paddr + alpha_mv.pci_dac_offset; + + DBGA2("pci_map_single: [%p,%lx] -> DAC %lx from %p\n", + cpu_addr, size, ret, __builtin_return_address(0)); + + return ret; + } + /* If the machine doesn't define a pci_tbi routine, we have to assume it doesn't support sg mapping. */ if (! alpha_mv.mv_pci_tbi) { @@ -217,12 +239,30 @@ ret = arena->dma_base + dma_ofs * PAGE_SIZE; ret += (unsigned long)cpu_addr & ~PAGE_MASK; - DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n", - cpu_addr, size, npages, ret, __builtin_return_address(0)); + DBGA2("pci_map_single: [%p,%lx] np %ld -> sg %lx from %p\n", + cpu_addr, size, npages, ret, __builtin_return_address(0)); return ret; } +dma_addr_t +pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir) +{ + if (dir == PCI_DMA_NONE) + BUG(); + return pci_map_single_1(pdev, cpu_addr, size, + (pdev->dma_mask >> 32) != 0); +} + +dma_addr_t +pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset, + size_t size, int dir) +{ + if (dir == PCI_DMA_NONE) + BUG(); + return pci_map_single_1(pdev, (char *)page_address(page) + offset, + size, (pdev->dma_mask >> 32) != 0); +} /* Unmap a single streaming mode DMA translation. The DMA_ADDR and SIZE must match what was provided for in a previous pci_map_single @@ -231,7 +271,7 @@ wrote there. */ void -pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, int direction) { unsigned long flags; @@ -242,17 +282,21 @@ if (direction == PCI_DMA_NONE) BUG(); -#if !DEBUG_NODIRECT if (dma_addr >= __direct_map_base && dma_addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ - DBGA2("pci_unmap_single: direct [%x,%lx] from %p\n", + DBGA2("pci_unmap_single: direct [%lx,%lx] from %p\n", dma_addr, size, __builtin_return_address(0)); return; } -#endif + + if (dma_addr > 0xffffffff) { + DBGA2("pci64_unmap_single: DAC [%lx,%lx] from %p\n", + dma_addr, size, __builtin_return_address(0)); + return; + } arena = hose->sg_pci; if (!arena || dma_addr < arena->dma_base) @@ -260,7 +304,7 @@ dma_ofs = (dma_addr - arena->dma_base) >> PAGE_SHIFT; if (dma_ofs * PAGE_SIZE >= arena->size) { - printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %x " + printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %lx " " base %x size %x\n", dma_addr, arena->dma_base, arena->size); return; @@ -273,21 +317,24 @@ iommu_arena_free(arena, dma_ofs, npages); - - /* - If we're freeing ptes above the `next_entry' pointer (they + /* If we're freeing ptes above the `next_entry' pointer (they may have snuck back into the TLB since the last wrap flush), - we need to flush the TLB before reallocating the latter. - */ + we need to flush the TLB before reallocating the latter. */ if (dma_ofs >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); spin_unlock_irqrestore(&arena->lock, flags); - DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", - dma_addr, size, npages, __builtin_return_address(0)); + DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n", + dma_addr, size, npages, __builtin_return_address(0)); } +void +pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr, + size_t size, int direction) +{ + pci_unmap_single(pdev, dma_addr, size, direction); +} /* Allocate and map kernel buffer using consistent mode DMA for PCI device. Returns non-NULL cpu-view pointer to the buffer if @@ -295,7 +342,7 @@ else DMA_ADDRP is undefined. */ void * -pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) +pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) { void *cpu_addr; long order = get_order(size); @@ -311,8 +358,7 @@ } memset(cpu_addr, 0, size); - *dma_addrp = pci_map_single(pdev, cpu_addr, size, - PCI_DMA_BIDIRECTIONAL); + *dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0); if (*dma_addrp == 0) { free_pages((unsigned long)cpu_addr, order); return NULL; @@ -324,7 +370,6 @@ return cpu_addr; } - /* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must be values that were returned from pci_alloc_consistent. SIZE must be the same as what as passed into pci_alloc_consistent. @@ -332,7 +377,7 @@ DMA_ADDR past this call are illegal. */ void -pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr, +pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr, dma_addr_t dma_addr) { pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); @@ -352,27 +397,35 @@ Write dma_length of each leader with the combined lengths of the mergable followers. */ +#define SG_ENT_VIRT_ADDRESS(SG) \ + ((SG)->address \ + ? (SG)->address \ + : page_address((SG)->page) + (SG)->offset) + +#define SG_ENT_PHYS_ADDRESS(SG) \ + __pa(SG_ENT_VIRT_ADDRESS(SG)) + static void sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) { - unsigned long next_vaddr; + unsigned long next_paddr; struct scatterlist *leader; long leader_flag, leader_length; leader = sg; leader_flag = 0; leader_length = leader->length; - next_vaddr = (unsigned long)leader->address + leader_length; + next_paddr = SG_ENT_PHYS_ADDRESS(leader) + leader_length; for (++sg; sg < end; ++sg) { unsigned long addr, len; - addr = (unsigned long) sg->address; + addr = SG_ENT_PHYS_ADDRESS(sg); len = sg->length; - if (next_vaddr == addr) { + if (next_paddr == addr) { sg->dma_address = -1; leader_length += len; - } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0 && virt_ok) { + } else if (((next_paddr | addr) & ~PAGE_MASK) == 0 && virt_ok) { sg->dma_address = -2; leader_flag = 1; leader_length += len; @@ -384,7 +437,7 @@ leader_length = len; } - next_vaddr = addr + len; + next_paddr = addr + len; } leader->dma_address = leader_flag; @@ -397,9 +450,9 @@ static inline int sg_fill(struct scatterlist *leader, struct scatterlist *end, struct scatterlist *out, struct pci_iommu_arena *arena, - dma_addr_t max_dma) + dma_addr_t max_dma, int dac_allowed) { - unsigned long paddr = virt_to_phys(leader->address); + unsigned long paddr = SG_ENT_PHYS_ADDRESS(leader); long size = leader->dma_length; struct scatterlist *sg; unsigned long *ptes; @@ -414,13 +467,24 @@ out->dma_address = paddr + __direct_map_base; out->dma_length = size; - DBGA(" sg_fill: [%p,%lx] -> direct %x\n", - leader->address, size, out->dma_address); + DBGA(" sg_fill: [%p,%lx] -> direct %lx\n", + __va(paddr), size, out->dma_address); return 0; } #endif + /* If physically contiguous and DAC is available, use it. */ + if (leader->dma_address == 0 && dac_allowed) { + out->dma_address = paddr + alpha_mv.pci_dac_offset; + out->dma_length = size; + + DBGA(" sg_fill: [%p,%lx] -> DAC %lx\n", + __va(paddr), size, out->dma_address); + + return 0; + } + /* Otherwise, we'll use the iommu to make the pages virtually contiguous. */ @@ -433,17 +497,16 @@ return -1; /* Otherwise, break up the remaining virtually contiguous - hunks into individual direct maps. */ + hunks into individual direct maps and retry. */ sg_classify(leader, end, 0); - /* Retry. */ - return sg_fill(leader, end, out, arena, max_dma); + return sg_fill(leader, end, out, arena, max_dma, dac_allowed); } out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr; out->dma_length = size; - DBGA(" sg_fill: [%p,%lx] -> sg %x np %ld\n", - leader->address, size, out->dma_address, npages); + DBGA(" sg_fill: [%p,%lx] -> sg %lx np %ld\n", + __va(paddr), size, out->dma_address, npages); /* All virtually contiguous. We need to find the length of each physically contiguous subsegment to fill in the ptes. */ @@ -455,7 +518,7 @@ #endif size = sg->length; - paddr = virt_to_phys(sg->address); + paddr = SG_ENT_PHYS_ADDRESS(sg); while (sg+1 < end && (int) sg[1].dma_address == -1) { size += sg[1].length; @@ -470,11 +533,11 @@ #if DEBUG_ALLOC > 0 DBGA(" (%ld) [%p,%x] np %ld\n", - last_sg - leader, last_sg->address, + last_sg - leader, SG_ENT_VIRT_ADDRESS(last_sg), last_sg->length, npages); while (++last_sg <= sg) { DBGA(" (%ld) [%p,%x] cont\n", - last_sg - leader, last_sg->address, + last_sg - leader, SG_ENT_VIRT_ADDRESS(last_sg), last_sg->length); } #endif @@ -491,15 +554,19 @@ struct pci_controller *hose; struct pci_iommu_arena *arena; dma_addr_t max_dma; + int dac_allowed; if (direction == PCI_DMA_NONE) BUG(); + dac_allowed = ((pdev->dma_mask >> 32) != 0); + /* Fast path single entry scatterlists. */ if (nents == 1) { sg->dma_length = sg->length; sg->dma_address - = pci_map_single(pdev, sg->address, sg->length, direction); + = pci_map_single_1(pdev, SG_ENT_VIRT_ADDRESS(sg), + sg->length, dac_allowed); return sg->dma_address != 0; } @@ -527,7 +594,7 @@ for (out = sg; sg < end; ++sg) { if ((int) sg->dma_address < 0) continue; - if (sg_fill(sg, end, out, arena, max_dma) < 0) + if (sg_fill(sg, end, out, arena, max_dma, dac_allowed) < 0) goto error; out++; } @@ -542,7 +609,7 @@ return out - start; -error: + error: printk(KERN_WARNING "pci_map_sg failed: " "could not allocate dma page tables\n"); @@ -553,7 +620,6 @@ return 0; } - /* Unmap a set of streaming mode DMA translations. Again, cpu read rules concerning calls here are the same as for pci_unmap_single() above. */ @@ -586,7 +652,8 @@ spin_lock_irqsave(&arena->lock, flags); for (end = sg + nents; sg < end; ++sg) { - unsigned long addr, size; + dma64_addr_t addr; + size_t size; long npages, ofs; dma_addr_t tend; @@ -595,7 +662,13 @@ if (!size) break; -#if !DEBUG_NODIRECT + if (addr > 0xffffffff) { + /* It's a DAC address -- nothing to do. */ + DBGA(" (%ld) DAC [%lx,%lx]\n", + sg - end + nents, addr, size); + continue; + } + if (addr >= __direct_map_base && addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ @@ -603,7 +676,6 @@ sg - end + nents, addr, size); continue; } -#endif DBGA(" (%ld) sg [%lx,%lx]\n", sg - end + nents, addr, size); @@ -617,29 +689,27 @@ if (fend < tend) fend = tend; } - /* - If we're freeing ptes above the `next_entry' pointer (they + /* If we're freeing ptes above the `next_entry' pointer (they may have snuck back into the TLB since the last wrap flush), - we need to flush the TLB before reallocating the latter. - */ + we need to flush the TLB before reallocating the latter. */ if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, fbeg, fend); spin_unlock_irqrestore(&arena->lock, flags); - DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); + DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg)); } + /* Return whether the given PCI device DMA address mask can be supported properly. */ int -pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) +pci_dma_supported(struct pci_dev *pdev, u64 mask) { struct pci_controller *hose; struct pci_iommu_arena *arena; -#if !DEBUG_NODIRECT /* If there exists a direct map, and the mask fits either MAX_DMA_ADDRESS defined such that GFP_DMA does something useful, or the total system memory as shifted by the @@ -648,7 +718,6 @@ && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask || __direct_map_base + (max_low_pfn<sysdata : pci_isa_hose; @@ -758,4 +827,50 @@ p[i] = IOMMU_RESERVED_PTE; return 0; +} + +/* True if the machine supports DAC addressing, and DEV can + make use of it given MASK. */ + +int +pci_dac_dma_supported(struct pci_dev *dev, u64 mask) +{ + dma64_addr_t dac_offset = alpha_mv.pci_dac_offset; + int ok = 1; + + /* If this is not set, the machine doesn't support DAC at all. */ + if (dac_offset == 0) + ok = 0; + + /* The device has to be able to address our DAC bit. */ + if ((dac_offset & dev->dma_mask) != dac_offset) + ok = 0; + + /* If both conditions above are met, we are fine. */ + DBGA("pci_dac_dma_supported %s from %p\n", + ok ? "yes" : "no", __builtin_return_address(0)); + + return ok; +} + +dma64_addr_t +pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, + unsigned long offset, int direction) +{ + return (alpha_mv.pci_dac_offset + + __pa(page_address(page)) + + (dma64_addr_t) offset); +} + +struct page * +pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset; + return virt_to_page(__va(paddr)); +} + +unsigned long +pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + return (dma_addr & ~PAGE_MASK); } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_cabriolet.c Thu Jan 25 00:16:23 2001 +++ linux/arch/alpha/kernel/sys_cabriolet.c Sun Sep 16 23:31:44 2001 @@ -389,6 +389,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: PYXIS_DAC_OFFSET, nr_irqs: 35, device_interrupt: cabriolet_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_dp264.c Sun Aug 12 19:38:47 2001 +++ linux/arch/alpha/kernel/sys_dp264.c Sun Sep 16 23:31:44 2001 @@ -574,6 +574,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 64, device_interrupt: dp264_device_interrupt, @@ -598,6 +599,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 64, device_interrupt: dp264_device_interrupt, @@ -621,6 +623,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 64, device_interrupt: dp264_device_interrupt, @@ -644,6 +647,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 64, device_interrupt: dp264_device_interrupt, @@ -672,6 +676,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 64, device_interrupt: dp264_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_eiger.c Fri Mar 2 20:12:07 2001 +++ linux/arch/alpha/kernel/sys_eiger.c Sun Sep 16 23:31:44 2001 @@ -233,6 +233,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TSUNAMI_DAC_OFFSET, nr_irqs: 128, device_interrupt: eiger_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_miata.c Sun May 20 02:43:05 2001 +++ linux/arch/alpha/kernel/sys_miata.c Sun Sep 16 23:31:44 2001 @@ -256,6 +256,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: PYXIS_DAC_OFFSET, nr_irqs: 48, device_interrupt: pyxis_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_rawhide.c Tue Jun 12 04:15:27 2001 +++ linux/arch/alpha/kernel/sys_rawhide.c Sun Sep 16 23:31:44 2001 @@ -254,6 +254,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: MCPCIA_DEFAULT_MEM_BASE, + pci_dac_offset: MCPCIA_DAC_OFFSET, nr_irqs: 128, device_interrupt: rawhide_srm_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_ruffian.c Thu Feb 8 21:56:29 2001 +++ linux/arch/alpha/kernel/sys_ruffian.c Sun Sep 16 23:31:44 2001 @@ -220,6 +220,7 @@ max_dma_address: ALPHA_RUFFIAN_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: PYXIS_DAC_OFFSET, nr_irqs: 48, device_interrupt: pyxis_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_sx164.c Fri Oct 27 19:55:01 2000 +++ linux/arch/alpha/kernel/sys_sx164.c Sun Sep 16 23:31:44 2001 @@ -129,7 +129,9 @@ struct percpu_struct *cpu = (struct percpu_struct*) ((char*)hwrpb + hwrpb->processor_offset); - if (alpha_using_srm && (cpu->pal_revision & 0xffff) == 0x117) { + if (amask(AMASK_MAX) != 0 + && alpha_using_srm + && (cpu->pal_revision & 0xffff) == 0x117) { __asm__ __volatile__( "lda $16,8($31)\n" "call_pal 9\n" /* Allow PALRES insns in kernel mode */ @@ -160,6 +162,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: PYXIS_DAC_OFFSET, nr_irqs: 48, device_interrupt: pyxis_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_titan.c linux/arch/alpha/kernel/sys_titan.c --- /opt/kernel/linux-2.4.10/arch/alpha/kernel/sys_titan.c Fri Mar 2 20:12:07 2001 +++ linux/arch/alpha/kernel/sys_titan.c Sun Sep 16 23:31:44 2001 @@ -378,6 +378,7 @@ max_dma_address: ALPHA_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, + pci_dac_offset: TITAN_DAC_OFFSET, nr_irqs: 80, /* 64 + 16 */ device_interrupt: privateer_device_interrupt, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/ia64/sn/io/pci_dma.c linux/arch/ia64/sn/io/pci_dma.c --- /opt/kernel/linux-2.4.10/arch/ia64/sn/io/pci_dma.c Thu Apr 12 21:16:35 2001 +++ linux/arch/ia64/sn/io/pci_dma.c Sun Sep 16 23:31:44 2001 @@ -182,7 +182,7 @@ } /* - * On sn1 we use the alt_address entry of the scatterlist to store + * On sn1 we use the orig_address entry of the scatterlist to store * the physical address corresponding to the given virtual address */ int diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/parisc/kernel/ccio-dma.c linux/arch/parisc/kernel/ccio-dma.c --- /opt/kernel/linux-2.4.10/arch/parisc/kernel/ccio-dma.c Fri Feb 9 20:29:44 2001 +++ linux/arch/parisc/kernel/ccio-dma.c Sun Sep 16 23:31:44 2001 @@ -638,7 +638,7 @@ } -static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +static int ccio_dma_supported( struct pci_dev *dev, u64 mask) { if (dev == NULL) { printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/parisc/kernel/ccio-rm-dma.c linux/arch/parisc/kernel/ccio-rm-dma.c --- /opt/kernel/linux-2.4.10/arch/parisc/kernel/ccio-rm-dma.c Tue Dec 5 21:29:39 2000 +++ linux/arch/parisc/kernel/ccio-rm-dma.c Sun Sep 16 23:31:44 2001 @@ -93,7 +93,7 @@ } -static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +static int ccio_dma_supported( struct pci_dev *dev, u64 mask) { if (dev == NULL) { printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/parisc/kernel/pci-dma.c linux/arch/parisc/kernel/pci-dma.c --- /opt/kernel/linux-2.4.10/arch/parisc/kernel/pci-dma.c Fri Feb 9 20:29:44 2001 +++ linux/arch/parisc/kernel/pci-dma.c Sun Sep 16 23:31:44 2001 @@ -77,7 +77,7 @@ static inline void dump_resmap(void) {;} #endif -static int pa11_dma_supported( struct pci_dev *dev, dma_addr_t mask) +static int pa11_dma_supported( struct pci_dev *dev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/parisc/kernel/sba_iommu.c linux/arch/parisc/kernel/sba_iommu.c --- /opt/kernel/linux-2.4.10/arch/parisc/kernel/sba_iommu.c Fri Feb 9 20:29:44 2001 +++ linux/arch/parisc/kernel/sba_iommu.c Sun Sep 16 23:31:44 2001 @@ -779,7 +779,7 @@ } static int -sba_dma_supported( struct pci_dev *dev, dma_addr_t mask) +sba_dma_supported( struct pci_dev *dev, u64 mask) { if (dev == NULL) { printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c --- /opt/kernel/linux-2.4.10/arch/sparc64/kernel/iommu_common.c Tue Aug 28 16:09:44 2001 +++ linux/arch/sparc64/kernel/iommu_common.c Sun Sep 16 23:31:44 2001 @@ -12,7 +12,7 @@ */ #ifdef VERIFY_SG -int verify_lengths(struct scatterlist *sg, int nents, int npages) +static int verify_lengths(struct scatterlist *sg, int nents, int npages) { int sg_len, dma_len; int i, pgcount; @@ -22,8 +22,8 @@ sg_len += sg[i].length; dma_len = 0; - for (i = 0; i < nents && sg[i].dvma_length; i++) - dma_len += sg[i].dvma_length; + for (i = 0; i < nents && sg[i].dma_length; i++) + dma_len += sg[i].dma_length; if (sg_len != dma_len) { printk("verify_lengths: Error, different, sg[%d] dma[%d]\n", @@ -32,13 +32,13 @@ } pgcount = 0; - for (i = 0; i < nents && sg[i].dvma_length; i++) { + for (i = 0; i < nents && sg[i].dma_length; i++) { unsigned long start, end; - start = sg[i].dvma_address; + start = sg[i].dma_address; start = start & IO_PAGE_MASK; - end = sg[i].dvma_address + sg[i].dvma_length; + end = sg[i].dma_address + sg[i].dma_length; end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK; pgcount += ((end - start) >> IO_PAGE_SHIFT); @@ -55,15 +55,16 @@ return 0; } -int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte) +static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte) { struct scatterlist *sg = *__sg; iopte_t *iopte = *__iopte; - u32 dlen = dma_sg->dvma_length; - u32 daddr = dma_sg->dvma_address; + u32 dlen = dma_sg->dma_length; + u32 daddr; unsigned int sglen; unsigned long sgaddr; + daddr = dma_sg->dma_address; sglen = sg->length; sgaddr = (unsigned long) sg->address; while (dlen > 0) { @@ -136,7 +137,7 @@ return nents; } -int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte) +static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte) { struct scatterlist *dma_sg = sg; struct scatterlist *orig_dma_sg = dma_sg; @@ -147,7 +148,7 @@ if (nents <= 0) break; dma_sg++; - if (dma_sg->dvma_length == 0) + if (dma_sg->dma_length == 0) break; } @@ -174,14 +175,15 @@ verify_maps(sg, nents, iopte) < 0) { int i; - printk("verify_sglist: Crap, messed up mappings, dumping, iodma at %08x.\n", - (u32) (sg->dvma_address & IO_PAGE_MASK)); + printk("verify_sglist: Crap, messed up mappings, dumping, iodma +at "); + printk("%016lx.\n", sg->dma_address & PAGE_MASK); for (i = 0; i < nents; i++) { printk("sg(%d): address(%p) length(%x) " - "dma_address[%08x] dma_length[%08x]\n", + "dma_address[%016lx] dma_length[%016x]\n", i, sg[i].address, sg[i].length, - sg[i].dvma_address, sg[i].dvma_length); + sg[i].dma_address, sg[i].dma_length); } } @@ -204,8 +206,8 @@ sg++; addr = (unsigned long) sg->address; if (! VCONTIG(prev, addr)) { - dma_sg->dvma_address = dent_addr; - dma_sg->dvma_length = dent_len; + dma_sg->dma_address = dent_addr; + dma_sg->dma_length = dent_len; dma_sg++; dent_addr = ((dent_addr + @@ -218,8 +220,8 @@ dent_len += sg->length; prev = addr + sg->length; } - dma_sg->dvma_address = dent_addr; - dma_sg->dvma_length = dent_len; + dma_sg->dma_address = dent_addr; + dma_sg->dma_length = dent_len; return ((unsigned long) dent_addr + (unsigned long) dent_len + diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/sparc64/kernel/iommu_common.h linux/arch/sparc64/kernel/iommu_common.h --- /opt/kernel/linux-2.4.10/arch/sparc64/kernel/iommu_common.h Tue Aug 28 16:09:44 2001 +++ linux/arch/sparc64/kernel/iommu_common.h Sun Sep 16 23:31:44 2001 @@ -34,10 +34,7 @@ #undef VERIFY_SG #ifdef VERIFY_SG -int verify_lengths(struct scatterlist *sg, int nents, int npages); -int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte); -int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte); -void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages); +extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages); #endif /* Two addresses are "virtually contiguous" if and only if: @@ -47,4 +44,4 @@ #define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) -unsigned long prepare_sg(struct scatterlist *sg, int nents); +extern unsigned long prepare_sg(struct scatterlist *sg, int nents); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c --- /opt/kernel/linux-2.4.10/arch/sparc64/kernel/pci_iommu.c Tue Aug 28 16:09:44 2001 +++ linux/arch/sparc64/kernel/pci_iommu.c Sun Sep 16 23:31:44 2001 @@ -192,7 +192,7 @@ first_page = __get_free_pages(GFP_ATOMIC, order); if (first_page == 0UL) return NULL; - memset((char *)first_page, 0, PAGE_SIZE << order); + memset((char *)first_page, 0, IO_PAGE_SIZE << order); pcp = pdev->sysdata; iommu = pcp->pbm->iommu; @@ -378,7 +378,8 @@ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU if (iopte_val(*base) == IOPTE_INVALID) - printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0)); + printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", + bus_addr, sz, __builtin_return_address(0)); #endif bus_addr &= IO_PAGE_MASK; @@ -423,18 +424,26 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection) +#define SG_ENT_PHYS_ADDRESS(SG) \ + ((SG)->address ? \ + __pa((SG)->address) : \ + (__pa(page_address((SG)->page)) + (SG)->offset)) + +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, + int nused, int nelems, unsigned long iopte_protection +) { struct scatterlist *dma_sg = sg; + struct scatterlist *sg_end = sg + nelems; int i; for (i = 0; i < nused; i++) { unsigned long pteval = ~0UL; u32 dma_npages; - dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dvma_length + - ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; + dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + + dma_sg->dma_length + + ((PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; do { unsigned long offset; signed int len; @@ -447,7 +456,7 @@ for (;;) { unsigned long tmp; - tmp = (unsigned long) __pa(sg->address); + tmp = SG_ENT_PHYS_ADDRESS(sg); len = sg->length; if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { pteval = tmp & IO_PAGE_MASK; @@ -479,10 +488,12 @@ * adjusting pteval along the way. Stop when we * detect a page crossing event. */ - while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - pteval == __pa(sg->address) && + while (sg < sg_end && + (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && + (pteval == SG_ENT_PHYS_ADDRESS(sg)) && ((pteval ^ - (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { + (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) > +> IO_PAGE_SHIFT) == 0UL) { pteval += sg->length; sg++; } @@ -511,8 +522,13 @@ /* Fast path single entry scatterlists. */ if (nelems == 1) { - sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction); - sglist->dvma_length = sglist->length; + sglist->dma_address = + pci_map_single(pdev, + (sglist->address ? + sglist->address : + (page_address(sglist->page) + sglist->offset)), + sglist->length, direction); + sglist->dma_length = sglist->length; return 1; } @@ -540,8 +556,8 @@ used = nelems; sgtmp = sglist; - while (used && sgtmp->dvma_length) { - sgtmp->dvma_address += dma_base; + while (used && sgtmp->dma_length) { + sgtmp->dma_address += dma_base; sgtmp++; used--; } @@ -559,7 +575,7 @@ iopte_protection = IOPTE_CONSISTENT(ctx); if (direction != PCI_DMA_TODEVICE) iopte_protection |= IOPTE_WRITE; - fill_sg (base, sglist, used, iopte_protection); + fill_sg (base, sglist, used, nelems, iopte_protection); #ifdef VERIFY_SG verify_sglist(sglist, nelems, base, npages); #endif @@ -591,20 +607,20 @@ iommu = pcp->pbm->iommu; strbuf = &pcp->pbm->stc; - bus_addr = sglist->dvma_address & IO_PAGE_MASK; + bus_addr = sglist->dma_address & IO_PAGE_MASK; for (i = 1; i < nelems; i++) - if (sglist[i].dvma_length == 0) + if (sglist[i].dma_length == 0) break; i--; - npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); #ifdef DEBUG_PCI_IOMMU if (iopte_val(*base) == IOPTE_INVALID) - printk("pci_unmap_sg called on non-mapped region %08x,%d from %016lx\n", sglist->dvma_address, nelems, __builtin_return_address(0)); + printk("pci_unmap_sg called on non-mapped region %08x,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0)); #endif spin_lock_irqsave(&iommu->lock, flags); @@ -616,7 +632,7 @@ /* Step 1: Kick data out of streaming buffers if necessary. */ if (strbuf->strbuf_enabled) { - u32 vaddr = bus_addr; + u32 vaddr = (u32) bus_addr; PCI_STC_FLUSHFLAG_INIT(strbuf); if (strbuf->strbuf_ctxflush && @@ -735,7 +751,7 @@ iopte_t *iopte; iopte = iommu->page_table + - ((sglist[0].dvma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT); ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; } @@ -754,13 +770,13 @@ unsigned long i, npages; u32 bus_addr; - bus_addr = sglist[0].dvma_address & IO_PAGE_MASK; + bus_addr = sglist[0].dma_address & IO_PAGE_MASK; for(i = 1; i < nelems; i++) - if (!sglist[i].dvma_length) + if (!sglist[i].dma_length) break; i--; - npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE) pci_iommu_write(strbuf->strbuf_pflush, bus_addr); } @@ -774,10 +790,10 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask) +int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) { struct pcidev_cookie *pcp = pdev->sysdata; - u32 dma_addr_mask; + u64 dma_addr_mask; if (pdev == NULL) { dma_addr_mask = 0xffffffff; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c --- /opt/kernel/linux-2.4.10/arch/sparc64/kernel/sbus.c Tue Aug 28 16:09:44 2001 +++ linux/arch/sparc64/kernel/sbus.c Sun Sep 16 23:31:44 2001 @@ -376,17 +376,23 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_bits) +#define SG_ENT_PHYS_ADDRESS(SG) \ + ((SG)->address ? \ + __pa((SG)->address) : \ + (__pa(page_address((SG)->page)) + (SG)->offset)) + +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits) { struct scatterlist *dma_sg = sg; + struct scatterlist *sg_end = sg + nelems; int i; for (i = 0; i < nused; i++) { unsigned long pteval = ~0UL; u32 dma_npages; - dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dvma_length + + dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + + dma_sg->dma_length + ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; do { unsigned long offset; @@ -400,7 +406,7 @@ for (;;) { unsigned long tmp; - tmp = (unsigned long) __pa(sg->address); + tmp = (unsigned long) SG_ENT_PHYS_ADDRESS(sg); len = sg->length; if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { pteval = tmp & IO_PAGE_MASK; @@ -432,10 +438,12 @@ * adjusting pteval along the way. Stop when we * detect a page crossing event. */ - while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - pteval == __pa(sg->address) && + while (sg < sg_end && + (pteval << (64 - PAGE_SHIFT)) != 0UL && + (pteval == SG_ENT_PHYS_ADDRESS(sg)) && ((pteval ^ - (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { + (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) > +> PAGE_SHIFT) == 0UL) { pteval += sg->length; sg++; } @@ -461,8 +469,13 @@ /* Fast path single entry scatterlists. */ if (nents == 1) { - sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length, dir); - sg->dvma_length = sg->length; + sg->dma_address = + sbus_map_single(sdev, + (sg->address ? + sg->address : + (page_address(sg->page) + sg->offset)), + sg->length, dir); + sg->dma_length = sg->length; return 1; } @@ -478,8 +491,8 @@ sgtmp = sg; used = nents; - while (used && sgtmp->dvma_length) { - sgtmp->dvma_address += dma_base; + while (used && sgtmp->dma_length) { + sgtmp->dma_address += dma_base; sgtmp++; used--; } @@ -489,7 +502,7 @@ if (dir != SBUS_DMA_TODEVICE) iopte_bits |= IOPTE_WRITE; - fill_sg(iopte, sg, used, iopte_bits); + fill_sg(iopte, sg, used, nents, iopte_bits); #ifdef VERIFY_SG verify_sglist(sg, nents, iopte, npages); #endif @@ -512,17 +525,18 @@ /* Fast path single entry scatterlists. */ if (nents == 1) { - sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length, direction); + sbus_unmap_single(sdev, sg->dma_address, sg->dma_length, directi +on); return; } - dvma_base = sg[0].dvma_address & IO_PAGE_MASK; + dvma_base = sg[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nents; i++) { - if (sg[i].dvma_length == 0) + if (sg[i].dma_length == 0) break; } i--; - size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base; + size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - dvma_base; iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); @@ -550,13 +564,13 @@ u32 base; int i; - base = sg[0].dvma_address & IO_PAGE_MASK; + base = sg[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nents; i++) { - if (sg[i].dvma_length == 0) + if (sg[i].dma_length == 0) break; } i--; - size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base; + size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; spin_lock_irqsave(&iommu->lock, flags); strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/cciss.c linux/drivers/block/cciss.c --- /opt/kernel/linux-2.4.10/drivers/block/cciss.c Tue Sep 18 23:10:43 2001 +++ linux/drivers/block/cciss.c Mon Sep 24 00:15:35 2001 @@ -612,7 +612,7 @@ { buff = kmalloc(iocommand.buf_size, GFP_KERNEL); if( buff == NULL) - return -EFAULT; + return -ENOMEM; } if (iocommand.Request.Type.Direction == XFER_WRITE) { @@ -681,7 +681,7 @@ { kfree(buff); cmd_free(h, c, 0); - return( -EFAULT); + return( -EFAULT); } if (iocommand.Request.Type.Direction == XFER_READ) @@ -1126,20 +1126,22 @@ static inline void complete_command( CommandList_struct *cmd, int timeout) { int status = 1; - int i; + int i, ddir; u64bit temp64; if (timeout) status = 0; /* unmap the DMA mapping for all the scatter gather elements */ + if (cmd->Request.Type.Direction == XFER_READ) + ddir = PCI_DMA_FROMDEVICE; + else + ddir = PCI_DMA_TODEVICE; for(i=0; iHeader.SGList; i++) { temp64.val32.lower = cmd->SG[i].Addr.lower; temp64.val32.upper = cmd->SG[i].Addr.upper; - pci_unmap_single(hba[cmd->ctlr]->pdev, - temp64.val, cmd->SG[i].Len, - (cmd->Request.Type.Direction == XFER_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + pci_unmap_page(hba[cmd->ctlr]->pdev, + temp64.val, cmd->SG[i].Len, ddir); } if(cmd->err_info->CommandStatus != 0) @@ -1232,7 +1234,7 @@ static int cpq_back_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments) { - if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) + if (BH_CONTIG(rq->bhtail, bh)) return 1; return cpq_new_segment(q, rq, max_segments); } @@ -1240,7 +1242,7 @@ static int cpq_front_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments) { - if (bh->b_data + bh->b_size == rq->bh->b_data) + if (BH_CONTIG(bh, rq->bh)) return 1; return cpq_new_segment(q, rq, max_segments); } @@ -1250,7 +1252,7 @@ { int total_segments = rq->nr_segments + nxt->nr_segments; - if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) + if (BH_CONTIG(rq->bhtail, nxt->bh)) total_segments--; if (total_segments > MAXSGENTRIES) @@ -1271,21 +1273,20 @@ ctlr_info_t *h= q->queuedata; CommandList_struct *c; int log_unit, start_blk, seg, sect; - char *lastdataend; + unsigned long long lastdataend; struct buffer_head *bh; struct list_head *queue_head = &q->queue_head; struct request *creq; u64bit temp64; - struct my_sg tmp_sg[MAXSGENTRIES]; - int i; + struct scatterlist tmp_sg[MAXSGENTRIES]; + int i, ddir; - // Loop till the queue is empty if or it is plugged - while (1) - { - if (q->plugged || list_empty(queue_head)) { - start_io(h); - return; - } + if (q->plugged) + goto startio; + +next: + if (list_empty(queue_head)) + goto startio; creq = blkdev_entry_next_request(queue_head); if (creq->nr_segments > MAXSGENTRIES) @@ -1297,15 +1298,12 @@ h->ctlr, creq->rq_dev, creq); blkdev_dequeue_request(creq); complete_buffers(creq->bh, 0); - start_io(h); - return; + goto startio; } if (( c = cmd_alloc(h, 1)) == NULL) - { - start_io(h); - return; - } + goto startio; + c->cmd_type = CMD_RWREQ; bh = c->bh = creq->bh; @@ -1329,36 +1327,37 @@ printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector, (int) creq->nr_sectors); #endif /* CCISS_DEBUG */ - seg = 0; - lastdataend = NULL; - sect = 0; + seg = sect = 0; + lastdataend = ~0ULL; while(bh) { sect += bh->b_size/512; - if (bh->b_data == lastdataend) + if (bh_phys(bh) == lastdataend) { // tack it on to the last segment - tmp_sg[seg-1].len +=bh->b_size; + tmp_sg[seg-1].length +=bh->b_size; lastdataend += bh->b_size; } else { if (seg == MAXSGENTRIES) BUG(); - tmp_sg[seg].len = bh->b_size; - tmp_sg[seg].start_addr = bh->b_data; - lastdataend = bh->b_data + bh->b_size; + tmp_sg[seg].page = bh->b_page; + tmp_sg[seg].length = bh->b_size; + tmp_sg[seg].offset = bh_offset(bh); + lastdataend = bh_phys(bh) + bh->b_size; seg++; } bh = bh->b_reqnext; } + /* get the DMA records for the setup */ - for (i=0; iSG[i].Len = tmp_sg[i].len; - temp64.val = (__u64) pci_map_single( h->pdev, - tmp_sg[i].start_addr, - tmp_sg[i].len, - (c->Request.Type.Direction == XFER_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + if (c->Request.Type.Direction == XFER_READ) + ddir = PCI_DMA_FROMDEVICE; + else + ddir = PCI_DMA_TODEVICE; + for (i=0; iSG[i].Len = tmp_sg[i].length; + temp64.val = pci_map_page(h->pdev, tmp_sg[i].page, + tmp_sg[i].length, tmp_sg[i].offset, ddir); c->SG[i].Addr.lower = temp64.val32.lower; c->SG[i].Addr.upper = temp64.val32.upper; c->SG[i].Ext = 0; // we are not chaining @@ -1382,10 +1381,8 @@ c->Request.CDB[8]= sect & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; - blkdev_dequeue_request(creq); - /* * ehh, we can't really end the request here since it's not * even started yet. for now it shouldn't hurt though @@ -1399,7 +1396,11 @@ h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - } // while loop + + goto next; + +startio: + start_io(h); } static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -1877,7 +1878,18 @@ sprintf(hba[i]->devname, "cciss%d", i); hba[i]->ctlr = i; hba[i]->pdev = pdev; - + + /* configure PCI DMA stuff */ + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) + printk("cciss: using DAC cycles\n"); + else if (!pci_set_dma_mask(pdev, (u64) 0xffffffff)) + printk("cciss: not using DAC cycles\n"); + else { + printk("cciss: no suitable DMA available\n"); + free_hba(i); + return -ENODEV; + } + if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) { printk(KERN_ERR "cciss: Unable to get major number " @@ -1945,9 +1957,10 @@ cciss_procinit(i); q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); - q->queuedata = hba[i]; - blk_init_queue(q, do_cciss_request); - blk_queue_headactive(q, 0); + q->queuedata = hba[i]; + blk_init_queue(q, do_cciss_request); + blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_headactive(q, 0); /* fill in the other Kernel structs */ blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/cciss.h linux/drivers/block/cciss.h --- /opt/kernel/linux-2.4.10/drivers/block/cciss.h Tue May 22 19:23:16 2001 +++ linux/drivers/block/cciss.h Sun Sep 16 23:31:44 2001 @@ -15,11 +15,6 @@ #define MAJOR_NR COMPAQ_CISS_MAJOR -struct my_sg { - int len; - char *start_addr; -}; - struct ctlr_info; typedef struct ctlr_info ctlr_info_t; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- /opt/kernel/linux-2.4.10/drivers/block/cpqarray.c Tue Sep 18 23:10:43 2001 +++ linux/drivers/block/cpqarray.c Mon Sep 24 00:15:35 2001 @@ -358,7 +358,7 @@ static int cpq_back_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments) { - if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) + if (BH_CONTIG(rq->bhtail, bh)) return 1; return cpq_new_segment(q, rq, max_segments); } @@ -366,7 +366,7 @@ static int cpq_front_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments) { - if (bh->b_data + bh->b_size == rq->bh->b_data) + if (BH_CONTIG(bh, rq->bh)) return 1; return cpq_new_segment(q, rq, max_segments); } @@ -376,7 +376,7 @@ { int total_segments = rq->nr_segments + nxt->nr_segments; - if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) + if (BH_CONTIG(rq->bhtail, nxt->bh)) total_segments--; if (total_segments > SG_MAX) @@ -523,6 +523,7 @@ q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); q->queuedata = hba[i]; blk_init_queue(q, do_ida_request); + blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask); blk_queue_headactive(q, 0); blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); @@ -913,20 +914,19 @@ ctlr_info_t *h = q->queuedata; cmdlist_t *c; int seg, sect; - char *lastdataend; + unsigned long lastdataend; struct list_head * queue_head = &q->queue_head; struct buffer_head *bh; struct request *creq; - struct my_sg tmp_sg[SG_MAX]; + struct scatterlist tmp_sg[SG_MAX]; int i; -// Loop till the queue is empty if or it is plugged - while (1) -{ - if (q->plugged || list_empty(queue_head)) { - start_io(h); - return; - } + if (q->plugged) + goto startio; + +next: + if (list_empty(queue_head)) + goto startio; creq = blkdev_entry_next_request(queue_head); if (creq->nr_segments > SG_MAX) @@ -938,15 +938,11 @@ h->ctlr, creq->rq_dev, creq); blkdev_dequeue_request(creq); complete_buffers(creq->bh, 0); - start_io(h); - return; + goto startio; } if ((c = cmd_alloc(h,1)) == NULL) - { - start_io(h); - return; - } + goto startio; bh = creq->bh; @@ -963,19 +959,20 @@ printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors); ); - seg = 0; lastdataend = NULL; - sect = 0; + seg = sect = 0; + lastdataend = ~0UL; while(bh) { sect += bh->b_size/512; - if (bh->b_data == lastdataend) { - tmp_sg[seg-1].size += bh->b_size; + if (bh_phys(bh) == lastdataend) { + tmp_sg[seg-1].length += bh->b_size; lastdataend += bh->b_size; } else { if (seg == SG_MAX) BUG(); - tmp_sg[seg].size = bh->b_size; - tmp_sg[seg].start_addr = bh->b_data; - lastdataend = bh->b_data + bh->b_size; + tmp_sg[seg].page = bh->b_page; + tmp_sg[seg].length = bh->b_size; + tmp_sg[seg].offset = bh_offset(bh); + lastdataend = bh_phys(bh) + bh->b_size; seg++; } bh = bh->b_reqnext; @@ -983,10 +980,10 @@ /* Now do all the DMA Mappings */ for( i=0; i < seg; i++) { - c->req.sg[i].size = tmp_sg[i].size; - c->req.sg[i].addr = (__u32) pci_map_single( - h->pci_dev, tmp_sg[i].start_addr, - tmp_sg[i].size, + c->req.sg[i].size = tmp_sg[i].length; + c->req.sg[i].addr = (__u32) pci_map_page( + h->pci_dev, tmp_sg[i].page, tmp_sg[i].length, + tmp_sg[i].offset, (creq->cmd == READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } @@ -1020,7 +1017,11 @@ h->Qdepth++; if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - } // while loop + + goto next; + +startio: + start_io(h); } /* @@ -1093,7 +1094,7 @@ /* unmap the DMA mapping for all the scatter gather elements */ for(i=0; ireq.hdr.sg_cnt; i++) { - pci_unmap_single(hba[cmd->ctlr]->pci_dev, + pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr, cmd->req.sg[i].size, (cmd->req.hdr.cmd == IDA_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- /opt/kernel/linux-2.4.10/drivers/block/cpqarray.h Tue May 22 19:23:16 2001 +++ linux/drivers/block/cpqarray.h Sun Sep 16 23:31:44 2001 @@ -56,11 +56,6 @@ #ifdef __KERNEL__ -struct my_sg { - int size; - char *start_addr; -}; - struct ctlr_info; typedef struct ctlr_info ctlr_info_t; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/elevator.c linux/drivers/block/elevator.c --- /opt/kernel/linux-2.4.10/drivers/block/elevator.c Fri Jul 20 05:59:41 2001 +++ linux/drivers/block/elevator.c Sun Sep 16 23:31:44 2001 @@ -110,7 +110,6 @@ break; } else if (__rq->sector - count == bh->b_rsector) { ret = ELEVATOR_FRONT_MERGE; - __rq->elevator_sequence -= count; *req = __rq; break; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- /opt/kernel/linux-2.4.10/drivers/block/ll_rw_blk.c Fri Sep 21 06:02:01 2001 +++ linux/drivers/block/ll_rw_blk.c Mon Sep 24 01:08:46 2001 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -123,6 +124,8 @@ */ static int queue_nr_requests, batch_requests; +unsigned long blk_max_low_pfn; + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -244,6 +247,59 @@ q->make_request_fn = mfn; } +/** + * blk_queue_bounce_limit - set bounce buffer limit for queue + * @q: the request queue for the device + * @dma_addr: bus address limit + * + * Description: + * Different hardware can have different requirements as to what pages + * it can do I/O directly to. A low level driver can call + * blk_queue_bounce_limit to have lower memory pages allocated as bounce + * buffers for doing I/O to pages residing above @page. By default + * the block layer sets this to the highest numbered "low" memory page. + **/ +void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr) +{ + struct page *bounce_page = mem_map + (dma_addr >> PAGE_SHIFT); + unsigned long mb = dma_addr >> 20; + + /* + * just make sure that no pages are considered above this one... + */ + if (dma_addr == BLK_BOUNCE_ANY) + bounce_page = (struct page *) BLK_BOUNCE_ANY; + + /* + * keep this for debugging for now... + */ + if (dma_addr != BLK_BOUNCE_HIGH) { + printk("blk: queue %p, ", q); + if (dma_addr == BLK_BOUNCE_ANY) + printk("no I/O memory limit\n"); + else + printk("I/O limit %luMb (mask 0x%Lx)\n", mb, (u64) dma_addr); + } + + q->bounce_limit = bounce_page; +} + + +/* + * can we merge the two segments, or do we need to start a new one? + */ +inline int blk_seg_merge_ok(request_queue_t *q, struct buffer_head *bh, + struct buffer_head *nxt) +{ + if (!BH_CONTIG(bh, nxt)) + return 0; + + if (BH_PHYS_4G(bh, nxt)) + return 1; + + return 0; +} + static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments) { if (req->nr_segments < max_segments) { @@ -256,16 +312,18 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req, struct buffer_head *bh, int max_segments) { - if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data) + if (blk_seg_merge_ok(q, req->bhtail, bh)) return 1; + return ll_new_segment(q, req, max_segments); } static int ll_front_merge_fn(request_queue_t *q, struct request *req, struct buffer_head *bh, int max_segments) { - if (bh->b_data + bh->b_size == req->bh->b_data) + if (blk_seg_merge_ok(q, bh, req->bh)) return 1; + return ll_new_segment(q, req, max_segments); } @@ -274,7 +332,7 @@ { int total_segments = req->nr_segments + next->nr_segments; - if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) + if (blk_seg_merge_ok(q, req->bhtail, next->bh)) total_segments--; if (total_segments > max_segments) @@ -413,6 +471,8 @@ */ q->plug_device_fn = generic_plug_device; q->head_active = 1; + + blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); } #define blkdev_free_rq(list) list_entry((list)->next, struct request, table); @@ -679,9 +739,7 @@ * driver. Create a bounce buffer if the buffer data points into * high memory - keep the original buffer otherwise. */ -#if CONFIG_HIGHMEM - bh = create_bounce(rw, bh); -#endif + bh = blk_queue_bounce(q, rw, bh); /* look for a free request. */ /* @@ -726,8 +784,13 @@ elevator->elevator_merge_cleanup_fn(q, req, count); bh->b_reqnext = req->bh; req->bh = bh; + /* + * may not be valid, but queues not having bounce + * enabled for highmem pages must not look at + * ->buffer anyway + */ req->buffer = bh->b_data; - req->current_nr_sectors = count; + req->current_nr_sectors = req->hard_cur_sectors = count; req->sector = req->hard_sector = sector; req->nr_sectors = req->hard_nr_sectors += count; blk_started_io(count); @@ -777,7 +840,7 @@ req->errors = 0; req->hard_sector = req->sector = sector; req->hard_nr_sectors = req->nr_sectors = count; - req->current_nr_sectors = count; + req->current_nr_sectors = req->hard_cur_sectors = count; req->nr_segments = 1; /* Always 1 for a new request. */ req->nr_hw_segments = 1; /* Always 1 for a new request. */ req->buffer = bh->b_data; @@ -1082,6 +1145,7 @@ req->nr_sectors = req->hard_nr_sectors; req->current_nr_sectors = bh->b_size >> 9; + req->hard_cur_sectors = req->current_nr_sectors; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; printk("end_request: buffer-list destroyed\n"); @@ -1130,7 +1194,7 @@ */ queue_nr_requests = 64; if (total_ram > MB(32)) - queue_nr_requests = 128; + queue_nr_requests = 256; /* * Batch frees according to queue length @@ -1138,6 +1202,8 @@ batch_requests = queue_nr_requests >> 3; printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); + blk_max_low_pfn = max_low_pfn; + #ifdef CONFIG_AMIGA_Z2RAM z2_init(); #endif @@ -1256,3 +1322,6 @@ EXPORT_SYMBOL(generic_make_request); EXPORT_SYMBOL(blkdev_release_request); EXPORT_SYMBOL(generic_unplug_device); +EXPORT_SYMBOL(blk_queue_bounce_limit); +EXPORT_SYMBOL(blk_max_low_pfn); +EXPORT_SYMBOL(blk_seg_merge_ok); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/block/loop.c linux/drivers/block/loop.c --- /opt/kernel/linux-2.4.10/drivers/block/loop.c Mon Sep 17 22:16:30 2001 +++ linux/drivers/block/loop.c Mon Sep 24 00:15:36 2001 @@ -472,9 +472,7 @@ goto err; } -#if CONFIG_HIGHMEM - rbh = create_bounce(rw, rbh); -#endif + rbh = blk_queue_bounce(q, rw, rbh); /* * file backed, queue for loop_thread to handle diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c --- /opt/kernel/linux-2.4.10/drivers/ide/hpt34x.c Sun May 20 02:43:06 2001 +++ linux/drivers/ide/hpt34x.c Sun Sep 16 23:31:44 2001 @@ -425,6 +425,7 @@ hwif->autodma = 0; hwif->dmaproc = &hpt34x_dmaproc; + hwif->highmem = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c --- /opt/kernel/linux-2.4.10/drivers/ide/hpt366.c Wed Aug 15 05:01:07 2001 +++ linux/drivers/ide/hpt366.c Sun Sep 16 23:31:44 2001 @@ -730,6 +730,7 @@ hwif->autodma = 1; else hwif->autodma = 0; + hwif->highmem = 1; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- /opt/kernel/linux-2.4.10/drivers/ide/ide-cd.c Thu Aug 16 18:30:45 2001 +++ linux/drivers/ide/ide-cd.c Mon Sep 24 00:33:24 2001 @@ -694,7 +694,7 @@ case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: - wait = WAIT_CMD; + wait = ATAPI_WAIT_PC; break; default: wait = 0; @@ -745,7 +745,7 @@ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { - ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); + ide_set_handler (drive, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ return ide_started; } else { @@ -1009,7 +1009,7 @@ /* Done moving data! Wait for another interrupt. */ - ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1125,7 +1125,7 @@ pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); - pc.timeout = WAIT_CMD; + pc.timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr); @@ -1134,7 +1134,7 @@ #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) { @@ -1178,7 +1178,7 @@ pc.c[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); - pc.timeout = WAIT_CMD; + pc.timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr); } @@ -1399,7 +1399,7 @@ } /* Now we wait for another interrupt. */ - ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); + ide_set_handler (drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } @@ -1410,7 +1410,7 @@ struct packet_command *pc = (struct packet_command *)rq->buffer; if (!pc->timeout) - pc->timeout = WAIT_CMD; + pc->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr); @@ -1626,7 +1626,7 @@ } /* re-arm handler */ - ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1651,7 +1651,7 @@ pc.c[7] = (nframes >> 8) & 0xff; pc.c[8] = nframes & 0xff; put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]); - pc.timeout = 2 * WAIT_CMD; + pc.timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr); } @@ -2190,7 +2190,7 @@ ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (cgc->timeout <= 0) - cgc->timeout = WAIT_CMD; + cgc->timeout = ATAPI_WAIT_PC; /* here we queue the commands from the uniform CD-ROM layer. the packet must be complete, as we do not @@ -2633,7 +2633,9 @@ CDROM_CONFIG_FLAGS (drive)->test_write = 1; if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS (drive)->dvd = 1; +#if 0 if (cap.dvd_ram_write) +#endif CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; if (cap.dvd_r_write) CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h --- /opt/kernel/linux-2.4.10/drivers/ide/ide-cd.h Sun Sep 23 19:32:30 2001 +++ linux/drivers/ide/ide-cd.h Mon Sep 24 00:30:52 2001 @@ -35,6 +35,11 @@ #define NO_DOOR_LOCKING 0 #endif +/* + * typical timeout for packet command + */ +#define ATAPI_WAIT_PC (60 * HZ) + /************************************************************************/ #define SECTOR_BITS 9 diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c --- /opt/kernel/linux-2.4.10/drivers/ide/ide-disk.c Mon Aug 13 23:56:19 2001 +++ linux/drivers/ide/ide-disk.c Sun Sep 16 23:31:44 2001 @@ -27,9 +27,10 @@ * Version 1.09 added increment of rq->sector in ide_multwrite * added UDMA 3/4 reporting * Version 1.10 request queue changes, Ultra DMA 100 + * Version 1.11 Highmem I/O support, Jens Axboe */ -#define IDEDISK_VERSION "1.10" +#define IDEDISK_VERSION "1.11" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -139,7 +140,9 @@ byte stat; int i; unsigned int msect, nsect; + unsigned long flags; struct request *rq; + char *to; /* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { @@ -150,8 +153,8 @@ ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); return ide_started; } + msect = drive->mult_count; - read_next: rq = HWGROUP(drive)->rq; if (msect) { @@ -160,14 +163,15 @@ msect -= nsect; } else nsect = 1; - idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); + to = ide_map_buffer(rq, &flags); + idedisk_input_data(drive, to, nsect * SECTOR_WORDS); #ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); #endif + ide_unmap_buffer(to, &flags); rq->sector += nsect; - rq->buffer += nsect<<9; rq->errors = 0; i = (rq->nr_sectors -= nsect); if (((long)(rq->current_nr_sectors -= nsect)) <= 0) @@ -201,14 +205,16 @@ #endif if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { rq->sector++; - rq->buffer += 512; rq->errors = 0; i = --rq->nr_sectors; --rq->current_nr_sectors; if (((long)rq->current_nr_sectors) <= 0) ide_end_request(1, hwgroup); if (i > 0) { - idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); + unsigned long flags; + char *to = ide_map_buffer(rq, &flags); + idedisk_output_data (drive, to, SECTOR_WORDS); + ide_unmap_buffer(to, &flags); ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); return ide_started; } @@ -238,14 +244,14 @@ do { char *buffer; int nsect = rq->current_nr_sectors; - + unsigned long flags; + if (nsect > mcount) nsect = mcount; mcount -= nsect; - buffer = rq->buffer; + buffer = ide_map_buffer(rq, &flags); rq->sector += nsect; - rq->buffer += nsect << 9; rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect; @@ -259,7 +265,7 @@ } else { rq->bh = bh; rq->current_nr_sectors = bh->b_size >> 9; - rq->buffer = bh->b_data; + rq->hard_cur_sectors = rq->current_nr_sectors; } } @@ -268,6 +274,7 @@ * re-entering us on the last transfer. */ idedisk_output_data(drive, buffer, nsect<<7); + ide_unmap_buffer(buffer, &flags); } while (mcount); return 0; @@ -452,8 +459,11 @@ return ide_stopped; } } else { + unsigned long flags; + char *buffer = ide_map_buffer(rq, &flags); ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); - idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); + idedisk_output_data(drive, buffer, SECTOR_WORDS); + ide_unmap_buffer(buffer, &flags); } return ide_started; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c --- /opt/kernel/linux-2.4.10/drivers/ide/ide-dma.c Sun Sep 9 19:43:02 2001 +++ linux/drivers/ide/ide-dma.c Sun Sep 16 23:31:44 2001 @@ -251,33 +251,48 @@ { struct buffer_head *bh; struct scatterlist *sg = hwif->sg_table; + unsigned long lastdataend = ~0UL; int nents = 0; if (hwif->sg_dma_active) BUG(); - + if (rq->cmd == READ) hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; else hwif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; do { - unsigned char *virt_addr = bh->b_data; - unsigned int size = bh->b_size; + /* + * continue segment from before? + */ + if (bh_phys(bh) == lastdataend) { + sg[nents - 1].length += bh->b_size; + lastdataend += bh->b_size; + } else { + struct scatterlist *sge; + /* + * start new segment + */ + if (nents >= PRD_ENTRIES) + return 0; - if (nents >= PRD_ENTRIES) - return 0; + sge = &sg[nents]; + memset(sge, 0, sizeof(*sge)); + if ((sge->page = bh->b_page)) + sge->offset = bh_offset(bh); + else { + if (((unsigned long) bh->b_data) < PAGE_SIZE) + BUG(); + sge->address = bh->b_data; + } - while ((bh = bh->b_reqnext) != NULL) { - if ((virt_addr + size) != (unsigned char *) bh->b_data) - break; - size += bh->b_size; + sge->length = bh->b_size; + lastdataend = bh_phys(bh) + bh->b_size; + nents++; } - memset(&sg[nents], 0, sizeof(*sg)); - sg[nents].address = virt_addr; - sg[nents].length = size; - nents++; - } while (bh != NULL); + } while ((bh = bh->b_reqnext) != NULL); return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } @@ -305,7 +320,7 @@ return 0; sg = HWIF(drive)->sg_table; - while (i && sg_dma_len(sg)) { + while (i) { u32 cur_addr; u32 cur_len; @@ -319,36 +334,35 @@ */ while (cur_len) { - if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); - goto use_pio_instead; - } else { - u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); - - if (bcount > cur_len) - bcount = cur_len; - *table++ = cpu_to_le32(cur_addr); - xcount = bcount & 0xffff; - if (is_trm290_chipset) - xcount = ((xcount >> 2) - 1) << 16; - if (xcount == 0x0000) { - /* - * Most chipsets correctly interpret a length of 0x0000 as 64KB, - * but at least one (e.g. CS5530) misinterprets it as zero (!). - * So here we break the 64KB entry into two 32KB entries instead. - */ - if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); - goto use_pio_instead; - } - *table++ = cpu_to_le32(0x8000); - *table++ = cpu_to_le32(cur_addr + 0x8000); - xcount = 0x8000; - } - *table++ = cpu_to_le32(xcount); - cur_addr += bcount; - cur_len -= bcount; + u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); + + if (count++ >= PRD_ENTRIES) + BUG(); + + if (bcount > cur_len) + bcount = cur_len; + *table++ = cpu_to_le32(cur_addr); + xcount = bcount & 0xffff; + if (is_trm290_chipset) + xcount = ((xcount >> 2) - 1) << 16; + if (xcount == 0x0000) { + /* + * Most chipsets correctly interpret a length + * of 0x0000 as 64KB, but at least one + * (e.g. CS5530) misinterprets it as zero (!). + * So here we break the 64KB entry into two + * 32KB entries instead. + */ + if (count++ >= PRD_ENTRIES) + goto use_pio_instead; + + *table++ = cpu_to_le32(0x8000); + *table++ = cpu_to_le32(cur_addr + 0x8000); + xcount = 0x8000; } + *table++ = cpu_to_le32(xcount); + cur_addr += bcount; + cur_len -= bcount; } sg++; @@ -532,6 +546,20 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ +static inline void ide_toggle_bounce(ide_drive_t *drive, int on) +{ + dma64_addr_t addr = BLK_BOUNCE_HIGH; + + if (on && drive->media == ide_disk && HWIF(drive)->highmem) { + if (!PCI_DMA_BUS_IS_PHYS) + addr = BLK_BOUNCE_ANY; + else + addr = HWIF(drive)->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(&drive->queue, addr); +} + /* * ide_dmaproc() initiates/aborts DMA read/write operations on a drive. * @@ -554,18 +582,20 @@ ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); - unsigned int count, reading = 0; + unsigned int count, reading = 0, set_high = 1; byte dma_stat; switch (func) { case ide_dma_off: printk("%s: DMA disabled\n", drive->name); + set_high = 0; case ide_dma_off_quietly: outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); case ide_dma_on: drive->using_dma = (func == ide_dma_on); if (drive->using_dma) outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + ide_toggle_bounce(drive, set_high); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -696,8 +726,8 @@ request_region(dma_base, num_ports, hwif->name); hwif->dma_base = dma_base; hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, - PRD_ENTRIES * PRD_BYTES, - &hwif->dmatable_dma); + PRD_ENTRIES * PRD_BYTES, + &hwif->dmatable_dma); if (hwif->dmatable_cpu == NULL) goto dma_alloc_failure; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c --- /opt/kernel/linux-2.4.10/drivers/ide/pdc202xx.c Fri Sep 7 18:28:38 2001 +++ linux/drivers/ide/pdc202xx.c Sun Sep 16 23:31:44 2001 @@ -892,6 +892,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; + hwif->highmem = 1; if (!noautodma) hwif->autodma = 1; } else { diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/ide/piix.c linux/drivers/ide/piix.c --- /opt/kernel/linux-2.4.10/drivers/ide/piix.c Mon Aug 13 23:56:19 2001 +++ linux/drivers/ide/piix.c Sun Sep 16 23:31:44 2001 @@ -521,6 +521,7 @@ if (!hwif->dma_base) return; + hwif->highmem = 1; #ifndef CONFIG_BLK_DEV_IDEDMA hwif->autodma = 0; #else /* CONFIG_BLK_DEV_IDEDMA */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/net/acenic.c linux/drivers/net/acenic.c --- /opt/kernel/linux-2.4.10/drivers/net/acenic.c Mon Sep 10 17:06:32 2001 +++ linux/drivers/net/acenic.c Sun Sep 16 23:31:44 2001 @@ -161,10 +161,6 @@ #define SMP_CACHE_BYTES L1_CACHE_BYTES #endif -#if (BITS_PER_LONG == 64) -#define ACE_64BIT_PTR 1 -#endif - #ifndef SET_MODULE_OWNER #define SET_MODULE_OWNER(dev) {do{} while(0);} #define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT @@ -199,9 +195,15 @@ *dma_handle = virt_to_bus(virt_ptr); return virt_ptr; } + #define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) -#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) -#define pci_unmap_single(cookie, address, size, dir) +#define pci_map_page(cookie, page, off, size, dir) \ + virt_to_bus(page_address(page)+(off)) +#define pci_unmap_page(cookie, address, size, dir) +#define pci_set_dma_mask(dev, mask) \ + (((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO) +#define pci_dma_supported(dev, mask) \ + (((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0) #endif #if (LINUX_VERSION_CODE < 0x02032b) @@ -259,11 +261,6 @@ #define ace_if_down(dev) {do{} while(0);} #endif -#ifndef pci_set_dma_mask -#define pci_set_dma_mask(dev, mask) dev->dma_mask = mask; -#endif - - #if (LINUX_VERSION_CODE >= 0x02031b) #define NEW_NETINIT #define ACE_PROBE_ARG void @@ -585,7 +582,7 @@ dev->irq = pdev->irq; dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (1) { static void ace_watchdog(struct net_device *dev); dev->tx_timeout = &ace_watchdog; @@ -727,6 +724,8 @@ kfree(dev); continue; } + if (ap->pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; boards_found++; } @@ -793,14 +792,12 @@ struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; if (skb) { -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_std_skbuff[i].mapping; - pci_unmap_single(ap->pdev, mapping, - ACE_STD_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); -#endif + pci_unmap_page(ap->pdev, mapping, + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->rx_std_ring[i].size = 0; ap->skb->rx_std_skbuff[i].skb = NULL; @@ -812,14 +809,13 @@ struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; if (skb) { -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_mini_skbuff[i].mapping; - pci_unmap_single(ap->pdev, mapping, - ACE_MINI_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); -#endif + pci_unmap_page(ap->pdev, mapping, + ACE_MINI_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); + ap->rx_mini_ring[i].size = 0; ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); @@ -829,14 +825,12 @@ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_jumbo_skbuff[i].mapping; - pci_unmap_single(ap->pdev, mapping, - ACE_JUMBO_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); -#endif + pci_unmap_page(ap->pdev, mapping, + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->rx_jumbo_ring[i].size = 0; ap->skb->rx_jumbo_skbuff[i].skb = NULL; @@ -1195,12 +1189,6 @@ ap->pci_latency); /* - * Make sure to enable the 64 bit DMA mask if we're in a 64bit slot - */ - if (!(pci_state & PCI_32BIT)) - pci_set_dma_mask(ap->pdev, (dma_addr_t)~0ULL); - - /* * Set the max DMA transfer size. Seems that for most systems * the performance is better when no MAX parameter is * set. However for systems enabling PCI write and invalidate, @@ -1294,12 +1282,24 @@ #endif /* + * Configure DMA attributes. + */ + if (!pci_set_dma_mask(ap->pdev, (u64) 0xffffffffffffffff)) { + ap->pci_using_dac = 1; + } else if (!pci_set_dma_mask(ap->pdev, (u64) 0xffffffff)) { + ap->pci_using_dac = 0; + } else { + ecode = -ENODEV; + goto init_error; + } + + /* * Initialize the generic info block and the command+event rings * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ if (!(info = pci_alloc_consistent(ap->pdev, sizeof(struct ace_info), - &ap->info_dma))) { + &ap->info_dma))) { ecode = -EAGAIN; goto init_error; } @@ -1340,12 +1340,8 @@ ace_load_firmware(dev); ap->fw_running = 0; - tmp_ptr = (unsigned long) ap->info_dma; -#ifdef ACE_64BIT_PTR + tmp_ptr = (u64) ap->info_dma; writel(tmp_ptr >> 32, ®s->InfoPtrHi); -#else - writel(0, ®s->InfoPtrHi); -#endif writel(tmp_ptr & 0xffffffff, ®s->InfoPtrLo); memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event)); @@ -1779,13 +1775,14 @@ * Make sure IP header starts on a fresh cache line. */ skb_reserve(skb, 2 + 16); - mapping = pci_map_single(ap->pdev, skb->data, - ACE_STD_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); + mapping = pci_map_page(ap->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; -#ifndef DUMMY_PCI_UNMAP ap->skb->rx_std_skbuff[idx].mapping = mapping; -#endif rd = &ap->rx_std_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1843,13 +1840,14 @@ * Make sure the IP header ends up on a fresh cache line */ skb_reserve(skb, 2 + 16); - mapping = pci_map_single(ap->pdev, skb->data, - ACE_MINI_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); + mapping = pci_map_page(ap->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + ACE_MINI_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; -#ifndef DUMMY_PCI_UNMAP ap->skb->rx_mini_skbuff[idx].mapping = mapping; -#endif rd = &ap->rx_mini_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1904,13 +1902,14 @@ * Make sure the IP header ends up on a fresh cache line */ skb_reserve(skb, 2 + 16); - mapping = pci_map_single(ap->pdev, skb->data, - ACE_JUMBO_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); + mapping = pci_map_page(ap->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_jumbo_skbuff[idx].skb = skb; -#ifndef DUMMY_PCI_UNMAP ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; -#endif rd = &ap->rx_jumbo_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -2113,10 +2112,8 @@ skb = rip->skb; rip->skb = NULL; -#ifndef DUMMY_PCI_UNMAP - pci_unmap_single(ap->pdev, rip->mapping, mapsize, - PCI_DMA_FROMDEVICE); -#endif + pci_unmap_page(ap->pdev, rip->mapping, mapsize, + PCI_DMA_FROMDEVICE); skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -2180,22 +2177,19 @@ do { struct sk_buff *skb; -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; -#endif struct tx_ring_info *info; info = ap->skb->tx_skbuff + idx; skb = info->skb; -#ifndef DUMMY_PCI_UNMAP mapping = info->mapping; if (mapping) { - pci_unmap_single(ap->pdev, mapping, info->maplen, - PCI_DMA_TODEVICE); + pci_unmap_page(ap->pdev, mapping, info->maplen, + PCI_DMA_TODEVICE); info->mapping = 0; } -#endif + if (skb) { ap->stats.tx_packets++; ap->stats.tx_bytes += skb->len; @@ -2472,23 +2466,19 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { struct sk_buff *skb; -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; -#endif struct tx_ring_info *info; info = ap->skb->tx_skbuff + i; skb = info->skb; -#ifndef DUMMY_PCI_UNMAP mapping = info->mapping; if (mapping) { memset(ap->tx_ring+i, 0, sizeof(struct tx_desc)); - pci_unmap_single(ap->pdev, mapping, info->maplen, - PCI_DMA_TODEVICE); + pci_unmap_page(ap->pdev, mapping, info->maplen, + PCI_DMA_TODEVICE); info->mapping = 0; } -#endif if (skb) { dev_kfree_skb(skb); info->skb = NULL; @@ -2508,79 +2498,35 @@ return 0; } - -/* - * Following below should be (in more clean form!) in arch/ARCH/kernel/pci_*. - * For now, let it stay here. - */ -#if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS -#ifndef DUMMY_PCI_UNMAP -#error Sorry, cannot DMA from high memory on this architecture. -#endif - -#if defined(CONFIG_X86) -#define DMAADDR_OFFSET 0 -typedef unsigned long long dmaaddr_high_t; -#elif defined(CONFIG_PPC) -#define DMAADDR_OFFSET PCI_DRAM_OFFSET -typedef unsigned long dmaaddr_high_t; -#endif - - -static inline dmaaddr_high_t -pci_map_single_high(struct pci_dev *hwdev, struct page *page, - int offset, size_t size, int dir) -{ - dmaaddr_high_t phys; - - phys = (page-mem_map) * (dmaaddr_high_t) PAGE_SIZE + offset; - - return (phys + DMAADDR_OFFSET); -} - -#else - -typedef unsigned long dmaaddr_high_t; - -static inline dmaaddr_high_t -pci_map_single_high(struct pci_dev *hwdev, struct page *page, - int offset, size_t size, int dir) -{ - return pci_map_single(hwdev, page_address(page) + offset, size, dir); -} - -#endif - - -static inline dmaaddr_high_t +static inline dma_addr_t ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb, struct sk_buff *tail, u32 idx) { unsigned long addr; struct tx_ring_info *info; - addr = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + addr = pci_map_page(ap->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + skb->len, PCI_DMA_TODEVICE); info = ap->skb->tx_skbuff + idx; info->skb = tail; -#ifndef DUMMY_PCI_UNMAP info->mapping = addr; info->maplen = skb->len; -#endif return addr; } static inline void -ace_load_tx_bd(struct tx_desc *desc, dmaaddr_high_t addr, u32 flagsize) +ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize) { #if !USE_TX_COAL_NOW flagsize &= ~BD_FLG_COAL_NOW; #endif -#ifdef ACE_64BIT_PTR desc->addr.addrhi = addr >> 32; -#endif desc->addr.addrlo = addr; desc->flagsize = flagsize; } @@ -2642,16 +2588,16 @@ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; struct tx_ring_info *info; - dmaaddr_high_t phys; + dma_addr_t phys; len += frag->size; info = ap->skb->tx_skbuff + idx; desc = ap->tx_ring + idx; - phys = pci_map_single_high(ap->pdev, frag->page, - frag->page_offset, - frag->size, - PCI_DMA_TODEVICE); + phys = pci_map_page(ap->pdev, frag->page, + frag->page_offset, + frag->size, + PCI_DMA_TODEVICE); flagsize = (frag->size << 16); if (skb->ip_summed == CHECKSUM_HW) @@ -2671,10 +2617,8 @@ } else { info->skb = NULL; } -#ifndef DUMMY_PCI_UNMAP info->mapping = phys; info->maplen = frag->size; -#endif ace_load_tx_bd(desc, phys, flagsize); } } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/net/acenic.h linux/drivers/net/acenic.h --- /opt/kernel/linux-2.4.10/drivers/net/acenic.h Thu Jun 28 23:47:10 2001 +++ linux/drivers/net/acenic.h Sun Sep 16 23:31:44 2001 @@ -582,16 +582,9 @@ aceaddr stats2_ptr; }; -#if defined(CONFIG_X86) || defined(CONFIG_PPC) -/* Intel has null pci_unmap_single, no reasons to remember mapping. */ -#define DUMMY_PCI_UNMAP -#endif - struct ring_info { struct sk_buff *skb; -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; -#endif }; /* Funny... As soon as we add maplen on alpha, it starts to work @@ -600,10 +593,8 @@ */ struct tx_ring_info { struct sk_buff *skb; -#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; int maplen; -#endif }; /* @@ -691,6 +682,7 @@ u32 last_tx, last_std_rx, last_mini_rx; #endif struct net_device_stats stats; + int pci_using_dac; }; @@ -712,31 +704,11 @@ static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr) { - unsigned long baddr = (unsigned long) addr; -#ifdef ACE_64BIT_PTR + u64 baddr = (u64) addr; aa->addrlo = baddr & 0xffffffff; aa->addrhi = baddr >> 32; -#else - /* Don't bother setting zero every time */ - aa->addrlo = baddr; -#endif - mb(); -} - - -#if 0 -static inline void *get_aceaddr(aceaddr *aa) -{ - unsigned long addr; mb(); -#ifdef ACE_64BIT_PTR - addr = (u64)aa->addrhi << 32 | aa->addrlo; -#else - addr = aa->addrlo; -#endif - return (void *)addr; } -#endif static inline void ace_set_txprd(struct ace_regs *regs, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- /opt/kernel/linux-2.4.10/drivers/net/sk98lin/skge.c Tue Aug 7 17:30:50 2001 +++ linux/drivers/net/sk98lin/skge.c Sun Sep 16 23:31:44 2001 @@ -443,6 +443,11 @@ if (pci_enable_device(pdev)) continue; + /* Configure DMA attributes. */ + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + pci_set_dma_mask(pdev, (u64) 0xffffffff)) + continue; + if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); @@ -1769,10 +1774,12 @@ #endif /* set up descriptor and CONTROL dword */ - PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, - pMessage->data, - pMessage->len, - PCI_DMA_TODEVICE); + PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev, + virt_to_page(pMessage->data), + ((unsigned long) pMessage->data & + ~PAGE_MASK), + pMessage->len, + PCI_DMA_TODEVICE); pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; @@ -1864,9 +1871,9 @@ /* release the DMA mapping */ PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; PhysAddr |= (SK_U64) pTxd->VDataLow; - pci_unmap_single(&pAC->PciDev, PhysAddr, - pTxd->pMBuf->len, - PCI_DMA_TODEVICE); + pci_unmap_page(&pAC->PciDev, PhysAddr, + pTxd->pMBuf->len, + PCI_DMA_TODEVICE); /* free message */ DEV_KFREE_SKB_ANY(pTxd->pMBuf); @@ -1945,10 +1952,12 @@ pRxPort->pRxdRingTail = pRxd->pNextRxd; pRxPort->RxdRingFree--; Length = pAC->RxBufSize; - PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, - pMsgBlock->data, - pAC->RxBufSize - 2, - PCI_DMA_FROMDEVICE); + PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev, + virt_to_page(pMsgBlock->data), + ((unsigned long) pMsgBlock->data & + ~PAGE_MASK), + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pRxd->pMBuf = pMsgBlock; @@ -2092,9 +2101,9 @@ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; pci_dma_sync_single(&pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); @@ -2116,9 +2125,9 @@ skb_reserve(pNewMsg, 2); skb_put(pNewMsg, FrameLength); pci_dma_sync_single(&pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); ReQueueRxBuffer(pAC, pRxPort, pMsg, @@ -2136,10 +2145,10 @@ PhysAddr |= (SK_U64) pRxd->VDataLow; /* release the DMA mapping */ - pci_unmap_single(&pAC->PciDev, - PhysAddr, - pAC->RxBufSize - 2, - PCI_DMA_FROMDEVICE); + pci_unmap_page(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); /* set length in message */ skb_put(pMsg, FrameLength); @@ -2261,10 +2270,10 @@ /* release the DMA mapping */ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_unmap_single(&pAC->PciDev, - PhysAddr, - pAC->RxBufSize - 2, - PCI_DMA_FROMDEVICE); + pci_unmap_page(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); DEV_KFREE_SKB_IRQ(pRxd->pMBuf); pRxd->pMBuf = NULL; pRxPort->RxdRingFree++; @@ -2341,10 +2350,10 @@ if (pRxd->pMBuf != NULL) { PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_unmap_single(&pAC->PciDev, - PhysAddr, - pAC->RxBufSize - 2, - PCI_DMA_FROMDEVICE); + pci_unmap_page(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); DEV_KFREE_SKB(pRxd->pMBuf); pRxd->pMBuf = NULL; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/net/sungem.c linux/drivers/net/sungem.c --- /opt/kernel/linux-2.4.10/drivers/net/sungem.c Thu Sep 20 23:11:57 2001 +++ linux/drivers/net/sungem.c Mon Sep 24 00:15:36 2001 @@ -416,7 +416,8 @@ while (entry != limit) { struct sk_buff *skb; struct gem_txd *txd; - u32 dma_addr, dma_len; + dma_addr_t dma_addr; + u32 dma_len; int frag; skb = gp->tx_skbs[entry]; @@ -442,10 +443,10 @@ for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &gp->init_block->txd[entry]; - dma_addr = (u32) le64_to_cpu(txd->buffer); + dma_addr = le64_to_cpu(txd->buffer); dma_len = le64_to_cpu(txd->control_word) & TXDCTRL_BUFSZ; - pci_unmap_single(gp->pdev, dma_addr, dma_len, PCI_DMA_TODEVICE); + pci_unmap_page(gp->pdev, dma_addr, dma_len, PCI_DMA_TODEVICE); entry = NEXT_TX(entry); } @@ -496,7 +497,7 @@ struct gem_rxd *rxd = &gp->init_block->rxd[entry]; struct sk_buff *skb; u64 status = cpu_to_le64(rxd->status_word); - u32 dma_addr; + dma_addr_t dma_addr; int len; if ((status & RXDCTRL_OWN) != 0) @@ -518,7 +519,7 @@ goto next; } - dma_addr = (u32) cpu_to_le64(rxd->buffer); + dma_addr = cpu_to_le64(rxd->buffer); if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; @@ -527,15 +528,18 @@ drops++; goto drop_it; } - pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); + pci_unmap_page(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE(gp), + PCI_DMA_FROMDEVICE); gp->rx_skbs[entry] = new_skb; new_skb->dev = gp->dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); - rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev, - new_skb->data, - RX_BUF_ALLOC_SIZE(gp), - PCI_DMA_FROMDEVICE)); + rxd->buffer = cpu_to_le64(pci_map_page(gp->pdev, + virt_to_page(new_skb->data), + ((unsigned long) new_skb->data & + ~PAGE_MASK), + RX_BUF_ALLOC_SIZE(gp), + PCI_DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ @@ -659,37 +663,45 @@ if (skb_shinfo(skb)->nr_frags == 0) { struct gem_txd *txd = &gp->init_block->txd[entry]; - u32 mapping, len; + dma_addr_t mapping; + u32 len; len = skb->len; - mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE); + mapping = pci_map_page(gp->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + len, PCI_DMA_TODEVICE); ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len; txd->buffer = cpu_to_le64(mapping); txd->control_word = cpu_to_le64(ctrl); entry = NEXT_TX(entry); } else { struct gem_txd *txd; - u32 first_len, first_mapping; + u32 first_len; + dma_addr_t first_mapping; int frag, first_entry = entry; /* We must give this initial chunk to the device last. * Otherwise we could race with the device. */ first_len = skb->len - skb->data_len; - first_mapping = pci_map_single(gp->pdev, skb->data, - first_len, PCI_DMA_TODEVICE); + first_mapping = pci_map_page(gp->pdev, virt_to_page(skb->data), + ((unsigned long) skb->data & ~PAGE_MASK), + first_len, PCI_DMA_TODEVICE); entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; - u32 len, mapping; + u32 len; + dma_addr_t mapping; u64 this_ctrl; len = this_frag->size; - mapping = pci_map_single(gp->pdev, - ((void *) page_address(this_frag->page) + - this_frag->page_offset), - len, PCI_DMA_TODEVICE); + mapping = pci_map_page(gp->pdev, + this_frag->page, + this_frag->page_offset, + len, PCI_DMA_TODEVICE); this_ctrl = ctrl; if (frag == skb_shinfo(skb)->nr_frags - 1) this_ctrl |= TXDCTRL_EOF; @@ -946,19 +958,18 @@ struct gem_init_block *gb = gp->init_block; struct sk_buff *skb; int i; - u32 dma_addr; + dma_addr_t dma_addr; for (i = 0; i < RX_RING_SIZE; i++) { struct gem_rxd *rxd; rxd = &gb->rxd[i]; if (gp->rx_skbs[i] != NULL) { - skb = gp->rx_skbs[i]; - dma_addr = (u32) le64_to_cpu(rxd->buffer); - pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE(gp), - PCI_DMA_FROMDEVICE); + dma_addr = le64_to_cpu(rxd->buffer); + pci_unmap_page(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE(gp), + PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); gp->rx_skbs[i] = NULL; } @@ -976,10 +987,10 @@ for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &gb->txd[i]; - dma_addr = (u32) le64_to_cpu(txd->buffer); - pci_unmap_single(gp->pdev, dma_addr, - le64_to_cpu(txd->control_word) & - TXDCTRL_BUFSZ, PCI_DMA_TODEVICE); + dma_addr = le64_to_cpu(txd->buffer); + pci_unmap_page(gp->pdev, dma_addr, + le64_to_cpu(txd->control_word) & + TXDCTRL_BUFSZ, PCI_DMA_TODEVICE); if (frag != skb_shinfo(skb)->nr_frags) i++; @@ -994,7 +1005,7 @@ struct gem_init_block *gb = gp->init_block; struct net_device *dev = gp->dev; int i, gfp_flags = GFP_KERNEL; - u32 dma_addr; + dma_addr_t dma_addr; if (from_irq) gfp_flags = GFP_ATOMIC; @@ -1017,9 +1028,12 @@ gp->rx_skbs[i] = skb; skb->dev = dev; skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); - dma_addr = pci_map_single(gp->pdev, skb->data, - RX_BUF_ALLOC_SIZE(gp), - PCI_DMA_FROMDEVICE); + dma_addr = pci_map_page(gp->pdev, + virt_to_page(skb->data), + ((unsigned long) skb->data & + ~PAGE_MASK), + RX_BUF_ALLOC_SIZE(gp), + PCI_DMA_FROMDEVICE); rxd->buffer = cpu_to_le64(dma_addr); rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); skb_reserve(skb, RX_OFFSET); @@ -1135,13 +1149,15 @@ static void gem_init_dma(struct gem *gp) { + u64 desc_dma = (u64) gp->gblock_dvma; u32 val; val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE); writel(val, gp->regs + TXDMA_CFG); - writel(0, gp->regs + TXDMA_DBHI); - writel(gp->gblock_dvma, gp->regs + TXDMA_DBLOW); + writel(desc_dma >> 32, gp->regs + TXDMA_DBHI); + writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW); + desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd)); writel(0, gp->regs + TXDMA_KICK); @@ -1149,10 +1165,8 @@ ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); writel(val, gp->regs + RXDMA_CFG); - writel(0, gp->regs + RXDMA_DBHI); - writel((gp->gblock_dvma + - (TX_RING_SIZE * sizeof(struct gem_txd))), - gp->regs + RXDMA_DBLOW); + writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); + writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); @@ -1560,8 +1574,10 @@ } { - u32 cfg = readl(gp->regs + GREG_BIFCFG); + u32 cfg; + /* XXX Why do I do this? -DaveM XXX */ + cfg = readl(gp->regs + GREG_BIFCFG); cfg |= GREG_BIFCFG_B64DIS; writel(cfg, gp->regs + GREG_BIFCFG); @@ -1619,7 +1635,7 @@ unsigned long gemreg_base, gemreg_len; struct net_device *dev; struct gem *gp; - int i, err; + int i, err, pci_using_dac; if (gem_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -1632,6 +1648,29 @@ } pci_set_master(pdev); + /* Configure DMA attributes. */ + + /* All of the GEM documentation states that 64-bit DMA addressing + * is fully supported and should work just fine. However the + * front end for RIO based GEMs is different and only supports + * 32-bit addressing. + * + * For now we assume the various PPC GEMs are 32-bit only as well. + */ + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_GEM && + !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, (u64) 0xffffffff); + if (err) { + printk(KERN_ERR PFX "No usable DMA configuration, " + "aborting.\n"); + return err; + } + pci_using_dac = 0; + } + gemreg_base = pci_resource_start(pdev, 0); gemreg_len = pci_resource_len(pdev, 0); @@ -1715,6 +1754,8 @@ /* GEM can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + if (pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; return 0; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/pci/pci.c linux/drivers/pci/pci.c --- /opt/kernel/linux-2.4.10/drivers/pci/pci.c Tue Sep 18 07:52:35 2001 +++ linux/drivers/pci/pci.c Mon Sep 24 00:15:36 2001 @@ -834,17 +834,27 @@ } int -pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +pci_set_dma_mask(struct pci_dev *dev, u64 mask) { - if(! pci_dma_supported(dev, mask)) - return -EIO; + if (!pci_dma_supported(dev, mask)) + return -EIO; - dev->dma_mask = mask; + dev->dma_mask = mask; - return 0; + return 0; } +int +pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (!pci_dac_dma_supported(dev, mask)) + return -EIO; + + dev->dma_mask = mask; + return 0; +} + /* * Translate the low bits of the PCI base * to the resource type @@ -1678,7 +1688,8 @@ if (!page) return 0; page->vaddr = pci_alloc_consistent (pool->dev, - pool->allocation, &page->dma); + pool->allocation, + &page->dma); if (page->vaddr) { memset (page->bitmap, 0xff, mapsize); // bit set == free if (pool->flags & SLAB_POISON) @@ -1864,14 +1875,14 @@ if ((page = pool_find_page (pool, dma)) == 0) { printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, dma); + pool->name, vaddr, (int) (dma & 0xffffffff)); return; } #ifdef CONFIG_PCIPOOL_DEBUG if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, dma); + pool->name, vaddr, (int) (dma & 0xffffffff)); return; } #endif @@ -1956,6 +1967,7 @@ EXPORT_SYMBOL(pci_find_subsys); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_dma_mask); +EXPORT_SYMBOL(pci_dac_set_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/pci/setup-bus.c linux/drivers/pci/setup-bus.c --- /opt/kernel/linux-2.4.10/drivers/pci/setup-bus.c Sun May 20 02:43:06 2001 +++ linux/drivers/pci/setup-bus.c Sun Sep 16 23:31:44 2001 @@ -23,7 +23,7 @@ #include -#define DEBUG_CONFIG 1 +#define DEBUG_CONFIG 0 #if DEBUG_CONFIG # define DBGC(args) printk args #else diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c --- /opt/kernel/linux-2.4.10/drivers/pci/setup-res.c Sun May 20 02:43:06 2001 +++ linux/drivers/pci/setup-res.c Sun Sep 16 23:31:44 2001 @@ -25,7 +25,7 @@ #include -#define DEBUG_CONFIG 1 +#define DEBUG_CONFIG 0 #if DEBUG_CONFIG # define DBGC(args) printk args #else diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- /opt/kernel/linux-2.4.10/drivers/scsi/aha1542.c Fri Sep 7 18:28:37 2001 +++ linux/drivers/scsi/aha1542.c Sun Sep 16 23:31:44 2001 @@ -67,12 +67,10 @@ int nseg, int badseg) { - printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n", + printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx length %d\n", badseg, nseg, sgpnt[badseg].address, SCSI_PA(sgpnt[badseg].address), - sgpnt[badseg].alt_address, - sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0, sgpnt[badseg].length); /* @@ -716,7 +714,7 @@ unsigned char *ptr; printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i); for (i = 0; i < SCpnt->use_sg; i++) { - printk(KERN_CRIT "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address, + printk(KERN_CRIT "%d: %p %d\n", i, sgpnt[i].address, sgpnt[i].length); }; printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- /opt/kernel/linux-2.4.10/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sat May 5 00:16:28 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Mon Sep 24 01:14:54 2001 @@ -81,7 +81,9 @@ present: 0, /* number of 7xxx's present */\ unchecked_isa_dma: 0, /* no memory DMA restrictions */\ use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 1 \ + use_new_eh_code: 1, \ + can_dma_32: 1, \ + single_sg_ok: 1, \ } #endif /* _AIC7XXX_LINUX_HOST_H_ */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- /opt/kernel/linux-2.4.10/drivers/scsi/hosts.c Thu Jul 5 20:28:17 2001 +++ linux/drivers/scsi/hosts.c Mon Sep 24 00:50:53 2001 @@ -235,6 +235,8 @@ retval->cmd_per_lun = tpnt->cmd_per_lun; retval->unchecked_isa_dma = tpnt->unchecked_isa_dma; retval->use_clustering = tpnt->use_clustering; + retval->can_dma_32 = tpnt->can_dma_32; + retval->single_sg_ok = tpnt->single_sg_ok; retval->select_queue_depths = tpnt->select_queue_depths; retval->max_sectors = tpnt->max_sectors; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- /opt/kernel/linux-2.4.10/drivers/scsi/hosts.h Sun Sep 23 19:33:41 2001 +++ linux/drivers/scsi/hosts.h Mon Sep 24 00:50:39 2001 @@ -291,6 +291,10 @@ */ unsigned emulated:1; + unsigned can_dma_32:1; + + unsigned single_sg_ok:1; + /* * Name of proc directory */ @@ -390,6 +394,9 @@ unsigned in_recovery:1; unsigned unchecked_isa_dma:1; unsigned use_clustering:1; + unsigned can_dma_32:1; + unsigned single_sg_ok:1; + /* * True if this host was loaded as a loadable module */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- /opt/kernel/linux-2.4.10/drivers/scsi/ide-scsi.c Fri Feb 9 20:30:23 2001 +++ linux/drivers/scsi/ide-scsi.c Sun Sep 16 23:31:44 2001 @@ -695,7 +695,7 @@ int segments = pc->scsi_cmd->use_sg; struct scatterlist *sg = pc->scsi_cmd->request_buffer; - if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024) + if (!drive->using_dma || !pc->request_transfer || pc->request_transfer & 1023) return NULL; if (idescsi_set_direction(pc)) return NULL; @@ -706,12 +706,22 @@ printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10); #endif /* IDESCSI_DEBUG_LOG */ while (segments--) { - bh->b_data = sg->address; + if (sg->address) { + bh->b_page = virt_to_page(sg->address); + bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK); + } else if (sg->page) { + bh->b_page = sg->page; + bh->b_data = (char *) sg->offset; + } + bh->b_size = sg->length; bh = bh->b_reqnext; sg++; } } else { + /* + * non-sg requests are guarenteed not to reside in highmem /jens + */ if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL) return NULL; #if IDESCSI_DEBUG_LOG diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- /opt/kernel/linux-2.4.10/drivers/scsi/ips.c Thu Aug 16 18:49:49 2001 +++ linux/drivers/scsi/ips.c Sun Sep 16 23:31:44 2001 @@ -3546,7 +3546,7 @@ Scsi_Cmnd *p; Scsi_Cmnd *q; ips_copp_wait_item_t *item; - int ret; + int ret, sg_entries = 0; int intr_status; unsigned long cpu_flags; unsigned long cpu_flags2; @@ -3743,6 +3743,8 @@ int i; sg = SC->request_buffer; + scb->org_sg_list = sg; + sg_entries = pci_map_sg(ha->pcidev, sg, SC->use_sg, ips_command_direction[scb->scsi_cmd->cmnd[0]]); if (SC->use_sg == 1) { if (sg[0].length > ha->max_xfer) { @@ -3752,12 +3754,12 @@ scb->data_len = sg[0].length; scb->dcdb.transfer_length = scb->data_len; - scb->data_busaddr = VIRT_TO_BUS(sg[0].address); + scb->data_busaddr = sg_dma_address(&sg[0]); scb->sg_len = 0; } else { /* Check for the first Element being bigger than MAX_XFER */ if (sg[0].length > ha->max_xfer) { - scb->sg_list[0].address = VIRT_TO_BUS(sg[0].address); + scb->sg_list[0].address = sg_dma_address(&sg[0]); scb->sg_list[0].length = ha->max_xfer; scb->data_len = ha->max_xfer; scb->breakup = 0; @@ -3765,8 +3767,8 @@ scb->sg_len = 1; } else { - for (i = 0; i < SC->use_sg; i++) { - scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); + for (i = 0; i < sg_entries; i++) { + scb->sg_list[i].address = sg_dma_address(&sg[i]); scb->sg_list[i].length = sg[i].length; if (scb->data_len + sg[i].length > ha->max_xfer) { @@ -3781,7 +3783,7 @@ } if (!scb->breakup) - scb->sg_len = SC->use_sg; + scb->sg_len = sg_entries; else scb->sg_len = scb->breakup; } @@ -4441,11 +4443,11 @@ if (sg[0].length - (bk_save * ha->max_xfer)) { /* Further breakup required */ scb->data_len = ha->max_xfer; - scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer)); + scb->data_busaddr = sg_dma_address(&sg[0] + (bk_save * ha->max_xfer)); scb->breakup = bk_save + 1; } else { scb->data_len = sg[0].length - (bk_save * ha->max_xfer); - scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer)); + scb->data_busaddr = sg_dma_address(&sg[0] + (bk_save * ha->max_xfer)); } scb->dcdb.transfer_length = scb->data_len; @@ -4462,7 +4464,7 @@ /* pointed to by bk_save */ if (scb->sg_break) { scb->sg_len = 1; - scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address+ha->max_xfer*scb->sg_break); + scb->sg_list[0].address = sg_dma_address(&sg[bk_save] + ha->max_xfer*scb->sg_break); if (ha->max_xfer > sg[bk_save].length-ha->max_xfer * scb->sg_break) scb->sg_list[0].length = sg[bk_save].length-ha->max_xfer * scb->sg_break; else @@ -4480,7 +4482,7 @@ } else { /* ( sg_break == 0 ), so this is our first look at a new sg piece */ if (sg[bk_save].length > ha->max_xfer) { - scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address); + scb->sg_list[0].address = sg_dma_address(&sg[bk_save]); scb->sg_list[0].length = ha->max_xfer; scb->breakup = bk_save; scb->sg_break = 1; @@ -4493,7 +4495,7 @@ scb->sg_break = 0; /* We're only doing full units here */ for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { - scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i - bk_save].address = sg_dma_address(&sg[i]); scb->sg_list[i - bk_save].length = sg[i].length; if (scb->data_len + sg[i].length > ha->max_xfer) { scb->breakup = i; /* sneaky, if not more work, than breakup is 0 */ @@ -4560,6 +4562,7 @@ break; } /* end case */ + pci_unmap_sg(ha->pcidev, scb->org_sg_list, scb->sg_len, ips_command_direction[scb->scsi_cmd->cmnd[0]]); return ; } #ifndef NO_IPS_CMDLINE diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- /opt/kernel/linux-2.4.10/drivers/scsi/ips.h Fri Jul 20 06:08:13 2001 +++ linux/drivers/scsi/ips.h Sun Sep 16 23:31:44 2001 @@ -419,7 +419,8 @@ present : 0, \ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ - use_new_eh_code : 1 \ + use_new_eh_code : 1, \ + can_dma_32 : 1 \ } #endif @@ -1026,6 +1027,7 @@ u32 flags; u32 op_code; IPS_SG_LIST *sg_list; + struct scatterlist *org_sg_list; Scsi_Cmnd *scsi_cmd; struct ips_scb *q_next; ips_scb_callback callback; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- /opt/kernel/linux-2.4.10/drivers/scsi/megaraid.c Mon Sep 17 22:16:30 2001 +++ linux/drivers/scsi/megaraid.c Mon Sep 24 00:15:36 2001 @@ -2933,9 +2933,7 @@ sizeof (mega_mailbox64), &(megaCfg->dma_handle64)); - mega_register_mailbox (megaCfg, - virt_to_bus ((void *) megaCfg-> - mailbox64ptr)); + mega_register_mailbox (megaCfg, megaCfg->dma_handle64); #else mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg-> diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h --- /opt/kernel/linux-2.4.10/drivers/scsi/megaraid.h Wed Jul 25 23:12:02 2001 +++ linux/drivers/scsi/megaraid.h Sun Sep 16 23:31:44 2001 @@ -220,7 +220,8 @@ cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ present: 0, /* Present */\ unchecked_isa_dma: 0, /* Default Unchecked ISA DMA */\ - use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\ + use_clustering: ENABLE_CLUSTERING, /* Enable Clustering */\ + can_dma_32: 1, \ } #endif diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/osst.c linux/drivers/scsi/osst.c --- /opt/kernel/linux-2.4.10/drivers/scsi/osst.c Fri Jul 20 06:18:15 2001 +++ linux/drivers/scsi/osst.c Sun Sep 16 23:31:44 2001 @@ -4933,7 +4933,6 @@ tb->sg[0].address = (unsigned char *)__get_free_pages(priority, order); if (tb->sg[0].address != NULL) { - tb->sg[0].alt_address = NULL; tb->sg[0].length = b_size; break; } @@ -4969,7 +4968,6 @@ tb = NULL; break; } - tb->sg[segs].alt_address = NULL; tb->sg[segs].length = b_size; got += b_size; segs++; @@ -5043,7 +5041,6 @@ normalize_buffer(STbuffer); return FALSE; } - STbuffer->sg[segs].alt_address = NULL; STbuffer->sg[segs].length = b_size; STbuffer->sg_segs += 1; got += b_size; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- /opt/kernel/linux-2.4.10/drivers/scsi/qlogicfc.c Fri Sep 7 18:28:37 2001 +++ linux/drivers/scsi/qlogicfc.c Sun Sep 16 23:31:44 2001 @@ -21,6 +21,9 @@ * * Big endian support and dynamic DMA mapping added * by Jakub Jelinek . + * + * Conversion to final pci64 DMA interfaces + * by David S. Miller . */ /* @@ -63,31 +66,10 @@ #include "sd.h" #include "hosts.h" -#if 1 -/* Once pci64_ DMA mapping interface is in, kill this. */ -typedef dma_addr_t dma64_addr_t; -#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p)) -#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a)) -#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir)) -#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir)) -#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir)) -#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir)) -#if BITS_PER_LONG > 32 #define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32))) #define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a))))) -#else -#define pci64_dma_hi32(a) 0 -#define pci64_dma_lo32(a) (a) -#endif /* BITS_PER_LONG */ -#define pci64_dma_build(hi,lo) (lo) -#define sg_dma64_address(s) sg_dma_address(s) -#define sg_dma64_len(s) sg_dma_len(s) -#if BITS_PER_LONG > 32 -#define PCI64_DMA_BITS 64 -#else -#define PCI64_DMA_BITS 32 -#endif /* BITS_PER_LONG */ -#endif +#define pci64_dma_build(hi,lo) \ + ((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32))) #include "qlogicfc.h" @@ -243,13 +225,8 @@ }; /* entry header type commands */ -#if PCI64_DMA_BITS > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a -#else -#define ENTRY_COMMAND 0x11 -#define ENTRY_CONTINUATION 0x02 -#endif #define ENTRY_STATUS 0x03 #define ENTRY_MARKER 0x04 @@ -260,23 +237,12 @@ #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 -#if PCI64_DMA_BITS > 32 - struct dataseg { u_int d_base; u_int d_base_hi; u_int d_count; }; -#else - -struct dataseg { - u_int d_base; - u_int d_count; -}; - -#endif - struct Command_Entry { struct Entry_header hdr; u_int handle; @@ -301,18 +267,10 @@ #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -#if PCI64_DMA_BITS > 32 -struct Continuation_Entry { - struct Entry_header hdr; - struct dataseg dataseg[DATASEGS_PER_CONT]; -}; -#else struct Continuation_Entry { struct Entry_header hdr; - u32 rsvd; struct dataseg dataseg[DATASEGS_PER_CONT]; }; -#endif struct Marker_Entry { struct Entry_header hdr; @@ -741,7 +699,7 @@ struct isp2x00_hostdata *hostdata; struct pci_dev *pdev; unsigned short device_ids[2]; - dma64_addr_t busaddr; + dma_addr_t busaddr; int i; @@ -753,7 +711,7 @@ tmpt->proc_name = "isp2x00"; if (pci_present() == 0) { - printk("qlogicfc : PCI not present\n"); + printk(KERN_INFO "qlogicfc : PCI not present\n"); return 0; } @@ -763,6 +721,11 @@ if (pci_enable_device(pdev)) continue; + /* Try to configure DMA attributes. */ + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + pci_set_dma_mask(pdev, (u64) 0xffffffff)) + continue; + host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); if (!host) { printk("qlogicfc%d : could not register host.\n", hosts); @@ -776,11 +739,11 @@ memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); hostdata->pci_dev = pdev; - hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); + hostdata->res = pci_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); if (!hostdata->res){ printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts); - pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); + pci_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -813,7 +776,7 @@ hostdata->host_id = hosts; if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); + pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -822,7 +785,7 @@ if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc%d : interrupt %d already in use\n", hostdata->host_id, host->irq); - pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); + pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -831,7 +794,7 @@ "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); - pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); + pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -990,7 +953,7 @@ u_int port_id; struct sns_cb *req; u_char *sns_response; - dma64_addr_t busaddr; + dma_addr_t busaddr; struct isp2x00_hostdata *hostdata; hostdata = (struct isp2x00_hostdata *) host->hostdata; @@ -1007,7 +970,7 @@ } printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); - req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); + req = (struct sns_cb *)pci_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); if (!req){ printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); @@ -1109,12 +1072,12 @@ done = 1; } else { printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); - pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); + pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 0; } } - pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); + pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 1; } @@ -1124,7 +1087,7 @@ int isp2x00_release(struct Scsi_Host *host) { struct isp2x00_hostdata *hostdata; - dma64_addr_t busaddr; + dma_addr_t busaddr; ENTER("isp2x00_release"); @@ -1137,7 +1100,7 @@ busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); - pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); + pci_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); LEAVE("isp2x00_release"); @@ -1281,7 +1244,7 @@ if (Cmnd->use_sg) { sg = (struct scatterlist *) Cmnd->request_buffer; - sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); cmd->segment_cnt = cpu_to_le16(sg_count); ds = cmd->dataseg; /* fill in first two sg entries: */ @@ -1290,11 +1253,9 @@ n = DATASEGS_PER_COMMAND; for (i = 0; i < n; i++) { - ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); -#if PCI64_DMA_BITS > 32 - ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); -#endif - ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg))); + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg))); + ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } sg_count -= DATASEGS_PER_COMMAND; @@ -1316,31 +1277,30 @@ if (n > DATASEGS_PER_CONT) n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); -#if PCI64_DMA_BITS > 32 - ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); -#endif - ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg))); + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg))); + ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } sg_count -= n; } } else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) { - dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + struct page *page = virt_to_page(Cmnd->request_buffer); + unsigned long offset = ((unsigned long)Cmnd->request_buffer & + ~PAGE_MASK); + dma_addr_t busaddr = pci_map_page(hostdata->pci_dev, + page, offset, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + Cmnd->SCp.dma_handle = busaddr; - *(dma64_addr_t *)&Cmnd->SCp = busaddr; cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr)); -#if PCI64_DMA_BITS > 32 cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr)); -#endif cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); cmd->segment_cnt = cpu_to_le16(1); } else { cmd->dataseg[0].d_base = 0; -#if PCI64_DMA_BITS > 32 cmd->dataseg[0].d_base_hi = 0; -#endif cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } @@ -1433,16 +1393,17 @@ Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i]; if (Cmnd->use_sg) - pci64_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + pci_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, + Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen && - Cmnd->sc_data_direction != PCI_DMA_NONE) - pci64_unmap_single(hostdata->pci_dev, - *(dma64_addr_t *)&Cmnd->SCp, - Cmnd->request_bufflen, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + Cmnd->sc_data_direction != PCI_DMA_NONE) { + pci_unmap_page(hostdata->pci_dev, + Cmnd->SCp.dma_handle, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + } hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16; @@ -1539,16 +1500,16 @@ hostdata->queued--; if (Cmnd != NULL) { if (Cmnd->use_sg) - pci64_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + pci_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, + Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) - pci64_unmap_single(hostdata->pci_dev, - *(dma64_addr_t *)&Cmnd->SCp, - Cmnd->request_bufflen, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + pci_unmap_page(hostdata->pci_dev, + Cmnd->SCp.dma_handle, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); Cmnd->result = 0x0; (*Cmnd->scsi_done) (Cmnd); } else @@ -1594,13 +1555,14 @@ hostdata->queued--; if (Cmnd->use_sg) - pci64_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + pci_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) - pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, - Cmnd->request_bufflen, - scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + pci_unmap_page(hostdata->pci_dev, + Cmnd->SCp.dma_handle, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); /* * if any of the following are true we do not @@ -1859,7 +1821,7 @@ u_short param[8]; struct isp2x00_hostdata *hostdata; int loop_count; - dma64_addr_t busaddr; + dma_addr_t busaddr; ENTER("isp2x00_reset_hardware"); @@ -1970,9 +1932,15 @@ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8; hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8; - /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */ - busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); + /* FIXME: If the DMA transfer goes one way only, this should use + * PCI_DMA_TODEVICE and below as well. + */ + busaddr = pci_map_page(hostdata->pci_dev, + virt_to_page(&hostdata->control_block), + ((unsigned long) &hostdata->control_block & + ~PAGE_MASK), + sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); param[0] = MBOX_INIT_FIRMWARE; param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16); @@ -1984,21 +1952,24 @@ isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); - pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); + pci_unmap_page(hostdata->pci_dev, busaddr, + sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); - pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); + pci_unmap_page(hostdata->pci_dev, busaddr, + sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } - pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); + pci_unmap_page(hostdata->pci_dev, busaddr, + sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); LEAVE("isp2x00_reset_hardware"); return 0; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h --- /opt/kernel/linux-2.4.10/drivers/scsi/qlogicfc.h Mon Jun 26 21:02:16 2000 +++ linux/drivers/scsi/qlogicfc.h Sun Sep 16 23:31:44 2001 @@ -100,7 +100,8 @@ cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING, \ + can_dma_32: 1 \ } #endif /* _QLOGICFC_H */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- /opt/kernel/linux-2.4.10/drivers/scsi/scsi.c Fri Jul 20 06:07:04 2001 +++ linux/drivers/scsi/scsi.c Sun Sep 16 23:31:44 2001 @@ -178,10 +178,13 @@ * handler in the list - ultimately they call scsi_request_fn * to do the dirty deed. */ -void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) { - blk_init_queue(&SDpnt->request_queue, scsi_request_fn); - blk_queue_headactive(&SDpnt->request_queue, 0); - SDpnt->request_queue.queuedata = (void *) SDpnt; +void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) +{ + request_queue_t *q = &SDpnt->request_queue; + + blk_init_queue(q, scsi_request_fn); + blk_queue_headactive(q, 0); + q->queuedata = (void *) SDpnt; } #ifdef MODULE diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- /opt/kernel/linux-2.4.10/drivers/scsi/scsi.h Sun Sep 23 19:33:41 2001 +++ linux/drivers/scsi/scsi.h Mon Sep 24 00:19:13 2001 @@ -386,15 +386,6 @@ #define ASKED_FOR_SENSE 0x20 #define SYNC_RESET 0x40 -#if defined(__mc68000__) || defined(CONFIG_APUS) -#include -#define CONTIGUOUS_BUFFERS(X,Y) \ - (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data)) -#else -#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data) -#endif - - /* * This is the crap from the old error handling code. We have it in a special * place so that we can more easily delete it later on. @@ -633,6 +624,8 @@ struct scatterlist *buffer; /* which buffer */ int buffers_residual; /* how many buffers left */ + dma_addr_t dma_handle; + volatile int Status; volatile int Message; volatile int have_data_in; @@ -745,7 +738,8 @@ unsigned request_bufflen; /* Actual request size */ struct timer_list eh_timeout; /* Used to time out the command. */ - void *request_buffer; /* Actual requested buffer */ + void *request_buffer; /* Actual requested buffer */ + void **bounce_buffers; /* Array of bounce buffers when using scatter-gather */ /* These elements define the operation we ultimately want to perform */ unsigned char data_cmnd[MAX_COMMAND_SIZE]; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- /opt/kernel/linux-2.4.10/drivers/scsi/scsi_debug.c Sun Nov 12 04:01:11 2000 +++ linux/drivers/scsi/scsi_debug.c Sun Sep 16 23:31:44 2001 @@ -154,10 +154,7 @@ if (SCpnt->use_sg) { sgpnt = (struct scatterlist *) SCpnt->buffer; for (i = 0; i < SCpnt->use_sg; i++) { - lpnt = (int *) sgpnt[i].alt_address; - printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); - if (lpnt) - printk(" (Alt %x) ", lpnt[15]); + printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length); }; } else { printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, @@ -175,12 +172,6 @@ printk("\n"); if (flag == 0) return; - lpnt = (unsigned int *) sgpnt[0].alt_address; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - }; #if 0 printk("\n"); lpnt = (unsigned int *) sgpnt[0].address; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- /opt/kernel/linux-2.4.10/drivers/scsi/scsi_lib.c Sun Aug 12 19:51:42 2001 +++ linux/drivers/scsi/scsi_lib.c Sun Sep 16 23:31:44 2001 @@ -388,6 +388,7 @@ req->nr_sectors -= nsect; req->current_nr_sectors = bh->b_size >> 9; + req->hard_cur_sectors = req->current_nr_sectors; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; printk("scsi_end_request: buffer-list destroyed\n"); @@ -410,7 +411,6 @@ q = &SCpnt->device->request_queue; - req->buffer = bh->b_data; /* * Bleah. Leftovers again. Stick the leftovers in * the front of the queue, and goose the queue again. @@ -489,6 +489,8 @@ */ static void scsi_release_buffers(Scsi_Cmnd * SCpnt) { + struct request *req = &SCpnt->request; + ASSERT_LOCK(&io_request_lock, 0); /* @@ -496,20 +498,22 @@ */ if (SCpnt->use_sg) { struct scatterlist *sgpnt; + void **bbpnt; int i; sgpnt = (struct scatterlist *) SCpnt->request_buffer; + bbpnt = SCpnt->bounce_buffers; - for (i = 0; i < SCpnt->use_sg; i++) { - if (sgpnt[i].alt_address) { - scsi_free(sgpnt[i].address, sgpnt[i].length); + if (bbpnt) { + for (i = 0; i < SCpnt->use_sg; i++) { + if (bbpnt[i]) + scsi_free(sgpnt[i].address, sgpnt[i].length); } } scsi_free(SCpnt->request_buffer, SCpnt->sglist_len); } else { - if (SCpnt->request_buffer != SCpnt->request.buffer) { - scsi_free(SCpnt->request_buffer, SCpnt->request_bufflen); - } + if (SCpnt->request_buffer != req->buffer) + scsi_free(SCpnt->request_buffer,SCpnt->request_bufflen); } /* @@ -545,6 +549,7 @@ int result = SCpnt->result; int this_count = SCpnt->bufflen >> 9; request_queue_t *q = &SCpnt->device->request_queue; + struct request *req = &SCpnt->request; /* * We must do one of several things here: @@ -568,26 +573,32 @@ */ if (SCpnt->use_sg) { struct scatterlist *sgpnt; + void **bbpnt; int i; sgpnt = (struct scatterlist *) SCpnt->buffer; + bbpnt = SCpnt->bounce_buffers; - for (i = 0; i < SCpnt->use_sg; i++) { - if (sgpnt[i].alt_address) { - if (SCpnt->request.cmd == READ) { - memcpy(sgpnt[i].alt_address, - sgpnt[i].address, - sgpnt[i].length); + if (bbpnt) { + for (i = 0; i < SCpnt->use_sg; i++) { + if (bbpnt[i]) { + if (req->cmd == READ) { + memcpy(bbpnt[i], + sgpnt[i].address, + sgpnt[i].length); + } + scsi_free(sgpnt[i].address, sgpnt[i].length); } - scsi_free(sgpnt[i].address, sgpnt[i].length); } } scsi_free(SCpnt->buffer, SCpnt->sglist_len); } else { - if (SCpnt->buffer != SCpnt->request.buffer) { - if (SCpnt->request.cmd == READ) { - memcpy(SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); + if (SCpnt->buffer != req->buffer) { + if (req->cmd == READ) { + unsigned long flags; + char *to = bh_kmap_irq(req->bh, &flags); + memcpy(to, SCpnt->buffer, SCpnt->bufflen); + bh_kunmap_irq(to, &flags); } scsi_free(SCpnt->buffer, SCpnt->bufflen); } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- /opt/kernel/linux-2.4.10/drivers/scsi/scsi_merge.c Thu Jul 5 20:28:17 2001 +++ linux/drivers/scsi/scsi_merge.c Mon Sep 24 01:18:29 2001 @@ -6,6 +6,7 @@ * Based upon conversations with large numbers * of people at Linux Expo. * Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com). + * Support for highmem I/O: Jens Axboe */ /* @@ -48,7 +49,6 @@ #include #include - #define __KERNEL_SYSCALLS__ #include @@ -95,7 +95,7 @@ printk("Segment 0x%p, blocks %d, addr 0x%lx\n", bh, bh->b_size >> 9, - virt_to_phys(bh->b_data - 1)); + bh_phys(bh) - 1); } panic("Ththththaats all folks. Too dangerous to continue.\n"); } @@ -120,9 +120,11 @@ { int jj; struct scatterlist *sgpnt; + void **bbpnt; int consumed = 0; sgpnt = (struct scatterlist *) SCpnt->request_buffer; + bbpnt = SCpnt->bounce_buffers; /* * Now print out a bunch of stats. First, start with the request @@ -136,15 +138,13 @@ */ for(jj=0; jj < SCpnt->use_sg; jj++) { - printk("[%d]\tlen:%d\taddr:%p\talt:%p\n", + printk("[%d]\tlen:%d\taddr:%p\tbounce:%p\n", jj, sgpnt[jj].length, sgpnt[jj].address, - sgpnt[jj].alt_address); - if( sgpnt[jj].alt_address != NULL ) - { - consumed = (sgpnt[jj].length >> 9); - } + (bbpnt ? bbpnt[jj] : NULL)); + if (bbpnt && bbpnt[jj]) + consumed += sgpnt[jj].length; } printk("Total %d sectors consumed\n", consumed); panic("DMA pool exhausted"); @@ -223,11 +223,10 @@ * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ - if (dma_host && - virt_to_phys(bhnext->b_data) - 1 == ISA_DMA_THRESHOLD) { + if (dma_host && bh_phys(bhnext) - 1 == ISA_DMA_THRESHOLD) { ret++; reqsize = bhnext->b_size; - } else if (CONTIGUOUS_BUFFERS(bh, bhnext)) { + } else if (BH_CONTIG(bh, bhnext)) { /* * This one is OK. Let it go. */ @@ -241,8 +240,7 @@ * kind of screwed and we need to start * another segment. */ - if( dma_host - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD + if( dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD && reqsize + bhnext->b_size > PAGE_SIZE ) { ret++; @@ -304,7 +302,7 @@ } #define MERGEABLE_BUFFERS(X,Y) \ -(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \ +(((((long)bh_phys((X))+(X)->b_size)|((long)bh_phys((Y)))) & \ (DMA_CHUNK_SIZE - 1)) == 0) #ifdef DMA_CHUNK_SIZE @@ -419,6 +417,8 @@ if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) return 0; + else if (!BH_PHYS_4G(req->bhtail, bh)) + return 0; if (use_clustering) { /* @@ -427,14 +427,11 @@ * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ - if (dma_host && - virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) { + if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD) goto new_end_segment; - } - if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) { + if (BH_CONTIG(req->bhtail, bh)) { #ifdef DMA_SEGMENT_SIZE_LIMITED - if( dma_host - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) { + if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) { segment_size = 0; count = __count_segments(req, use_clustering, dma_host, &segment_size); if( segment_size + bh->b_size > PAGE_SIZE ) { @@ -478,6 +475,8 @@ if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) return 0; + else if (!BH_PHYS_4G(bh, req->bh)) + return 0; if (use_clustering) { /* @@ -486,14 +485,12 @@ * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ - if (dma_host && - virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) { + if (dma_host && bh_phys(bh) - 1 == ISA_DMA_THRESHOLD) { goto new_start_segment; } - if (CONTIGUOUS_BUFFERS(bh, req->bh)) { + if (BH_CONTIG(bh, req->bh)) { #ifdef DMA_SEGMENT_SIZE_LIMITED - if( dma_host - && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) { + if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) { segment_size = bh->b_size; count = __count_segments(req, use_clustering, dma_host, &segment_size); if( count != req->nr_segments ) { @@ -640,6 +637,8 @@ if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors) return 0; + else if (!BH_PHYS_4G(req->bhtail, next->bh)) + return 0; /* * The main question is whether the two segments at the boundaries @@ -652,18 +651,15 @@ * DMA capable host, make sure that a segment doesn't span * the DMA threshold boundary. */ - if (dma_host && - virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) { + if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD) goto dont_combine; - } #ifdef DMA_SEGMENT_SIZE_LIMITED /* * We currently can only allocate scatter-gather bounce * buffers in chunks of PAGE_SIZE or less. */ - if (dma_host - && CONTIGUOUS_BUFFERS(req->bhtail, next->bh) - && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD ) + if (dma_host && BH_CONTIG(req->bhtail, next->bh) + && bh_phys(req->bhtail) - 1 >= ISA_DMA_THRESHOLD ) { int segment_size = 0; int count = 0; @@ -675,7 +671,7 @@ } } #endif - if (CONTIGUOUS_BUFFERS(req->bhtail, next->bh)) { + if (BH_CONTIG(req->bhtail, next->bh)) { /* * This one is OK. Let it go. */ @@ -807,30 +803,8 @@ int sectors; struct scatterlist * sgpnt; int this_count; + void ** bbpnt; - /* - * FIXME(eric) - don't inline this - it doesn't depend on the - * integer flags. Come to think of it, I don't think this is even - * needed any more. Need to play with it and see if we hit the - * panic. If not, then don't bother. - */ - if (!SCpnt->request.bh) { - /* - * Case of page request (i.e. raw device), or unlinked buffer - * Typically used for swapping, but this isn't how we do - * swapping any more. - */ - panic("I believe this is dead code. If we hit this, I was wrong"); -#if 0 - SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9; - SCpnt->request_buffer = SCpnt->request.buffer; - SCpnt->use_sg = 0; - /* - * FIXME(eric) - need to handle DMA here. - */ -#endif - return 1; - } req = &SCpnt->request; /* * First we need to know how many scatter gather segments are needed. @@ -847,24 +821,39 @@ * buffer. */ if (dma_host && scsi_dma_free_sectors <= 10) { - this_count = SCpnt->request.current_nr_sectors; + this_count = req->current_nr_sectors; goto single_segment; } + /* - * Don't bother with scatter-gather if there is only one segment. + * we really want to use sg even for a single segment request, + * however some people just cannot be bothered to write decent + * driver code so we can't risk to break somebody making the + * assumption that sg requests will always contain at least 2 + * segments. check the host single_sg_ok flag -- resort to + * possible high page bounce instead of using sg if it's not set */ - if (count == 1) { - this_count = SCpnt->request.nr_sectors; + if (count == 1 && !SCpnt->host->single_sg_ok) { + this_count = req->current_nr_sectors; goto single_segment; } + + /* + * for sane drivers, use sg even for 1 entry request + */ SCpnt->use_sg = count; + SCpnt->sglist_len = (SCpnt->use_sg * sizeof(struct scatterlist)); - /* - * Allocate the actual scatter-gather table itself. - * scsi_malloc can only allocate in chunks of 512 bytes + /* If we could potentially require ISA bounce buffers, allocate + * space for this array here. + */ + if (dma_host) + SCpnt->sglist_len += (SCpnt->use_sg * sizeof(void *)); + + /* scsi_malloc can only allocate in chunks of 512 bytes so + * round it up. */ - SCpnt->sglist_len = (SCpnt->use_sg - * sizeof(struct scatterlist) + 511) & ~511; + SCpnt->sglist_len = (SCpnt->sglist_len + 511) & ~511; sgpnt = (struct scatterlist *) scsi_malloc(SCpnt->sglist_len); @@ -877,7 +866,7 @@ * simply write the first buffer all by itself. */ printk("Warning - running *really* short on DMA buffers\n"); - this_count = SCpnt->request.current_nr_sectors; + this_count = req->current_nr_sectors; goto single_segment; } /* @@ -889,13 +878,19 @@ SCpnt->request_bufflen = 0; bhprev = NULL; - for (count = 0, bh = SCpnt->request.bh; - bh; bh = bh->b_reqnext) { + if (dma_host) + bbpnt = (void **) ((char *)sgpnt + + (SCpnt->use_sg * sizeof(struct scatterlist))); + else + bbpnt = NULL; + + SCpnt->bounce_buffers = bbpnt; + + for (count = 0, bh = req->bh; bh; bh = bh->b_reqnext) { if (use_clustering && bhprev != NULL) { - if (dma_host && - virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) { + if (dma_host && bh_phys(bhprev) - 1 == ISA_DMA_THRESHOLD) { /* Nothing - fall through */ - } else if (CONTIGUOUS_BUFFERS(bhprev, bh)) { + } else if (BH_CONTIG(bhprev, bh)) { /* * This one is OK. Let it go. Note that we * do not have the ability to allocate @@ -904,7 +899,7 @@ */ if( dma_host ) { #ifdef DMA_SEGMENT_SIZE_LIMITED - if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD + if (bh_phys(bh) - 1 < ISA_DMA_THRESHOLD || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) { sgpnt[count - 1].length += bh->b_size; bhprev = bh; @@ -923,12 +918,15 @@ } } } - count++; - sgpnt[count - 1].address = bh->b_data; - sgpnt[count - 1].length += bh->b_size; - if (!dma_host) { + + sgpnt[count].page = bh->b_page; + sgpnt[count].offset = bh_offset(bh); + sgpnt[count].length = bh->b_size; + + if (!dma_host) SCpnt->request_bufflen += bh->b_size; - } + + count++; bhprev = bh; } @@ -951,12 +949,16 @@ for (i = 0; i < count; i++) { sectors = (sgpnt[i].length >> 9); SCpnt->request_bufflen += sgpnt[i].length; + /* + * only done for dma_host, in which case .page is not + * set since it's guarenteed to be a low memory page + */ if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD) { if( scsi_dma_free_sectors - sectors <= 10 ) { /* * If this would nearly drain the DMA - * pool, mpty, then let's stop here. + * pool empty, then let's stop here. * Don't make this request any larger. * This is kind of a safety valve that * we use - we could get screwed later @@ -970,7 +972,7 @@ break; } - sgpnt[i].alt_address = sgpnt[i].address; + bbpnt[i] = sgpnt[i].address; sgpnt[i].address = (char *) scsi_malloc(sgpnt[i].length); /* @@ -986,8 +988,8 @@ } break; } - if (SCpnt->request.cmd == WRITE) { - memcpy(sgpnt[i].address, sgpnt[i].alt_address, + if (req->cmd == WRITE) { + memcpy(sgpnt[i].address, bbpnt[i], sgpnt[i].length); } } @@ -1031,8 +1033,7 @@ * single-block requests if we had hundreds of free sectors. */ if( scsi_dma_free_sectors > 30 ) { - for (this_count = 0, bh = SCpnt->request.bh; - bh; bh = bh->b_reqnext) { + for (this_count = 0, bh = req->bh; bh; bh = bh->b_reqnext) { if( scsi_dma_free_sectors - this_count < 30 || this_count == sectors ) { @@ -1045,7 +1046,7 @@ /* * Yow! Take the absolute minimum here. */ - this_count = SCpnt->request.current_nr_sectors; + this_count = req->current_nr_sectors; } /* @@ -1058,28 +1059,31 @@ * segment. Possibly the entire request, or possibly a small * chunk of the entire request. */ - bh = SCpnt->request.bh; - buff = SCpnt->request.buffer; + bh = req->bh; + buff = req->buffer = bh->b_data; - if (dma_host) { + if (dma_host || PageHighMem(bh->b_page)) { /* * Allocate a DMA bounce buffer. If the allocation fails, fall * back and allocate a really small one - enough to satisfy * the first buffer. */ - if (virt_to_phys(SCpnt->request.bh->b_data) - + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) { + if (bh_phys(bh) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) { buff = (char *) scsi_malloc(this_count << 9); if (!buff) { printk("Warning - running low on DMA memory\n"); - this_count = SCpnt->request.current_nr_sectors; + this_count = req->current_nr_sectors; buff = (char *) scsi_malloc(this_count << 9); if (!buff) { dma_exhausted(SCpnt, 0); } } - if (SCpnt->request.cmd == WRITE) - memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9); + if (req->cmd == WRITE) { + unsigned long flags; + char *buf = bh_kmap_irq(bh, &flags); + memcpy(buff, buf, this_count << 9); + bh_kunmap_irq(buf, &flags); + } } } SCpnt->request_bufflen = this_count << 9; @@ -1120,21 +1124,11 @@ */ void initialize_merge_fn(Scsi_Device * SDpnt) { - request_queue_t *q; - struct Scsi_Host *SHpnt; - SHpnt = SDpnt->host; - - q = &SDpnt->request_queue; + struct Scsi_Host *SHpnt = SDpnt->host; + request_queue_t *q = &SDpnt->request_queue; + dma64_addr_t bounce_limit; /* - * If the host has already selected a merge manager, then don't - * pick a new one. - */ -#if 0 - if (q->back_merge_fn && q->front_merge_fn) - return; -#endif - /* * If this host has an unlimited tablesize, then don't bother with a * merge manager. The whole point of the operation is to make sure * that requests don't grow too large, and this host isn't picky. @@ -1166,4 +1160,20 @@ q->merge_requests_fn = scsi_merge_requests_fn_dc; SDpnt->scsi_init_io_fn = scsi_init_io_vdc; } + + /* + * now enable highmem I/O, if appropriate + */ + bounce_limit = BLK_BOUNCE_HIGH; + if (SHpnt->can_dma_32 && (SDpnt->type == TYPE_DISK)) { + if (!PCI_DMA_BUS_IS_PHYS) + /* Platforms with virtual-DMA translation + * hardware have no practical limit. + */ + bounce_limit = BLK_BOUNCE_ANY; + else + bounce_limit = SHpnt->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(q, bounce_limit); } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- /opt/kernel/linux-2.4.10/drivers/scsi/sr.c Mon Aug 27 23:20:21 2001 +++ linux/drivers/scsi/sr.c Sun Sep 16 23:31:44 2001 @@ -264,6 +264,7 @@ struct scatterlist *sg, *old_sg = NULL; int i, fsize, bsize, sg_ent, sg_count; char *front, *back; + void **bbpnt, **old_bbpnt = NULL; back = front = NULL; sg_ent = SCpnt->use_sg; @@ -291,17 +292,25 @@ * extend or allocate new scatter-gather table */ sg_count = SCpnt->use_sg; - if (sg_count) + if (sg_count) { old_sg = (struct scatterlist *) SCpnt->request_buffer; - else { + old_bbpnt = SCpnt->bounce_buffers; + } else { sg_count = 1; sg_ent++; } - i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511; + /* Get space for scatterlist and bounce buffer array. */ + i = sg_ent * sizeof(struct scatterlist); + i += sg_ent * sizeof(void *); + i = (i + 511) & ~511; + if ((sg = scsi_malloc(i)) == NULL) goto no_mem; + bbpnt = (void **) + ((char *)sg + (sg_ent * sizeof(struct scatterlist))); + /* * no more failing memory allocs possible, we can safely assign * SCpnt values now @@ -312,13 +321,15 @@ i = 0; if (fsize) { - sg[0].address = sg[0].alt_address = front; + sg[0].address = bbpnt[0] = front; sg[0].length = fsize; i++; } if (old_sg) { memcpy(sg + i, old_sg, SCpnt->use_sg * sizeof(struct scatterlist)); - scsi_free(old_sg, ((SCpnt->use_sg * sizeof(struct scatterlist)) + 511) & ~511); + memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *)); + scsi_free(old_sg, (((SCpnt->use_sg * sizeof(struct scatterlist)) + + (SCpnt->use_sg * sizeof(void *))) + 511) & ~511); } else { sg[i].address = SCpnt->request_buffer; sg[i].length = SCpnt->request_bufflen; @@ -326,11 +337,12 @@ SCpnt->request_bufflen += (fsize + bsize); SCpnt->request_buffer = sg; + SCpnt->bounce_buffers = bbpnt; SCpnt->use_sg += i; if (bsize) { sg[SCpnt->use_sg].address = back; - sg[SCpnt->use_sg].alt_address = back; + bbpnt[SCpnt->use_sg] = back; sg[SCpnt->use_sg].length = bsize; SCpnt->use_sg++; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/st.c linux/drivers/scsi/st.c --- /opt/kernel/linux-2.4.10/drivers/scsi/st.c Sun Aug 12 20:21:47 2001 +++ linux/drivers/scsi/st.c Sun Sep 16 23:31:44 2001 @@ -3222,7 +3222,6 @@ tb->sg[0].address = (unsigned char *) __get_free_pages(priority, order); if (tb->sg[0].address != NULL) { - tb->sg[0].alt_address = NULL; tb->sg[0].length = b_size; break; } @@ -3258,7 +3257,6 @@ tb = NULL; break; } - tb->sg[segs].alt_address = NULL; tb->sg[segs].length = b_size; got += b_size; segs++; @@ -3332,7 +3330,6 @@ normalize_buffer(STbuffer); return FALSE; } - STbuffer->sg[segs].alt_address = NULL; STbuffer->sg[segs].length = b_size; STbuffer->sg_segs += 1; got += b_size; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx.c Thu Jul 5 20:28:16 2001 +++ linux/drivers/scsi/sym53c8xx.c Sun Sep 16 23:31:44 2001 @@ -989,8 +989,8 @@ if (vbp) { dma_addr_t daddr; vp = (m_addr_t) pci_alloc_consistent(mp->bush, - PAGE_SIZE<vaddr = vp; @@ -1140,26 +1140,26 @@ /* Linux version with pci bus iommu kernel interface */ /* To keep track of the dma mapping (sg/single) that has been set */ -#define __data_mapped SCp.phase -#define __data_mapping SCp.have_data_in +#define __data_mapped(cmd) (cmd)->SCp.phase +#define __data_mapping(cmd) (cmd)->SCp.dma_handle static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) { int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - switch(cmd->__data_mapped) { + switch(__data_mapped(cmd)) { case 2: pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - pci_unmap_single(pdev, cmd->__data_mapping, - cmd->request_bufflen, dma_dir); + pci_unmap_page(pdev, __data_mapping(cmd), + cmd->request_bufflen, dma_dir); break; } - cmd->__data_mapped = 0; + __data_mapped(cmd) = 0; } -static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +static dma_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) { dma_addr_t mapping; int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); @@ -1167,10 +1167,13 @@ if (cmd->request_bufflen == 0) return 0; - mapping = pci_map_single(pdev, cmd->request_buffer, - cmd->request_bufflen, dma_dir); - cmd->__data_mapped = 1; - cmd->__data_mapping = mapping; + mapping = pci_map_page(pdev, + virt_to_page(cmd->request_buffer), + ((unsigned long)cmd->request_buffer & + ~PAGE_MASK), + cmd->request_bufflen, dma_dir); + __data_mapped(cmd) = 1; + __data_mapping(cmd) = mapping; return mapping; } @@ -1184,8 +1187,8 @@ return 0; use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); - cmd->__data_mapped = 2; - cmd->__data_mapping = use_sg; + __data_mapped(cmd) = 2; + __data_mapping(cmd) = use_sg; return use_sg; } @@ -1194,12 +1197,12 @@ { int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - switch(cmd->__data_mapped) { + switch(__data_mapped(cmd)) { case 2: pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - pci_dma_sync_single(pdev, cmd->__data_mapping, + pci_dma_sync_single(pdev, __data_mapping(cmd), cmd->request_bufflen, dma_dir); break; } @@ -5031,12 +5034,12 @@ /* ** 64 bit (53C895A or 53C896) ? */ - if (np->features & FE_DAC) -#ifdef SCSI_NCR_USE_64BIT_DAC - np->rv_ccntl1 |= (XTIMOD | EXTIBMV); -#else - np->rv_ccntl1 |= (DDAC); -#endif + if (np->features & FE_DAC) { + if (np->features & FE_DAC_IN_USE) + np->rv_ccntl1 |= (XTIMOD | EXTIBMV); + else + np->rv_ccntl1 |= (DDAC); + } /* ** Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ? @@ -12070,15 +12073,9 @@ ** code will get more complex later). */ -#ifdef SCSI_NCR_USE_64BIT_DAC #define SCATTER_ONE(data, badd, len) \ (data)->addr = cpu_to_scr(badd); \ (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); -#else -#define SCATTER_ONE(data, badd, len) \ - (data)->addr = cpu_to_scr(badd); \ - (data)->size = cpu_to_scr(len); -#endif #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) @@ -12090,7 +12087,7 @@ cp->data_len = cmd->request_bufflen; if (cmd->request_bufflen) { - u_long baddr = map_scsi_single_data(np, cmd); + dma_addr_t baddr = map_scsi_single_data(np, cmd); SCATTER_ONE(data, baddr, cmd->request_bufflen); if (CROSS_16MB(baddr, cmd->request_bufflen)) { @@ -12141,7 +12138,7 @@ data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segn = 0; segn < use_sg; segn++) { - u_long baddr = scsi_sg_dma_address(&scatter[segn]); + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segn]); unsigned int len = scsi_sg_dma_len(&scatter[segn]); SCATTER_ONE(&data[segn], @@ -12180,7 +12177,7 @@ data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segment = 0; segment < use_sg; segment++) { - u_long baddr = scsi_sg_dma_address(&scatter[segment]); + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segment]); unsigned int len = scsi_sg_dma_len(&scatter[segment]); SCATTER_ONE(&data[segment], @@ -13100,14 +13097,6 @@ (int) (PciDeviceFn(pdev) & 0xf8) >> 3, (int) (PciDeviceFn(pdev) & 7)); -#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING - if (pci_set_dma_mask(pdev, (dma_addr_t) (0xffffffffUL))) { - printk(KERN_WARNING NAME53C8XX - "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); - return -1; - } -#endif - /* ** Read info from the PCI config space. ** pci_read_config_xxx() functions are assumed to be used for @@ -13175,6 +13164,28 @@ break; } +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + /* Configure DMA attributes. For DAC capable boards, we can encode + ** 32+8 bits for SCSI DMA data addresses with the extra bits used + ** in the size field. We use normal 32-bit PCI addresses for + ** descriptors. + */ + if (chip->features & FE_DAC) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffffff)) + chip->features &= ~FE_DAC_IN_USE; + else + chip->features |= FE_DAC_IN_USE; + } + + if (!(chip->features & FE_DAC_IN_USE)) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } + } +#endif + /* ** Ignore Symbios chips controlled by SISL RAID controller. ** This controller sets value 0x52414944 at RAM end - 16. @@ -13611,8 +13622,8 @@ cmd->SCp.ptr = NULL; cmd->SCp.buffer = NULL; #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING - cmd->__data_mapped = 0; - cmd->__data_mapping = 0; + __data_mapped(cmd) = 0; + __data_mapping(cmd) = 0; #endif NCR_LOCK_NCB(np, flags); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h --- /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx.h Sun Sep 23 19:34:33 2001 +++ linux/drivers/scsi/sym53c8xx.h Mon Sep 24 01:15:32 2001 @@ -97,7 +97,9 @@ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \ max_sectors: MAX_SEGMENTS*8, \ - use_clustering: DISABLE_CLUSTERING} + use_clustering: DISABLE_CLUSTERING}, \ + can_dma_32: 1, \ + single_sg_ok: 1} #else diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx_comm.h Thu Jul 5 20:28:16 2001 +++ linux/drivers/scsi/sym53c8xx_comm.h Sun Sep 16 23:31:44 2001 @@ -2186,7 +2186,7 @@ (int) (PciDeviceFn(pdev) & 7)); #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING - if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) { + if (!pci_dma_supported(pdev, 0xffffffff)) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); return -1; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h --- /opt/kernel/linux-2.4.10/drivers/scsi/sym53c8xx_defs.h Sun Sep 23 19:34:21 2001 +++ linux/drivers/scsi/sym53c8xx_defs.h Mon Sep 17 00:00:27 2001 @@ -184,20 +184,6 @@ #endif /* - * Should we enable DAC cycles on Sparc64 platform? - * Until further investigation we do not enable it - * at the moment. - * We may want to enable it for __ia64__ (untested) - */ -#if defined(__ia64__) -# if !defined(SCSI_NCR_USE_64BIT_DAC) -# define SCSI_NCR_USE_64BIT_DAC -# endif -#else -# undef SCSI_NCR_USE_64BIT_DAC -#endif - -/* * Immediate arbitration */ #if defined(CONFIG_SCSI_NCR53C8XX_IARB) @@ -205,13 +191,6 @@ #endif /* - * Should we enable DAC cycles on sparc64 platforms? - * Until further investigation we do not enable it - * anywhere at the moment. - */ -#undef SCSI_NCR_USE_64BIT_DAC - -/* * Sync transfer frequency at startup. * Allow from 5Mhz to 80Mhz default 20 Mhz. */ @@ -746,6 +725,7 @@ #define FE_66MHZ (1<<23) /* 66MHz PCI Support */ #define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */ #define FE_ISTAT1 (1<<25) /* Have ISTAT1, MBOX0, MBOX1 registers */ +#define FE_DAC_IN_USE (1<<26) /* Platform does DAC cycles */ #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/fs/buffer.c linux/fs/buffer.c --- /opt/kernel/linux-2.4.10/fs/buffer.c Fri Sep 21 02:25:51 2001 +++ linux/fs/buffer.c Mon Sep 24 00:15:36 2001 @@ -1439,13 +1439,11 @@ bh->b_page = page; if (offset >= PAGE_SIZE) BUG(); - if (PageHighMem(page)) - /* - * This catches illegal uses and preserves the offset: - */ - bh->b_data = (char *)(0 + offset); - else - bh->b_data = page_address(page) + offset; + /* + * ->virtual is NULL on highmem pages, so we can catch the + * offset even though using page_address on it + */ + bh->b_data = page_address(page) + offset; } /* diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/bitops.h Tue Jul 10 06:26:24 2001 +++ linux/include/asm-alpha/bitops.h Sun Sep 16 23:31:44 2001 @@ -20,7 +20,7 @@ * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1). */ -extern __inline__ void +static inline void set_bit(unsigned long nr, volatile void * addr) { unsigned long temp; @@ -41,7 +41,7 @@ /* * WARNING: non atomic version. */ -extern __inline__ void +static inline void __set_bit(unsigned long nr, volatile void * addr) { int *m = ((int *) addr) + (nr >> 5); @@ -52,7 +52,7 @@ #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() -extern __inline__ void +static inline void clear_bit(unsigned long nr, volatile void * addr) { unsigned long temp; @@ -81,7 +81,7 @@ *m ^= 1 << (nr & 31); } -extern __inline__ void +static inline void change_bit(unsigned long nr, volatile void * addr) { unsigned long temp; @@ -99,7 +99,7 @@ :"Ir" (1UL << (nr & 31)), "m" (*m)); } -extern __inline__ int +static inline int test_and_set_bit(unsigned long nr, volatile void *addr) { unsigned long oldbit; @@ -129,7 +129,7 @@ /* * WARNING: non atomic version. */ -extern __inline__ int +static inline int __test_and_set_bit(unsigned long nr, volatile void * addr) { unsigned long mask = 1 << (nr & 0x1f); @@ -140,7 +140,7 @@ return (old & mask) != 0; } -extern __inline__ int +static inline int test_and_clear_bit(unsigned long nr, volatile void * addr) { unsigned long oldbit; @@ -170,7 +170,7 @@ /* * WARNING: non atomic version. */ -extern __inline__ int +static inline int __test_and_clear_bit(unsigned long nr, volatile void * addr) { unsigned long mask = 1 << (nr & 0x1f); @@ -195,7 +195,7 @@ return (old & mask) != 0; } -extern __inline__ int +static inline int test_and_change_bit(unsigned long nr, volatile void * addr) { unsigned long oldbit; @@ -220,7 +220,7 @@ return oldbit != 0; } -extern __inline__ int +static inline int test_bit(int nr, volatile void * addr) { return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; @@ -233,7 +233,7 @@ * Do a binary search on the bits. Due to the nature of large * constants on the alpha, it is worthwhile to split the search. */ -extern inline unsigned long ffz_b(unsigned long x) +static inline unsigned long ffz_b(unsigned long x) { unsigned long sum = 0; @@ -245,7 +245,7 @@ return sum; } -extern inline unsigned long ffz(unsigned long word) +static inline unsigned long ffz(unsigned long word) { #if defined(__alpha_cix__) && defined(__alpha_fix__) /* Whee. EV67 can calculate it directly. */ @@ -272,12 +272,32 @@ * differs in spirit from the above ffz (man ffs). */ -extern inline int ffs(int word) +static inline int ffs(int word) { int result = ffz(~word); return word ? result+1 : 0; } +/* Compute powers of two for the given integer. */ +static inline int floor_log2(unsigned long word) +{ + long bit; +#if defined(__alpha_cix__) && defined(__alpha_fix__) + __asm__("ctlz %1,%0" : "=r"(bit) : "r"(word)); + return 63 - bit; +#else + for (bit = -1; word ; bit++) + word >>= 1; + return bit; +#endif +} + +static inline int ceil_log2(unsigned int word) +{ + long bit = floor_log2(word); + return bit + (word > (1UL << bit)); +} + /* * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word @@ -285,7 +305,7 @@ #if defined(__alpha_cix__) && defined(__alpha_fix__) /* Whee. EV67 can calculate it directly. */ -extern __inline__ unsigned long hweight64(unsigned long w) +static inline unsigned long hweight64(unsigned long w) { unsigned long result; __asm__("ctpop %1,%0" : "=r"(result) : "r"(w)); @@ -306,7 +326,7 @@ /* * Find next zero bit in a bitmap reasonably efficiently.. */ -extern inline unsigned long +static inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 6); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/core_cia.h Fri Sep 14 00:21:32 2001 +++ linux/include/asm-alpha/core_cia.h Sun Sep 16 23:31:44 2001 @@ -263,6 +263,9 @@ #define PYXIS_IIC_CTRL (IDENT_ADDR + 0x87A00002C0UL) #define PYXIS_RESET (IDENT_ADDR + 0x8780000900UL) +/* Offset between ram physical addresses and pci64 DAC bus addresses. */ +#define PYXIS_DAC_OFFSET (1UL << 40) + /* * Data structure for handling CIA machine checks. */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/core_mcpcia.h Fri Sep 14 00:21:32 2001 +++ linux/include/asm-alpha/core_mcpcia.h Sun Sep 16 23:31:44 2001 @@ -181,6 +181,8 @@ #define MCPCIA_IO_BIAS MCPCIA_IO(4) #define MCPCIA_MEM_BIAS MCPCIA_DENSE(4) +/* Offset between ram physical addresses and pci64 DAC bus addresses. */ +#define MCPCIA_DAC_OFFSET (1UL << 40) /* * Data structure for handling MCPCIA machine checks: diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/core_titan.h linux/include/asm-alpha/core_titan.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/core_titan.h Fri Sep 14 00:21:32 2001 +++ linux/include/asm-alpha/core_titan.h Sun Sep 16 23:31:44 2001 @@ -308,14 +308,18 @@ * devices can use their familiar numbers and have them map to bus 0. */ -#define TITAN_IO_BIAS TITAN_IO(0) -#define TITAN_MEM_BIAS TITAN_MEM(0) +#define TITAN_IO_BIAS TITAN_IO(0) +#define TITAN_MEM_BIAS TITAN_MEM(0) /* The IO address space is larger than 0xffff */ #define TITAN_IO_SPACE (TITAN_CONF(0) - TITAN_IO(0)) /* TIG Space */ #define TITAN_TIG_SPACE (TITAN_BASE + 0x100000000UL) + +/* Offset between ram physical addresses and pci64 DAC bus addresses. */ +/* ??? Just a guess. Ought to confirm it hasn't been moved. */ +#define TITAN_DAC_OFFSET (1UL << 40) /* * Data structure for handling TITAN machine checks: diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/core_tsunami.h Fri Sep 14 00:21:32 2001 +++ linux/include/asm-alpha/core_tsunami.h Sun Sep 16 23:31:44 2001 @@ -275,7 +275,7 @@ /* The IO address space is larger than 0xffff */ #define TSUNAMI_IO_SPACE (TSUNAMI_CONF(0) - TSUNAMI_IO(0)) -/* Offset between ram physical addresses and pci64 DAC bus addresses */ +/* Offset between ram physical addresses and pci64 DAC bus addresses. */ #define TSUNAMI_DAC_OFFSET (1UL << 40) /* diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/machvec.h Fri Sep 14 00:21:32 2001 +++ linux/include/asm-alpha/machvec.h Sun Sep 16 23:31:44 2001 @@ -39,6 +39,7 @@ unsigned long iack_sc; unsigned long min_io_address; unsigned long min_mem_address; + unsigned long pci_dac_offset; void (*mv_pci_tbi)(struct pci_controller *hose, dma_addr_t start, dma_addr_t end); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/pci.h Mon May 21 22:38:41 2001 +++ linux/include/asm-alpha/pci.h Sun Sep 16 23:31:44 2001 @@ -15,6 +15,7 @@ struct pci_bus; struct resource; struct pci_iommu_arena; +struct page; /* A controller. Used to manage multiple PCI busses. */ @@ -60,12 +61,17 @@ /* IOMMU controls. */ +/* The PCI address space does not equal the physical memory address space. + The networking and block device layers use this boolean for bounce buffer + decisions. */ +#define PCI_DMA_BUS_IS_PHYS 0 + /* Allocate and map kernel buffer using consistant mode DMA for PCI device. Returns non-NULL cpu-view pointer to the buffer if successful and sets *DMA_ADDRP to the pci side dma address as well, else DMA_ADDRP is undefined. */ -extern void *pci_alloc_consistent(struct pci_dev *, long, dma_addr_t *); +extern void *pci_alloc_consistent(struct pci_dev *, size_t, dma_addr_t *); /* Free and unmap a consistant DMA buffer. CPU_ADDR and DMA_ADDR must be values that were returned from pci_alloc_consistant. SIZE must @@ -73,14 +79,18 @@ References to the memory and mappings assosciated with CPU_ADDR or DMA_ADDR past this call are illegal. */ -extern void pci_free_consistent(struct pci_dev *, long, void *, dma_addr_t); +extern void pci_free_consistent(struct pci_dev *, size_t, void *, dma_addr_t); /* Map a single buffer of the indicate size for PCI DMA in streaming mode. The 32-bit PCI bus mastering 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. */ -extern dma_addr_t pci_map_single(struct pci_dev *, void *, long, int); +extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int); + +/* Likewise, but for a page instead of an address. */ +extern dma_addr_t pci_map_page(struct pci_dev *, struct page *, + unsigned long, size_t, int); /* Unmap a single streaming mode DMA translation. The DMA_ADDR and SIZE must match what was provided for in a previous pci_map_single @@ -88,7 +98,8 @@ the cpu to the buffer are guarenteed to see whatever the device wrote there. */ -extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long, int); +extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int); +extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int); /* Map a set of buffers described by scatterlist in streaming mode for PCI DMA. This is the scather-gather version of the above @@ -121,7 +132,7 @@ point you give the PCI dma address back to the card, the device again owns the buffer. */ -extern inline void +static inline void pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, int direction) { @@ -132,7 +143,7 @@ translations after a transfer. The same as pci_dma_sync_single but for a scatter-gather list, same rules and usage. */ -extern inline void +static inline void pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int direction) { @@ -144,7 +155,22 @@ only drive the low 24-bits during PCI bus mastering, then you would pass 0x00ffffff as the mask to this function. */ -extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask); +extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); + +/* True if the machine supports DAC addressing, and DEV can + make use of it given MASK. */ +extern int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask); + +/* Convert to/from DAC dma address and struct page. */ +extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *, struct page *, unsigned long, int); +extern struct page *pci_dac_dma_to_page(struct pci_dev *, dma64_addr_t); +extern unsigned long pci_dac_dma_to_offset(struct pci_dev *, dma64_addr_t); + +static __inline__ void +pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* Nothing to do. */ +} /* Return the index of the PCI controller for device PDEV. */ extern int pci_controller_num(struct pci_dev *pdev); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/scatterlist.h linux/include/asm-alpha/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/scatterlist.h Tue Feb 8 05:09:05 2000 +++ linux/include/asm-alpha/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -1,19 +1,25 @@ #ifndef _ALPHA_SCATTERLIST_H #define _ALPHA_SCATTERLIST_H -#include - +#include + struct scatterlist { - char *address; /* Source/target vaddr. */ - char *alt_address; /* Location of actual if address is a - dma indirect buffer, else NULL. */ - dma_addr_t dma_address; + /* This will disappear in 2.5.x */ + char *address; + + /* These two are only valid if ADDRESS member of this + struct is NULL. */ + struct page *page; + unsigned int offset; + unsigned int length; - unsigned int dma_length; + + dma_addr_t dma_address; + __u32 dma_length; }; -#define sg_dma_address(sg) ((sg)->dma_address) -#define sg_dma_len(sg) ((sg)->dma_length) +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->dma_length) #define ISA_DMA_THRESHOLD (~0UL) diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-alpha/types.h linux/include/asm-alpha/types.h --- /opt/kernel/linux-2.4.10/include/asm-alpha/types.h Tue Feb 8 05:09:05 2000 +++ linux/include/asm-alpha/types.h Sun Sep 16 23:31:44 2001 @@ -47,10 +47,8 @@ #define BITS_PER_LONG 64 -/* PCI dma addresses are 32-bits wide. Ignore PCI64 for now, since - we'll typically be sending it all through iommu tables anyway. */ - -typedef u32 dma_addr_t; +typedef u64 dma_addr_t; +typedef u64 dma64_addr_t; #endif /* __KERNEL__ */ #endif /* _ALPHA_TYPES_H */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-arm/pci.h linux/include/asm-arm/pci.h --- /opt/kernel/linux-2.4.10/include/asm-arm/pci.h Sun Aug 12 20:14:00 2001 +++ linux/include/asm-arm/pci.h Sun Sep 16 23:31:44 2001 @@ -152,7 +152,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-arm/scatterlist.h linux/include/asm-arm/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-arm/scatterlist.h Sun Sep 3 20:19:11 2000 +++ linux/include/asm-arm/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -5,7 +5,6 @@ struct scatterlist { char *address; /* virtual address */ - char *alt_address; /* indirect dma address, or NULL */ dma_addr_t dma_address; /* dma address */ unsigned int length; /* length */ }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h --- /opt/kernel/linux-2.4.10/include/asm-i386/kmap_types.h Mon Sep 17 22:16:30 2001 +++ linux/include/asm-i386/kmap_types.h Mon Sep 24 00:15:36 2001 @@ -7,6 +7,7 @@ KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, + KM_BH_IRQ, KM_TYPE_NR }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-i386/pci.h linux/include/asm-i386/pci.h --- /opt/kernel/linux-2.4.10/include/asm-i386/pci.h Sun Sep 23 19:31:59 2001 +++ linux/include/asm-i386/pci.h Mon Sep 24 00:17:47 2001 @@ -34,6 +34,12 @@ struct pci_dev; +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + /* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices, * NULL for PCI-like buses (ISA, EISA). @@ -84,6 +90,27 @@ /* Nothing to do */ } +/* + * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical + * to pci_map_single, but takes a struct page instead of a virtual address + */ +static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, + unsigned long offset, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + + return (page - mem_map) * PAGE_SIZE + offset; +} + +static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, + size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + /* 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 @@ -102,8 +129,26 @@ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + int i; + if (direction == PCI_DMA_NONE) BUG(); + + /* + * temporary 2.4 hack + */ + for (i = 0; i < nents; i++ ) { + if (sg[i].address && sg[i].page) + BUG(); + else if (!sg[i].address && !sg[i].page) + BUG(); + + if (sg[i].address) + sg[i].dma_address = virt_to_bus(sg[i].address); + else + sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset; + } + return nents; } @@ -157,7 +202,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { /* * we fall back to GFP_DMA when the mask isn't all 1s, @@ -170,13 +215,42 @@ return 1; } +/* This is always fine. */ +#define pci_dac_dma_supported(pci_dev, mask) (1) + +static __inline__ dma64_addr_t +pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) +{ + return ((dma64_addr_t) page_to_bus(page) + + (dma64_addr_t) offset); +} + +static __inline__ struct page * +pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + unsigned long poff = (dma_addr >> PAGE_SHIFT); + + return mem_map + poff; +} + +static __inline__ unsigned long +pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + return (dma_addr & ~PAGE_MASK); +} + +static __inline__ void +pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* Nothing to do. */ +} + /* These macros should be used after a pci_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. * You should only work with the number of sg entries pci_map_sg - * returns, or alternatively stop on the first sg_dma_len(sg) which - * is 0. + * returns. */ -#define sg_dma_address(sg) (virt_to_bus((sg)->address)) +#define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) /* Return the index of the PCI controller for device. */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-i386/scatterlist.h linux/include/asm-i386/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-i386/scatterlist.h Mon Dec 30 12:01:10 1996 +++ linux/include/asm-i386/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -1,10 +1,32 @@ #ifndef _I386_SCATTERLIST_H #define _I386_SCATTERLIST_H -struct scatterlist { - char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ +/* + * Drivers must set either ->address or (preferred) ->page and ->offset + * to indicate where data must be transferred to/from. + * + * Using ->page is recommended since it handles highmem data as well as + * low mem. ->address is restricted to data which has a virtual mapping, and + * it will go away in the future. Updating to ->page can be automated very + * easily -- something like + * + * sg->address = some_ptr; + * + * can be rewritten as + * + * sg->page = virt_to_page(some_ptr); + * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK; + * + * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens + */ +struct scatterlist +{ + char *address; + + struct page *page; + unsigned int offset; + + dma_addr_t dma_address; unsigned int length; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-i386/types.h linux/include/asm-i386/types.h --- /opt/kernel/linux-2.4.10/include/asm-i386/types.h Thu Jan 27 17:58:15 2000 +++ linux/include/asm-i386/types.h Sun Sep 16 23:33:08 2001 @@ -27,6 +27,8 @@ */ #ifdef __KERNEL__ +#include + typedef signed char s8; typedef unsigned char u8; @@ -41,9 +43,14 @@ #define BITS_PER_LONG 32 -/* Dma addresses are 32-bits wide. */ +/* DMA addresses come in generic and 64-bit flavours. */ +#ifdef CONFIG_HIGHMEM +typedef u64 dma_addr_t; +#else typedef u32 dma_addr_t; +#endif +typedef u64 dma64_addr_t; #endif /* __KERNEL__ */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h --- /opt/kernel/linux-2.4.10/include/asm-ia64/pci.h Wed May 16 19:31:27 2001 +++ linux/include/asm-ia64/pci.h Sun Sep 16 23:31:44 2001 @@ -52,7 +52,7 @@ * you would pass 0x00ffffff as the mask to this function. */ static inline int -pci_dma_supported (struct pci_dev *hwdev, dma_addr_t mask) +pci_dma_supported (struct pci_dev *hwdev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-ia64/scatterlist.h linux/include/asm-ia64/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-ia64/scatterlist.h Sat Aug 12 04:09:06 2000 +++ linux/include/asm-ia64/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -8,11 +8,6 @@ struct scatterlist { char *address; /* location data is to be transferred to */ - /* - * Location of actual buffer if ADDRESS points to a DMA - * indirection buffer, NULL otherwise: - */ - char *alt_address; char *orig_address; /* Save away the original buffer address (used by pci-dma.c) */ unsigned int length; /* buffer length */ }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-m68k/scatterlist.h linux/include/asm-m68k/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-m68k/scatterlist.h Tue May 11 18:57:14 1999 +++ linux/include/asm-m68k/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; unsigned long dvma_address; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-mips/pci.h linux/include/asm-mips/pci.h --- /opt/kernel/linux-2.4.10/include/asm-mips/pci.h Sun Sep 9 19:43:01 2001 +++ linux/include/asm-mips/pci.h Sun Sep 16 23:31:44 2001 @@ -215,7 +215,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { /* * we fall back to GFP_DMA when the mask isn't all 1s, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-mips/scatterlist.h linux/include/asm-mips/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-mips/scatterlist.h Tue Dec 16 21:46:12 1997 +++ linux/include/asm-mips/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; __u32 dvma_address; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h --- /opt/kernel/linux-2.4.10/include/asm-mips64/pci.h Sun Sep 9 19:43:02 2001 +++ linux/include/asm-mips64/pci.h Sun Sep 16 23:31:44 2001 @@ -220,7 +220,7 @@ } #endif /* CONFIG_MAPPED_PCI_IO */ -static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { /* * we fall back to GFP_DMA when the mask isn't all 1s, diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-mips64/scatterlist.h linux/include/asm-mips64/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-mips64/scatterlist.h Fri Feb 25 07:53:35 2000 +++ linux/include/asm-mips64/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; __u32 dvma_address; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-parisc/pci.h linux/include/asm-parisc/pci.h --- /opt/kernel/linux-2.4.10/include/asm-parisc/pci.h Wed May 16 19:31:27 2001 +++ linux/include/asm-parisc/pci.h Sun Sep 16 23:31:44 2001 @@ -113,7 +113,7 @@ ** See Documentation/DMA-mapping.txt */ struct pci_dma_ops { - int (*dma_supported)(struct pci_dev *dev, dma_addr_t mask); + int (*dma_supported)(struct pci_dev *dev, u64 mask); void *(*alloc_consistent)(struct pci_dev *dev, size_t size, dma_addr_t *iova); void (*free_consistent)(struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t iova); dma_addr_t (*map_single)(struct pci_dev *dev, void *addr, size_t size, int direction); diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-parisc/scatterlist.h linux/include/asm-parisc/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-parisc/scatterlist.h Tue Dec 5 21:29:39 2000 +++ linux/include/asm-parisc/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; /* an IOVA can be 64-bits on some PA-Risc platforms. */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h --- /opt/kernel/linux-2.4.10/include/asm-ppc/pci.h Tue May 22 00:02:06 2001 +++ linux/include/asm-ppc/pci.h Sun Sep 16 23:31:44 2001 @@ -108,7 +108,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-ppc/scatterlist.h linux/include/asm-ppc/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-ppc/scatterlist.h Tue May 22 00:02:06 2001 +++ linux/include/asm-ppc/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -9,8 +9,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-s390/scatterlist.h linux/include/asm-s390/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-s390/scatterlist.h Tue Feb 13 23:13:44 2001 +++ linux/include/asm-s390/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-s390x/scatterlist.h linux/include/asm-s390x/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-s390x/scatterlist.h Tue Feb 13 23:13:44 2001 +++ linux/include/asm-s390x/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sh/pci.h linux/include/asm-sh/pci.h --- /opt/kernel/linux-2.4.10/include/asm-sh/pci.h Sat Sep 8 21:29:09 2001 +++ linux/include/asm-sh/pci.h Sun Sep 16 23:31:44 2001 @@ -191,7 +191,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sh/scatterlist.h linux/include/asm-sh/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-sh/scatterlist.h Sun Mar 5 18:33:55 2000 +++ linux/include/asm-sh/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -3,8 +3,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; }; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h --- /opt/kernel/linux-2.4.10/include/asm-sparc/pci.h Wed May 16 19:31:27 2001 +++ linux/include/asm-sparc/pci.h Sun Sep 16 23:31:44 2001 @@ -108,7 +108,7 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) { return 1; } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-sparc/scatterlist.h Tue Feb 1 08:37:19 2000 +++ linux/include/asm-sparc/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -6,8 +6,6 @@ struct scatterlist { char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ unsigned int length; __u32 dvma_address; /* A place to hang host-specific addresses at. */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h --- /opt/kernel/linux-2.4.10/include/asm-sparc64/pci.h Wed May 16 19:31:27 2001 +++ linux/include/asm-sparc64/pci.h Sun Sep 16 23:31:44 2001 @@ -28,6 +28,12 @@ /* Dynamic DMA mapping stuff. */ +/* The PCI address space does not equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (0) + #include struct pci_dev; @@ -64,6 +70,11 @@ */ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); +/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ +#define pci_map_page(dev, page, off, size, dir) \ + pci_map_single(dev, (page_address(page) + (off)), size, dir) +#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir) + /* 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 @@ -79,13 +90,15 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); +extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction); /* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction); +extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nhwents, int direction); /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. @@ -96,7 +109,8 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); +extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction); /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. @@ -111,7 +125,51 @@ * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask); +extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); + +/* PCI IOMMU mapping bypass support. */ + +/* PCI 64-bit addressing works for all slots on all controller + * types on sparc64. However, it requires that the device + * can drive enough of the 64 bits. + */ +#define PCI64_REQUIRED_MASK (~(dma64_addr_t)0) +#define PCI64_ADDR_BASE 0xfffc000000000000 + +/* Usage of the pci_dac_foo interfaces is only valid if this + * test passes. + */ +#define pci_dac_dma_supported(pci_dev, mask) \ + ((((mask) & PCI64_REQUIRED_MASK) == PCI64_REQUIRED_MASK) ? 1 : 0) + +static __inline__ dma64_addr_t +pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) +{ + return (PCI64_ADDR_BASE + + __pa(page_address(page)) + offset); +} + +static __inline__ struct page * +pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + unsigned long paddr = (dma_addr & PAGE_MASK) - PCI64_ADDR_BASE; + + return virt_to_page(__va(paddr)); +} + +static __inline__ unsigned long +pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) +{ + return (dma_addr & ~PAGE_MASK); +} + +static __inline__ void +pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* DAC cycle addressing does not make use of the + * PCI controller's streaming cache, so nothing to do. + */ +} /* Return the index of the PCI controller for device PDEV. */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sparc64/scatterlist.h linux/include/asm-sparc64/scatterlist.h --- /opt/kernel/linux-2.4.10/include/asm-sparc64/scatterlist.h Tue Dec 21 07:05:52 1999 +++ linux/include/asm-sparc64/scatterlist.h Sun Sep 16 23:31:44 2001 @@ -5,17 +5,23 @@ #include struct scatterlist { - char * address; /* Location data is to be transferred to */ - char * alt_address; /* Location of actual if address is a - * dma indirect buffer. NULL otherwise */ - unsigned int length; + /* This will disappear in 2.5.x */ + char *address; - __u32 dvma_address; /* A place to hang host-specific addresses at. */ - __u32 dvma_length; + /* These two are only valid if ADDRESS member of this + * struct is NULL. + */ + struct page *page; + unsigned int offset; + + unsigned int length; + + dma_addr_t dma_address; + __u32 dma_length; }; -#define sg_dma_address(sg) ((sg)->dvma_address) -#define sg_dma_len(sg) ((sg)->dvma_length) +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->dma_length) #define ISA_DMA_THRESHOLD (~0UL) diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/asm-sparc64/types.h linux/include/asm-sparc64/types.h --- /opt/kernel/linux-2.4.10/include/asm-sparc64/types.h Tue Feb 1 08:37:19 2000 +++ linux/include/asm-sparc64/types.h Sun Sep 16 23:31:44 2001 @@ -45,9 +45,10 @@ #define BITS_PER_LONG 64 -/* Dma addresses are 32-bits wide for now. */ +/* Dma addresses come in generic and 64-bit flavours. */ typedef u32 dma_addr_t; +typedef u64 dma64_addr_t; #endif /* __KERNEL__ */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/linux/blkdev.h linux/include/linux/blkdev.h --- /opt/kernel/linux-2.4.10/include/linux/blkdev.h Sun Sep 23 19:32:57 2001 +++ linux/include/linux/blkdev.h Mon Sep 24 01:08:46 2001 @@ -7,6 +7,8 @@ #include #include +#include + struct request_queue; typedef struct request_queue request_queue_t; struct elevator_s; @@ -36,7 +38,7 @@ unsigned long hard_sector, hard_nr_sectors; unsigned int nr_segments; unsigned int nr_hw_segments; - unsigned long current_nr_sectors; + unsigned long current_nr_sectors, hard_cur_sectors; void * special; char * buffer; struct completion * waiting; @@ -110,6 +112,8 @@ */ char head_active; + struct page *bounce_limit; + /* * Is meant to protect the queue in the future instead of * io_request_lock @@ -122,6 +126,32 @@ wait_queue_head_t wait_for_request; }; +extern unsigned long blk_max_low_pfn; + +#define BLK_BOUNCE_HIGH (blk_max_low_pfn * PAGE_SIZE) +#define BLK_BOUNCE_ANY (~(unsigned long long) 0) + +extern void blk_queue_bounce_limit(request_queue_t *, u64); + +#ifdef CONFIG_HIGHMEM +extern struct buffer_head *create_bounce(int, struct buffer_head *); +extern inline struct buffer_head *blk_queue_bounce(request_queue_t *q, int rw, + struct buffer_head *bh) +{ + if (bh->b_page <= q->bounce_limit) + return bh; + + return create_bounce(rw, bh); +} +#else +#define blk_queue_bounce(q, rw, bh) (bh) +#endif + +#define bh_phys(bh) (page_to_phys((bh)->b_page) + bh_offset((bh))) + +#define BH_CONTIG(b1, b2) (bh_phys((b1)) + (b1)->b_size == bh_phys((b2))) +#define BH_PHYS_4G(b1, b2) ((bh_phys((b1)) | 0xffffffff) == ((bh_phys((b2)) + (b2)->b_size - 1) | 0xffffffff)) + struct blk_dev_struct { /* * queue_proc has to be atomic @@ -160,6 +190,8 @@ extern void blk_queue_headactive(request_queue_t *, int); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void generic_unplug_device(void *); +extern inline int blk_seg_merge_ok(request_queue_t *, struct buffer_head *, + struct buffer_head *); extern int * blk_size[MAX_BLKDEV]; diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/linux/highmem.h linux/include/linux/highmem.h --- /opt/kernel/linux-2.4.10/include/linux/highmem.h Sun Sep 23 19:31:02 2001 +++ linux/include/linux/highmem.h Mon Sep 24 00:17:37 2001 @@ -13,8 +13,7 @@ /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); -extern struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig); - +extern struct buffer_head *create_bounce(int rw, struct buffer_head * bh_orig); static inline char *bh_kmap(struct buffer_head *bh) { @@ -26,6 +25,42 @@ kunmap(bh->b_page); } +/* + * remember to add offset! and never ever reenable interrupts between a + * bh_kmap_irq and bh_kunmap_irq!! + */ +static inline char *bh_kmap_irq(struct buffer_head *bh, unsigned long *flags) +{ + unsigned long addr; + + __save_flags(*flags); + + /* + * could be low + */ + if (!PageHighMem(bh->b_page)) + return bh->b_data; + + /* + * it's a highmem page + */ + __cli(); + addr = (unsigned long) kmap_atomic(bh->b_page, KM_BH_IRQ); + + if (addr & ~PAGE_MASK) + BUG(); + + return (char *) addr + bh_offset(bh); +} + +static inline void bh_kunmap_irq(char *buffer, unsigned long *flags) +{ + unsigned long ptr = (unsigned long) buffer & PAGE_MASK; + + kunmap_atomic((void *) ptr, KM_BH_IRQ); + __restore_flags(*flags); +} + #else /* CONFIG_HIGHMEM */ static inline unsigned int nr_free_highpages(void) { return 0; } @@ -37,8 +72,10 @@ #define kmap_atomic(page,idx) kmap(page) #define kunmap_atomic(page,idx) kunmap(page) -#define bh_kmap(bh) ((bh)->b_data) -#define bh_kunmap(bh) do { } while (0) +#define bh_kmap(bh) ((bh)->b_data) +#define bh_kunmap(bh) do { } while (0) +#define bh_kmap_irq(bh, flags) ((bh)->b_data) +#define bh_kunmap_irq(bh, flags) do { } while (0) #endif /* CONFIG_HIGHMEM */ diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/linux/ide.h linux/include/linux/ide.h --- /opt/kernel/linux-2.4.10/include/linux/ide.h Sun Sep 23 19:32:55 2001 +++ linux/include/linux/ide.h Mon Sep 24 01:08:55 2001 @@ -507,6 +507,7 @@ unsigned reset : 1; /* reset after probe */ unsigned autodma : 1; /* automatically try to enable DMA at boot */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ + unsigned highmem : 1; /* can do full 32-bit dma */ byte channel; /* for dual-port chips: 0=primary, 1=secondary */ #ifdef CONFIG_BLK_DEV_IDEPCI struct pci_dev *pci_dev; /* for pci chipsets */ @@ -812,6 +813,21 @@ ide_preempt, /* insert rq in front of current request */ ide_end /* insert rq at end of list, but don't wait for it */ } ide_action_t; + +/* + * temporarily mapping a (possible) highmem bio + */ +#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) + +extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags) +{ + return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq); +} + +extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags) +{ + bh_kunmap_irq(buffer, flags); +} /* * This function issues a special IDE device request diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/include/linux/pci.h linux/include/linux/pci.h --- /opt/kernel/linux-2.4.10/include/linux/pci.h Sun Sep 23 19:31:59 2001 +++ linux/include/linux/pci.h Mon Sep 24 00:17:47 2001 @@ -353,7 +353,7 @@ struct pci_driver *driver; /* which driver has allocated this device */ void *driver_data; /* data private to the driver */ - dma_addr_t dma_mask; /* Mask of the bits of bus address this + u64 dma_mask; /* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change this if your device has broken DMA @@ -559,7 +559,8 @@ int pci_enable_device(struct pci_dev *dev); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); -int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); +int pci_set_dma_mask(struct pci_dev *dev, u64 mask); +int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask); int pci_assign_resource(struct pci_dev *dev, int i); /* Power management related routines */ @@ -641,7 +642,8 @@ static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } static inline void pci_disable_device(struct pci_dev *dev) { } static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } -static inline int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) { return -EIO; } +static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } +static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} static inline int pci_register_driver(struct pci_driver *drv) { return 0;} static inline void pci_unregister_driver(struct pci_driver *drv) { } diff -ur --exclude-from /home/axboe/cdrom/exclude /opt/kernel/linux-2.4.10/kernel/ksyms.c linux/kernel/ksyms.c --- /opt/kernel/linux-2.4.10/kernel/ksyms.c Tue Sep 18 00:28:32 2001 +++ linux/kernel/ksyms.c Mon Sep 24 00:15:36 2001 @@ -121,6 +121,8 @@ EXPORT_SYMBOL(kunmap_high); EXPORT_SYMBOL(highmem_start_page); EXPORT_SYMBOL(create_bounce); +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); #endif /* filesystem internal functions */