Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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