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