err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
        memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
 
+       if (!err && fw->size > INTEL_UC_RSVD_GGTT_PER_FW) {
+               drm_err(&i915->drm,
+                       "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n",
+                       intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
+                       fw->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K);
+
+               /* try to find another blob to load */
+               release_firmware(fw);
+               err = -ENOENT;
+       }
+
        /* Any error is terminal if overriding. Don't bother searching for older versions */
        if (err && intel_uc_fw_is_overridden(uc_fw))
                goto fail;
 
 static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
 {
-       struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
+       struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
+       struct i915_ggtt *ggtt = gt->ggtt;
        struct drm_mm_node *node = &ggtt->uc_fw;
+       u32 offset = uc_fw->type * INTEL_UC_RSVD_GGTT_PER_FW;
+
+       /*
+        * The media GT shares the GGTT with the root GT, which means that
+        * we need to use different offsets for the binaries on the media GT.
+        * To keep the math simple, we use 8MB for the root tile and 8MB for
+        * the media one. This will need to be updated if we ever have more
+        * than 1 media GT.
+        */
+       BUILD_BUG_ON(INTEL_UC_FW_NUM_TYPES * INTEL_UC_RSVD_GGTT_PER_FW > SZ_8M);
+       GEM_BUG_ON(gt->type == GT_MEDIA && gt->info.id > 1);
+       if (gt->type == GT_MEDIA)
+               offset += SZ_8M;
 
        GEM_BUG_ON(!drm_mm_node_allocated(node));
        GEM_BUG_ON(upper_32_bits(node->start));
        GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
+       GEM_BUG_ON(offset + uc_fw->obj->base.size > node->size);
+       GEM_BUG_ON(uc_fw->obj->base.size > INTEL_UC_RSVD_GGTT_PER_FW);
 
-       return lower_32_bits(node->start);
+       return lower_32_bits(node->start + offset);
 }
 
 static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
        dummy->bi.pages = obj->mm.pages;
 
        GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
-       GEM_BUG_ON(dummy->node_size > ggtt->uc_fw.size);
 
        /* uc_fw->obj cache domains were not controlled across suspend */
        if (i915_gem_object_has_struct_page(obj))
 
 #ifndef _INTEL_UC_FW_H_
 #define _INTEL_UC_FW_H_
 
+#include <linux/sizes.h>
 #include <linux/types.h>
 #include "intel_uc_fw_abi.h"
 #include "intel_device_info.h"
                                                     (uc)->fw.file_selected.minor_ver, \
                                                     (uc)->fw.file_selected.patch_ver))
 
+/*
+ * When we load the uC binaries, we pin them in a reserved section at the top of
+ * the GGTT, which is ~18 MBs. On multi-GT systems where the GTs share the GGTT,
+ * we also need to make sure that each binary is pinned to a unique location
+ * during load, because the different GT can go through the FW load at the same
+ * time (see uc_fw_ggtt_offset() for details).
+ * Given that the available space is much greater than what is required by the
+ * binaries, to keep things simple instead of dynamically partitioning the
+ * reserved section to make space for all the blobs we can just reserve a static
+ * chunk for each binary.
+ */
+#define INTEL_UC_RSVD_GGTT_PER_FW SZ_2M
+
 #ifdef CONFIG_DRM_I915_DEBUG_GUC
 void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
                               enum intel_uc_fw_status status);