Modern Linux systems require large amount of graphics memory to store frame buffers, textures, vertices and other graphics-related data. Given the very dynamic nature of many of that data, managing graphics memory efficiently is thus crucial for the graphics stack and plays a central role in the DRM infrastructure.
The DRM core includes two memory managers, namely Translation Table Maps (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory manager to be developed and tried to be a one-size-fits-them all solution. It provides a single userspace API to accommodate the need of all hardware, supporting both Unified Memory Architecture (UMA) devices and devices with dedicated video RAM (i.e. most discrete video cards). This resulted in a large, complex piece of code that turned out to be hard to use for driver development.
GEM started as an Intel-sponsored project in reaction to TTM's complexity. Its design philosophy is completely different: instead of providing a solution to every graphics memory-related problems, GEM identified common code between drivers and created a support library to share it. GEM has simpler initialization and execution requirements than TTM, but has no video RAM management capabilities and is thus limited to UMA devices.
TTM design background and information belongs here.
Warning This section is outdated.
Drivers wishing to support TTM must pass a filled ttm_bo_driver structure to ttm_bo_device_init, together with an initialized global reference to the memory manager. The ttm_bo_driver structure contains several fields with function pointers for initializing the TTM, allocating and freeing memory, waiting for command completion and fence synchronization, and memory migration.
There should be one global reference structure for your memory manager as a whole, and there will be others for each object created by the memory manager at runtime. Your global TTM should have a type of TTM_GLOBAL_TTM_MEM. The size field for the global object should be sizeof(struct ttm_mem_global), and the init and release hooks should point at your driver-specific init and release routines, which probably eventually call ttm_mem_global_init and ttm_mem_global_release, respectively.
Once your global TTM accounting structure is set up and initialized by calling ttm_global_item_ref() on it, you need to create a buffer object TTM to provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, driver-specific init and release functions may be provided, likely eventually calling ttm_bo_global_ref_init() and ttm_bo_global_ref_release(), respectively. Also, like the previous object, ttm_global_item_ref() is used to create an initial reference count for the TTM, which will call your initialization function.
See the radeon_ttm.c file for an example of usage.
The GEM design approach has resulted in a memory manager that doesn't provide full coverage of all (or even all common) use cases in its userspace or kernel API. GEM exposes a set of standard memory-related operations to userspace and a set of helper functions to drivers, and let drivers implement hardware-specific operations with their own private API.
The GEM userspace API is described in the GEM - the Graphics Execution Manager article on LWN. While slightly outdated, the document provides a good overview of the GEM API principles. Buffer allocation and read and write operations, described as part of the common GEM API, are currently implemented using driver-specific ioctls.
GEM is data-agnostic. It manages abstract buffer objects without knowing what individual buffers contain. APIs that require knowledge of buffer contents or purpose, such as buffer allocation or synchronization primitives, are thus outside of the scope of GEM and must be implemented using driver-specific ioctls.
Buffer object allocation is relatively straightforward and largely provided by Linux's shmem layer, which provides memory to back each object.
Device-specific operations, such as command execution, pinning, buffer read & write, mapping, and domain ownership transfers are left to driver-specific ioctls.
Drivers that use GEM must set the DRIVER_GEM bit in the struct struct drm_driver driver_features field. The DRM core will then automatically initialize the GEM core before calling the load operation. Behind the scene, this will create a DRM Memory Manager object which provides an address space pool for object allocation.
In a KMS configuration, drivers need to allocate and initialize a command ring buffer following core GEM initialization if required by the hardware. UMA devices usually have what is called a "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the device. This space is typically not managed by GEM, and must be initialized separately into its own DRM MM object.
GEM splits creation of GEM objects and allocation of the memory that backs them in two distinct operations.
GEM objects are represented by an instance of struct struct drm_gem_object. Drivers usually need to extend GEM objects with private information and thus create a driver-specific GEM object structure type that embeds an instance of struct struct drm_gem_object.
To create a GEM object, a driver allocates memory for an instance of its specific GEM object type and initializes the embedded struct struct drm_gem_object with a call to drm_gem_object_init(). The function takes a pointer to the DRM device, a pointer to the GEM object and the buffer object size in bytes.
GEM uses shmem to allocate anonymous pageable memory. drm_gem_object_init() will create an shmfs file of the requested size and store it into the struct struct drm_gem_object filp field. The memory is used as either main storage for the object when the graphics hardware uses system memory directly or as a backing store otherwise.
Drivers are responsible for the actual physical pages allocation by calling shmem_read_mapping_page_gfp() for each page. Note that they can decide to allocate pages when initializing the GEM object, or to delay allocation until the memory is needed (for instance when a page fault occurs as a result of a userspace memory access or when the driver needs to start a DMA transfer involving the memory).
Anonymous pageable memory allocation is not always desired, for instance when the hardware requires physically contiguous system memory as is often the case in embedded devices. Drivers can create GEM objects with no shmfs backing (called private GEM objects) by initializing them with a call to drm_gem_private_object_init() instead of drm_gem_object_init(). Storage for private GEM objects must be managed by drivers.
All GEM objects are reference-counted by the GEM core. References can be acquired and release by calling drm_gem_object_get() and drm_gem_object_put() respectively. The caller must hold the struct drm_device struct_mutex lock when calling drm_gem_object_get(). As a convenience, GEM provides drm_gem_object_put_unlocked() functions that can be called without holding the lock.
When the last reference to a GEM object is released the GEM core calls the struct drm_driver gem_free_object_unlocked operation. That operation is mandatory for GEM-enabled drivers and must free the GEM object and all associated resources.
void (*gem_free_object) (struct drm_gem_object *obj); Drivers are responsible for freeing all GEM object resources. This includes the resources created by the GEM core, which need to be released with drm_gem_object_release().
Communication between userspace and the kernel refers to GEM objects using local handles, global names or, more recently, file descriptors. All of those are 32-bit integer values; the usual Linux kernel limits apply to the file descriptors.
GEM handles are local to a DRM file. Applications get a handle to a GEM object through a driver-specific ioctl, and can use that handle to refer to the GEM object in other standard or driver-specific ioctls. Closing a DRM file handle frees all its GEM handles and dereferences the associated GEM objects.
To create a handle for a GEM object drivers call drm_gem_handle_create(). The function takes a pointer to the DRM file and the GEM object and returns a locally unique handle. When the handle is no longer needed drivers delete it with a call to drm_gem_handle_delete(). Finally the GEM object associated with a handle can be retrieved by a call to drm_gem_object_lookup().
Handles don't take ownership of GEM objects, they only take a reference to the object that will be dropped when the handle is destroyed. To avoid leaking GEM objects, drivers must make sure they drop the reference(s) they own (such as the initial reference taken at object creation time) as appropriate, without any special consideration for the handle. For example, in the particular case of combined GEM object and handle creation in the implementation of the dumb_create operation, drivers must drop the initial reference to the GEM object before returning the handle.
GEM names are similar in purpose to handles but are not local to DRM files. They can be passed between processes to reference a GEM object globally. Names can't be used directly to refer to objects in the DRM API, applications must convert handles to names and names to handles using the DRM_IOCTL_GEM_FLINK and DRM_IOCTL_GEM_OPEN ioctls respectively. The conversion is handled by the DRM core without any driver-specific support.
GEM also supports buffer sharing with dma-buf file descriptors through PRIME. GEM-based drivers must use the provided helpers functions to implement the exporting and importing correctly. See ?. Since sharing file descriptors is inherently more secure than the easily guessable and global GEM names it is the preferred buffer sharing mechanism. Sharing buffers through GEM names is only supported for legacy userspace. Furthermore PRIME also allows cross-device buffer sharing since it is based on dma-bufs.
Because mapping operations are fairly heavyweight GEM favours read/write-like access to buffers, implemented through driver-specific ioctls, over mapping buffers to userspace. However, when random access to the buffer is needed (to perform software rendering for instance), direct access to the object can be more efficient.
The mmap system call can't be used directly to map GEM objects, as they don't have their own file handle. Two alternative methods currently co-exist to map GEM objects to userspace. The first method uses a driver-specific ioctl to perform the mapping operation, calling do_mmap() under the hood. This is often considered dubious, seems to be discouraged for new GEM-enabled drivers, and will thus not be described here.
The second method uses the mmap system call on the DRM file handle. void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); DRM identifies the GEM object to be mapped by a fake offset passed through the mmap offset argument. Prior to being mapped, a GEM object must thus be associated with a fake offset. To do so, drivers must call drm_gem_create_mmap_offset() on the object.
Once allocated, the fake offset value must be passed to the application in a driver-specific way and can then be used as the mmap offset argument.
The GEM core provides a helper method drm_gem_mmap() to handle object mapping. The method can be set directly as the mmap file operation handler. It will look up the GEM object based on the offset value and set the VMA operations to the struct drm_driver gem_vm_ops field. Note that drm_gem_mmap() doesn't map memory to userspace, but relies on the driver-provided fault handler to map pages individually.
To use drm_gem_mmap(), drivers must fill the struct struct drm_driver gem_vm_ops field with a pointer to VM operations.
The open and close operations must update the GEM object reference count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper functions directly as open and close handlers.
The fault operation handler is responsible for mapping individual pages to userspace when a page fault occurs. Depending on the memory allocation scheme, drivers can allocate pages at fault time, or can decide to allocate memory for the GEM object at the time the object is created.
Drivers that want to map the GEM object upfront instead of handling page faults can implement their own mmap file operation handler.
For platforms without MMU the GEM core provides a helper method drm_gem_cma_get_unmapped_area(). The mmap() routines will call this to get a proposed address for the mapping.
To use drm_gem_cma_get_unmapped_area(), drivers must fill the struct struct file_operations get_unmapped_area field with a pointer on drm_gem_cma_get_unmapped_area().
When mapped to the device or used in a command buffer, backing pages for an object are flushed to memory and marked write combined so as to be coherent with the GPU. Likewise, if the CPU accesses an object after the GPU has finished rendering to the object, then the object must be made coherent with the CPU's view of memory, usually involving GPU cache flushing of various kinds. This core CPU<->GPU coherency management is provided by a device-specific ioctl, which evaluates an object's current domain and performs any necessary flushing or synchronization to put the object into the desired coherency domain (note that the object may be busy, i.e. an active render target; in that case, setting the domain blocks the client and waits for rendering to complete before performing any necessary flushing operations).
Perhaps the most important GEM function for GPU devices is providing a command execution interface to clients. Client programs construct command buffers containing references to previously allocated memory objects, and then submit them to GEM. At that point, GEM takes care to bind all the objects into the GTT, execute the buffer, and provide necessary synchronization between clients accessing the same buffers. This often involves evicting some objects from the GTT and re-binding others (a fairly expensive operation), and providing relocation support which hides fixed GTT offsets from clients. Clients must take care not to submit command buffers that reference more objects than can fit in the GTT; otherwise, GEM will reject them and no rendering will occur. Similarly, if several objects in the buffer require fence registers to be allocated for correct rendering (e.g. 2D blits on pre-965 chips), care must be taken not to require more fence registers than are available to the client. Such resource management should be abstracted from the client in libdrm.
Called upon GEM handle creation.
Called upon GEM handle release.
If driver subclasses struct drm_gem_object, it can implement this optional hook for printing additional driver specific info.
drm_printf_indent() should be used in the callback passing it the indent argument.
This callback is called from drm_gem_print_info().
Export backing buffer as a dma_buf. If this is not set drm_gem_prime_export() is used.
Pin backing buffer in memory.
Returns a Scatter-Gather table representation of the buffer. Used when exporting a buffer.
This callback is mandatory if buffer export is supported.
Returns a virtual address for the buffer.
Releases the the address previously returned by vmap.
Virtual memory operations used with mmap.
This is optional but necessary for mmap support.
Please use drm_gem_object_get() to acquire and drm_gem_object_put() or drm_gem_object_put_unlocked() to release a reference to a GEM buffer object.
This is the GEM file_priv handle count of this object.
Each handle also holds a reference. Note that when the handle_count drops to 0 any global names (e.g. the id in the flink namespace) will be cleared.
DRM dev this object belongs to.
SHMEM file node used as backing storage for swappable buffer objects. GEM also supports driver private objects with driver-specific backing storage (contiguous CMA memory, special reserved blocks). In this case filp is NULL.
Mapping info for this object to support mmap. Drivers are supposed to allocate the mmap offset using drm_gem_create_mmap_offset(). The offset itself can be retrieved using drm_vma_node_offset_addr().
Memory mapping itself is handled by drm_gem_mmap(), which also checks that userspace is allowed to access the object.
Size of the object, in bytes. Immutable over the object's lifetime.
Global name for this object, starts at 1. 0 means unnamed. Access is covered by drm_device.object_name_lock. This is used by the GEM_FLINK and GEM_OPEN ioctls.
dma-buf associated with this GEM object.
Pointer to the dma-buf associated with this gem object (either through importing or exporting). We break the resulting reference loop when the last gem handle for this object is released.
dma-buf attachment backing this object.
Any foreign dma_buf imported as a gem object has this set to the attachment point for the device. This is invariant over the lifetime of a gem object.
The drm_driver.gem_free_object callback is responsible for cleaning up the dma_buf attachment and references acquired at import time.
Note that the drm gem/prime core does not depend upon drivers setting this field any more. So for drivers where this doesn't make sense (e.g. virtual devices or a displaylink behind an usb bus) they can simply leave it as NULL.
Optional GEM object functions. If this is set, it will be used instead of the corresponding drm_driver GEM callbacks.
New drivers should use this.
This structure defines the generic parts for GEM buffer objects, which are mostly around handling mmap and userspace handles.
Buffer objects are often abbreviated to BO.
This macro autogenerates a suitable struct file_operations for GEM based drivers, which can be assigned to drm_driver.fops. Note that this structure cannot be shared between drivers, because it contains a reference to the current module using THIS_MODULE.
Note that the declaration is already marked as static - if you need a non-static version of this you're probably doing it wrong and will break the THIS_MODULE reference by accident.
This function acquires an additional reference to obj. It is illegal to call this without already holding a reference. No locks required.
This function is meant to be used by drivers which are not encumbered with drm_device.struct_mutex legacy locking and which are using the gem_free_object_unlocked callback. It avoids all the locking checks and locking overhead of drm_gem_object_put() and drm_gem_object_put_unlocked().
Drivers should never call this directly in their code. Instead they should wrap it up into a driver_gem_object_put(struct driver_gem_object *obj) wrapper function, and use that. Shared code should never call this, to avoid breaking drivers by accident which still depend upon drm_device.struct_mutex locking.
Initialize an already allocated GEM object of the specified size with shmfs backing store.
Initialize an already allocated GEM object of the specified size with no GEM provided backing store. Instead the caller is responsible for backing the object and handling it.
Removes the GEM handle from the filp lookup table which has been added with drm_gem_handle_create(). If this is the last handle also cleans up linked resources like GEM names.
This implements the drm_driver.dumb_map_offset kms driver callback for drivers which use gem to manage their backing storage.
This implements the drm_driver.dumb_destroy kms driver callback for drivers which use gem to manage their backing storage.
Create a handle for this object. This adds a handle reference to the object, which includes a regular reference count. Callers will likely want to dereference the object afterwards.
Since this publishes obj to userspace it must be fully set up by this point, drivers must call this last in their buffer object creation callbacks.
This routine frees fake offsets allocated by drm_gem_create_mmap_offset().
Note that drm_gem_object_release() already calls this function, so drivers don't have to take care of releasing the mmap offset themselves when freeing the GEM object.
GEM memory mapping works by handing back to userspace a fake mmap offset it can use in a subsequent mmap(2) call. The DRM core code then looks up the object based on the offset and sets up the various memory mapping structures.
This routine allocates and attaches a fake offset for obj, in cases where the virtual size differs from the physical size (ie. drm_gem_object.size). Otherwise just use drm_gem_create_mmap_offset().
This function is idempotent and handles an already allocated mmap offset transparently. Drivers do not need to check for this case.
This routine allocates and attaches a fake offset for obj.
Drivers can call drm_gem_free_mmap_offset() before freeing obj to release the fake offset again.
This reads the page-array of the shmem-backing storage of the given gem object. An array of pages is returned. If a page is not allocated or swapped-out, this will allocate/swap-in the required pages. Note that the whole object is covered by the page-array and pinned in memory.
Use drm_gem_put_pages() to release the array and unpin all pages.
This uses the GFP-mask set on the shmem-mapping (see mapping_set_gfp_mask()). If you require other GFP-masks, you have to do those allocations yourself.
Note that you are not allowed to change gfp-zones during runtime. That is, shmem_read_mapping_page_gfp() must be called with the same gfp_zone(gfp) as set during initialization. If you have special zone constraints, set them after drm_gem_object_init() via mapping_set_gfp_mask(). shmem-core takes care to keep pages in the required zone during swap-in.
A reference to the object named by the handle if such exists on filp, NULL otherwise.
This releases any structures and resources used by obj and is the invers of drm_gem_object_init().
Called after the last reference to the object has been lost. Must be called holding drm_device.struct_mutex.
This releases a reference to obj. Callers must not hold the drm_device.struct_mutex lock when calling this function.
This releases a reference to obj. Callers must hold the drm_device.struct_mutex lock when calling this function, even when the driver doesn't use drm_device.struct_mutex for anything.
For drivers not encumbered with legacy locking use drm_gem_object_put_unlocked() instead.
This function implements the #vm_operations_struct open() callback for GEM drivers. This must be used together with drm_gem_vm_close().
This function implements the #vm_operations_struct close() callback for GEM drivers. This must be used together with drm_gem_vm_open().
Set up the VMA to prepare mapping of the GEM object using the gem_vm_ops provided by the driver. Depending on their requirements, drivers can either provide a fault handler in their gem_vm_ops (in which case any accesses to the object will be trapped, to perform migration, GTT binding, surface register allocation, or performance monitoring), or mmap the buffer memory synchronously after calling drm_gem_mmap_obj.
This function is mainly intended to implement the DMABUF mmap operation, when the GEM object is not looked up based on its fake offset. To implement the DRM mmap operation, drivers should use the drm_gem_mmap() function.
drm_gem_mmap_obj() assumes the user is granted access to the buffer while drm_gem_mmap() prevents unprivileged users from mapping random objects. So callers must verify access restrictions before calling this helper.
Return 0 or success or -EINVAL if the object size is smaller than the VMA size, or if no gem_vm_ops are provided.
If a driver supports GEM object mapping, mmap calls on the DRM file descriptor will end up here.
Look up the GEM object based on the offset passed in (vma->vm_pgoff will contain the fake offset we created when the GTT map ioctl was called on the object) and map it with a call to drm_gem_mmap_obj().
If the caller is not granted access to the buffer object, the mmap will fail with EACCES. Please see the vma manager for more information.
Make sure the backing buffer is pinned in memory.
Relax the requirement that the backing buffer is pinned in memory.
A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative error code on failure.
The Contiguous Memory Allocator reserves a pool of memory at early boot that is used to service requests for large blocks of contiguous memory.
The DRM GEM/CMA helpers use this allocator as a means to provide buffer objects that are physically contiguous in memory. This is useful for display drivers that are unable to map scattered buffers via an IOMMU.
scatter/gather table for imported PRIME buffers. The table can have more than one entry but they are guaranteed to have contiguous DMA addresses.
This macro autogenerates a suitable struct file_operations for CMA based drivers, which can be assigned to drm_driver.fops. Note that this structure cannot be shared between drivers, because it contains a reference to the current module using THIS_MODULE.
This macro provides a shortcut for setting the default GEM operations in the drm_driver structure for drivers that need the virtual address also on imported buffers.
This function creates a CMA GEM object and allocates a contiguous chunk of memory as backing store. The backing memory has the writecombine attribute set.
A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative error code on failure.
This function frees the backing memory of the CMA GEM object, cleans up the GEM object state and frees the memory used to store the object itself. If the buffer is imported and the virtual address is set, it is released. Drivers using the CMA helpers should set this as their drm_driver.gem_free_object_unlocked callback.
This aligns the pitch and size arguments to the minimum required. This is an internal helper that can be wrapped by a driver to account for hardware with more specific alignment requirements. It should not be used directly as their drm_driver.dumb_create callback.
This function computes the pitch of the dumb buffer and rounds it up to an integer number of bytes per pixel. Drivers for hardware that doesn't have any additional restrictions on the pitch can directly use this function as their drm_driver.dumb_create callback.
For hardware with additional restrictions, drivers can adjust the fields set up by userspace and pass the IOCTL data along to the drm_gem_cma_dumb_create_internal() function.
This function implements an augmented version of the GEM DRM file mmap operation for CMA objects: In addition to the usual GEM VMA setup it immediately faults in the entire object instead of using on-demaind faulting. Drivers which employ the CMA helpers should use this function as their ->:c:func: mmap() handler in the DRM device file's file_operations structure.
Instead of directly referencing this function, drivers should use the DEFINE_DRM_GEM_CMA_FOPS().macro.
This function is used in noMMU platforms to propose address mapping for a given buffer. It's intended to be used as a direct handler for the struct file_operations.get_unmapped_area operation.
mapping address on success or a negative error code on failure.
This function can be used as the drm_driver->gem_print_info callback. It prints paddr and vaddr for use in e.g. debugfs output.
This function exports a scatter/gather table suitable for PRIME usage by calling the standard DMA mapping API. Drivers using the CMA helpers should set this as their drm_driver.gem_prime_get_sg_table callback.
A pointer to the scatter/gather table of pinned pages or NULL on failure.
This function imports a scatter/gather table exported via DMA-BUF by another driver. Imported buffers must be physically contiguous in memory (i.e. the scatter/gather table must contain a single entry). Drivers that use the CMA helpers should set this as their drm_driver.gem_prime_import_sg_table callback.
A pointer to a newly created GEM object or an ERR_PTR-encoded negative error code on failure.
This function maps a buffer imported via DRM PRIME into a userspace process's address space. Drivers that use the CMA helpers should set this as their drm_driver.gem_prime_mmap callback.
This function maps a buffer exported via DRM PRIME into the kernel's virtual address space. Since the CMA buffers are already mapped into the kernel virtual address space this simply returns the cached virtual address. Drivers using the CMA helpers should set this as their DRM driver's drm_driver.gem_prime_vmap callback.
The kernel virtual address of the CMA GEM object's backing store.
This function removes a buffer exported via DRM PRIME from the kernel's virtual address space. This is a no-op because CMA buffers cannot be unmapped from kernel space. Drivers using the CMA helpers should set this as their drm_driver.gem_prime_vunmap callback.
This sets the GEM object functions to the default CMA helper functions. This function can be used as the drm_driver.gem_create_object callback.
A pointer to a allocated GEM object or an error pointer on failure.
This function imports a scatter/gather table using drm_gem_cma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel virtual address. This ensures that a CMA GEM object always has its virtual address set. This address is released when the object is freed.
This function can be used as the drm_driver.gem_prime_import_sg_table callback. The DRM_GEM_CMA_VMAP_DRIVER_OPS() macro provides a shortcut to set the necessary DRM driver operations.
The vma-manager is responsible to map arbitrary driver-dependent memory regions into the linear user address-space. It provides offsets to the caller which can then be used on the address_space of the drm-device. It takes care to not overlap regions, size them appropriately and to not confuse mm-core by inconsistent fake vm_pgoff fields. Drivers shouldn't use this for object placement in VMEM. This manager should only be used to manage mappings into linear user-space VMs.
We use drm_mm as backend to manage object allocations. But it is highly optimized for alloc/free calls, not lookups. Hence, we use an rb-tree to speed up offset lookups.
You must not use multiple offset managers on a single address_space. Otherwise, mm-core will be unable to tear down memory mappings as the VM will no longer be linear.
This offset manager works on page-based addresses. That is, every argument and return code (with the exception of drm_vma_node_offset_addr()) is given in number of pages, not number of bytes. That means, object sizes and offsets must always be page-aligned (as usual). If you want to get a valid byte-based user-space address for a given offset, please see drm_vma_node_offset_addr().
Additionally to offset management, the vma offset manager also handles access management. For every open-file context that is allowed to access a given node, you must call drm_vma_node_allow(). Otherwise, an mmap() call on this open-file with the offset of the node will fail with -EACCES. To revoke access again, use drm_vma_node_revoke(). However, the caller is responsible for destroying already existing mappings, if required.
Same as drm_vma_offset_lookup_locked() but does not allow any offset into the node. It only returns the exact object with the given start address.
Node at exact start address start.
Lock VMA manager for extended lookups. Only locked VMA function calls are allowed while holding this lock. All other contexts are blocked from VMA until the lock is released via drm_vma_offset_unlock_lookup().
Use this if you need to take a reference to the objects returned by drm_vma_offset_lookup_locked() before releasing this lock again.
This lock must not be used for anything else than extended lookups. You must not call any other VMA helpers while holding this lock.
You're in atomic-context while holding this lock!
Release lookup-lock. See drm_vma_offset_lock_lookup() for more information.
Reset a node to its initial state. This must be called before using it with any VMA offset manager.
This must not be called on an already allocated node, or you will leak memory.
Return the start address of the given node. This can be used as offset into the linear VM space that is provided by the VMA offset manager. Note that this can only be used for page-based addressing. If you need a proper offset for user-space mappings, you must apply "<< PAGE_SHIFT" or use the drm_vma_node_offset_addr() helper instead.
Start address of node for page-based addressing. 0 if the node does not have an offset allocated.
Return the size as number of pages for the given node. This is the same size that was passed to drm_vma_offset_add(). If no offset is allocated for the node, this is 0.
Size of node as number of pages. 0 if the node does not have an offset allocated.
Same as drm_vma_node_start() but returns the address as a valid offset that can be used for user-space mappings during mmap(). This must not be called on unlinked nodes.
Offset of node for byte-based addressing. 0 if the node does not have an object allocated.
Unmap all userspace mappings for a given offset node. The mappings must be associated with the file_mapping address-space. If no offset exists nothing is done.
This call is unlocked. The caller must guarantee that drm_vma_offset_remove() is not called on this node concurrently.
This checks whether tag is granted access to node. It is the same as drm_vma_node_is_allowed() but suitable as drop-in helper for TTM verify_access() callbacks.
0 if access is granted, -EACCES otherwise.
Initialize a new offset-manager. The offset and area size available for the manager are given as page_offset and size. Both are interpreted as page-numbers, not bytes.
Adding/removing nodes from the manager is locked internally and protected against concurrent access. However, node allocation and destruction is left for the caller. While calling into the vma-manager, a given node must always be guaranteed to be referenced.
Destroy an object manager which was previously created via drm_vma_offset_manager_init(). The caller must remove all allocated nodes before destroying the manager. Otherwise, drm_mm will refuse to free the requested resources.
The manager must not be accessed after this function is called.
Find a node given a start address and object size. This returns the _best_ match for the given node. That is, start may point somewhere into a valid region and the given node will be returned, as long as the node spans the whole requested area (given the size in number of pages as pages).
Note that before lookup the vma offset manager lookup lock must be acquired with drm_vma_offset_lock_lookup(). See there for an example. This can then be used to implement weakly referenced lookups using kref_get_unless_zero().
Returns NULL if no suitable node can be found. Otherwise, the best match is returned. It's the caller's responsibility to make sure the node doesn't get destroyed before the caller can access it.
Add a node to the offset-manager. If the node was already added, this does nothing and return 0. pages is the size of the object given in number of pages. After this call succeeds, you can access the offset of the node until it is removed again.
If this call fails, it is safe to retry the operation or call drm_vma_offset_remove(), anyway. However, no cleanup is required in that case.
pages is not required to be the same size as the underlying memory object that you want to map. It only limits the size that user-space can map into their address space.
0 on success, negative error code on failure.
Remove a node from the offset manager. If the node wasn't added before, this does nothing. After this call returns, the offset and size will be 0 until a new offset is allocated via drm_vma_offset_add() again. Helper functions like drm_vma_node_start() and drm_vma_node_offset_addr() will return 0 if no offset is allocated.
Add tag to the list of allowed open-files for this node. If tag is already on this list, the ref-count is incremented.
The list of allowed-users is preserved across drm_vma_offset_add() and drm_vma_offset_remove() calls. You may even call it if the node is currently not added to any offset-manager.
You must remove all open-files the same number of times as you added them before destroying the node. Otherwise, you will leak memory.
This is locked against concurrent access internally.
Decrement the ref-count of tag in the list of allowed open-files on node. If the ref-count drops to zero, remove tag from the list. You must call this once for every drm_vma_node_allow() on tag.
If tag is not on the list, nothing is done.
Search the list in node whether tag is currently on the list of allowed open-files (see drm_vma_node_allow()).
PRIME is the cross device buffer sharing framework in drm, originally created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME buffers are dma-buf based file descriptors.
Similar to GEM global names, PRIME file descriptors are also used to share buffer objects across processes. They offer additional security: as file descriptors must be explicitly sent over UNIX domain sockets to be shared between applications, they can't be guessed like the globally unique GEM names.
Drivers that support the PRIME API must set the DRIVER_PRIME bit in the struct struct drm_driver driver_features field, and implement the prime_handle_to_fd and prime_fd_to_handle operations.
int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle); Those two operations convert a handle to a PRIME file descriptor and vice versa. Drivers must use the kernel dma-buf buffer sharing framework to manage the PRIME file descriptors. Similar to the mode setting API PRIME is agnostic to the underlying buffer object manager, as long as handles are 32bit unsigned integers.
While non-GEM drivers must implement the operations themselves, GEM drivers must use the drm_gem_prime_handle_to_fd() and drm_gem_prime_fd_to_handle() helper functions. Those helpers rely on the driver gem_prime_export and gem_prime_import operations to create a dma-buf instance from a GEM object (dma-buf exporter role) and to create a GEM object from a dma-buf instance (dma-buf importer role).
struct dma_buf * (*gem_prime_export)(struct drm_device *dev, struct drm_gem_object *obj, int flags); struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf); These two operations are mandatory for GEM drivers that support PRIME.
This just contains the internal struct dma_buf and handle caches for each struct drm_file used by the PRIME core code.
Allocates drm_prime_attachment and calls drm_driver.gem_prime_pin for device specific attachment. This can be used as the dma_buf_ops.attach callback.
Returns 0 on success, negative error code on failure.
Cleans up dma_buf_attachment. This can be used as the dma_buf_ops.detach callback.
Calls drm_driver.gem_prime_get_sg_table and then maps the scatterlist. This can be used as the dma_buf_ops.map_dma_buf callback.
Not implemented. The unmap is done at drm_gem_map_detach(). This can be used as the dma_buf_ops.unmap_dma_buf callback.
This wraps dma_buf_export() for use by generic GEM drivers that are using drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take a reference to the drm_device and the exported drm_gem_object (stored in dma_buf_export_info.priv) which is released by drm_gem_dmabuf_release().
Generic release function for dma_bufs exported as PRIME buffers. GEM drivers must use this in their dma_buf ops structure as the release callback. drm_gem_dmabuf_release() should be used in conjunction with drm_gem_dmabuf_export().
Sets up a kernel virtual mapping. This can be used as the dma_buf_ops.vmap callback.
Returns the kernel virtual address.
Releases a kernel virtual mapping. This can be used as the dma_buf_ops.vunmap callback.
Provides memory mapping for the buffer. This can be used as the dma_buf_ops.mmap callback.
Returns 0 on success or a negative error code on failure.
This is the implementation of the gem_prime_export functions for GEM drivers using the PRIME helpers.
This is the PRIME export function which must be used mandatorily by GEM drivers to ensure correct lifetime management of the underlying GEM object. The actual exporting from GEM object to a dma-buf is done through the gem_prime_export driver callback.
This function sets up a userspace mapping for PRIME exported buffers using the same codepath that is used for regular GEM buffer mapping on the DRM fd. The fake GEM offset is added to vma->vm_pgoff and drm_driver->fops->mmap is called to set up the mapping.
Drivers can use this as their drm_driver.gem_prime_mmap callback.
This is the core of drm_gem_prime_import. It's designed to be called by drivers who want to use a different device structure than dev->dev for attaching via dma_buf.
This is the implementation of the gem_prime_import functions for GEM drivers using the PRIME helpers.
This is the PRIME import function which must be used mandatorily by GEM drivers to ensure correct lifetime management of the underlying GEM object. The actual importing of GEM object from the dma-buf is done through the gem_import_export driver callback.
This helper creates an sg table object from a set of pages the driver is responsible for mapping the pages into the importers address space for use with dma_buf itself.
Exports an sg table into an array of pages and addresses. This is currently required by the TTM driver in order to do correct fault handling.
This is the cleanup functions which GEM drivers need to call when they use drm_gem_prime_import to import dma-bufs.
drm_mm provides a simple range allocator. The drivers are free to use the resource allocator from the linux core if it suits them, the upside of drm_mm is that it's in the DRM core. Which means that it's easier to extend for some of the crazier special purpose needs of gpus.
The main data struct is drm_mm, allocations are tracked in drm_mm_node. Drivers are free to embed either of them into their own suitable datastructures. drm_mm itself will not do any memory allocations of its own, so if drivers choose not to embed nodes they need to still allocate them themselves.
The range allocator also supports reservation of preallocated blocks. This is useful for taking over initial mode setting configurations from the firmware, where an object needs to be created which exactly matches the firmware's scanout target. As long as the range is still free it can be inserted anytime after the allocator is initialized, which helps with avoiding looped dependencies in the driver load sequence.
drm_mm maintains a stack of most recently freed holes, which of all simplistic datastructures seems to be a fairly decent approach to clustering allocations and avoiding too much fragmentation. This means free space searches are O(num_holes). Given that all the fancy features drm_mm supports something better would be fairly complex and since gfx thrashing is a fairly steep cliff not a real concern. Removing a node again is O(1).
drm_mm supports a few features: Alignment and range restrictions can be supplied. Furthermore every drm_mm_node has a color value (which is just an opaque unsigned long) which in conjunction with a driver callback can be used to implement sophisticated placement restrictions. The i915 DRM driver uses this to implement guard pages between incompatible caching domains in the graphics TT.
Two behaviors are supported for searching and allocating: bottom-up and top-down. The default is bottom-up. Top-down allocation can be used if the memory area has different restrictions, or just to reduce fragmentation.
Finally iteration helpers to walk all nodes and all holes are provided as are some basic allocator dumpers for debugging.
Note that this range allocator is not thread-safe, drivers need to protect modifications with their own locking. The idea behind this is that for a full memory manager additional data needs to be protected anyway, hence internal locking would be fully redundant.
Very often GPUs need to have continuous allocations for a given object. When evicting objects to make space for a new one it is therefore not most efficient when we simply start to select all objects from the tail of an LRU until there's a suitable hole: Especially for big objects or nodes that otherwise have special allocation constraints there's a good chance we evict lots of (smaller) objects unnecessarily.
The DRM range allocator supports this use-case through the scanning interfaces. First a scan operation needs to be initialized with drm_mm_scan_init() or drm_mm_scan_init_with_range(). The driver adds objects to the roster, probably by walking an LRU list, but this can be freely implemented. Eviction candiates are added using drm_mm_scan_add_block() until a suitable hole is found or there are no further evictable objects. Eviction roster metadata is tracked in struct drm_mm_scan.
The driver must walk through all objects again in exactly the reverse order to restore the allocator state. Note that while the allocator is used in the scan mode no other operation is allowed.
Finally the driver evicts all objects selected (drm_mm_scan_remove_block() reported true) in the scan, and any overlapping nodes after color adjustment (drm_mm_scan_color_evict()). Adding and removing an object is O(1), and since freeing a node is also O(1) the overall complexity is O(scanned_objects). So like the free stack which needs to be walked before a scan operation even begins this is linear in the number of objects. It doesn't seem to hurt too badly.
Search for the smallest hole (within the search range) that fits the desired node.
Allocates the node from the bottom of the found hole.
Search for the lowest hole (address closest to 0, within the search range) that fits the desired node.
Search for the highest hole (address closest to U64_MAX, within the search range) that fits the desired node.
Allocates the node from the top of the found hole. The specified alignment for the node is applied to the base of the node (drm_mm_node.start).
Search for the most recently evicted hole (within the search range) that fits the desired node. This is appropriate for use immediately after performing an eviction scan (see drm_mm_scan_init()) and removing the selected nodes to form a hole.
Only check the first hole for suitablity and report -ENOSPC immediately otherwise, rather than check every hole until a suitable one is found. Can only be used in conjunction with another search method such as DRM_MM_INSERT_HIGH or DRM_MM_INSERT_LOW.
Only check the highest hole (the hole with the largest address) and insert the node at the top of the hole or report -ENOSPC if unsuitable.
Does not search all holes.
Only check the lowest hole (the hole with the smallest address) and insert the node at the bottom of the hole or report -ENOSPC if unsuitable.
The struct drm_mm range manager supports finding a suitable modes using a number of search trees. These trees are oranised by size, by address and in most recent eviction order. This allows the user to find either the smallest hole to reuse, the lowest or highest address to reuse, or simply reuse the most recent eviction that fits. When allocating the drm_mm_node from within the hole, the drm_mm_insert_mode also dictate whether to allocate the lowest matching address or the highest.
Start address of the allocated block.
Size of the allocated block.
This represents an allocated block in a drm_mm allocator. Except for pre-reserved nodes inserted using drm_mm_reserve_node() the structure is entirely opaque and should only be accessed through the provided funcions. Since allocation of these nodes is entirely handled by the driver they can be embedded.
Optional driver callback to further apply restrictions on a hole. The node argument points at the node containing the hole from which the block would be allocated (see drm_mm_hole_follows() and friends). The other arguments are the size of the block to be allocated. The driver can adjust the start and end as needed to e.g. insert guard pages.
DRM range allocator with a few special functions and features geared towards managing GPU memory. Except for the color_adjust callback the structure is entirely opaque and should only be accessed through the provided functions and macros. This structure can be embedded into larger driver structures.
This structure tracks data needed for the eviction roaster set up using drm_mm_scan_init(), and used with drm_mm_scan_add_block() and drm_mm_scan_remove_block(). The structure is entirely opaque and should only be accessed through the provided functions and macros. It is meant to be allocated temporarily by the driver on the stack.
Drivers are required to clear a node prior to using it with the drm_mm range manager.
Drivers should use this helper for proper encapsulation of drm_mm internals.
True if the node is allocated.
Drivers should clear the struct drm_mm prior to initialisation if they want to use this function.
True if the mm is initialized.
Holes are embedded into the drm_mm using the tail of a drm_mm_node. If you wish to know whether a hole follows this particular node, query this function. See also drm_mm_hole_node_start() and drm_mm_hole_node_end().
True if a hole follows the node.
Start of the subsequent hole.
This is useful for driver-specific debug dumpers. Otherwise drivers should not inspect holes themselves. Drivers must check first whether a hole indeed follows by looking at drm_mm_hole_follows().
End of the subsequent hole.
As the drm_mm range manager hides its node_list deep with its structure, extracting it looks painful and repetitive. This is not expected to be used outside of the drm_mm_for_each_node() macros and similar internal functions.
The node list, may be empty.
This iterator walks over all nodes in the range allocator. It is implemented with list_for_each(), so not save against removal of elements.
This iterator walks over all nodes in the range allocator. It is implemented with list_for_each_safe(), so save against removal of elements.
This iterator walks over all holes in the range allocator. It is implemented with list_for_each(), so not save against removal of elements. entry is used internally and will not reflect a real drm_mm_node for the very first hole. Hence users of this iterator may not access it.
Implementation Note: We need to inline list_for_each_entry in order to be able to set hole_start and hole_end on each iteration while keeping the macro sane.
This is a simplified version of drm_mm_insert_node_in_range() with no range restrictions applied.
The preallocated node must be cleared to 0.
0 on success, -ENOSPC if there's no suitable hole.
This is a simplified version of drm_mm_insert_node_generic() with color set to 0.
True if the allocator is completely free, false if there's still a node allocated in it.
This iterator walks over all nodes in the range allocator that lie between start and end. It is implemented similarly to list_for_each(), but using the internal interval tree to accelerate the search for the starting node, and so not safe against removal of elements. It assumes that end is within (or is the upper limit of) the drm_mm allocator. If [start, end] are beyond the range of the drm_mm, the iterator may walk over the special _unallocated_ drm_mm.head_node, and may even continue indefinitely.
This is a simplified version of drm_mm_scan_init_with_range() with no range restrictions applied.
This simply sets up the scanning routines with the parameters for the desired hole.
Warning: As long as the scan list is non-empty, no other operations than adding/removing nodes to/from the scan list are allowed.
This functions inserts an already set-up drm_mm_node into the allocator, meaning that start, size and color must be set by the caller. All other fields must be cleared to 0. This is useful to initialize the allocator with preallocated objects which must be set-up before the range allocator can be set-up, e.g. when taking over a firmware framebuffer.
0 on success, -ENOSPC if there's no hole where node is.
Remove a memory node from the allocator.
This just removes a node from its drm_mm allocator. The node does not need to be cleared again before it can be re-inserted into this or any other drm_mm allocator. It is a bug to call this function on a unallocated node.
This is useful for when drivers embed the drm_mm_node structure and hence can't move allocations by reassigning pointers. It's a combination of remove and insert with the guarantee that the allocation start will match.
Add a node to the scan list that might be freed to make space for the desired hole.
True if a hole has been found, false otherwise.
Nodes must be removed in exactly the reverse order from the scan list as they have been added (e.g. using list_add() as they are added and then list_for_each() over that eviction list to remove), otherwise the internal state of the memory manager will be corrupted.
When the scan list is empty, the selected memory nodes can be freed. An immediately following drm_mm_insert_node_in_range_generic() or one of the simpler versions of that function with !DRM_MM_SEARCH_BEST will then return the just freed block (because its at the top of the free_stack list).
True if this block should be evicted, false otherwise. Will always return false when no hole has been found.
After completing an eviction scan and removing the selected nodes, we may need to remove a few more nodes from either side of the target hole if mm.color_adjust is being used.
A node to evict, or NULL if there are no overlapping nodes.
Note that mm must be cleared to 0 before calling this function.
Note that it is a bug to call this function on an allocator which is not clean.
Flush dcache lines of a set of pages.
List of pages to be flushed.
Number of pages in the array.
Flush every data cache line entry that points to an address belonging to a page in the array.
Flush dcache lines pointing to a scather-gather.
Flush every data cache line entry that points to an address in the sg.
Flush every data cache line entry that points to an address in the region requested.
DRM synchronisation objects (syncobj, see struct drm_syncobj) are persistent objects that contain an optional fence. The fence can be updated with a new fence, or be NULL.
syncobj's can be waited upon, where it will wait for the underlying fence.
syncobj's can be export to fd's and back, these fd's are opaque and have no other use case, except passing the syncobj between processes.
Their primary use-case is to implement Vulkan fences and semaphores.
syncobj have a kref reference count, but also have an optional file. The file is only created once the syncobj is exported. The file takes a reference on the kref.
Reference count of this object.
NULL or a pointer to the fence bound to this object.
This field should not be used directly. Use drm_syncobj_fence_get() and drm_syncobj_replace_fence() instead.
List of callbacks to call when the fence gets replaced.
Protects cb_list and write-locks fence.
A file backing for this syncobj.
This structure defines a generic sync object which wraps a dma_fence.
This struct will be initialized by drm_syncobj_add_callback, additional data can be passed along by embedding drm_syncobj_cb in another struct. The callback will get called the next time drm_syncobj_replace_fence is called.
This acquires an additional reference to obj. It is illegal to call this without already holding a reference. No locks required.
release a reference to a sync object.
This acquires additional reference to drm_syncobj.fence contained in obj, if not NULL. It is illegal to call this without already holding a reference. No locks required.
Either the fence of obj or NULL if there's none.
lookup and reference a sync object.
sync object handle to lookup.
Returns a reference to the syncobj pointed to by handle or NULL. The reference must be released by calling drm_syncobj_put().
replace fence in a sync object.
fence to install in sync file.
This replaces the fence on a sync object.
This is just a convenience function that combines drm_syncobj_find() and drm_syncobj_fence_get().
Returns 0 on success or a negative error value on failure. On success fence contains a reference to the fence, which must be released by calling dma_fence_put().
Only to be called from kref_put in drm_syncobj_put.
This is the first function to create a sync object. After creating, drivers probably want to make it available to userspace, either through drm_syncobj_get_handle() or drm_syncobj_get_fd().
Returns 0 on success or a negative error value on failure.
Exports a sync object created with drm_syncobj_create() as a handle on file_private to userspace.
Exports a sync object created with drm_syncobj_create() as a file descriptor.
The GPU scheduler provides entities which allow userspace to push jobs into software queues which are then scheduled on a hardware run queue. The software queues have a priority among them. The scheduler selects the entities from the run queue using a FIFO. The scheduler provides dependency handling features among jobs. The driver is supposed to provide callback functions for backend operations to the scheduler like submitting a job to hardware run queue, returning the dependencies of a job etc.
Entities themselves maintain a queue of jobs that will be scheduled on the hardware.
The jobs in a entity are always scheduled in the order that they were pushed.
A wrapper around a job queue (typically attached to the DRM file_priv).
used to append this struct to the list of entities in the runqueue.
runqueue on which this entity is currently scheduled.
lock to modify the runqueue to which this entity belongs.
the list of jobs of this entity.
a linearly increasing seqno incremented with each new drm_sched_fence which is part of the entity.
a unique context for all the fences which belong to this entity. The drm_sched_fence.scheduled uses the fence_context but drm_sched_fence.finished uses fence_context + 1.
the dependency fence of the job which is on the top of the job queue.
callback for the dependency fence above.
points to the finished fence of the last scheduled job.
last group leader pushing a job into the entity.
Marks the enity as removed from rq and destined for termination.
Entities will emit jobs in order to their corresponding hardware ring, and the scheduler will alternate between entities based on scheduling policy.
queue of entities to be scheduled.
to modify the entities list.
the scheduler to which this rq belongs to.
list of the entities to be scheduled.
the entity which is to be scheduled.
Run queue is a set of entities scheduling command submissions for one specific ring. It implements the scheduling policy that selects the next entity to emit commands from.
fences corresponding to the scheduling of a job.
this fence is what will be signaled by the scheduler when the job is scheduled.
this fence is what will be signaled by the scheduler when the job is completed.
When setting up an out fence for the job, you should use this, since it's available immediately upon drm_sched_job_init(), and the fence returned by the driver from run_job() won't be created until the dependencies have resolved.
the callback for the parent fence below.
the fence returned by drm_sched_backend_ops.run_job when scheduling the job on hardware. We signal the drm_sched_fence.finished fence once parent is signalled.
the scheduler instance to which the job having this struct belongs to.
the lock used by the scheduled and the finished fences.
A job to be run by an entity.
used to append this struct to the queue of jobs in an entity.
the scheduler instance on which this job is scheduled.
contains the fences for the scheduling of job.
the callback for the finished fence.
schedules the function drm_sched_job_finish once the job has finished to remove the job from the drm_gpu_scheduler.ring_mirror_list.
used to append this struct to the drm_gpu_scheduler.ring_mirror_list.
a unique id assigned to each job scheduled on the scheduler.
increment on every hang caused by this job. If this exceeds the hang limit of the scheduler then the job is marked guilty and will not be scheduled further.
the priority of the job.
the entity to which this job belongs.
A job is created by the driver using drm_sched_job_init(), and should call drm_sched_entity_push_job() once it wants the scheduler to schedule the job.
Called when the scheduler is considering scheduling this job next, to get another struct dma_fence for this job to block on. Once it returns NULL, run_job() may be called.
Called to execute the job once all of the dependencies have been resolved. This may be called multiple times, if timedout_job() has happened and drm_sched_job_recovery() decides to try it again.
Called when a job has taken too long to execute, to trigger GPU recovery.
Called once the job's finished fence has been signaled and it's time to clean it up.
Define the backend operations called by the scheduler, these functions should be implemented in driver side.
backend operations provided by the driver.
the max size of the hardware queue.
the time after which a job is removed from the scheduler.
name of the ring for which this scheduler is being used.
priority wise array of run queues.
the wait queue on which the scheduler sleeps until a job is ready to be scheduled.
once drm_sched_entity_do_release is called the scheduler waits on this wait queue until all the scheduled jobs are finished.
the number of jobs currently in the hardware queue.
used to assign unique id to the each job.
schedules a delayed call to drm_sched_job_timedout after the timeout interval is over.
the kthread on which the scheduler which run.
the list of jobs which are currently in the job queue.
lock to protect the ring_mirror_list.
once the hangs by a job crosses this limit then it is marked guilty and it will be considered for scheduling further.
One scheduler is implemented for each hardware ring.
scheduler where the timeout handling should be started.
Start timeout handling immediately when the driver detects a hardware fault.
Suspend the delayed work timeout for the scheduler. This is done by modifying the delayed work timeout to an arbitrary large value, MAX_SCHEDULE_TIMEOUT in this case. Note that this function can be called from an IRQ context.
Resume the delayed work timeout for the scheduler. Note that this function can be called from an IRQ context.
Refer to drm_sched_entity_push_job() documentation for locking considerations.
Returns 0 for success, negative error code otherwise.
Return 0 on success, otherwise error code.
Tears down and cleans up the scheduler.


