summaryrefslogtreecommitdiffstats
path: root/kernel/smp.c
AgeCommit message (Expand)Author
2013-04-30kernel/smp.c: cleanupsAndrew Morton
2013-04-30kernel/smp.c: use '|=' for csd_lockliguang
2013-02-21smp: make smp_call_function_many() use logic similar to smp_call_function_sin...Shaohua Li
2013-01-28smp: Fix SMP function call empty cpu mask raceWang YanQing
2012-06-05smp: Remove ipi_call_lock[_irq]()/ipi_call_unlock[_irq]()Yong Zhang
2012-05-08smp: Implement kick_all_cpus_sync()Thomas Gleixner
2012-05-03smp, idle: Allocate idle thread for each possible cpu during bootSuresh Siddha
2012-03-28smp: add func to IPI cpus based on parameter funcGilad Ben-Yossef
2012-03-28smp: introduce a generic on_each_cpu_mask() functionGilad Ben-Yossef
2011-10-31kernel: Map most files to use export.h instead of module.hPaul Gortmaker
2011-06-17generic-ipi: Fix kexec boot crash by initializing call_single_queue before en...Takao Indoh
2011-03-22smp: move smp setup functions to kernel/smp.cAmerigo Wang
2011-03-17smp_call_function_interrupt: use typedef and %pfMilton Miller
2011-03-17smp_call_function_many: handle concurrent clearing of maskMilton Miller
2011-03-17call_function_many: add missing orderingMilton Miller
2011-03-17call_function_many: fix list delete vs add raceMilton Miller
2011-01-20Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/ker...Linus Torvalds
2011-01-20kernel/smp.c: consolidate writes in smp_call_function_interrupt()Milton Miller
2011-01-20kernel/smp.c: fix smp_call_function_many() SMP raceAnton Blanchard
2011-01-20smp: Allow on_each_cpu() to be called while early_boot_irqs_disabled status t...Tejun Heo
2011-01-13kernel: clean up USE_GENERIC_SMP_HELPERSAmerigo Wang
2010-10-27Typedef SMP call function pointerDavid Howells
2010-09-10generic-ipi: Fix deadlock in __smp_call_function_singleHeiko Carstens
2010-05-27kernel/: convert cpu notifier to return encapsulate errno valueAkinobu Mita
2010-03-30include cleanup: Update gfp.h and slab.h includes to prepare for breaking imp...Tejun Heo
2010-01-18generic-ipi: Optimize accesses by using DEFINE_PER_CPU_SHARED_ALIGNED for IPI...Milton Miller
2010-01-16smp_call_function_any(): pass the node value to cpumask_of_node()David John
2009-12-15Merge branch 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/k...Linus Torvalds
2009-12-15generic-ipi: cleanup for generic_smp_call_function_interrupt()Xiao Guangrong
2009-12-14smp: Convert smplocks to raw_spinlocksThomas Gleixner
2009-11-18generic-ipi: Add smp_call_function_any()Rusty Russell
2009-10-23generic-ipi: Fix misleading smp_call_function*() descriptionSheng Yang
2009-09-24cpumask: remove arch_send_call_function_ipiRusty Russell
2009-09-23generic-ipi: make struct call_function_data locklessXiao Guangrong
2009-08-26Merge branch 'x86/urgent' into x86/patH. Peter Anvin
2009-08-21generic-ipi: Allow cpus not yet online to call smp_call_function with irqs di...Suresh Siddha
2009-08-07generic-ipi: fix hotplug_cfd()Xiao Guangrong
2009-06-09cpumask: alloc zeroed cpumask for static cpumask_var_tsYinghai Lu
2009-03-13generic-ipi: eliminate WARN_ON()s during oops/panicIngo Molnar
2009-02-25generic-ipi: cleanupsIngo Molnar
2009-02-25generic-ipi: remove CSD_FLAG_WAITPeter Zijlstra
2009-02-25generic-ipi: remove kmalloc()Peter Zijlstra
2009-02-25generic IPI: simplify barriers and lockingNick Piggin
2009-01-30generic-ipi: use per cpu data for single cpu ipi callsSteven Rostedt
2009-01-01cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits.: coreRusty Russell
2008-12-30cpumask: arch_send_call_function_ipi_mask: coreRusty Russell
2008-12-30cpumask: smp_call_function_many()Rusty Russell
2008-11-06generic-ipi: fix the smp_mb() placementSuresh Siddha
2008-08-25smp: have smp_call_function_single() detect invalid CPUsH. Peter Anvin
2008-08-12generic-ipi: fix stack and rcu interaction bug in smp_call_function_mask(), fixNick Piggin
light .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * QUICC Engine GPIOs
 *
 * Copyright (c) MontaVista Software, Inc. 2008.
 *
 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <asm/qe.h>

