^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Bus driver for MIPS Common Device Memory Map (CDMM).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2014-2015 Imagination Technologies Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/cdmm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/hazards.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/mipsregs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Access control and status register fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CDMM_ACSR_DEVTYPE_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define CDMM_ACSR_DEVTYPE (255ul << CDMM_ACSR_DEVTYPE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define CDMM_ACSR_DEVSIZE_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CDMM_ACSR_DEVSIZE (31ul << CDMM_ACSR_DEVSIZE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define CDMM_ACSR_DEVREV_SHIFT 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define CDMM_ACSR_DEVREV (15ul << CDMM_ACSR_DEVREV_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define CDMM_ACSR_UW (1ul << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define CDMM_ACSR_UR (1ul << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CDMM_ACSR_SW (1ul << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CDMM_ACSR_SR (1ul << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Each block of device registers is 64 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CDMM_DRB_SIZE 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define to_mips_cdmm_driver(d) container_of(d, struct mips_cdmm_driver, drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Default physical base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static phys_addr_t mips_cdmm_default_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Bus operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static const struct mips_cdmm_device_id *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) mips_cdmm_lookup(const struct mips_cdmm_device_id *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct mips_cdmm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) for (; table->type; ++table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ret = (dev->type == table->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return ret ? table : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static int mips_cdmm_match(struct device *dev, struct device_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return mips_cdmm_lookup(cdrv->id_table, cdev) != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int mips_cdmm_uevent(struct device *dev, struct kobj_uevent_env *env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) retval = add_uevent_var(env, "CDMM_CPU=%u", cdev->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) retval = add_uevent_var(env, "CDMM_TYPE=0x%02x", cdev->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) retval = add_uevent_var(env, "CDMM_REV=%u", cdev->rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) retval = add_uevent_var(env, "MODALIAS=mipscdmm:t%02X", cdev->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* Device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define CDMM_ATTR(name, fmt, arg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static ssize_t name##_show(struct device *_dev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct device_attribute *attr, char *buf) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct mips_cdmm_device *dev = to_mips_cdmm_device(_dev); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return sprintf(buf, fmt, arg); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static DEVICE_ATTR_RO(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) CDMM_ATTR(cpu, "%u\n", dev->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) CDMM_ATTR(type, "0x%02x\n", dev->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) CDMM_ATTR(revision, "%u\n", dev->rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) CDMM_ATTR(modalias, "mipscdmm:t%02X\n", dev->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) CDMM_ATTR(resource, "\t%016llx\t%016llx\t%016lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) (unsigned long long)dev->res.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) (unsigned long long)dev->res.end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) dev->res.flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static struct attribute *mips_cdmm_dev_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) &dev_attr_cpu.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) &dev_attr_type.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) &dev_attr_revision.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) &dev_attr_modalias.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) &dev_attr_resource.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ATTRIBUTE_GROUPS(mips_cdmm_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct bus_type mips_cdmm_bustype = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .name = "cdmm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .dev_groups = mips_cdmm_dev_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .match = mips_cdmm_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .uevent = mips_cdmm_uevent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) EXPORT_SYMBOL_GPL(mips_cdmm_bustype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * Standard driver callback helpers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * All the CDMM driver callbacks need to be executed on the appropriate CPU from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * workqueues. For the standard driver callbacks we need a work function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * (mips_cdmm_{void,int}_work()) to do the actual call from the right CPU, and a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * wrapper function (generated with BUILD_PERCPU_HELPER) to arrange for the work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * function to be called on that CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * struct mips_cdmm_work_dev - Data for per-device call work.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * @fn: CDMM driver callback function to call for the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * @dev: CDMM device to pass to @fn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct mips_cdmm_work_dev {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) void *fn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct mips_cdmm_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * mips_cdmm_void_work() - Call a void returning CDMM driver callback.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * @data: struct mips_cdmm_work_dev pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * function which doesn't return a value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static long mips_cdmm_void_work(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct mips_cdmm_work_dev *work = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) void (*fn)(struct mips_cdmm_device *) = work->fn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) fn(work->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * mips_cdmm_int_work() - Call an int returning CDMM driver callback.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * @data: struct mips_cdmm_work_dev pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * function which returns an int.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static long mips_cdmm_int_work(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct mips_cdmm_work_dev *work = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int (*fn)(struct mips_cdmm_device *) = work->fn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return fn(work->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) #define _BUILD_RET_void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) #define _BUILD_RET_int return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * BUILD_PERCPU_HELPER() - Helper to call a CDMM driver callback on right CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * @_ret: Return type (void or int).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * @_name: Name of CDMM driver callback function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * Generates a specific device callback function to call a CDMM driver callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * function on the appropriate CPU for the device, and if applicable return the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * result.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) #define BUILD_PERCPU_HELPER(_ret, _name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static _ret mips_cdmm_##_name(struct device *dev) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(dev->driver); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct mips_cdmm_work_dev work = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .fn = cdrv->_name, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .dev = cdev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) _BUILD_RET_##_ret work_on_cpu(cdev->cpu, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) mips_cdmm_##_ret##_work, &work); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* Driver callback functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) BUILD_PERCPU_HELPER(int, probe) /* int mips_cdmm_probe(struct device) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) BUILD_PERCPU_HELPER(int, remove) /* int mips_cdmm_remove(struct device) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) BUILD_PERCPU_HELPER(void, shutdown) /* void mips_cdmm_shutdown(struct device) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* Driver registration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * mips_cdmm_driver_register() - Register a CDMM driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * @drv: CDMM driver information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Register a CDMM driver with the CDMM subsystem. The driver will be informed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * of matching devices which are discovered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * Returns: 0 on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) int mips_cdmm_driver_register(struct mips_cdmm_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) drv->drv.bus = &mips_cdmm_bustype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (drv->probe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) drv->drv.probe = mips_cdmm_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (drv->remove)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) drv->drv.remove = mips_cdmm_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (drv->shutdown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) drv->drv.shutdown = mips_cdmm_shutdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return driver_register(&drv->drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) EXPORT_SYMBOL_GPL(mips_cdmm_driver_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * mips_cdmm_driver_unregister() - Unregister a CDMM driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * @drv: CDMM driver information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Unregister a CDMM driver from the CDMM subsystem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) void mips_cdmm_driver_unregister(struct mips_cdmm_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) driver_unregister(&drv->drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) EXPORT_SYMBOL_GPL(mips_cdmm_driver_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* CDMM initialisation and bus discovery */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * struct mips_cdmm_bus - Info about CDMM bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * @phys: Physical address at which it is mapped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * @regs: Virtual address where registers can be accessed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * @drbs: Total number of DRBs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * @drbs_reserved: Number of DRBs reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * @discovered: Whether the devices on the bus have been discovered yet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * @offline: Whether the CDMM bus is going offline (or very early
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * coming back online), in which case it should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * reconfigured each time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct mips_cdmm_bus {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) phys_addr_t phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) unsigned int drbs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) unsigned int drbs_reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) bool discovered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) bool offline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static struct mips_cdmm_bus mips_cdmm_boot_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static DEFINE_PER_CPU(struct mips_cdmm_bus *, mips_cdmm_buses);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static atomic_t mips_cdmm_next_id = ATOMIC_INIT(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * mips_cdmm_get_bus() - Get the per-CPU CDMM bus information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * Get information about the per-CPU CDMM bus, if the bus is present.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * The caller must prevent migration to another CPU, either by disabling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * pre-emption or by running from a pinned kernel thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * Returns: Pointer to CDMM bus information for the current CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * May return ERR_PTR(-errno) in case of error, so check with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * IS_ERR().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static struct mips_cdmm_bus *mips_cdmm_get_bus(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct mips_cdmm_bus *bus, **bus_p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) unsigned int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (!cpu_has_cdmm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* Avoid early use of per-cpu primitives before initialised */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (cpu == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return &mips_cdmm_boot_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* Get bus pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) bus_p = per_cpu_ptr(&mips_cdmm_buses, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) bus = *bus_p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* Attempt allocation if NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (unlikely(!bus)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (unlikely(!bus))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) bus = ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) *bus_p = bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * mips_cdmm_cur_base() - Find current physical base address of CDMM region.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * Returns: Physical base address of CDMM region according to cdmmbase CP0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * register, or 0 if the CDMM region is disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static phys_addr_t mips_cdmm_cur_base(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) unsigned long cdmmbase = read_c0_cdmmbase();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (!(cdmmbase & MIPS_CDMMBASE_EN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return (cdmmbase >> MIPS_CDMMBASE_ADDR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) << MIPS_CDMMBASE_ADDR_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * mips_cdmm_phys_base() - Choose a physical base address for CDMM region.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * Picking a suitable physical address at which to map the CDMM region is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * platform specific, so this weak function can be overridden by platform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * code to pick a suitable value if none is configured by the bootloader.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * By default this method tries to find a CDMM-specific node in the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * dtb. Note that this won't work for early serial console.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) phys_addr_t __weak mips_cdmm_phys_base(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) np = of_find_compatible_node(NULL, NULL, "mti,mips-cdmm");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) err = of_address_to_resource(np, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return res.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * @bus: Pointer to bus information for current CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * IS_ERR(bus) is checked, so no need for caller to check.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * The caller must prevent migration to another CPU, either by disabling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * pre-emption or by running from a pinned kernel thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * Returns 0 on success, -errno on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static int mips_cdmm_setup(struct mips_cdmm_bus *bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) unsigned long cdmmbase, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (IS_ERR(bus))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return PTR_ERR(bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /* Don't set up bus a second time unless marked offline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (bus->offline) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* If CDMM region is still set up, nothing to do */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (bus->phys == mips_cdmm_cur_base())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * The CDMM region isn't set up as expected, so it needs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * reconfiguring, but then we can stop checking it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) bus->offline = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) } else if (bus->phys > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* If the CDMM region is already configured, inherit that setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (!bus->phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) bus->phys = mips_cdmm_cur_base();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* Otherwise, ask platform code for suggestions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (!bus->phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) bus->phys = mips_cdmm_phys_base();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /* Otherwise, copy what other CPUs have done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (!bus->phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) bus->phys = mips_cdmm_default_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) /* Otherwise, complain once */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (!bus->phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) bus->phys = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * If you hit this, either your bootloader needs to set up the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * CDMM on the boot CPU, or else you need to implement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * mips_cdmm_phys_base() for your platform (see asm/cdmm.h).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) pr_err("cdmm%u: Failed to choose a physical base\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /* Already complained? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (bus->phys == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) /* Record our success for other CPUs to copy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) mips_cdmm_default_base = bus->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) pr_debug("cdmm%u: Enabling CDMM region at %pa\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) smp_processor_id(), &bus->phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* Enable CDMM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) cdmmbase = read_c0_cdmmbase();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) cdmmbase &= (1ul << MIPS_CDMMBASE_ADDR_SHIFT) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) cdmmbase |= (bus->phys >> MIPS_CDMMBASE_ADDR_START)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) << MIPS_CDMMBASE_ADDR_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) cdmmbase |= MIPS_CDMMBASE_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) write_c0_cdmmbase(cdmmbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) tlbw_use_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) bus->regs = (void __iomem *)CKSEG1ADDR(bus->phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) bus->drbs = 1 + ((cdmmbase & MIPS_CDMMBASE_SIZE) >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) MIPS_CDMMBASE_SIZE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) bus->drbs_reserved = !!(cdmmbase & MIPS_CDMMBASE_CI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * mips_cdmm_early_probe() - Minimally probe for a specific device on CDMM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * @dev_type: CDMM type code to look for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * Minimally configure the in-CPU Common Device Memory Map (CDMM) and look for a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * specific device. This can be used to find a device very early in boot for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * example to configure an early FDC console device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * The caller must prevent migration to another CPU, either by disabling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * pre-emption or by running from a pinned kernel thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * Returns: MMIO pointer to device memory. The caller can read the ACSR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * register to find more information about the device (such as the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * version number or the number of blocks).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) * May return IOMEM_ERR_PTR(-errno) in case of error, so check with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) * IS_ERR().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) void __iomem *mips_cdmm_early_probe(unsigned int dev_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct mips_cdmm_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) void __iomem *cdmm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) u32 acsr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) unsigned int drb, type, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (WARN_ON(!dev_type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return IOMEM_ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) bus = mips_cdmm_get_bus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) err = mips_cdmm_setup(bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return IOMEM_ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) /* Skip the first block if it's reserved for more registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) drb = bus->drbs_reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) cdmm = bus->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) /* Look for a specific device type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) for (; drb < bus->drbs; drb += size + 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (type == dev_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return cdmm + drb * CDMM_DRB_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return IOMEM_ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) EXPORT_SYMBOL_GPL(mips_cdmm_early_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * mips_cdmm_release() - Release a removed CDMM device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * @dev: Device object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * Clean up the struct mips_cdmm_device for an unused CDMM device. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * called automatically by the driver core when a device is removed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static void mips_cdmm_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) kfree(cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) * mips_cdmm_bus_discover() - Discover the devices on the CDMM bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) * @bus: CDMM bus information, must already be set up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void mips_cdmm_bus_discover(struct mips_cdmm_bus *bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) void __iomem *cdmm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) u32 acsr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) unsigned int drb, type, size, rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct mips_cdmm_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) unsigned int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) int id = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* Skip the first block if it's reserved for more registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) drb = bus->drbs_reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) cdmm = bus->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) /* Discover devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) bus->discovered = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) pr_info("cdmm%u discovery (%u blocks)\n", cpu, bus->drbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) for (; drb < bus->drbs; drb += size + 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) rev = (acsr & CDMM_ACSR_DEVREV) >> CDMM_ACSR_DEVREV_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (!type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) pr_info("cdmm%u-%u: @%u (%#x..%#x), type 0x%02x, rev %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) cpu, id, drb, drb * CDMM_DRB_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) (drb + size + 1) * CDMM_DRB_SIZE - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) type, rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) dev = kzalloc(sizeof(*dev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dev->cpu = cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) dev->res.start = bus->phys + drb * CDMM_DRB_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) dev->res.end = bus->phys +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) (drb + size + 1) * CDMM_DRB_SIZE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) dev->res.flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) dev->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) dev->rev = rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) dev->dev.parent = get_cpu_device(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) dev->dev.bus = &mips_cdmm_bustype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) dev->dev.id = atomic_inc_return(&mips_cdmm_next_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) dev->dev.release = mips_cdmm_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) dev_set_name(&dev->dev, "cdmm%u-%u", cpu, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) ++id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) ret = device_register(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) put_device(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * CPU hotplug and initialisation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * All the CDMM driver callbacks need to be executed on the appropriate CPU from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * workqueues. For the CPU callbacks, they need to be called for all devices on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * that CPU, so the work function calls bus_for_each_dev, using a helper
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * (generated with BUILD_PERDEV_HELPER) to call the driver callback if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * device's CPU matches.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * BUILD_PERDEV_HELPER() - Helper to call a CDMM driver callback if CPU matches.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * @_name: Name of CDMM driver callback function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * Generates a bus_for_each_dev callback function to call a specific CDMM driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * callback function for the device if the device's CPU matches that pointed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * by the data argument.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * This is used for informing drivers for all devices on a given CPU of some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * event (such as the CPU going online/offline).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) * It is expected to already be called from the appropriate CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) #define BUILD_PERDEV_HELPER(_name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) static int mips_cdmm_##_name##_helper(struct device *dev, void *data) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) struct mips_cdmm_driver *cdrv; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) unsigned int cpu = *(unsigned int *)data; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (cdev->cpu != cpu || !dev->driver) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) cdrv = to_mips_cdmm_driver(dev->driver); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (!cdrv->_name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) return 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return cdrv->_name(cdev); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* bus_for_each_dev callback helper functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) BUILD_PERDEV_HELPER(cpu_down) /* int mips_cdmm_cpu_down_helper(...) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) BUILD_PERDEV_HELPER(cpu_up) /* int mips_cdmm_cpu_up_helper(...) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * mips_cdmm_cpu_down_prep() - Callback for CPUHP DOWN_PREP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * Tear down the CDMM bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) * @cpu: unsigned int CPU number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * This function is executed on the hotplugged CPU and calls the CDMM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * driver cpu_down callback for all devices on that CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static int mips_cdmm_cpu_down_prep(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct mips_cdmm_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) long ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* Inform all the devices on the bus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) mips_cdmm_cpu_down_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * While bus is offline, each use of it should reconfigure it just in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * case it is first use when coming back online again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) bus = mips_cdmm_get_bus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (!IS_ERR(bus))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) bus->offline = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * mips_cdmm_cpu_online() - Callback for CPUHP ONLINE: Bring up the CDMM bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * @cpu: unsigned int CPU number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) * This work_on_cpu callback function is executed on a given CPU to discover
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * CDMM devices on that CPU, or to call the CDMM driver cpu_up callback for all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * devices already discovered on that CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * It is used as work_on_cpu callback function during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * initialisation. When CPUs are brought online the function is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * invoked directly on the hotplugged CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static int mips_cdmm_cpu_online(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct mips_cdmm_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) long ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) bus = mips_cdmm_get_bus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) ret = mips_cdmm_setup(bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /* Bus now set up, so we can drop the offline flag if still set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) bus->offline = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (!bus->discovered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) mips_cdmm_bus_discover(bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) /* Inform all the devices on the bus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) mips_cdmm_cpu_up_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * mips_cdmm_init() - Initialise CDMM bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * Initialise CDMM bus, discover CDMM devices for online CPUs, and arrange for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * hotplug notifications so the CDMM drivers can be kept up to date.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) static int __init mips_cdmm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) /* Register the bus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) ret = bus_register(&mips_cdmm_bustype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) /* We want to be notified about new CPUs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "bus/cdmm:online",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) mips_cdmm_cpu_online, mips_cdmm_cpu_down_prep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) pr_warn("cdmm: Failed to register CPU notifier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) subsys_initcall(mips_cdmm_init);