Looking to buy a home? In these cities, prices are attractive, there are plenty of homes to choose from -- and buyers have the upper hand, according to Realtor.com.
This large metro area in southern South Carolina includes old towns like Beaufort, as well as more modern developments like the resort communities on Hilton Head Island.
"[The area] has history and charm without the hassles of bigger cities," said Edward Dukes, a broker with Low Country Real Estate.
The region was also the best buyers' market in the nation in February, according to Realtor.com. Home prices dropped 5% from the year before, hitting a median price of $269,900.
Homes stay on the market for an average of 156 days, giving buyers plenty of time to shop around and bargain with sellers. But the great deals may not last long.
"More deals are closing, there are more multiple bids, and fewer homes on the market," said Dukes.
Realtor.com bases its rankings on median listings prices, supplies of homes for sale and days to sell new listing. Housing markets include the entire metro areas.


FAQ: How to Come to Belarus?
Belarus is one of the last terra incognitas in Europe and can turn out to be an intriguing place for a curious traveler who is fed up with all European cities. As visa restrictions are getting softer Belarus is becoming more attractive.
FAQ from our partners 34travel.me.


text:
by admin | Nov 20, 2019 | September 2018 | 0 comments
His blindness could not be reversed, nor could his delight be contained at the Miracle Campus.
BLINDNESS and deLIGHT do not go together, at least not until you meet Simon Masango.
He gave a gift to patients and staff alike at a recent eye surgical session. His disappointment was tempered with vocal gratitude.
When told that his vision, or lack of it, could not be helped, Simon Masango replied:
"I am fine. I liked coming to your home. I liked the church service. I liked meeting everyone. I liked having good food and being one of your many guests."
Distinguished with long grey hair, Simon acted like a sighted person, "looking" new acquaintances in their eyes and shaking hands with a jovial welcome.
Simon was a welder his entire adult life. Now at 67, he can no longer work because he cannot see. "I've had much sadness in my life," he said softly but still smiling.
In 2009, his eyes were injured while working as a welder in South Africa. His employer did not take him for medical care, so Simon sought help for himself. "I was fired for going to the hospital without the company's permission. I could not go back to the hospital when they told me to return because of financial problems."
Simon had more than one injury to his eyes while welding. "Once, one eye was hit by a stone while I was grinding. That was a bad injury."
His wife of 30 years left him after his last accident. "She stayed for a while, but…"
The couple had 12 children. His wife took 6 of the children when she moved to South Africa.
The others? Years ago Simon came home from working in South Africa and 3 of his children were "terribly sick." They passed away. "I was not home when they first got sick," he remembered quietly.
Another died in 2002, another a few years later, and still another died just last year. "Now I am alone."
The Luke Commission staff members meet Simon after a Sunday evening church service on the Miracle Campus, and it was joy for all at first sight.
A few seconds after making this statement, Simon recovered his joyful countenance and said, "I am still happy, because I believe in Jesus."
Simon met The Luke Commission when the team came to his rural community in January 2018. His name and contact information were taken down so he could be brought to the Miracle Campus in May, when vision surgeons came to perform cataract and other surgeries. "They told me maybe the eye doctors could help."
After his eyes were examined carefully, Simon was informed that nothing could alter his blindness.
He paused, smiled pensively, and declared: "I hoped God would touch my eyes, and I could see again. But if it does not happen, I can still see you all with my heart."
(by Janet Tuinstra, who met Simon and thought he could see just fine. Maybe he could…)