struct qe_gpio_chip {
	struct of_mm_gpio_chip mm_gc;
	spinlock_t lock;

	unsigned long pin_flags[QE_PIO_PINS];
#define QE_PIN_REQUESTED 0

	/* shadowed data register to clear/set bits safely */
	u32 cpdata;

	/* saved_regs used to restore dedicated functions */
	struct qe_pio_regs saved_regs;
};

static inline struct qe_gpio_chip *
to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
{
	return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
}

static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
{
	struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
	struct qe_pio_regs __iomem *regs = mm_gc->regs;

	qe_gc->cpdata = in_be32(&regs->cpdata);
	qe_gc->saved_regs.cpdata = qe_gc->cpdata;
	qe_gc->saved_regs.cpdir1 = in_be32(&regs->cpdir1);
	qe_gc->saved_regs.cpdir2 = in_be32(&regs->cpdir2);
	qe_gc->saved_regs.cppar1 = in_be32(&regs->cppar1);
	qe_gc->saved_regs.cppar2 = in_be32(&regs->cppar2);
	qe_gc->saved_regs.cpodr = in_be32(&regs->cpodr);
}

static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
	struct qe_pio_regs __iomem *regs = mm_gc->regs;
	u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);

	return in_be32(&regs->cpdata) & pin_mask;
}

static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
	struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
	struct qe_pio_regs __iomem *regs = mm_gc->regs;
	unsigned long flags;
	u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);

	spin_lock_irqsave(&qe_gc->lock, flags);

	if (val)
		qe_gc->cpdata |= pin_mask;
	else
		qe_gc->cpdata &= ~pin_mask;

	out_be32(&regs->cpdata, qe_gc->cpdata);

	spin_unlock_irqrestore(&qe_gc->lock, flags);
}

static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
	struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
	unsigned long flags;

	spin_lock_irqsave(&qe_gc->lock, flags);

	__par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0);

	spin_unlock_irqrestore(&qe_gc->lock, flags);

	return 0;
}

static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
	struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
	unsigned long flags;

	qe_gpio_set(gc, gpio, val);

	spin_lock_irqsave(&qe_gc->lock, flags);

	__par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);

	spin_unlock_irqrestore(&qe_gc->lock, flags);

	return 0;
}

struct qe_pin {
	/*
	 * The qe_gpio_chip name is unfortunate, we should change that to
	 * something like qe_pio_controller. Someday.
	 */
	struct qe_gpio_chip *controller;
	int num;
};

/**
 * qe_pin_request - Request a QE pin
 * @np:		device node to get a pin from
 * @index:	index of a pin in the device tree
 * Context:	non-atomic
 *
 * This function return qe_pin so that you could use it with the rest of
 * the QE Pin Multiplexing API.
 */
struct qe_pin *qe_pin_request(struct device_node *np, int index)
{
	struct qe_pin *qe_pin;
	struct gpio_chip *gc;
	struct of_mm_gpio_chip *mm_gc;
	struct qe_gpio_chip *qe_gc;
	int err;
	unsigned long flags;

	qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
	if (!qe_pin) {
		pr_debug("%s: can't allocate memory\n", __func__);
		return ERR_PTR(-ENOMEM);
	}

	err = of_get_gpio(np, index);
	if (err < 0)
		goto err0;
	gc = gpio_to_chip(err);
	if (WARN_ON(!gc))
		goto err0;

	if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
		pr_debug("%s: tried to get a non-qe pin\n", __func__);
		err = -EINVAL;
		goto err0;
	}

	mm_gc = to_of_mm_gpio_chip(gc);
	qe_gc = to_qe_gpio_chip(mm_gc);

	spin_lock_irqsave(&qe_gc->lock, flags);

	err -= gc->base;
	if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
		qe_pin->controller = qe_gc;
		qe_pin->num = err;
		err = 0;
	} else {
		err = -EBUSY;
	}

	spin_unlock_irqrestore(&qe_gc->lock, flags);

	if (!err)
		return qe_pin;
err0:
	kfree(qe_pin);
	pr_debug("%s failed with status %d\n", __func__, err);
	return ERR_PTR(err);
}
EXPORT_SYMBOL(qe_pin_request);

/**
 * qe_pin_free - Free a pin
 * @qe_pin:	pointer to the qe_pin structure
 * Context:	any
 *
 * This function frees the qe_pin structure and makes a pin available
 * for further qe_pin_request() calls.
 */
void qe_pin_free(struct qe_pin *qe_pin)
{
	struct qe_gpio_chip *qe_gc = qe_pin->controller;
	unsigned long flags;
	const int pin = qe_pin->num;

	spin_lock_irqsave(&qe_gc->lock, flags);
	test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]);
	spin_unlock_irqrestore(&qe_gc->lock, flags);

	kfree(qe_pin);
}
EXPORT_SYMBOL(qe_pin_free);

/**
 * qe_pin_set_dedicated - Revert a pin to a dedicated peripheral function mode
 * @qe_pin:	pointer to the qe_pin structure
 * Context:	any
 *
 * This function resets a pin to a dedicated peripheral function that
 * has been set up by the firmware.
 */
void qe_pin_set_dedicated(struct qe_pin *qe_pin)
{
	struct qe_gpio_chip *qe_gc = qe_pin->controller;
	struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
	struct qe_pio_regs *sregs = &qe_gc->saved_regs;
	int pin = qe_pin->num;
	u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1));
	u32 mask2 = 0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2);
	bool second_reg = pin > (QE_PIO_PINS / 2) - 1;
	unsigned long flags;

	spin_lock_irqsave(&qe_gc->lock, flags);

	if (second_reg) {
		clrsetbits_be32(&regs->cpdir2, mask2, sregs->cpdir2 & mask2);
		clrsetbits_be32(&regs->cppar2, mask2, sregs->cppar2 & mask2);
	} else {
		clrsetbits_be32(&regs->cpdir1, mask2, sregs->cpdir1 & mask2);
		clrsetbits_be32(&regs->cppar1, mask2, sregs->cppar1 & mask2);
	}

	if (sregs->cpdata & mask1)
		qe_gc->cpdata |= mask1;
	else
		qe_gc->cpdata &= ~mask1;

	out_be32(&regs->cpdata, qe_gc->cpdata);
	clrsetbits_be32(&regs->cpodr, mask1, sregs->cpodr & mask1);

	spin_unlock_irqrestore(&qe_gc->lock, flags);
}
EXPORT_SYMBOL(qe_pin_set_dedicated);

/**
 * qe_pin_set_gpio - Set a pin to the GPIO mode
 * @qe_pin:	pointer to the qe_pin structure
 * Context:	any
 *
 * This function sets a pin to the GPIO mode.
 */
void qe_pin_set_gpio(struct qe_pin *qe_pin)
{
	struct qe_gpio_chip *qe_gc = qe_pin->controller;
	struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
	unsigned long flags;

	spin_lock_irqsave(&qe_gc->lock