@@ -1185,27 +1185,9 @@ static void i915_pci_shutdown(struct pci_dev *pdev)
i915_driver_shutdown(i915);
}
-static struct pci_driver i915_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
- .probe = i915_pci_probe,
- .remove = i915_pci_remove,
- .shutdown = i915_pci_shutdown,
- .driver.pm = &i915_pm_ops,
-};
-
-static int __init i915_init(void)
+static int i915_check_nomodeset(void)
{
bool use_kms = true;
- int err;
-
- err = i915_globals_init();
- if (err)
- return err;
-
- err = i915_mock_selftests();
- if (err)
- return err > 0 ? 0 : err;
/*
* Enable KMS by default, unless explicitly overriden by
@@ -1222,31 +1204,88 @@ static int __init i915_init(void)
if (!use_kms) {
/* Silently fail loading to not upset userspace. */
DRM_DEBUG_DRIVER("KMS disabled.\n");
- return 0;
+ return 1;
}
- i915_pmu_init();
+ return 0;
+}
- err = pci_register_driver(&i915_pci_driver);
- if (err) {
- i915_pmu_exit();
- i915_globals_exit();
- return err;
+static struct pci_driver i915_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = i915_pci_probe,
+ .remove = i915_pci_remove,
+ .shutdown = i915_pci_shutdown,
+ .driver.pm = &i915_pm_ops,
+};
+
+static int i915_register_pci_driver(void)
+{
+ return pci_register_driver(&i915_pci_driver);
+}
+
+static void i915_unregister_pci_driver(void)
+{
+ pci_unregister_driver(&i915_pci_driver);
+}
+
+static const struct {
+ int (*init)(void);
+ void (*exit)(void);
+} init_funcs[] = {
+ { i915_globals_init, i915_globals_exit },
+ { i915_mock_selftests, NULL },
+ { i915_check_nomodeset, NULL },
+ { i915_pmu_init, i915_pmu_exit },
+ { i915_register_pci_driver, i915_unregister_pci_driver },
+ { i915_perf_sysctl_register, i915_perf_sysctl_unregister },
+};
+static int init_progress;
+
+static int __init i915_init(void)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(init_funcs); i++) {
+ err = init_funcs[i].init();
+ if (err < 0) {
+ while (i--) {
+ if (init_funcs[i].exit)
+ init_funcs[i].exit();
+ }
+ return err;
+ } else if (err > 0) {
+ /*
+ * Early-exit success is reserved for things which
+ * don't have an exit() function because we have no
+ * idea how far they got or how to partially tear
+ * them down.
+ */
+ WARN_ON(init_funcs[i].exit);
+
+ /*
+ * We don't want to advertise devices with an only
+ * partially initialized driver.
+ */
+ WARN_ON(i915_pci_driver.driver.owner);
+ break;
+ }
}
- i915_perf_sysctl_register();
+ init_progress = i;
+
return 0;
}
static void __exit i915_exit(void)
{
- if (!i915_pci_driver.driver.owner)
- return;
+ int i;
- i915_perf_sysctl_unregister();
- pci_unregister_driver(&i915_pci_driver);
- i915_pmu_exit();
- i915_globals_exit();
+ for (i = init_progress - 1; i >= 0; i--) {
+ GEM_BUG_ON(i >= ARRAY_SIZE(init_funcs));
+ if (init_funcs[i].exit)
+ init_funcs[i].exit();
+ }
}
module_init(i915_init);
@@ -4483,9 +4483,10 @@ static int destroy_config(int id, void *p, void *data)
return 0;
}
-void i915_perf_sysctl_register(void)
+int i915_perf_sysctl_register(void)
{
sysctl_header = register_sysctl_table(dev_root);
+ return 0;
}
void i915_perf_sysctl_unregister(void)
@@ -23,7 +23,7 @@ void i915_perf_fini(struct drm_i915_private *i915);
void i915_perf_register(struct drm_i915_private *i915);
void i915_perf_unregister(struct drm_i915_private *i915);
int i915_perf_ioctl_version(void);
-void i915_perf_sysctl_register(void);
+int i915_perf_sysctl_register(void);
void i915_perf_sysctl_unregister(void);
int i915_perf_open_ioctl(struct drm_device *dev, void *data,
@@ -1088,7 +1088,7 @@ static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
static enum cpuhp_state cpuhp_slot = CPUHP_INVALID;
-void i915_pmu_init(void)
+int i915_pmu_init(void)
{
int ret;
@@ -1101,6 +1101,8 @@ void i915_pmu_init(void)
ret);
else
cpuhp_slot = ret;
+
+ return 0;
}
void i915_pmu_exit(void)
@@ -147,14 +147,14 @@ struct i915_pmu {
};
#ifdef CONFIG_PERF_EVENTS
-void i915_pmu_init(void);
+int i915_pmu_init(void);
void i915_pmu_exit(void);
void i915_pmu_register(struct drm_i915_private *i915);
void i915_pmu_unregister(struct drm_i915_private *i915);
void i915_pmu_gt_parked(struct drm_i915_private *i915);
void i915_pmu_gt_unparked(struct drm_i915_private *i915);
#else
-static inline void i915_pmu_init(void) {}
+static inline int i915_pmu_init(void) { return 0; }
static inline void i915_pmu_exit(void) {}
static inline void i915_pmu_register(struct drm_i915_private *i915) {}
static inline void i915_pmu_unregister(struct drm_i915_private *i915) {}
@@ -187,7 +187,7 @@ int i915_mock_selftests(void)
err = run_selftests(mock, NULL);
if (err) {
i915_selftest.mock = err;
- return err;
+ return 1;
}
if (i915_selftest.mock < 0) {
@@ -430,7 +430,7 @@ module_param_named(st_timeout, i915_selftest.timeout_ms, uint, 0400);
module_param_named(st_filter, i915_selftest.filter, charp, 0400);
module_param_named_unsafe(mock_selftests, i915_selftest.mock, int, 0400);
-MODULE_PARM_DESC(mock_selftests, "Run selftests before loading, using mock hardware (0:disabled [default], 1:run tests then load driver, -1:run tests then exit module)");
+MODULE_PARM_DESC(mock_selftests, "Run selftests before loading, using mock hardware (0:disabled [default], 1:run tests then load driver, -1:run tests then leave dummy module)");
module_param_named_unsafe(live_selftests, i915_selftest.live, int, 0400);
MODULE_PARM_DESC(live_selftests, "Run selftests after driver initialisation on the live system (0:disabled [default], 1:run tests then continue, -1:run tests then exit module)");