redpajama_set_name: RedPajamaCommonCrawl


Furniture makes up a large part of any home and is an investment in your future. Many people struggle to find their perfect pieces at a price that shopping for furniture can be difficult. The following article will help you learn more about the furniture at affordable prices.
Look into the options at secondhand stores. It may have been a while since you've been in one, or it might be your first trip.You should know that these stores sometimes have great pieces of furniture there. You probably may just find pieces that are smaller, but every now and then there are couches that may work for you.
When you want to get new furniture for an office space in the home, get pieces that can be used for more than one thing. An example would be an armoire makes the perfect piece of furniture in which to place your printer and also store excess printing supplies.
When you are looking to purchase furniture, go to a large store's clearance area. Many such retailers maintain sizable portions in the store space just for displaying overstocked or clearance and overstock items. You can find excellent discontinued and high quality furnishings this way.
Always measure the area where your new furniture for. No matter what piece and size of furniture you are purchasing, the space must be measured to insure it will fit. Guessing can turn into disaster.
Online research helps you find a price range, comparing prices and learning measurements and colors, but nothing beats being able to actually feel the furniture. You can experience your personal reaction and inspect the piece in person.
Thrift stores are a great for purchasing furniture. You can't be sure what great pieces you can end up finding a beautiful piece of furniture for new styles.You can get more bang for your decorative buck by having a discount if you know how to search.
Think about online sources. You will also often find free delivery sometimes from online vendors. Shopping online may save you cash and is worth checking out.
Don't succumb to the temptation of your furniture at one time unless you must. You may want to buy just one item in a single piece each time to fit your financial needs.
Test out any used furniture before you buy it. You should ensure it is sturdy and doesn't have any damage that's hidden. Flipping something over will also let you look for labels or manufacturer marks that help determine value.
Learn the different woods used in building furniture. You don't want to pay high prices for fake wood.
You can't afford a new couch, but occasionally select small touches such as lamps and accent tables.This often makes a quick way to change the overall style of a space.
Check out the piece's details to be sure it's well-crafted. How secure are the buttons attached?Does the item's trim line up perfectly? If you aren't seeing perfection, that particular piece is likely one to be avoided as it is not constructed with quality in mind.
Fabric protector is useful on all upholstered furniture. There are several types you can use on your furniture. This protector keeps furniture safe from everyday messes.
Check the drawers before buying furniture. Be sure to pull all the drawers out and then shut them back up. Open and close all the cabinets to test them out. Be sure nothing either comes loose nor sticks. Make sure the drawers will remain open without looking like they will fall. It's important that the furniture functions properly.
Check out styles on the Internet. This can help you better idea of what you want.
See if a furniture warranty is available on the pieces you can obtain warranties for your purchased furniture.Furniture is expensive; think of investment.You use it often and you must make sure it's functional as long as possible. That's part of the reason guarantees and warranties can be so essential.
If you have various pieces or obtain furniture that you dislike, you may be able to have it altered. There are quite a number of ways you're able to make furniture look different. You can paint the piece, paint it, add covers to it, or find another way to make it what you want.
Second hand furniture outlets might be the perfect solution for you if you are on a little better.A lot of stores will allow you to rent the furniture and they'll sell it later. Often these items were only used to stage a home that is for sale. This furniture could be in perfect condition because it just was only used for a while.
Decide on the type of furniture you want before you start shopping.There are many different style options to choose from, country, country and modern styles. Other style options are casual, arts and crafts, and casual.
Only choose bedroom furniture you like. If you are purchasing a bed, invest in a quality mattress.You usually spend 1/3 of your lifespan in your bedroom. The bedroom is the place you go to relax and unwind, so spend time to obtain pieces that you love for it.
You can sometimes find great quality furniture at a second hand store. You might come across vintage pieces that perhaps could just a little TLC to get them looking beautiful. You could discover high-quality pieces that are of quality construction and simply need a little work. You may discover that it is less costly to purchase secondhand furniture and then do a brand new piece. This will also enable you to customize the furniture to fit your unique liking.
It can be hard to buy a house full of furniture if you don't know where to start. You have to educate yourself about the process before you shop. Hopefully, this article has been a great resource for you.


