* enumeration tasks, they don't fully conform to the Linux driver model.
* In particular, when such drivers are built as modules, they can't be
* "hotplugged".
+ + *
+ + * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
*/
struct platform_device *platform_device_register_simple(const char *name,
int id,
* allocated for the device allows drivers using such devices to be
* unloaded without waiting for the last reference to the device to be
* dropped.
+ + *
+ + * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
*/
struct platform_device *platform_device_register_data(
struct device *parent,
*
* Use this in legacy-style modules that probe hardware directly and
* register a single platform device and corresponding platform driver.
+ + *
+ + * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
*/
struct platform_device * __init_or_module platform_create_bundle(
struct platform_driver *driver,
static __initdata LIST_HEAD(early_platform_device_list);
/**
- - * early_platform_driver_register
+ + * early_platform_driver_register - register early platform driver
* @epdrv: early_platform driver structure
* @buf: string passed from early_param()
+ + *
+ + * Helper function for early_platform_init() / early_platform_init_buffer()
*/
int __init early_platform_driver_register(struct early_platform_driver *epdrv,
char *buf)
}
/**
- - * early_platform_add_devices - add a numbers of early platform devices
+ + * early_platform_add_devices - adds a number of early platform devices
* @devs: array of early platform devices to add
* @num: number of early platform devices in array
+ + *
+ + * Used by early architecture code to register early platform devices and
+ + * their platform data.
*/
void __init early_platform_add_devices(struct platform_device **devs, int num)
{
}
/**
- - * early_platform_driver_register_all
+ + * early_platform_driver_register_all - register early platform drivers
* @class_str: string to identify early platform driver class
+ + *
+ + * Used by architecture code to register all early platform drivers
+ + * for a certain class. If omitted then only early platform drivers
+ + * with matching kernel command line class parameters will be registered.
*/
void __init early_platform_driver_register_all(char *class_str)
{
}
/**
- - * early_platform_match
+ + * early_platform_match - find early platform device matching driver
* @epdrv: early platform driver structure
* @id: id to match against
*/
}
/**
- - * early_platform_left
+ + * early_platform_left - check if early platform driver has matching devices
* @epdrv: early platform driver structure
* @id: return true if id or above exists
*/
}
/**
- - * early_platform_driver_probe_id
+ + * early_platform_driver_probe_id - probe drivers matching class_str and id
* @class_str: string to identify early platform driver class
* @id: id to match against
* @nr_probe: number of platform devices to successfully probe before exiting
}
if (match) {
+++ /*
+++ * Set up a sensible init_name to enable
+++ * dev_name() and others to be used before the
+++ * rest of the driver core is initialized.
+++ */
+++ if (!match->dev.init_name) {
+++ if (match->id != -1)
+++ match->dev.init_name =
+++ kasprintf(GFP_KERNEL, "%s.%d",
+++ match->name,
+++ match->id);
+++ else
+++ match->dev.init_name =
+++ kasprintf(GFP_KERNEL, "%s",
+++ match->name);
+++
+++ if (!match->dev.init_name)
+++ return -ENOMEM;
+++ }
+++
if (epdrv->pdrv->probe(match))
pr_warning("%s: unable to probe %s early.\n",
class_str, match->name);
}
/**
- - * early_platform_driver_probe
+ + * early_platform_driver_probe - probe a class of registered drivers
* @class_str: string to identify early platform driver class
* @nr_probe: number of platform devices to successfully probe before exiting
* @user_only: only probe user specified early platform devices
+ + *
+ + * Used by architecture code to probe registered early platform drivers
+ + * within a certain class. For probe to happen a registered early platform
+ + * device matching a registered early platform driver is needed.
*/
int __init early_platform_driver_probe(char *class_str,
int nr_probe,
#include <linux/list.h>
#include <linux/dmaengine.h>
#include <linux/scatterlist.h>
- -#include <linux/timer.h>
#ifdef CONFIG_SUPERH
#include <asm/sh_bios.h>
/* Interface clock */
struct clk *iclk;
--- /* Data clock */
--- struct clk *dclk;
+++ /* Function clock */
+++ struct clk *fclk;
struct list_head node;
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
struct device *dma_dev;
-- - enum sh_dmae_slave_chan_id slave_tx;
-- - enum sh_dmae_slave_chan_id slave_rx;
++ + unsigned int slave_tx;
++ + unsigned int slave_rx;
struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx[2];
dma_cookie_t cookie_tx;
struct work_struct work_tx;
struct work_struct work_rx;
struct timer_list rx_timer;
++ + unsigned int rx_timeout;
#endif
};
struct sci_port *s = to_sci_port(port);
if (s->chan_rx) {
-- - unsigned long tout;
u16 scr = sci_in(port, SCSCR);
u16 ssr = sci_in(port, SCxSR);
/* Disable future Rx interrupts */
-- - sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE);
++ + if (port->type == PORT_SCIFA) {
++ + disable_irq_nosync(irq);
++ + scr |= 0x4000;
++ + } else {
++ + scr &= ~SCI_CTRL_FLAGS_RIE;
++ + }
++ + sci_out(port, SCSCR, scr);
/* Clear current interrupt */
sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-- - /* Calculate delay for 1.5 DMA buffers */
-- - tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
-- - port->fifosize / 2;
-- - dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n",
-- - tout * 1000 / HZ);
-- - if (tout < 2)
-- - tout = 2;
-- - mod_timer(&s->rx_timer, jiffies + tout);
++ + dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
++ + jiffies, s->rx_timeout);
++ + mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
return IRQ_HANDLED;
}
if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
--- WARN_ONCE(ret == IRQ_NONE,
--- "%s: %d IRQ %d, status %x, control %x\n", __func__,
--- irq, port->line, ssr_status, scr_status);
---
return ret;
}
(phase == CPUFREQ_RESUMECHANGE)) {
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(sci_port, &priv->ports, node)
--- sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
+++ sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
spin_unlock_irqrestore(&priv->lock, flags);
}
{
struct sci_port *sci_port = to_sci_port(port);
--- clk_enable(sci_port->dclk);
--- sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
---
--- if (sci_port->iclk)
--- clk_enable(sci_port->iclk);
+++ clk_enable(sci_port->iclk);
+++ sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+++ clk_enable(sci_port->fclk);
}
static void sci_clk_disable(struct uart_port *port)
{
struct sci_port *sci_port = to_sci_port(port);
--- if (sci_port->iclk)
--- clk_disable(sci_port->iclk);
---
--- clk_disable(sci_port->dclk);
+++ clk_disable(sci_port->fclk);
+++ clk_disable(sci_port->iclk);
}
static int sci_request_irq(struct sci_port *port)
spin_lock_irqsave(&port->lock, flags);
-- - xmit->tail += s->sg_tx.length;
++ + xmit->tail += sg_dma_len(&s->sg_tx);
xmit->tail &= UART_XMIT_SIZE - 1;
-- - port->icount.tx += s->sg_tx.length;
++ + port->icount.tx += sg_dma_len(&s->sg_tx);
async_tx_ack(s->desc_tx);
s->cookie_tx = -EINVAL;
s->desc_tx = NULL;
-- - spin_unlock_irqrestore(&port->lock, flags);
-- -
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
-- - if (uart_circ_chars_pending(xmit))
++ + if (!uart_circ_empty(xmit)) {
schedule_work(&s->work_tx);
++ + } else if (port->type == PORT_SCIFA) {
++ + u16 ctrl = sci_in(port, SCSCR);
++ + sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
++ + }
++ +
++ + spin_unlock_irqrestore(&port->lock, flags);
}
/* Locking: called with port lock held */
unsigned long flags;
int count;
-- - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
++ + dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
spin_lock_irqsave(&port->lock, flags);
count = sci_dma_rx_push(s, tty, s->buf_len_rx);
-- - mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5));
++ + mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
spin_unlock_irqrestore(&port->lock, flags);
sci_rx_dma_release(s, true);
return;
}
++ + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
++ + s->cookie_rx[i], i);
}
s->active_rx = s->cookie_rx[0];
return;
}
-- - dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__,
-- - s->cookie_rx[new], new);
-- -
s->active_rx = s->cookie_rx[!new];
++ +
++ + dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
++ + s->cookie_rx[new], new, s->active_rx);
}
static void work_fn_tx(struct work_struct *work)
*/
spin_lock_irq(&port->lock);
sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-- - sg->dma_address = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
++ + sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
sg->offset;
-- - sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
++ + sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-- - sg->dma_length = sg->length;
spin_unlock_irq(&port->lock);
-- - BUG_ON(!sg->length);
++ + BUG_ON(!sg_dma_len(sg));
desc = chan->device->device_prep_slave_sg(chan,
sg, s->sg_len_tx, DMA_TO_DEVICE,
static void sci_start_tx(struct uart_port *port)
{
++ + struct sci_port *s = to_sci_port(port);
unsigned short ctrl;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
-- - struct sci_port *s = to_sci_port(port);
-- -
-- - if (s->chan_tx) {
-- - if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0)
-- - schedule_work(&s->work_tx);
-- -
-- - return;
++ + if (port->type == PORT_SCIFA) {
++ + u16 new, scr = sci_in(port, SCSCR);
++ + if (s->chan_tx)
++ + new = scr | 0x8000;
++ + else
++ + new = scr & ~0x8000;
++ + if (new != scr)
++ + sci_out(port, SCSCR, new);
}
++ + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
++ + s->cookie_tx < 0)
++ + schedule_work(&s->work_tx);
#endif
-- -
-- - /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-- - ctrl = sci_in(port, SCSCR);
-- - ctrl |= SCI_CTRL_FLAGS_TIE;
-- - sci_out(port, SCSCR, ctrl);
++ + if (!s->chan_tx || port->type == PORT_SCIFA) {
++ + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
++ + ctrl = sci_in(port, SCSCR);
++ + sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
++ + }
}
static void sci_stop_tx(struct uart_port *port)
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
++ + if (port->type == PORT_SCIFA)
++ + ctrl &= ~0x8000;
ctrl &= ~SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
}
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl |= sci_in(port, SCSCR);
++ + if (port->type == PORT_SCIFA)
++ + ctrl &= ~0x4000;
sci_out(port, SCSCR, ctrl);
}
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
++ + if (port->type == PORT_SCIFA)
++ + ctrl &= ~0x4000;
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
sci_out(port, SCSCR, ctrl);
}
{
struct sci_port *s = (struct sci_port *)arg;
struct uart_port *port = &s->port;
-- -
u16 scr = sci_in(port, SCSCR);
++ +
++ + if (port->type == PORT_SCIFA) {
++ + scr &= ~0x4000;
++ + enable_irq(s->irqs[1]);
++ + }
sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
dev_dbg(port->dev, "DMA Rx timed out\n");
schedule_work(&s->work_rx);
sg_init_table(sg, 1);
sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
(int)buf[i] & ~PAGE_MASK);
-- - sg->dma_address = dma[i];
-- - sg->dma_length = sg->length;
++ + sg_dma_address(sg) = dma[i];
}
INIT_WORK(&s->work_rx, work_fn_rx);
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
++ +#ifdef CONFIG_SERIAL_SH_SCI_DMA
++ + struct sci_port *s = to_sci_port(port);
++ +#endif
unsigned int status, baud, smr_val, max_baud;
int t = -1;
++ + u16 scfcr = 0;
/*
* earlyprintk comes here early on with port->uartclk set to zero.
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
if (port->type != PORT_SCI)
-- - sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
++ + sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
smr_val = sci_in(port, SCSMR) & 3;
if ((termios->c_cflag & CSIZE) == CS7)
}
sci_init_pins(port, termios->c_cflag);
-- - sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0);
++ + sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
sci_out(port, SCSCR, SCSCR_INIT(port));
++ +#ifdef CONFIG_SERIAL_SH_SCI_DMA
++ + /*
++ + * Calculate delay for 1.5 DMA buffers: see
++ + * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
++ + * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
++ + * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
++ + * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
++ + * sizes), but it has been found out experimentally, that this is not
++ + * enough: the driver too often needlessly runs on a DMA timeout. 20ms
++ + * as a minimum seem to work perfectly.
++ + */
++ + if (s->chan_rx) {
++ + s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
++ + port->fifosize / 2;
++ + dev_dbg(port->dev,
++ + "DMA Rx t-out %ums, tty t-out %u jiffies\n",
++ + s->rx_timeout * 1000 / HZ, port->timeout);
++ + if (s->rx_timeout < msecs_to_jiffies(20))
++ + s->rx_timeout = msecs_to_jiffies(20);
++ + }
++ +#endif
++ +
if ((termios->c_cflag & CREAD) != 0)
sci_start_rx(port);
}
#endif
};
--- static void __devinit sci_init_single(struct platform_device *dev,
--- struct sci_port *sci_port,
--- unsigned int index,
--- struct plat_sci_port *p)
+++ static int __devinit sci_init_single(struct platform_device *dev,
+++ struct sci_port *sci_port,
+++ unsigned int index,
+++ struct plat_sci_port *p)
{
struct uart_port *port = &sci_port->port;
}
if (dev) {
--- sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
--- sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
+++ sci_port->iclk = clk_get(&dev->dev, "sci_ick");
+++ if (IS_ERR(sci_port->iclk)) {
+++ sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
+++ if (IS_ERR(sci_port->iclk)) {
+++ dev_err(&dev->dev, "can't get iclk\n");
+++ return PTR_ERR(sci_port->iclk);
+++ }
+++ }
+++
+++ /*
+++ * The function clock is optional, ignore it if we can't
+++ * find it.
+++ */
+++ sci_port->fclk = clk_get(&dev->dev, "sci_fck");
+++ if (IS_ERR(sci_port->fclk))
+++ sci_port->fclk = NULL;
+++
sci_port->enable = sci_clk_enable;
sci_port->disable = sci_clk_disable;
port->dev = &dev->dev;
#endif
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
+++ return 0;
}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
spin_lock_irqsave(&priv->lock, flags);
--- list_for_each_entry(p, &priv->ports, node)
+++ list_for_each_entry(p, &priv->ports, node) {
uart_remove_one_port(&sci_uart_driver, &p->port);
+++ clk_put(p->iclk);
+++ clk_put(p->fclk);
+++ }
spin_unlock_irqrestore(&priv->lock, flags);
kfree(priv);
return 0;
}
--- sci_init_single(dev, sciport, index, p);
+++ ret = sci_init_single(dev, sciport, index, p);
+++ if (ret)
+++ return ret;
ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
if (ret)
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
*
* Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009 Paul Mundt
+ * Copyright (C) 2009, 2010 Paul Mundt
*
* Based on intc2.c and ipr.c
*
#include <linux/list.h>
#include <linux/topology.h>
#include <linux/bitmap.h>
+ #include <linux/cpumask.h>
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
unsigned long handle;
};
+ ++struct intc_window {
+ ++ phys_addr_t phys;
+ ++ void __iomem *virt;
+ ++ unsigned long size;
+ ++};
+ ++
struct intc_desc_int {
struct list_head list;
struct sys_device sysdev;
unsigned int nr_prio;
struct intc_handle_int *sense;
unsigned int nr_sense;
+ ++ struct intc_window *window;
+ ++ unsigned int nr_windows;
struct irq_chip chip;
};
unsigned int cpu;
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ #ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+ #endif
addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
[_INTC_FN(handle)], irq);
unsigned int cpu;
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ #ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+ #endif
addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
[_INTC_FN(handle)], irq);
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
}
+ #ifdef CONFIG_SMP
+ /*
+ * This is held with the irq desc lock held, so we don't require any
+ * additional locking here at the intc desc level. The affinity mask is
+ * later tested in the enable/disable paths.
+ */
+ static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+ {
+ if (!cpumask_intersects(cpumask, cpu_online_mask))
+ return -1;
+
+ cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
+
+ return 0;
+ }
+ #endif
+
static void intc_mask_ack(unsigned int irq)
{
struct intc_desc_int *d = get_intc_desc(irq);
return 0;
}
+ ++static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
+ ++ unsigned long address)
+ ++{
+ ++ struct intc_window *window;
+ ++ int k;
+ ++
+ ++ /* scan through physical windows and convert address */
+ ++ for (k = 0; k < d->nr_windows; k++) {
+ ++ window = d->window + k;
+ ++
+ ++ if (address < window->phys)
+ ++ continue;
+ ++
+ ++ if (address >= (window->phys + window->size))
+ ++ continue;
+ ++
+ ++ address -= window->phys;
+ ++ address += (unsigned long)window->virt;
+ ++
+ ++ return address;
+ ++ }
+ ++
+ ++ /* no windows defined, register must be 1:1 mapped virt:phys */
+ ++ return address;
+ ++}
+ ++
static unsigned int __init intc_get_reg(struct intc_desc_int *d,
- -- unsigned long address)
+ ++ unsigned long address)
{
unsigned int k;
+ ++ address = intc_phys_to_virt(d, address);
+ ++
for (k = 0; k < d->nr_reg; k++) {
if (d->reg[k] == address)
return k;
if (desc->hw.ack_regs)
ack_handle[irq] = intc_ack_data(desc, d, enum_id);
+
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
+#endif
}
static unsigned int __init save_reg(struct intc_desc_int *d,
unsigned int smp)
{
if (value) {
+ ++ value = intc_phys_to_virt(d, value);
+ ++
d->reg[cnt] = value;
#ifdef CONFIG_SMP
d->smp[cnt] = smp;
generic_handle_irq((unsigned int)get_irq_data(irq));
}
- --void __init register_intc_controller(struct intc_desc *desc)
+ ++int __init register_intc_controller(struct intc_desc *desc)
{
unsigned int i, k, smp;
struct intc_hw_desc *hw = &desc->hw;
struct intc_desc_int *d;
+ ++ struct resource *res;
d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ ++ if (!d)
+ ++ goto err0;
INIT_LIST_HEAD(&d->list);
list_add(&d->list, &intc_list);
+ ++ if (desc->num_resources) {
+ ++ d->nr_windows = desc->num_resources;
+ ++ d->window = kzalloc(d->nr_windows * sizeof(*d->window),
+ ++ GFP_NOWAIT);
+ ++ if (!d->window)
+ ++ goto err1;
+ ++
+ ++ for (k = 0; k < d->nr_windows; k++) {
+ ++ res = desc->resource + k;
+ ++ WARN_ON(resource_type(res) != IORESOURCE_MEM);
+ ++ d->window[k].phys = res->start;
+ ++ d->window[k].size = resource_size(res);
+ ++ d->window[k].virt = ioremap_nocache(res->start,
+ ++ resource_size(res));
+ ++ if (!d->window[k].virt)
+ ++ goto err2;
+ ++ }
+ ++ }
+ ++
d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
+ ++ if (!d->reg)
+ ++ goto err2;
+ ++
#ifdef CONFIG_SMP
d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
+ ++ if (!d->smp)
+ ++ goto err3;
#endif
k = 0;
if (hw->prio_regs) {
d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
GFP_NOWAIT);
+ ++ if (!d->prio)
+ ++ goto err4;
for (i = 0; i < hw->nr_prio_regs; i++) {
smp = IS_SMP(hw->prio_regs[i]);
if (hw->sense_regs) {
d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
GFP_NOWAIT);
+ ++ if (!d->sense)
+ ++ goto err5;
for (i = 0; i < hw->nr_sense_regs; i++)
k += save_reg(d, k, hw->sense_regs[i].reg, 0);
d->chip.shutdown = intc_disable;
d->chip.set_type = intc_set_sense;
d->chip.set_wake = intc_set_wake;
+ #ifdef CONFIG_SMP
+ d->chip.set_affinity = intc_set_affinity;
+ #endif
if (hw->ack_regs) {
for (i = 0; i < hw->nr_ack_regs; i++)
/* enable bits matching force_enable after registering irqs */
if (desc->force_enable)
intc_enable_disable_enum(desc, d, desc->force_enable, 1);
+ ++
+ ++ return 0;
+ ++err5:
+ ++ kfree(d->prio);
+ ++err4:
+ ++#ifdef CONFIG_SMP
+ ++ kfree(d->smp);
+ ++err3:
+ ++#endif
+ ++ kfree(d->reg);
+ ++err2:
+ ++ for (k = 0; k < d->nr_windows; k++)
+ ++ if (d->window[k].virt)
+ ++ iounmap(d->window[k].virt);
+ ++
+ ++ kfree(d->window);
+ ++err1:
+ ++ kfree(d);
+ ++err0:
+ ++ pr_err("unable to allocate INTC memory\n");
+ ++
+ ++ return -ENOMEM;
}
static int intc_suspend(struct sys_device *dev, pm_message_t state)
out_unlock:
spin_unlock_irqrestore(&vector_lock, flags);
- if (irq > 0)
+ if (irq > 0) {
dynamic_irq_init(irq);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
+#endif
+ }
return irq;
}