Merge branches 'genesis/dmaengine', 'genesis/intc-extension' and 'genesis/i2c-updates'
authorPaul Mundt <lethal@linux-sh.org>
Wed, 7 Apr 2010 07:21:03 +0000 (16:21 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 7 Apr 2010 07:21:03 +0000 (16:21 +0900)
1  2  3 
drivers/dma/shdma.c
drivers/serial/sh-sci.c
drivers/sh/intc.c

diff --combined drivers/dma/shdma.c
index bbc3dfeed9b24bf8434c992002056a9b371c0b9d,5d17e09cb625412beaf0e8275f39142b7006a4c1,7cc31b3f40d810c2d3ad6c93b312399146f254b8..ed3ef22e68a4cb889ce7238f286edf37ea36eccd
   
   #include <linux/init.h>
   #include <linux/module.h>
++ #include <linux/slab.h>
   #include <linux/interrupt.h>
   #include <linux/dmaengine.h>
   #include <linux/delay.h>
   #include <linux/dma-mapping.h>
   #include <linux/platform_device.h>
   #include <linux/pm_runtime.h>
 --
 --#include <asm/dmaengine.h>
 ++#include <linux/sh_dma.h>
   
   #include "shdma.h"
   
@@@@ -43,7 -44,7 -45,7 +44,7 @@@@ enum sh_dmae_desc_status 
   #define LOG2_DEFAULT_XFER_SIZE       2
   
   /* A bitmask with bits enough for enum sh_dmae_slave_chan_id */
 --static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)];
 ++static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)];
   
   static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all);
   
@@@@ -265,7 -266,7 -267,7 +266,7 @@@@ static struct sh_desc *sh_dmae_get_desc
   }
   
   static struct sh_dmae_slave_config *sh_dmae_find_slave(
 --     struct sh_dmae_chan *sh_chan, enum sh_dmae_slave_chan_id slave_id)
 ++     struct sh_dmae_chan *sh_chan, struct sh_dmae_slave *param)
   {
        struct dma_device *dma_dev = sh_chan->common.device;
        struct sh_dmae_device *shdev = container_of(dma_dev,
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
   
 --     if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER)
 ++     if (param->slave_id >= SH_DMA_SLAVE_NUMBER)
                return NULL;
   
        for (i = 0; i < pdata->slave_num; i++)
 --             if (pdata->slave[i].slave_id == slave_id)
 ++             if (pdata->slave[i].slave_id == param->slave_id)
                        return pdata->slave + i;
   
        return NULL;
@@@@ -298,7 -299,7 -300,7 +299,7 @@@@ static int sh_dmae_alloc_chan_resources
        if (param) {
                struct sh_dmae_slave_config *cfg;
   
 --             cfg = sh_dmae_find_slave(sh_chan, param->slave_id);
 ++             cfg = sh_dmae_find_slave(sh_chan, param);
                if (!cfg)
                        return -EINVAL;
   
@@@@ -793,7 -794,7 -795,7 +794,7 @@@@ static irqreturn_t sh_dmae_interrupt(in
        return ret;
   }
   
 --#if defined(CONFIG_CPU_SH4)
 ++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
   static irqreturn_t sh_dmae_err(int irq, void *data)
   {
        struct sh_dmae_device *shdev = (struct sh_dmae_device *)data;
@@@@ -1034,7 -1035,7 -1036,7 +1035,7 @@@@ static int __init sh_dmae_probe(struct 
        /* Default transfer size of 32 bytes requires 32-byte alignment */
        shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE;
   
 --#if defined(CONFIG_CPU_SH4)
 ++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
        chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
   
        if (!chanirq_res)
   
   #else
        chanirq_res = errirq_res;
 --#endif /* CONFIG_CPU_SH4 */
 ++#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */
   
        if (chanirq_res->start == chanirq_res->end &&
            !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
   chan_probe_err:
        sh_dmae_chan_remove(shdev);
   eirqres:
 --#if defined(CONFIG_CPU_SH4)
 ++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
        free_irq(errirq, shdev);
   eirq_err:
   #endif
diff --combined drivers/serial/sh-sci.c
index cd52dd64edf0bf4568e9c142c47a9b2b94e5f388,980f39449ee5635ccb7b4f681151892e92a493b0,8eb094c1f61b2c2ab17cb68e420f16ad42428823..78e0545243d0f0d6b2aed2bfe2f63ab8e13fa08e
   #include <linux/list.h>
   #include <linux/dmaengine.h>
   #include <linux/scatterlist.h>
 - #include <linux/timer.h>
++ #include <linux/slab.h>
   
   #ifdef CONFIG_SUPERH
   #include <asm/sh_bios.h>
@@@@ -90,8 -91,8 -91,8 +91,8 @@@@ struct sci_port 
        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;
@@@@ -779,10 -780,10 -780,6 +780,6 @@@@ static irqreturn_t sci_mpxed_interrupt(
        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;
   }
   
@@@@ -916,10 -917,10 -913,10 +913,10 @@@@ static void sci_dma_tx_complete(void *a
   
        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;
@@@@ -1134,13 -1135,14 -1131,14 +1131,13 @@@@ static void work_fn_tx(struct work_stru
         */
        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,
@@@@ -1341,7 -1343,8 -1339,8 +1338,7 @@@@ static void sci_request_dma(struct uart
                        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);
diff --combined drivers/sh/intc.c
index a3d8677af6a52dd1db005fcb13d3fc12ede75c16,a700dfec8dc36d3d980732856605a5707928a9df,94ad6bd86a00c02754d6c3ac2666cc347a2816c7..3c584bdfec1e16054268c3674d6f45d3473f851e
@@@@ -2,7 -2,7 -2,7 +2,7 @@@@
    * 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/irq.h>
   #include <linux/module.h>
   #include <linux/io.h>
++ #include <linux/slab.h>
   #include <linux/interrupt.h>
   #include <linux/sh_intc.h>
   #include <linux/sysdev.h>
   #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) | \
@@@@ -44,6 -43,12 -45,6 +45,12 @@@@ struct intc_handle_int 
        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;
   };
   
@@@@ -235,10 -242,6 -236,10 +244,10 @@@@ static inline void _intc_enable(unsigne
        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);
@@@@ -258,10 -261,6 -259,10 +267,10 @@@@ static void intc_disable(unsigned int i
        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);
@@@@ -310,23 -309,6 -311,23 +319,23 @@@@ static int intc_set_wake(unsigned int i
        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);
@@@@ -446,11 -428,39 -447,11 +455,39 @@@@ static int intc_set_sense(unsigned int 
        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;
@@@@ -800,6 -810,8 -801,6 +837,8 @@@@ static unsigned int __init save_reg(str
                                    unsigned int smp)
   {
        if (value) {
+ +             value = intc_phys_to_virt(d, value);
+ +
                d->reg[cnt] = value;
   #ifdef CONFIG_SMP
                d->smp[cnt] = smp;
@@@@ -815,25 -827,52 -816,25 +854,52 @@@@ static void intc_redirect_irq(unsigned 
        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)