The Process Gear Mix (PGM) 101/2 is the entry level version of the successful range of gear metering systems designed for the processing of low viscosity materials.
The 101 system utilises medium speed gear pumps designed to process materials at flow rates to 4 litres per minute with the 102 using precision gear pumps for precision dispensing against higher pressures.
Both systems utilise the PGM philosophy of individually driven pumps operated by inverter controlled, geared AC motors. The motors are directly coupled to the pumps enabling system pressures of up to 60 bar to be achieved.
The system has easy use control systems with potentiometers used to adjust ratio and flow.


text:
'You'd Never Wear Leather Gaiters to go Duck Hunting in 1920!': Dressing Downton
By Mel Campbell
10th Oct, 2012
An Uplifting Obsession: 'People Movers' podcast
Jane Howard
Feeding the Hand that Bites: The Demise of Australian Literary Reviewing
Gideon Haigh
Extract: Michael Mohammed Ahmad's 'The Lebs'
Downton Abbey is basically a hi-res soap opera. Created by Gosford Park screenwriter Julian Fellowes for British commercial network ITV, the television series is set in a Yorkshire country house between 1912 and 1920, and features an open-ended series of intricate personal and professional dramas involving the aristocratic Crawley family, their servants and associates. The third season began screening in the UK in September.
My friends and I call the show 'Downtime Abbey', because watching it is deeply relaxing, and its chief pleasure is the gorgeous costumes. They represent a noble, elegant display of wealth that has since given way to more vulgar socio-economic disparities. Corporate bankers precipitate a global financial crisis in pursuit of their own short-term gain; Western consumer goods are churned out in Chinese factories whose working conditions would dismay Charles Dickens. Russian oligarchs own English football teams whose players' trashy wives and girlfriends attract their own notoriety. There's a popular genre of semi-scripted reality television we could call 'class clowning', which spans the proletarian grotesques of Jersey Shore, The Only Way Is Essex and The Shire, as well as the idle antics of wealthy socialites including Paris Hilton, Lauren Conrad and Kim Kardashian.
Then there is Downton Abbey. Such a nostalgic reconstruction of old money reportedly costs a million pounds of actual money per hour of filming, making Downton Abbey one of the most expensive television shows ever made.
About a third of the series' costumes are made from scratch. Many of the rest are hired from costume houses in London, Madrid and Paris, and then re-trimmed or re- dyed. Others are copied from period examples or pieced together from vintage garments in disrepair.
Downton's only original Edwardian costume is a modest pink striped frock worn by scullery maid Daisy in season two. Sourced from a private collector, it had never been worn. 'It was just so right somehow that I bought it for the show,' costume designer Susannah Buxton told Time magazine.
As a promotional exercise, Savile Row tailor Huntsman offered to provide evening suits for the Earl of Grantham and his heir, bourgeois lawyer Matthew Crawley. The firm, founded in 1849, consulted its archives for period-correct patterns rarely used today and charged £2700 ($4195) apiece – discounted from £4000 ($6215).
Imagine the staggering cost of having similar suits made for all six male principals, plus recurring cast members. Instead, they wear rented suits altered to fit; it's just common sense to spend money where it shows up best onscreen. NBC's 2011 drama The Playboy Club offers a cautionary tale of over-extravagant costuming – it commissioned eight bespoke satin Bunny outfits, with built-in corsetry, at US$3000 apiece. The 1960s-set series was canned after three episodes.
Why spend so much time and effort on costumes? A certain suspension of disbelief: the more elaborate the mise-en-scène, the more easily we can forget the presence of a modern screenwriter, director, cast and crew, and imagine this is what a particular era was actually like.
Ironically, the trend towards meticulous period production design also provokes some viewers to watch with detached pedantry, delighting in pointing out small anachronisms in everything from typefaces to dialogue. Many prestige dramas have endured this nitpicking. Typographers have complained that Mad Men uses fonts that weren't seen in advertising in the 1960s, or hadn't even been invented yet. Boardwalk Empire fans rail against the anachronistic slide guitar in its opening credits. And Abi Morgan, screenwriter of BBC's 1956-set thriller The Hour, was forced to apologise for the modern jargon littering her scripts, goaded by cries of 'it's aesthetically offensive' and 'you owe it to your audience'.
So it was for Downton Abbey. 'You'd never wear leather gaiters to go duck hunting in 1920 – that was much more an 1890s thing!' whinged some idiots after the Christmas Special screened. And, after a foxhunting scene featuring Lady Mary, an online equestrian forum complained, 'She's holding her whip upside down!'
Eagle-eyed fans on the website Recycled Movie Costumes have pointed out that Lady Edith's garden-party dress previously appeared in a TV production of A Room with a View, Lady Mary's evening dress was worn by Radha Mitchell in the 2004 film Finding Neverland, and other Downton Abbey costumes have been shared between multiple characters. Even the now-iconic purple suit worn by Violet, the Dowager Countess, was previously seen in the 1998 TV miniseries Berkeley Square.
Costume dramas inevitably reflect the tastes and concerns of the time they were made. For example, when Claudette Colbert played Cleopatra in 1934, her metallic, bias-cut costumes reflected art deco glamour; in 1963, Elizabeth Taylor was a mod Cleopatra in geometric eyeliner and bright block colours.
These days, we've developed a taste for ostentatiously quaint naturalism. Contemporary period dramas delight in revealing unpleasant social attitudes, then relegating them to the past like old fashions. Race, class and gender inequalities operate as sources of dramatic tension in Downton Abbey, but they're either handled in ways that pander to our own moral standards, or presented as so absurdly antiquated that we can't take them seriously.
The effect is like a hot bath or shower – immersive, intensely comforting, but always only a temporary pleasure. Some mornings, when life seems particularly daunting, I wish I could hide in the shower all day, just as I wish I could dress all fancy and live in a lovely castle. But my fingers are pruning up, the water grows cold and dreary, and I tire of Downton Abbey's mannered style and its historically inaccurate metaphors surrounding clothing.
For instance, in 1912 women basically treated corsets like bras: as a necessary, everyday item of underwear. Every female Downton Abbey character is corseted, from Cora the Countess of Grantham to lowly Daisy, and from buxom, middle-aged Mrs Patmore the cook, to the young, sylph-like Lady Mary.
Fashionable corsets at this time instilled a youthful silhouette inspired by classical Greek art, with a slightly elevated natural waist and sleek, streamlined hips. It's an especially nice detail that Violet still favours the older, straight-fronted corsets that threw the chest forward and the hips back. Even if a casual viewer isn't down with costume history, they'll still understand the Dowager Countess to be 'old-fashioned'.
But it never fails to irritate me when an actress in a period drama is interviewed and complains about how uncomfortable her corset was, while solemnly noting that this helped her understand how it felt to be a repressed woman of the past. No, it didn't, because viewing corsets as cruel devices of patriarchal control is a modern fantasy.
The plotline in which Sybil, the youngest and most politicised of the Earl's three daughters, complains about her corset and commissions an evening gown with bloomer- style trousers is annoyingly clumsy, a sop to contemporary beliefs about the past.
Just as only some women today wear push-up bras or five-inch stiletto heels – and then only some of the time – tight-lacing has always been a minority fetish. And just as the 'bra-burning feminist' is only a media cliché, suffragists did not spearhead the dress–reform movement. Lydia Becker, editor of the Women's Suffrage Journal from 1870–90, actually encouraged women to 'stick to their stays'.
The banal truth is that people in every era are socialised, and their bodies trained, to feel comfortable in the prevailing clothes. Had Sybil lived today, she might resent Spanx or G-strings, and show up to dinner in dungarees.
Meanwhile, Downton Abbey uses starched menswear to mimetically suggest English masculine reticence as well as class privilege. The Earl, Matthew, the butler Carson and the footmen, Thomas and William, all wear detachable shirt collars and shirtfront bibs, known as dickeys, which fastened to the shirt via several studs.
When bolshie Irish chauffeur Branson asks the valet, Bates, what happens to the Earl's worn-out collars, the reply that they're donated to charitable causes abroad is meant to contrast the Earl's well-meaning noblesse oblige with Branson's more radical – and modern – politics.
Yet, notably, only middle- and working-class men are shown with their starched clothes in disarray. Branson, when he's narrowly prevented from humiliating a visiting dignitary. Thomas, when he attempts to blackmail a duke, and later, when he fails in a black-market business venture. Bates, in prison charged with murdering his wife. And Matthew, brawling with Lady Mary's parvenu fiancé, the equally dishevelled newspaper baron Sir Richard Carlisle. That Downton Abbey's costumes instantly signal their wearers' status, and are usually immaculate, reflects a sentimental belief that class rule could be a force for good when everyone knew their place. The Crawley family's near-saintly use of their money and influence to help their servants and tenants contrasts markedly with the unflattering portrayal of characters foolish enough to attempt social mobility. This seems like the heavy hand of series creator Fellowes, a high Tory life peer married to a former royal lady-in-waiting, who has spent decades idealising the upper crust in his novels and film scripts.
What we really seek from costume dramas are emotional truths: impervious to anachronism, resonating down the ages to reassure us of the universality of human experience. So Downton Abbey's costumes aren't just historical window dressing, they're also carefully staged allusions to character.
The series' costume designer, Buxton, uses colour as a motif. Befitting her name, Violet is often shown in shades of purple; Lady Mary's passionate narrative arcs look dramatic in red, burgundy and black. Neglected middle daughter Edith often wears shades of peach, salmon and apricot; Sybil is cool in pale blues and greys.
Echoed colours and silhouettes also build links between characters. An early episode shows the three sisters in similarly cut suits, each in their signature colour. And as Cora and her daughters welcome a visitor to Downton, the shades of mauve in their outfits tie them together as a family. Yet the difference between Sybil's bright, youthful frock and Cora's subdued puce tea gown instantly conveys generational distinctions.
The servants' clothes more subtly reveal their personalities. The infuriatingly stoic Bates wears a neat, plain brown suit, black overcoat and bowler hat. The arrogant Thomas favours flashy suits on his days off, and his partner in household crime, sour-faced lady's maid O'Brien, is a slippery customer in black satin, never without an elaborate and absurd puff of curls on her forehead.
A cycle of occasional-specific clothing powerfully represents the rhythm of country life. Each Crawley family member wears three outfits a day – morning, afternoon and evening – with special costumes for riding, shooting, mourning and garden parties. The footmen's livery has an informal jacket for tasks below stairs, and formal white tie and tails for serving at table. Even housemaids Anna, Gwen, Ethel and Jane wear printed day dresses and plain aprons – they're shown receiving the dress fabric as Christmas presents from their employers – and black dresses with frilled aprons and headdresses for evening and formal occasions.
Downton Abbey strides through time, stuffing in historical events as diverse and dramatic as the sinking of the Titanic, World War I, the Russian Revolution and the Spanish influenza epidemic. The comparative subtlety of the costumes' evolution reflects the sedate insularity of life at Downton.
But it also mirrors the way we experience fashion – as a series of small everyday choices. Magazines, museums and glossy coffee-table books would have us believe that fashion dramatically rejects and reacts against past styles. Skirts were long; let's make 'em short! Hats were big; now small ones are in! The war emancipated women, so they all threw away their corsets! But in real life, that's not how it works.
Think about how you choose your own clothes. Perhaps you just liked the colour, or decided a particular cut suited you best. Maybe you wanted to try out a new trend, or thought it was ridiculous or trashy and decided to ignore it. Maybe you're copying something you've seen on a celebrity you admire, or in the culture you consume. Maybe there's a mood you want to achieve – to feel 'cool', or 'sporty'.
Downton Abbey is fascinating because it covers what costume historians consider a transitional period: a fillip between the blousy Gibson Girls of the fin-de-siècle and the svelte flappers of the 1920s. During wartime its costumes become more subdued, their decorations less ostentatious, and the same gowns are worn again and again. As the series progresses, skirts do indeed get shorter, dresses looser and hats smaller. Lady Mary swaps her long tweed coat with its nipped waist and full skirt for a boxy tweed jacket and a straight skirt to mid-calf. But these changes happen gradually, and in different ways for different characters.
Only in retrospect can we say clothes represent an era; costume drama is wonderful because it captures and focuses our appreciation for the past. And despite its narrative themes of change, Downton Abbey is ultimately conservative. It transmutes the inequitable, doomed system of landed peerage into a pageant with everyone in his or her place – and all beautifully attired.
Mel Campbell is a freelance journalist and critic who co-hosts the fortnightly literature and culture podcast The Rereaders. She is a columnist on writing at Overland magazine, and a university lecturer and writer-for-hire on film, TV and media. Her first book was the nonfiction investigation Out of Shape: Debunking Myths about Fashion and Fit (2013), and she's currently co-writing a second romantic comedy novel with Anthony Morris; their first was The Hot Guy (2017).
More from Mel Campbell
Culture — Kill Your Darlings
KYD Recommends: Our May Picks
Culture — Sam Twyford-Moore
Memoir — Lauren Carroll Harris
Not a Ghost Story
Books & Publishing — Sonia Nair
Burden of Proof: Bri Lee's 'Eggshell Skull'
Commentary — Rachel Watts
Notes on the Death of a Child
Interviews — Madeleine Dore
Extraordinary Lessons
You have 0 free articles remaining.
Subscribe to KYD and enjoy full digital access from just $17.50
If you're already a member, click here to log in
Unlock great Australian writing
The full version of this article is available to KYD Members.
Become a KYD Member today to unlock this piece and more great writing. Enjoy access to our full digital archive (plus more perks and discounts) for as little as $17.50!


