diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 698f510..60f5d51 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -72,6 +72,9 @@ options KDTRACE_HOOKS # Kernel DTrace hooks options DDB_CTF # Kernel ELF linker loads CTF data options INCLUDE_CONFIG_FILE # Include this file in kernel +# Linux API. +options OFED + # Debugging support. Always need this: options KDB # Enable kernel debugger support. options KDB_TRACE # Print a stack trace for a panic. diff --git a/sys/dev/drm2/drmP.h b/sys/dev/drm2/drmP.h index c724a2dc..1480565 100644 --- a/sys/dev/drm2/drmP.h +++ b/sys/dev/drm2/drmP.h @@ -101,7 +101,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include struct drm_file; @@ -111,6 +110,16 @@ struct drm_device; #include #include +#include +#include + +/* + * FIXME: linux/kernel.h pulls linux/page.h which redefines PAGE_MASK. + * Undo that here. This must be fixed in the DRM 3.8 branch. + */ +#undef PAGE_MASK +#define PAGE_MASK (PAGE_SIZE - 1) + #include "opt_compat.h" #include "opt_drm.h" #include "opt_syscons.h" @@ -255,11 +264,6 @@ enum { #define DRM_SUSER(p) (priv_check(p, PRIV_DRIVER) == 0) #define DRM_AGP_FIND_DEVICE() agp_find_device() #define DRM_MTRR_WC MDF_WRITECOMBINE -#define jiffies ticks -#define jiffies_to_msecs(x) (((int64_t)(x)) * 1000 / hz) -#define msecs_to_jiffies(x) (((int64_t)(x)) * hz / 1000) -#define time_after(a,b) ((long)(b) - (long)(a) < 0) -#define time_after_eq(a,b) ((long)(b) - (long)(a) <= 0) #define drm_msleep(x, msg) pause((msg), ((int64_t)(x)) * hz / 1000) /* DRM_READMEMORYBARRIER() prevents reordering of reads. @@ -634,8 +638,6 @@ struct drm_ati_pcigart_info { struct drm_dma_handle *dmah; /* handle for ATI PCIGART table */ }; -typedef vm_paddr_t resource_size_t; - /** * GEM specific mm private for tracking GEM objects */ diff --git a/sys/dev/drm2/drm_atomic.h b/sys/dev/drm2/drm_atomic.h index eb86373..819c99a 100644 --- a/sys/dev/drm2/drm_atomic.h +++ b/sys/dev/drm2/drm_atomic.h @@ -33,12 +33,11 @@ #include __FBSDID("$FreeBSD$"); +#include + typedef u_int atomic_t; typedef uint64_t atomic64_t; -#define BITS_PER_LONG (sizeof(long) * NBBY) -#define BITS_TO_LONGS(x) howmany(x, BITS_PER_LONG) - #define atomic_read(p) (*(volatile u_int *)(p)) #define atomic_set(p, v) do { *(u_int *)(p) = (v); } while (0) @@ -63,24 +62,3 @@ typedef uint64_t atomic64_t; #define __bit_word(b) ((b) / BITS_PER_LONG) #define __bit_mask(b) (1UL << (b) % BITS_PER_LONG) #define __bit_addr(p, b) ((volatile u_long *)(p) + __bit_word(b)) - -#define clear_bit(b, p) \ - atomic_clear_long(__bit_addr(p, b), __bit_mask(b)) -#define set_bit(b, p) \ - atomic_set_long(__bit_addr(p, b), __bit_mask(b)) -#define test_bit(b, p) \ - ((*__bit_addr(p, b) & __bit_mask(b)) != 0) - -static __inline u_long -find_first_zero_bit(const u_long *p, u_long max) -{ - u_long i, n; - - KASSERT(max % BITS_PER_LONG == 0, ("invalid bitmap size %lu", max)); - for (i = 0; i < max / BITS_PER_LONG; i++) { - n = ~p[i]; - if (n != 0) - return (i * BITS_PER_LONG + ffsl(n) - 1); - } - return (max); -} diff --git a/sys/dev/drm2/drm_bufs.c b/sys/dev/drm2/drm_bufs.c index 410c88f..a536126 100644 --- a/sys/dev/drm2/drm_bufs.c +++ b/sys/dev/drm2/drm_bufs.c @@ -112,6 +112,9 @@ int drm_addmap(struct drm_device * dev, unsigned long offset, DRM_ERROR("Requested removable map for non-DRM_SHM\n"); return EINVAL; } +#if PAGE_MASK == (~(PAGE_SIZE-1)) +#error PAGE_MASK from Linux +#endif if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", offset, size); diff --git a/sys/dev/drm2/drm_crtc.c b/sys/dev/drm2/drm_crtc.c index 7c6cb5d..42715bc 100644 --- a/sys/dev/drm2/drm_crtc.c +++ b/sys/dev/drm2/drm_crtc.c @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ char *fnname(int val) \ @@ -2445,7 +2447,7 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector; int ret = 0; struct drm_display_mode *dup_mode, *next; - DRM_LIST_HEAD(list); + LIST_HEAD(list); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c index cbd04b0..11ab456 100644 --- a/sys/dev/drm2/drm_fb_helper.c +++ b/sys/dev/drm2/drm_fb_helper.c @@ -75,7 +75,7 @@ vt_kms_postswitch(void *arg) return (0); } -static DRM_LIST_HEAD(kernel_fb_helper_list); +static LIST_HEAD(kernel_fb_helper_list); /* simple single crtc case helper function */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) diff --git a/sys/dev/drm2/drm_mm.h b/sys/dev/drm2/drm_mm.h index 7150e24..b3c55de 100644 --- a/sys/dev/drm2/drm_mm.h +++ b/sys/dev/drm2/drm_mm.h @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$"); #ifndef _DRM_MM_H_ #define _DRM_MM_H_ -#include +#include struct drm_mm_node { struct list_head node_list; diff --git a/sys/dev/drm2/drm_modes.c b/sys/dev/drm2/drm_modes.c index a2dbbdd..ee8303c 100644 --- a/sys/dev/drm2/drm_modes.c +++ b/sys/dev/drm2/drm_modes.c @@ -916,7 +916,7 @@ static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head */ void drm_mode_sort(struct list_head *mode_list) { - drm_list_sort(NULL, mode_list, drm_mode_compare); + list_sort(NULL, mode_list, drm_mode_compare); } /** diff --git a/sys/dev/drm2/drm_os_freebsd.h b/sys/dev/drm2/drm_os_freebsd.h index af03f8d..8a1758b 100644 --- a/sys/dev/drm2/drm_os_freebsd.h +++ b/sys/dev/drm2/drm_os_freebsd.h @@ -6,41 +6,12 @@ #include __FBSDID("$FreeBSD$"); -#include +#include -#if _BYTE_ORDER == _BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#else -#define __LITTLE_ENDIAN 1234 -#endif - -#define cpu_to_le16(x) htole16(x) -#define le16_to_cpu(x) le16toh(x) -#define cpu_to_le32(x) htole32(x) -#define le32_to_cpu(x) le32toh(x) - -#define cpu_to_be16(x) htobe16(x) -#define be16_to_cpu(x) be16toh(x) -#define cpu_to_be32(x) htobe32(x) -#define be32_to_cpu(x) be32toh(x) -#define be32_to_cpup(x) be32toh(*x) - -typedef vm_paddr_t dma_addr_t; -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -typedef int64_t s64; -typedef int32_t s32; -typedef int16_t s16; -typedef int8_t s8; -typedef int32_t __be32; +#include #define unlikely(x) __builtin_expect(!!(x), 0) #define likely(x) __builtin_expect(!!(x), 1) -#define container_of(ptr, type, member) ({ \ - __typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) #define DRM_HZ hz #define DRM_UDELAY(udelay) DELAY(udelay) @@ -53,16 +24,6 @@ typedef int32_t __be32; #define do_div(a, b) ((a) /= (b)) #define lower_32_bits(n) ((u32)(n)) -#define min_t(type, x, y) ({ \ - type __min1 = (x); \ - type __min2 = (y); \ - __min1 < __min2 ? __min1 : __min2; }) - -#define max_t(type, x, y) ({ \ - type __max1 = (x); \ - type __max2 = (y); \ - __max1 > __max2 ? __max1 : __max2; }) - #define memset_io(a, b, c) memset((a), (b), (c)) #define memcpy_fromio(a, b, c) memcpy((a), (b), (c)) #define memcpy_toio(a, b, c) memcpy((a), (b), (c)) @@ -86,15 +47,8 @@ typedef int32_t __be32; #define PCI_VENDOR_ID_SONY 0x104d #define PCI_VENDOR_ID_VIA 0x1106 -#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define hweight32(i) bitcount32(i) -static inline unsigned long -roundup_pow_of_two(unsigned long x) -{ - return (1UL << flsl(x - 1)); -} - /** * ror32 - rotate a 32-bit value right * @word: value to rotate diff --git a/sys/dev/drm2/drm_sman.h b/sys/dev/drm2/drm_sman.h index 3b1693f..549c67b 100644 --- a/sys/dev/drm2/drm_sman.h +++ b/sys/dev/drm2/drm_sman.h @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #define DRM_SMAN_H #include -#include #include /* diff --git a/sys/dev/drm2/i915/i915_dma.c b/sys/dev/drm2/i915/i915_dma.c index 24cd2cd..e03c276 100644 --- a/sys/dev/drm2/i915/i915_dma.c +++ b/sys/dev/drm2/i915/i915_dma.c @@ -1357,6 +1357,7 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) DRM_LOCK(dev); i915_gem_free_all_phys_object(dev); i915_gem_cleanup_ringbuffer(dev); + i915_gem_context_fini(dev); if (!locked) DRM_UNLOCK(dev); i915_gem_cleanup_aliasing_ppgtt(dev); @@ -1413,6 +1414,8 @@ i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) INIT_LIST_HEAD(&i915_file_priv->mm.request_list); file_priv->driver_priv = i915_file_priv; + idr_init(&i915_file_priv->context_idr); + return (0); } @@ -1437,6 +1440,7 @@ i915_driver_lastclose(struct drm_device * dev) void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { + i915_gem_context_close(dev, file_priv); i915_gem_release(dev, file_priv); } @@ -1491,6 +1495,8 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED), }; #ifdef COMPAT_FREEBSD32 diff --git a/sys/dev/drm2/i915/i915_drm.h b/sys/dev/drm2/i915/i915_drm.h index d4b0ae8..4dfb97d 100644 --- a/sys/dev/drm2/i915/i915_drm.h +++ b/sys/dev/drm2/i915/i915_drm.h @@ -204,6 +204,8 @@ typedef struct drm_i915_sarea { #define DRM_I915_GEM_EXECBUFFER2 0x29 #define DRM_I915_GET_SPRITE_COLORKEY 0x2a #define DRM_I915_SET_SPRITE_COLORKEY 0x2b +#define DRM_I915_GEM_CONTEXT_CREATE 0x2d +#define DRM_I915_GEM_CONTEXT_DESTROY 0x2e #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -248,6 +250,8 @@ typedef struct drm_i915_sarea { #define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) +#define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) /* Asynchronous page flipping: */ @@ -702,7 +706,7 @@ struct drm_i915_gem_exec_object2 { #define EXEC_OBJECT_NEEDS_FENCE (1<<0) uint64_t flags; - uint64_t rsvd1; + uint64_t rsvd1; /* now used for context info */ uint64_t rsvd2; }; @@ -746,6 +750,12 @@ struct drm_i915_gem_execbuffer2 { /** Resets the SO write offset registers for transform feedback on gen7. */ #define I915_EXEC_GEN7_SOL_RESET (1<<8) +#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) +#define i915_execbuffer2_set_context_id(eb2, context) \ + (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK +#define i915_execbuffer2_get_context_id(eb2) \ + ((eb2).rsvd1 & I915_EXEC_CONTEXT_ID_MASK) + struct drm_i915_gem_pin { /** Handle of the buffer to be pinned. */ uint32_t handle; @@ -968,4 +978,15 @@ struct drm_intel_sprite_colorkey { uint32_t flags; }; +struct drm_i915_gem_context_create { + /* output: id of new context*/ + __u32 ctx_id; + __u32 pad; +}; + +struct drm_i915_gem_context_destroy { + __u32 ctx_id; + __u32 pad; +}; + #endif /* _I915_DRM_H_ */ diff --git a/sys/dev/drm2/i915/i915_drv.c b/sys/dev/drm2/i915/i915_drv.c index 85ac10e..2380d23 100644 --- a/sys/dev/drm2/i915/i915_drv.c +++ b/sys/dev/drm2/i915/i915_drv.c @@ -612,7 +612,7 @@ __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) } static int -i8xx_do_reset(struct drm_device *dev, u8 flags) +i8xx_do_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int onems; @@ -657,7 +657,7 @@ i965_reset_complete(struct drm_device *dev) } static int -i965_do_reset(struct drm_device *dev, u8 flags) +i965_do_reset(struct drm_device *dev) { u8 gdrst; @@ -667,28 +667,30 @@ i965_do_reset(struct drm_device *dev, u8 flags) * triggers the reset; when done, the hardware will clear it. */ gdrst = pci_read_config(dev->device, I965_GDRST, 1); - pci_write_config(dev->device, I965_GDRST, gdrst | flags | 0x1, 1); + pci_write_config(dev->device, I965_GDRST, + gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE, 1); return (_intel_wait_for(dev, i965_reset_complete(dev), 500, 1, "915rst")); } static int -ironlake_do_reset(struct drm_device *dev, u8 flags) +ironlake_do_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv; u32 gdrst; dev_priv = dev->dev_private; gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); return (_intel_wait_for(dev, (I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1) != 0, 500, 1, "915rst")); } static int -gen6_do_reset(struct drm_device *dev, u8 flags) +gen6_do_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv; int ret; @@ -726,8 +728,43 @@ gen6_do_reset(struct drm_device *dev, u8 flags) return (ret); } +int intel_gpu_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = -ENODEV; + + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + ret = gen6_do_reset(dev); + break; + case 5: + ret = ironlake_do_reset(dev); + break; + case 4: + ret = i965_do_reset(dev); + break; + case 2: + ret = i8xx_do_reset(dev); + break; + } + + /* Also reset the gpu hangman. */ + if (dev_priv->stop_rings) { + DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); + dev_priv->stop_rings = 0; + if (ret == -ENODEV) { + DRM_ERROR("Reset not implemented, but ignoring " + "error for simulated gpu hangs\n"); + ret = 0; + } + } + + return ret; +} + int -i915_reset(struct drm_device *dev, u8 flags) +i915_reset(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; /* @@ -748,23 +785,9 @@ i915_reset(struct drm_device *dev, u8 flags) ret = -ENODEV; if (time_second - dev_priv->last_gpu_reset < 5) { DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); - } else { - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - ret = gen6_do_reset(dev, flags); - break; - case 5: - ret = ironlake_do_reset(dev, flags); - break; - case 4: - ret = i965_do_reset(dev, flags); - break; - case 2: - ret = i8xx_do_reset(dev, flags); - break; - } - } + } else + ret = intel_gpu_reset(dev); + dev_priv->last_gpu_reset = time_second; if (ret) { DRM_ERROR("Failed to reset chip.\n"); @@ -784,6 +807,7 @@ i915_reset(struct drm_device *dev, u8 flags) if (HAS_BLT(dev)) dev_priv->rings[BCS].init(&dev_priv->rings[BCS]); + i915_gem_context_init(dev); i915_gem_init_ppgtt(dev); drm_irq_uninstall(dev); diff --git a/sys/dev/drm2/i915/i915_drv.h b/sys/dev/drm2/i915/i915_drv.h index c332f83..bee4571 100644 --- a/sys/dev/drm2/i915/i915_drv.h +++ b/sys/dev/drm2/i915/i915_drv.h @@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + /* General customization: */ @@ -174,6 +177,17 @@ struct i915_hw_ppgtt { vm_paddr_t scratch_page_dma_addr; }; + +/* This must match up with the value previously used for execbuf2.rsvd1. */ +#define DEFAULT_CONTEXT_ID 0 +struct i915_hw_context { + int id; + bool is_initialized; + struct drm_i915_file_private *file_priv; + struct intel_ring_buffer *ring; + struct drm_i915_gem_object *obj; +}; + enum no_fbc_reason { FBC_NO_OUTPUT, /* no outputs enabled to compress */ FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */ @@ -700,6 +714,8 @@ typedef struct drm_i915_private { enum no_fbc_reason no_fbc_reason; + unsigned int stop_rings; + unsigned long cfb_size; unsigned int cfb_fb; int cfb_plane; @@ -723,8 +739,16 @@ typedef struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; + + bool hw_contexts_disabled; + uint32_t hw_context_size; } drm_i915_private_t; +/* Iterate over initialised rings */ +#define for_each_ring(ring__, dev_priv__, i__) \ + for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ + if (((ring__) = &(dev_priv__)->rings[(i__)]), intel_ring_initialized((ring__))) + enum hdmi_force_audio { HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */ HDMI_AUDIO_OFF, /* force turn off HDMI audio */ @@ -832,6 +856,7 @@ struct drm_i915_gem_object { unsigned int cache_level:2; unsigned int has_aliasing_ppgtt_mapping:1; + unsigned int has_global_gtt_mapping:1; vm_page_t *pages; @@ -927,6 +952,7 @@ struct drm_i915_file_private { struct list_head request_list; struct mtx lck; } mm; + struct idr context_idr; }; struct drm_i915_error_state { @@ -1026,7 +1052,8 @@ extern int i915_enable_hangcheck; const struct intel_device_info *i915_get_device_id(int device); -int i915_reset(struct drm_device *dev, u8 flags); +extern int intel_gpu_reset(struct drm_device *dev); +int i915_reset(struct drm_device *dev); /* i915_debug.c */ int i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, @@ -1205,6 +1232,17 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file); int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); +/* i915_gem_context.c */ +void i915_gem_context_init(struct drm_device *dev); +void i915_gem_context_fini(struct drm_device *dev); +void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); +int i915_switch_context(struct intel_ring_buffer *ring, + struct drm_file *file, int to_id); +int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); +int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); + void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_i915_gem_object *obj); @@ -1444,6 +1482,7 @@ __i915_write(64, 64) #define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) +#define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >=6) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c index 6d46207..45e770d 100644 --- a/sys/dev/drm2/i915/i915_gem.c +++ b/sys/dev/drm2/i915/i915_gem.c @@ -477,6 +477,7 @@ i915_gem_init_hw(struct drm_device *dev) } dev_priv->next_seqno = 1; + i915_gem_context_init(dev); i915_gem_init_ppgtt(dev); return (0); @@ -2586,11 +2587,16 @@ int i915_gpu_idle(struct drm_device *dev, bool do_retire) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; int ret, i; /* Flush everything onto the inactive list. */ - for (i = 0; i < I915_NUM_RINGS; i++) { - ret = i915_ring_idle(&dev_priv->rings[i], do_retire); + for_each_ring(ring, dev_priv, i) { + ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID); + if (ret) + return ret; + + ret = i915_ring_idle(ring, do_retire); if (ret) return ret; } diff --git a/sys/dev/drm2/i915/i915_gem_context.c b/sys/dev/drm2/i915/i915_gem_context.c new file mode 100644 index 0000000..4f55e9a --- /dev/null +++ b/sys/dev/drm2/i915/i915_gem_context.c @@ -0,0 +1,551 @@ +/* + * Copyright © 2011-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Ben Widawsky + * + */ + +/* + * This file implements HW context support. On gen5+ a HW context consists of an + * opaque GPU object which is referenced at times of context saves and restores. + * With RC6 enabled, the context is also referenced as the GPU enters and exists + * from RC6 (GPU has it's own internal power context, except on gen5). Though + * something like a context does exist for the media ring, the code only + * supports contexts for the render ring. + * + * In software, there is a distinction between contexts created by the user, + * and the default HW context. The default HW context is used by GPU clients + * that do not request setup of their own hardware context. The default + * context's state is never restored to help prevent programming errors. This + * would happen if a client ran and piggy-backed off another clients GPU state. + * The default context only exists to give the GPU some offset to load as the + * current to invoke a save of the context we actually care about. In fact, the + * code could likely be constructed, albeit in a more complicated fashion, to + * never use the default context, though that limits the driver's ability to + * swap out, and/or destroy other contexts. + * + * All other contexts are created as a request by the GPU client. These contexts + * store GPU state, and thus allow GPU clients to not re-emit state (and + * potentially query certain state) at any time. The kernel driver makes + * certain that the appropriate commands are inserted. + * + * The context life cycle is semi-complicated in that context BOs may live + * longer than the context itself because of the way the hardware, and object + * tracking works. Below is a very crude representation of the state machine + * describing the context life. + * refcount pincount active + * S0: initial state 0 0 0 + * S1: context created 1 0 0 + * S2: context is currently running 2 1 X + * S3: GPU referenced, but not current 2 0 1 + * S4: context is current, but destroyed 1 1 0 + * S5: like S3, but destroyed 1 0 1 + * + * The most common (but not all) transitions: + * S0->S1: client creates a context + * S1->S2: client submits execbuf with context + * S2->S3: other clients submits execbuf with context + * S3->S1: context object was retired + * S3->S2: clients submits another execbuf + * S2->S4: context destroy called with current context + * S3->S5->S0: destroy path + * S4->S5->S0: destroy path on current context + * + * There are two confusing terms used above: + * The "current context" means the context which is currently running on the + * GPU. The GPU has loaded it's state already and has stored away the gtt + * offset of the BO. The GPU is not actively referencing the data at this + * offset, but it will on the next context switch. The only way to avoid this + * is to do a GPU reset. + * + * An "active context' is one which was previously the "current context" and is + * on the active list waiting for the next context switch to occur. Until this + * happens, the object must remain at the same gtt offset. It is therefore + * possible to destroy a context, but it is still active. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include "i915_drv.h" + +#include +#include +#include +#include + +/* This is a HW constraint. The value below is the largest known requirement + * I've seen in a spec to date, and that was a workaround for a non-shipping + * part. It should be safe to decrease this, but it's more future proof as is. + */ +#define CONTEXT_ALIGN (64<<10) + +static struct i915_hw_context * +i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); +static int do_switch(struct i915_hw_context *to); + +static int get_context_size(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + u32 reg; + + switch (INTEL_INFO(dev)->gen) { + case 6: + reg = I915_READ(CXT_SIZE); + ret = GEN6_CXT_TOTAL_SIZE(reg) * 64; + break; + case 7: + reg = I915_READ(GEN7_CXT_SIZE); +#ifdef FREEBSD_WIP + if (IS_HASWELL(dev)) + ret = HSW_CXT_TOTAL_SIZE(reg) * 64; + else +#endif + ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; + break; + default: + BUG(); + } + + return ret; +} + +static void do_destroy(struct i915_hw_context *ctx) +{ + struct drm_device *dev = ctx->obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (ctx->file_priv) + idr_remove(&ctx->file_priv->context_idr, ctx->id); + else + BUG_ON(ctx != dev_priv->rings[RCS].default_context); + + drm_gem_object_unreference(&ctx->obj->base); + kfree(ctx); +} + +static struct i915_hw_context * +create_hw_context(struct drm_device *dev, + struct drm_i915_file_private *file_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_context *ctx; + int ret, id; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx == NULL) + return ERR_PTR(-ENOMEM); + + ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); + if (ctx->obj == NULL) { + kfree(ctx); + DRM_DEBUG_DRIVER("Context object allocated failed\n"); + return ERR_PTR(-ENOMEM); + } + + if (INTEL_INFO(dev)->gen >= 7) { + ret = i915_gem_object_set_cache_level(ctx->obj, + I915_CACHE_LLC_MLC); + if (ret) + goto err_out; + } + + /* The ring associated with the context object is handled by the normal + * object tracking code. We give an initial ring value simple to pass an + * assertion in the context switch code. + */ + ctx->ring = &dev_priv->rings[RCS]; + + /* Default context will never have a file_priv */ + if (file_priv == NULL) + return ctx; + + ctx->file_priv = file_priv; + +again: + if (idr_pre_get(&file_priv->context_idr, GFP_KERNEL) == 0) { + ret = -ENOMEM; + DRM_DEBUG_DRIVER("idr allocation failed\n"); + goto err_out; + } + + ret = idr_get_new_above(&file_priv->context_idr, ctx, + DEFAULT_CONTEXT_ID + 1, &id); + if (ret == 0) + ctx->id = id; + + if (ret == -EAGAIN) + goto again; + else if (ret) + goto err_out; + + return ctx; + +err_out: + do_destroy(ctx); + return ERR_PTR(ret); +} + +static inline bool is_default_context(struct i915_hw_context *ctx) +{ + return (ctx == ctx->ring->default_context); +} + +/** + * The default context needs to exist per ring that uses contexts. It stores the + * context state of the GPU for applications that don't utilize HW contexts, as + * well as an idle case. + */ +static int create_default_context(struct drm_i915_private *dev_priv) +{ + struct i915_hw_context *ctx; + int ret; + + BUG_ON(!sx_xlocked(&dev_priv->dev->dev_struct_lock)); + + ctx = create_hw_context(dev_priv->dev, NULL); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + /* We may need to do things with the shrinker which require us to + * immediately switch back to the default context. This can cause a + * problem as pinning the default context also requires GTT space which + * may not be available. To avoid this we always pin the + * default context. + */ + dev_priv->rings[RCS].default_context = ctx; + ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false); + if (ret) + goto err_destroy; + + ret = do_switch(ctx); + if (ret) + goto err_unpin; + + DRM_DEBUG_DRIVER("Default HW context loaded\n"); + return 0; + +err_unpin: + i915_gem_object_unpin(ctx->obj); +err_destroy: + do_destroy(ctx); + return ret; +} + +void i915_gem_context_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t ctx_size; + + if (!HAS_HW_CONTEXTS(dev)) { + dev_priv->hw_contexts_disabled = true; + return; + } + + /* If called from reset, or thaw... we've been here already */ + if (dev_priv->hw_contexts_disabled || + dev_priv->rings[RCS].default_context) + return; + + ctx_size = get_context_size(dev); + dev_priv->hw_context_size = get_context_size(dev); + dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096); + + if (ctx_size <= 0 || ctx_size > (1<<20)) { + dev_priv->hw_contexts_disabled = true; + return; + } + + if (create_default_context(dev_priv)) { + dev_priv->hw_contexts_disabled = true; + return; + } + + DRM_DEBUG_DRIVER("HW context support initialized\n"); +} + +void i915_gem_context_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->hw_contexts_disabled) + return; + + /* The only known way to stop the gpu from accessing the hw context is + * to reset it. Do this as the very last operation to avoid confusing + * other code, leading to spurious errors. */ + intel_gpu_reset(dev); + + i915_gem_object_unpin(dev_priv->rings[RCS].default_context->obj); + + do_destroy(dev_priv->rings[RCS].default_context); +} + +static int context_idr_cleanup(int id, void *p, void *data) +{ + struct i915_hw_context *ctx = p; + + BUG_ON(id == DEFAULT_CONTEXT_ID); + + do_destroy(ctx); + + return 0; +} + +void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + //DRM_LOCK(dev); /* Called from preclose(), the lock is already owned. */ + idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); + idr_destroy(&file_priv->context_idr); + //DRM_UNLOCK(dev); +} + +static struct i915_hw_context * +i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) +{ + return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); +} + +static inline int +mi_set_context(struct intel_ring_buffer *ring, + struct i915_hw_context *new_context, + u32 hw_flags) +{ + int ret; + + /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB + * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value + * explicitly, so we rely on the value at ring init, stored in + * itlb_before_ctx_switch. + */ + if (IS_GEN6(ring->dev) && ring->itlb_before_ctx_switch) { + ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0); + if (ret) + return ret; + } + + ret = intel_ring_begin(ring, 6); + if (ret) + return ret; + + if (IS_GEN7(ring->dev)) + intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE); + else + intel_ring_emit(ring, MI_NOOP); + + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_SET_CONTEXT); + intel_ring_emit(ring, new_context->obj->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + hw_flags); + /* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */ + intel_ring_emit(ring, MI_NOOP); + + if (IS_GEN7(ring->dev)) + intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE); + else + intel_ring_emit(ring, MI_NOOP); + + intel_ring_advance(ring); + + return ret; +} + +static int do_switch(struct i915_hw_context *to) +{ + struct intel_ring_buffer *ring = to->ring; + struct drm_i915_gem_object *from_obj = ring->last_context_obj; + u32 hw_flags = 0; + int ret; + + BUG_ON(from_obj != NULL && from_obj->pin_count == 0); + + if (from_obj == to->obj) + return 0; + + ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false); + if (ret) + return ret; + + /* Clear this page out of any CPU caches for coherent swap-in/out. Note + * that thanks to write = false in this call and us not setting any gpu + * write domains when putting a context object onto the active list + * (when switching away from it), this won't block. + * XXX: We need a real interface to do this instead of trickery. */ + ret = i915_gem_object_set_to_gtt_domain(to->obj, false); + if (ret) { + i915_gem_object_unpin(to->obj); + return ret; + } + + if (!to->obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(to->obj); + + if (!to->is_initialized || is_default_context(to)) + hw_flags |= MI_RESTORE_INHIBIT; + else if (from_obj == to->obj) /* not yet expected */ + hw_flags |= MI_FORCE_RESTORE; + + ret = mi_set_context(ring, to, hw_flags); + if (ret) { + i915_gem_object_unpin(to->obj); + return ret; + } + + /* The backing object for the context is done after switching to the + * *next* context. Therefore we cannot retire the previous context until + * the next context has already started running. In fact, the below code + * is a bit suboptimal because the retiring can occur simply after the + * MI_SET_CONTEXT instead of when the next seqno has completed. + */ + if (from_obj != NULL) { + from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; + i915_gem_object_move_to_active(from_obj, ring, + i915_gem_next_request_seqno(ring)); + /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the + * whole damn pipeline, we don't need to explicitly mark the + * object dirty. The only exception is that the context must be + * correct in case the object gets swapped out. Ideally we'd be + * able to defer doing this until we know the object would be + * swapped, but there is no way to do that yet. + */ + from_obj->dirty = 1; + BUG_ON(from_obj->ring != ring); + i915_gem_object_unpin(from_obj); + + drm_gem_object_unreference(&from_obj->base); + } + + drm_gem_object_reference(&to->obj->base); + ring->last_context_obj = to->obj; + to->is_initialized = true; + + return 0; +} + +/** + * i915_switch_context() - perform a GPU context switch. + * @ring: ring for which we'll execute the context switch + * @file_priv: file_priv associated with the context, may be NULL + * @id: context id number + * @seqno: sequence number by which the new context will be switched to + * @flags: + * + * The context life cycle is simple. The context refcount is incremented and + * decremented by 1 and create and destroy. If the context is in use by the GPU, + * it will have a refoucnt > 1. This allows us to destroy the context abstract + * object while letting the normal object tracking destroy the backing BO. + */ +int i915_switch_context(struct intel_ring_buffer *ring, + struct drm_file *file, + int to_id) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_hw_context *to; + + if (dev_priv->hw_contexts_disabled) + return 0; + + if (ring != &dev_priv->rings[RCS]) + return 0; + + if (to_id == DEFAULT_CONTEXT_ID) { + to = ring->default_context; + } else { + if (file == NULL) + return -EINVAL; + + to = i915_gem_context_get(file->driver_priv, to_id); + if (to == NULL) + return -ENOENT; + } + + return do_switch(to); +} + +int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_context_create *args = data; + struct drm_i915_file_private *file_priv = file->driver_priv; + struct i915_hw_context *ctx; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + if (dev_priv->hw_contexts_disabled) + return -ENODEV; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + ctx = create_hw_context(dev, file_priv); + DRM_UNLOCK(dev); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + args->ctx_id = ctx->id; + DRM_DEBUG_DRIVER("HW context %d created\n", args->ctx_id); + + return 0; +} + +int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_context_destroy *args = data; + struct drm_i915_file_private *file_priv = file->driver_priv; + struct i915_hw_context *ctx; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + ctx = i915_gem_context_get(file_priv, args->ctx_id); + if (!ctx) { + DRM_UNLOCK(dev); + return -ENOENT; + } + + do_destroy(ctx); + + DRM_UNLOCK(dev); + + DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id); + return 0; +} diff --git a/sys/dev/drm2/i915/i915_gem_execbuffer.c b/sys/dev/drm2/i915/i915_gem_execbuffer.c index 21e331f..3857638 100644 --- a/sys/dev/drm2/i915/i915_gem_execbuffer.c +++ b/sys/dev/drm2/i915/i915_gem_execbuffer.c @@ -213,7 +213,9 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, struct eb_objects { u_long hashmask; - LIST_HEAD(, drm_i915_gem_object) *buckets; + struct { /* Was: LIST_HEAD(, drm_i915_gem_object) *buckets */ + struct drm_i915_gem_object *lh_first; + } *buckets; }; static struct eb_objects * @@ -1130,6 +1132,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; vm_page_t **relocs_ma; + u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; u32 seqno; u32 mask; @@ -1158,6 +1161,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EINVAL; } ring = &dev_priv->rings[VCS]; + if (ctx_id != 0) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } break; case I915_EXEC_BLT: if (!HAS_BLT(dev)) { @@ -1165,6 +1173,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EINVAL; } ring = &dev_priv->rings[BCS]; + if (ctx_id != 0) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } break; default: DRM_DEBUG("execbuf with unknown ring: %d\n", @@ -1306,6 +1319,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; + ret = i915_switch_context(ring, file, ctx_id); + if (ret) + goto err; + seqno = i915_gem_next_request_seqno(ring); for (i = 0; i < I915_NUM_RINGS - 1; i++) { if (seqno < ring->sync_seqno[i]) { @@ -1461,6 +1478,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2.num_cliprects = args->num_cliprects; exec2.cliprects_ptr = args->cliprects_ptr; exec2.flags = I915_EXEC_RENDER; + i915_execbuffer2_set_context_id(exec2, 0); ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list); if (!ret) { diff --git a/sys/dev/drm2/i915/i915_irq.c b/sys/dev/drm2/i915/i915_irq.c index 16afb25..15d0a61 100644 --- a/sys/dev/drm2/i915/i915_irq.c +++ b/sys/dev/drm2/i915/i915_irq.c @@ -717,7 +717,7 @@ i915_error_work_func(void *context, int pending) if (atomic_load_acq_int(&dev_priv->mm.wedged)) { DRM_DEBUG("i915: resetting chip\n"); /* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); */ - if (!i915_reset(dev, GRDOM_RENDER)) { + if (!i915_reset(dev)) { atomic_store_rel_int(&dev_priv->mm.wedged, 0); /* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); */ } diff --git a/sys/dev/drm2/i915/i915_reg.h b/sys/dev/drm2/i915/i915_reg.h index 754e535..492fac4 100644 --- a/sys/dev/drm2/i915/i915_reg.h +++ b/sys/dev/drm2/i915/i915_reg.h @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); #define GRDOM_FULL (0<<2) #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) +#define GRDOM_RESET_ENABLE (1<<0) #define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ #define GEN6_MBC_SNPCR_SHIFT 21 @@ -200,6 +201,10 @@ __FBSDID("$FreeBSD$"); #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) +#define MI_ARB_ENABLE (1<<0) +#define MI_ARB_DISABLE (0<<0) + #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) @@ -1361,6 +1366,31 @@ __FBSDID("$FreeBSD$"); */ #define CCID 0x2180 #define CCID_EN (1<<0) +#define CXT_SIZE 0x21a0 +#define GEN6_CXT_POWER_SIZE(cxt_reg) ((cxt_reg >> 24) & 0x3f) +#define GEN6_CXT_RING_SIZE(cxt_reg) ((cxt_reg >> 18) & 0x3f) +#define GEN6_CXT_RENDER_SIZE(cxt_reg) ((cxt_reg >> 12) & 0x3f) +#define GEN6_CXT_EXTENDED_SIZE(cxt_reg) ((cxt_reg >> 6) & 0x3f) +#define GEN6_CXT_PIPELINE_SIZE(cxt_reg) ((cxt_reg >> 0) & 0x3f) +#define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_POWER_SIZE(cxt_reg) + \ + GEN6_CXT_RING_SIZE(cxt_reg) + \ + GEN6_CXT_RENDER_SIZE(cxt_reg) + \ + GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \ + GEN6_CXT_PIPELINE_SIZE(cxt_reg)) +#define GEN7_CXT_SIZE 0x21a8 +#define GEN7_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 25) & 0x7f) +#define GEN7_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 22) & 0x7) +#define GEN7_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 16) & 0x3f) +#define GEN7_CXT_EXTENDED_SIZE(ctx_reg) ((ctx_reg >> 9) & 0x7f) +#define GEN7_CXT_GT1_SIZE(ctx_reg) ((ctx_reg >> 6) & 0x7) +#define GEN7_CXT_VFSTATE_SIZE(ctx_reg) ((ctx_reg >> 0) & 0x3f) +#define GEN7_CXT_TOTAL_SIZE(ctx_reg) (GEN7_CXT_POWER_SIZE(ctx_reg) + \ + GEN7_CXT_RING_SIZE(ctx_reg) + \ + GEN7_CXT_RENDER_SIZE(ctx_reg) + \ + GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ + GEN7_CXT_GT1_SIZE(ctx_reg) + \ + GEN7_CXT_VFSTATE_SIZE(ctx_reg)) + /* * Overlay regs */ diff --git a/sys/dev/drm2/i915/intel_ringbuffer.h b/sys/dev/drm2/i915/intel_ringbuffer.h index c20777f..c391b12 100644 --- a/sys/dev/drm2/i915/intel_ringbuffer.h +++ b/sys/dev/drm2/i915/intel_ringbuffer.h @@ -122,11 +122,24 @@ struct intel_ring_buffer { */ uint32_t outstanding_lazy_request; + /** + * Do an explicit TLB flush before MI_SET_CONTEXT + */ + bool itlb_before_ctx_switch; + struct i915_hw_context *default_context; + struct drm_i915_gem_object *last_context_obj; + drm_local_map_t map; void *private; }; +static inline bool +intel_ring_initialized(struct intel_ring_buffer *ring) +{ + return ring->obj != NULL; +} + static inline unsigned intel_ring_flag(struct intel_ring_buffer *ring) { diff --git a/sys/modules/drm2/drm2/Makefile b/sys/modules/drm2/drm2/Makefile index 1d6baab..71c3c06 100644 --- a/sys/modules/drm2/drm2/Makefile +++ b/sys/modules/drm2/drm2/Makefile @@ -24,7 +24,6 @@ SRCS = \ drm_hashtab.c \ drm_ioctl.c \ drm_irq.c \ - drm_linux_list_sort.c \ drm_lock.c \ drm_memory.c \ drm_mm.c \ @@ -54,6 +53,9 @@ SRCS += drm_ioc32.c .endif SRCS +=device_if.h bus_if.h pci_if.h device_if.h iicbus_if.h opt_drm.h \ - opt_vm.h opt_compat.h opt_syscons.h + opt_vm.h opt_compat.h opt_syscons.h \ + opt_ofed.h vnode_if.h + +CFLAGS+= -I${.CURDIR}/../../../ofed/include .include diff --git a/sys/modules/drm2/i915kms/Makefile b/sys/modules/drm2/i915kms/Makefile index 75f08d2..c6820c0 100644 --- a/sys/modules/drm2/i915kms/Makefile +++ b/sys/modules/drm2/i915kms/Makefile @@ -7,6 +7,7 @@ SRCS = \ i915_dma.c \ i915_drv.c \ i915_gem.c \ + i915_gem_context.c \ i915_gem_execbuffer.c \ i915_gem_evict.c \ i915_gem_gtt.c \ @@ -38,6 +39,7 @@ SRCS += \ opt_acpi.h \ opt_compat.h \ opt_drm.h \ + opt_ofed.h \ opt_syscons.h \ acpi_if.h \ bus_if.h \ @@ -45,7 +47,10 @@ SRCS += \ device_if.h \ iicbb_if.h \ iicbus_if.h \ - pci_if.h + pci_if.h \ + vnode_if.h + +CFLAGS+= -I${.CURDIR}/../../../ofed/include .include diff --git a/sys/modules/drm2/radeonkms/Makefile b/sys/modules/drm2/radeonkms/Makefile index 076b825..ff6a3ad 100644 --- a/sys/modules/drm2/radeonkms/Makefile +++ b/sys/modules/drm2/radeonkms/Makefile @@ -97,6 +97,7 @@ SRCS += \ opt_acpi.h \ opt_compat.h \ opt_drm.h \ + opt_ofed.h \ opt_syscons.h \ acpi_if.h \ bus_if.h \ @@ -104,8 +105,11 @@ SRCS += \ device_if.h \ iicbb_if.h \ iicbus_if.h \ - pci_if.h + pci_if.h \ + vnode_if.h -CFLAGS += -I${.CURDIR}/../../../dev/drm2/radeon ${GCC_MS_EXTENSIONS} +CFLAGS += -I${.CURDIR}/../../../ofed/include \ + -I${.CURDIR}/../../../dev/drm2/radeon \ + ${GCC_MS_EXTENSIONS} .include diff --git a/sys/ofed/include/linux/idr.h b/sys/ofed/include/linux/idr.h index 207d7f7..e71bbfb 100644 --- a/sys/ofed/include/linux/idr.h +++ b/sys/ofed/include/linux/idr.h @@ -67,6 +67,7 @@ int idr_pre_get(struct idr *idp, gfp_t gfp_mask); int idr_get_new(struct idr *idp, void *ptr, int *id); int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); void *idr_replace(struct idr *idp, void *ptr, int id); +int idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data); void idr_remove(struct idr *idp, int id); void idr_remove_all(struct idr *idp); void idr_destroy(struct idr *idp); diff --git a/sys/ofed/include/linux/jiffies.h b/sys/ofed/include/linux/jiffies.h index ede36b4..04e44a5 100644 --- a/sys/ofed/include/linux/jiffies.h +++ b/sys/ofed/include/linux/jiffies.h @@ -30,7 +30,6 @@ #define _LINUX_JIFFIES_H_ #include -#include #include #include diff --git a/sys/ofed/include/linux/kernel.h b/sys/ofed/include/linux/kernel.h index e1bc220..8c6457b 100644 --- a/sys/ofed/include/linux/kernel.h +++ b/sys/ofed/include/linux/kernel.h @@ -136,8 +136,8 @@ #define simple_strtol strtol #define kstrtol(a,b,c) ({*(c) = strtol(a,0,b);}) -#define min(x, y) (x < y ? x : y) -#define max(x, y) (x > y ? x : y) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) #define min_t(type, _x, _y) (type)(_x) < (type)(_y) ? (type)(_x) : (_y) #define max_t(type, _x, _y) (type)(_x) > (type)(_y) ? (type)(_x) : (_y) diff --git a/sys/ofed/include/linux/linux_idr.c b/sys/ofed/include/linux/linux_idr.c index 0238c8e..6c1e992 100644 --- a/sys/ofed/include/linux/linux_idr.c +++ b/sys/ofed/include/linux/linux_idr.c @@ -209,6 +209,45 @@ out: return (res); } +static int +idr_for_each_layer(struct idr_layer *il, int layer, int id, + int (*fn)(int id, void *p, void *data), void *data) +{ + int idx, ret, sub_id; + + if (il == NULL) + return (0); + + for (idx = 0; idx < IDR_SIZE; ++idx) { + if (il->bitmap & (1 << idx)) + continue; + + sub_id = id | idx << (layer * IDR_BITS); + + if (layer > 0) + ret = idr_for_each_layer(il->ary[idx], layer - 1, sub_id, + fn, data); + else + ret = fn(sub_id, il->ary[idx], data); + + if (ret != 0) + return (ret); + } + + return (0); +} + +int +idr_for_each(struct idr *idr, + int (*fn)(int id, void *p, void *data), void *data) +{ + int ret; + + ret = idr_for_each_layer(idr->top, idr->layers - 1, 0, fn, data); + + return (ret); +} + int idr_pre_get(struct idr *idr, gfp_t gfp_mask) { diff --git a/sys/ofed/include/linux/list.h b/sys/ofed/include/linux/list.h index 2c36282..2433614 100644 --- a/sys/ofed/include/linux/list.h +++ b/sys/ofed/include/linux/list.h @@ -131,10 +131,20 @@ list_del_init(struct list_head *entry) n = list_entry(p->field.next, typeof(*p), field); &p->field != (h);\ p = n, n = list_entry(n->field.next, typeof(*n), field)) +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, __typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, __typeof(*n), member)) + #define list_for_each_entry_reverse(p, h, field) \ for (p = list_entry((h)->prev, typeof(*p), field); &p->field != (h); \ p = list_entry(p->field.prev, typeof(*p), field)) +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, __typeof(*pos), member);\ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, __typeof(*pos), member)) + #define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = p->prev) static inline void @@ -168,6 +178,16 @@ list_move_tail(struct list_head *entry, struct list_head *head) } static inline void +list_replace(struct list_head *old, struct list_head *new) +{ + + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void _list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { @@ -395,4 +415,48 @@ static inline int list_is_last(const struct list_head *list, tpos = hlist_entry((pos), typeof(*(tpos)), member); 1;}); \ pos = (n)) +struct _list_sort_thunk { + int (*cmp)(void *, struct list_head *, struct list_head *); + void *priv; +}; + +static int +_list_le_cmp(void *priv, const void *d1, const void *d2) +{ + struct list_head *le1, *le2; + struct _list_sort_thunk *thunk; + + thunk = priv; + le1 = *(__DECONST(struct list_head **, d1)); + le2 = *(__DECONST(struct list_head **, d2)); + return ((thunk->cmp)(thunk->priv, le1, le2)); +} + +/* + * Punt and use array sort. + */ +static inline void +list_sort(void *priv, struct list_head *head, + int (*cmp)(void *priv, struct list_head *a, struct list_head *b)) +{ + struct _list_sort_thunk thunk; + struct list_head **ar, *le; + int count, i; + + count = 0; + list_for_each(le, head) + count++; + ar = malloc(sizeof(struct list_head *) * count, M_TEMP, M_WAITOK); + i = 0; + list_for_each(le, head) + ar[i++] = le; + thunk.cmp = cmp; + thunk.priv = priv; + qsort_r(ar, count, sizeof(struct list_head *), &thunk, _list_le_cmp); + INIT_LIST_HEAD(head); + for (i = 0; i < count; i++) + list_add_tail(ar[i], head); + free(ar, M_TEMP); +} + #endif /* _LINUX_LIST_H_ */