VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
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);