The names « Loyola » and « Marymount » have long been associated with Catholic higher education in countries around the globe. Saint Ignatius Loyola, founder of the Society of Jesus, sanctioned the foundation of his order's first school in 1548. The Religious of the Sacred Heart of Mary have conducted educational institutions since their establishment in France in 1849 by Father Jean Gailhac. These two traditions of education have come together in Los Angeles as Loyola Marymount University.
The present University is the successor to the pioneer Catholic college and first institution of higher learning in Southern California. In 1865, the Vincentian Fathers inaugurated St. Vincent's College for boys in Los Angeles. When this school closed in 1911, members of the Society of Jesus opened the high school division of their newly founded Los Angeles College.
In articulating a vision for this unique collegiate enterprise, the Board of Trustees turned to the history of the 500 year old Jesuit educational philosophy, as well as to the history and traditions of the RSHMs and CSJs. They also recognized the riches of a variety of religious traditions represented among the dedicated faculty and staff, which complement and enhance the school's heritage of Catholic values.


text:
Tech Analysis & Market News
Mega Cap Stocks in news: Microsoft Corporation (NASDAQ:MSFT), Verizon Communications Inc. (NYSE:VZ), Apple Inc. (NASDAQ:AAPL), Wells Fargo (NYSE:WFC), JPMorgan Chase (NYSE:JPM)
It all kicked off when Microsoft Corporation (NASDAQ:MSFT) announced the Xbox One last year, with the corporation originally asking users to pop an always-online, high-definition camera in the middle of their living room. Microsoft Corporation (NASDAQ:MSFT) stock performance was 0.07% in last session and finished the day at $40.32. Traded volume was 23.21million shares in the last session and the average volume of the stock remained 32.90million shares. The beta of the stock remained 0.90. Microsoft Corporation (NASDAQ:MSFT) insider ownership is 7.90%.
The new $50 million Verizon Communications Inc. (NYSE:VZ) accounting and finance operations hub is attracting some new retail, medical and office businesses to a neighboring property. Verizon Communications Inc. (NYSE:VZ) dropped -0.28 percent to $49.15 Wednesday on volume of 12.70million shares. The intra-day range of the stock was $49.07 to $49.37. Verizon Communications Inc. (NYSE:VZ) has a market capitalization of $203.54billion.
Apple Inc. (NASDAQ:AAPL)'s average daily trading turnover in the 12 months to April was about half of the total for all of the stocks listed in Hong Kong and Australia, according to Bloomberg-compiled data. Apple Inc. (NASDAQ:AAPL)'s stock on June 03, 2014 reported a increase of 1.14% to the closing price of $644.82. Its fifty two weeks range is $388.87 -$647.89. The total market capitalization recorded $555.44billion. The overall volume in the last trading session was 11.98million shares. In its share capital, AAPL has 861.38million outstanding shares.
Wells Fargo & Co (NYSE:WFC) has promoted the compliance head of its brokerage unit to become chief compliance officer of a larger unit that integrates brokerage, wealth management and retirement savings services, the company said on Wednesday. On Wednesday, shares of Wells Fargo & Co (NYSE:WFC) dropped -0.10% to close the day at $51.04. Company return on investment (ROI) is 9.80% and its monthly performance is recorded as 3.72%. Wells Fargo & Co (NYSE:WFC) quarterly revenue growth is 9.18%.
JPMorgan Chase & Co. (NYSE:JPM) might contest the claim that U.S. banks haven't been punished. It's had to pay more than $20 billion to settle charges that it sold shoddy mortgages, among other transgressions. And it's irrelevant that BNP Paribas didn't break French or European laws. JPMorgan Chase & Co. (NYSE:JPM) stock performance was 0.14% in last session and finished the day at $55.68. Traded volume was 9.73million shares in the last session and the average volume of the stock remained 17.96million shares. The beta of the stock remained 1.62. JPMorgan Chase & Co. (NYSE:JPM) insider ownership is 0.10%.
Colin Pettis 06/05 AAPL, Apple Inc., JPM, JPMorgan Chase & Co., Microsoft Corporation, MSFT, NASDAQ:AAPL, NASDAQ:MSFT, NYSE:JPM, NYSE:VZ, NYSE:WFC, Verizon Communications Inc., VZ, Wells Fargo & Co, WFC
Previous Previous post: Micro-cap Losers: Overland Storage (NASDAQ:OVRL), Zhone Technologies Inc (NASDAQ:ZHNE), Prana Biotechnology (NASDAQ:PRAN), Progenics Pharmaceuticals (NASDAQ:PGNX), Mecox Lane (NASDAQ:MCOX)
Next Next post: Hot Watch List: The Procter & Gamble Company (NYSE:PG), AVX Corporation (NYSE:AVX), Google Inc (NASDAQ:GOOGL), Johnson & Johnson (NYSE:JNJ), Wal-Mart Stores (NYSE:WMT)
About TechNews.org


