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