text:
This wildlife rehabilitator rescued over 1,600 bats after they fell during Houston cold snap- QHN
A Texas wildlife rehabilitator nursed over 1,600 frozen bats back to health in her attic after many of them fell from their roosts during Houston's plunging temperatures last week.
Mary Warwick, the wildlife director at the Houston Humane Society, told CNN that she has been working with bats since 2019, when another cold snap sent Houston's bats falling from their roosts. But she had never staged a rescue operation quite this large before.
On December 21, temperatures in Houston dropped from the 60s during the day to 22 degrees at night. "That's a steep drop in temperature for the bats," Warwick explained. The Houston area is home to eight species of bats, including the tiny Mexican free-tailed bats that roost underneath several bridges in the city.
"As their body temperature dropped, they were no longer able to hold on inside the cavity of the bridge," Warwick said. "Some of them started to become so hypothermic they lost their footing and dropped."
Warwick was running errands when she realized she hadn't received any calls about bats needing help, which was unusual given the cold weather. She headed to one of Houston's bridges "and saw little dots on the ground," she said.
"There were about 138 bats that had become hypothermic," she went on. "They looked dead."
She went to work collecting the tiny bats in a box in her car, where she used the seat heater to start warming them up. "I live about 40 minutes from the bridge, and by 20 minutes, they were starting to move around, which gave me a lot of hope," she said.
Warwick returned that night to pick up another 50 frozen bats. Then she received a call from someone who had found 920 more bats in need of help.
At her home, Warwick sorted through the bats to determine which were still alive and which had died, from either the cold or the fall to the ground. She put them in incubators to raise their body temperatures and then administered subcutaneous fluids.
But caring for over 1,000 bats was overwhelming. So she reached out to Bat World Sanctuary, a nonprofit based in northern Texas. Bat World was unable to accommodate such a large contingent of bats, but they helped Warwick come up with a battle plan to care for the frozen creatures.
"We decided once I got them stabilized I could put them in my attic where it's cool but it's not freezing, and that would reduce their metabolism so they wouldn't need to eat, but they would drink water," she explained.
So Warwick divided the bats, using crates to keep each colony together, and left them in her attic to rest and regain their strength. Several other local citizens also called in bats that needed rescuing, bringing the total to 1,602 recuperating bats in Warwick's makeshift bat hospital. They spent around three days total in her attic, she said.
Only 115 bats collected died, according to Warwick. "I was very happy with that," she said. "Especially the initial fall – that's gotta be a hard fall, falling 20 feet from the bridge. It's remarkable that these little guys can make it through."
And on Wednesday, with temperatures in Houston stabilizing, most of the bats were released back to the bridges where they came from. A few still struggled to fly correctly and were returned to the attic, where Warwick said they'll receive "extra supportive care."
Warwick and other helpers from the humane society rented a scissor lift to bring the bats as close as possible to their roosting area under the bridge. "We wanted bats to have the best chance of hearing and seeing, getting motivated by their friends," she explained. "They're very social, they do actually have friends up there, they know their chirps."
Warwick said that she enjoys caring for bats partially because "they're so small and tiny, and sweet."
Warwick and other rehabilitators that work with bats are vaccinated against rabies so they can safely work with the animals, she explained. The Houston Humane Society recommends that people trying to rescue bats either wear thick leather gloves or avoid touching them at all.
Bats are a crucial element in Houston's ecosystem, Warwick added. They feed on mosquitoes and insects that eat crops, and also act as an important food source for hawks and other predators.
The Houston Humane Society is currently fundraising for a new facility that will include a dedicated bat room, she said.
"We've moved into their territory, where they live," she said. "It's important for us to take care of them."
Dec 2022 GST collections stand at Rs 1.49 trillion, shows govt data- QHN
EV industry ends 2022 with one million unit sales; worries loom ahead- QHN


The above is what happens when you forget that CAPS lock is on AND you're too lazy to do anything about it.
Ah, so today, we stumbled upon the idea of the Men's Room Decathlon. The idea is that we would all compete in bar games; pool, darts, corn hole, skee ball, bowling, pop-a-shot, etc.
I'm all about this. I'm not very good at most of those games but Skee ball is mother**king jam! Anyway, I'm digging this idea.
Thoughts? Would you form a team?