Merge commit 'kumar/next' into next
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 31 May 2010 00:01:50 +0000 (10:01 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 31 May 2010 00:01:50 +0000 (10:01 +1000)
Conflicts:
arch/powerpc/sysdev/fsl_msi.c

1  2 
arch/powerpc/Kconfig
arch/powerpc/kernel/traps.c
arch/powerpc/sysdev/fsl_msi.c

diff --combined arch/powerpc/Kconfig
@@@ -351,7 -351,7 +351,7 @@@ config ARCH_ENABLE_MEMORY_HOTREMOV
  
  config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
-       depends on PPC_BOOK3S && EXPERIMENTAL
+       depends on (PPC_BOOK3S || (FSL_BOOKE && !SMP)) && EXPERIMENTAL
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
@@@ -663,9 -663,6 +663,9 @@@ config ZONE_DM
  config NEED_DMA_MAP_STATE
        def_bool (PPC64 || NOT_COHERENT_CACHE)
  
 +config NEED_SG_DMA_LENGTH
 +      def_bool y
 +
  config GENERIC_ISA_DMA
        bool
        depends on PPC64 || POWER4 || 6xx && !CPM2
@@@ -1,5 -1,6 +1,6 @@@
  /*
   *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+  *  Copyright 2007-2010 Freescale Semiconductor, Inc.
   *
   *  This program is free software; you can redistribute it and/or
   *  modify it under the terms of the GNU General Public License
@@@ -305,7 -306,7 +306,7 @@@ static inline int check_io_access(struc
  #ifndef CONFIG_FSL_BOOKE
  #define get_mc_reason(regs)   ((regs)->dsisr)
  #else
- #define get_mc_reason(regs)   (mfspr(SPRN_MCSR) & MCSR_MASK)
+ #define get_mc_reason(regs)   (mfspr(SPRN_MCSR))
  #endif
  #define REASON_FP             ESR_FP
  #define REASON_ILLEGAL                (ESR_PIL | ESR_PUO)
@@@ -421,6 -422,91 +422,91 @@@ int machine_check_47x(struct pt_regs *r
        return 0;
  }
  #elif defined(CONFIG_E500)
+ int machine_check_e500mc(struct pt_regs *regs)
+ {
+       unsigned long mcsr = mfspr(SPRN_MCSR);
+       unsigned long reason = mcsr;
+       int recoverable = 1;
+       printk("Machine check in kernel mode.\n");
+       printk("Caused by (from MCSR=%lx): ", reason);
+       if (reason & MCSR_MCP)
+               printk("Machine Check Signal\n");
+       if (reason & MCSR_ICPERR) {
+               printk("Instruction Cache Parity Error\n");
+               /*
+                * This is recoverable by invalidating the i-cache.
+                */
+               mtspr(SPRN_L1CSR1, mfspr(SPRN_L1CSR1) | L1CSR1_ICFI);
+               while (mfspr(SPRN_L1CSR1) & L1CSR1_ICFI)
+                       ;
+               /*
+                * This will generally be accompanied by an instruction
+                * fetch error report -- only treat MCSR_IF as fatal
+                * if it wasn't due to an L1 parity error.
+                */
+               reason &= ~MCSR_IF;
+       }
+       if (reason & MCSR_DCPERR_MC) {
+               printk("Data Cache Parity Error\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_L2MMU_MHIT) {
+               printk("Hit on multiple TLB entries\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_NMI)
+               printk("Non-maskable interrupt\n");
+       if (reason & MCSR_IF) {
+               printk("Instruction Fetch Error Report\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_LD) {
+               printk("Load Error Report\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_ST) {
+               printk("Store Error Report\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_LDG) {
+               printk("Guarded Load Error Report\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_TLBSYNC)
+               printk("Simultaneous tlbsync operations\n");
+       if (reason & MCSR_BSL2_ERR) {
+               printk("Level 2 Cache Error\n");
+               recoverable = 0;
+       }
+       if (reason & MCSR_MAV) {
+               u64 addr;
+               addr = mfspr(SPRN_MCAR);
+               addr |= (u64)mfspr(SPRN_MCARU) << 32;
+               printk("Machine Check %s Address: %#llx\n",
+                      reason & MCSR_MEA ? "Effective" : "Physical", addr);
+       }
+       mtspr(SPRN_MCSR, mcsr);
+       return mfspr(SPRN_MCSR) == 0 && recoverable;
+ }
  int machine_check_e500(struct pt_regs *regs)
  {
        unsigned long reason = get_mc_reason(regs);
@@@ -855,15 -941,12 +941,15 @@@ void __kprobes program_check_exception(
                return;
        }
        if (reason & REASON_TRAP) {
 +              /* Debugger is first in line to stop recursive faults in
 +               * rcu_lock, notify_die, or atomic_notifier_call_chain */
 +              if (debugger_bpt(regs))
 +                      return;
 +
                /* trap exception */
                if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP)
                                == NOTIFY_STOP)
                        return;
 -              if (debugger_bpt(regs))
 -                      return;
  
                if (!(regs->msr & MSR_PR) &&  /* not user-mode */
                    report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved.
+  * Copyright (C) 2007-2010 Freescale Semiconductor, Inc.
   *
   * Author: Tony Li <tony.li@freescale.com>
   *       Jason Jin <Jason.jin@freescale.com>
  #include <asm/prom.h>
  #include <asm/hw_irq.h>
  #include <asm/ppc-pci.h>
+ #include <asm/mpic.h>
  #include "fsl_msi.h"
  
+ LIST_HEAD(msi_head);
  struct fsl_msi_feature {
        u32 fsl_pic_ip;
        u32 msiir_offset;
  };
  
- static struct fsl_msi *fsl_msi;
+ struct fsl_msi_cascade_data {
+       struct fsl_msi *msi_data;
+       int index;
+ };
  
  static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
  {
@@@ -54,10 -60,12 +60,12 @@@ static struct irq_chip fsl_msi_chip = 
  static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
                                irq_hw_number_t hw)
  {
+       struct fsl_msi *msi_data = h->host_data;
        struct irq_chip *chip = &fsl_msi_chip;
  
        irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING;
  
+       set_irq_chip_data(virq, msi_data);
        set_irq_chip_and_handler(virq, chip, handle_edge_irq);
  
        return 0;
@@@ -96,11 -104,12 +104,12 @@@ static int fsl_msi_check_device(struct 
  static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
  {
        struct msi_desc *entry;
-       struct fsl_msi *msi_data = fsl_msi;
+       struct fsl_msi *msi_data;
  
        list_for_each_entry(entry, &pdev->msi_list, list) {
                if (entry->irq == NO_IRQ)
                        continue;
+               msi_data = get_irq_data(entry->irq);
                set_irq_msi(entry->irq, NULL);
                msi_bitmap_free_hwirqs(&msi_data->bitmap,
                                       virq_to_hw(entry->irq), 1);
  }
  
  static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
-                                 struct msi_msg *msg)
+                               struct msi_msg *msg,
+                               struct fsl_msi *fsl_msi_data)
  {
-       struct fsl_msi *msi_data = fsl_msi;
+       struct fsl_msi *msi_data = fsl_msi_data;
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
        u32 base = 0;
  
  
  static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
  {
-       int rc, hwirq;
+       int rc, hwirq = -ENOMEM;
        unsigned int virq;
        struct msi_desc *entry;
        struct msi_msg msg;
-       struct fsl_msi *msi_data = fsl_msi;
+       struct fsl_msi *msi_data;
  
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+               list_for_each_entry(msi_data, &msi_head, list) {
+                       hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+                       if (hwirq >= 0)
+                               break;
+               }
                if (hwirq < 0) {
                        rc = hwirq;
                        pr_debug("%s: fail allocating msi interrupt\n",
                        rc = -ENOSPC;
                        goto out_free;
                }
+               set_irq_data(virq, msi_data);
                set_irq_msi(virq, entry);
  
-               fsl_compose_msi_msg(pdev, hwirq, &msg);
+               fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
                write_msi_msg(virq, &msg);
        }
        return 0;
  
  out_free:
+       /* free by the caller of this function */
        return rc;
  }
  
  static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
  {
        unsigned int cascade_irq;
-       struct fsl_msi *msi_data = fsl_msi;
+       struct fsl_msi *msi_data;
        int msir_index = -1;
        u32 msir_value = 0;
        u32 intr_index;
        u32 have_shift = 0;
+       struct fsl_msi_cascade_data *cascade_data;
+       cascade_data = (struct fsl_msi_cascade_data *)get_irq_data(irq);
+       msi_data = cascade_data->msi_data;
  
        raw_spin_lock(&desc->lock);
        if ((msi_data->feature &  FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto unlock;
  
-       msir_index = (int)desc->handler_data;
+       msir_index = cascade_data->index;
  
        if (msir_index >= NR_MSI_REG)
                cascade_irq = NO_IRQ;
  
        desc->status |= IRQ_INPROGRESS;
-       switch (fsl_msi->feature & FSL_PIC_IP_MASK) {
+       switch (msi_data->feature & FSL_PIC_IP_MASK) {
        case FSL_PIC_IP_MPIC:
                msir_value = fsl_msi_read(msi_data->msi_regs,
                        msir_index * 0x10);
@@@ -229,6 -250,30 +250,30 @@@ unlock
        raw_spin_unlock(&desc->lock);
  }
  
+ static int fsl_of_msi_remove(struct of_device *ofdev)
+ {
+       struct fsl_msi *msi = ofdev->dev.platform_data;
+       int virq, i;
+       struct fsl_msi_cascade_data *cascade_data;
+       if (msi->list.prev != NULL)
+               list_del(&msi->list);
+       for (i = 0; i < NR_MSI_REG; i++) {
+               virq = msi->msi_virqs[i];
+               if (virq != NO_IRQ) {
+                       cascade_data = get_irq_data(virq);
+                       kfree(cascade_data);
+                       irq_dispose_mapping(virq);
+               }
+       }
+       if (msi->bitmap.bitmap)
+               msi_bitmap_free(&msi->bitmap);
+       iounmap(msi->msi_regs);
+       kfree(msi);
+       return 0;
+ }
  static int __devinit fsl_of_msi_probe(struct of_device *dev,
                                const struct of_device_id *match)
  {
        int virt_msir;
        const u32 *p;
        struct fsl_msi_feature *features = match->data;
+       struct fsl_msi_cascade_data *cascade_data = NULL;
+       int len;
+       u32 offset;
  
        printk(KERN_DEBUG "Setting up Freescale MSI support\n");
  
        msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL);
        if (!msi) {
                dev_err(&dev->dev, "No memory for MSI structure\n");
-               err = -ENOMEM;
-               goto error_out;
+               return -ENOMEM;
        }
+       dev->dev.platform_data = msi;
  
 -      msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
 +      msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
                                      NR_MSI_IRQS, &fsl_msi_host_ops, 0);
  
        if (msi->irqhost == NULL) {
        }
  
        /* Get the MSI reg base */
 -      err = of_address_to_resource(dev->node, 0, &res);
 +      err = of_address_to_resource(dev->dev.of_node, 0, &res);
        if (err) {
                dev_err(&dev->dev, "%s resource error!\n",
 -                              dev->node->full_name);
 +                              dev->dev.of_node->full_name);
                goto error_out;
        }
  
                goto error_out;
        }
  
 -      p = of_get_property(dev->node, "interrupts", &count);
 +      p = of_get_property(dev->dev.of_node, "interrupts", &count);
        if (!p) {
                dev_err(&dev->dev, "no interrupts property found on %s\n",
 -                              dev->node->full_name);
 +                              dev->dev.of_node->full_name);
                err = -ENODEV;
                goto error_out;
        }
        if (count % 8 != 0) {
                dev_err(&dev->dev, "Malformed interrupts property on %s\n",
 -                              dev->node->full_name);
 +                              dev->dev.of_node->full_name);
                err = -EINVAL;
                goto error_out;
        }
+       offset = 0;
+       p = of_get_property(dev->node, "msi-available-ranges", &len);
+       if (p)
+               offset = *p / IRQS_PER_MSI_REG;
  
        count /= sizeof(u32);
-       for (i = 0; i < count / 2; i++) {
-               if (i > NR_MSI_REG)
-                       break;
+       for (i = 0; i < min(count / 2, NR_MSI_REG); i++) {
 -              virt_msir = irq_of_parse_and_map(dev->node, i);
 +              virt_msir = irq_of_parse_and_map(dev->dev.of_node, i);
                if (virt_msir != NO_IRQ) {
-                       set_irq_data(virt_msir, (void *)i);
+                       cascade_data = kzalloc(
+                                       sizeof(struct fsl_msi_cascade_data),
+                                       GFP_KERNEL);
+                       if (!cascade_data) {
+                               dev_err(&dev->dev,
+                                       "No memory for MSI cascade data\n");
+                               err = -ENOMEM;
+                               goto error_out;
+                       }
+                       msi->msi_virqs[i] = virt_msir;
+                       cascade_data->index = i + offset;
+                       cascade_data->msi_data = msi;
+                       set_irq_data(virt_msir, (void *)cascade_data);
                        set_irq_chained_handler(virt_msir, fsl_msi_cascade);
                }
        }
  
-       fsl_msi = msi;
+       list_add_tail(&msi->list, &msi_head);
  
-       WARN_ON(ppc_md.setup_msi_irqs);
-       ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
-       ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
-       ppc_md.msi_check_device = fsl_msi_check_device;
+       /* The multiple setting ppc_md.setup_msi_irqs will not harm things */
+       if (!ppc_md.setup_msi_irqs) {
+               ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
+               ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
+               ppc_md.msi_check_device = fsl_msi_check_device;
+       } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
+               dev_err(&dev->dev, "Different MSI driver already installed!\n");
+               err = -ENODEV;
+               goto error_out;
+       }
        return 0;
  error_out:
-       kfree(msi);
+       fsl_of_msi_remove(dev);
        return err;
  }
  
@@@ -345,12 -413,10 +413,13 @@@ static const struct of_device_id fsl_of
  };
  
  static struct of_platform_driver fsl_of_msi_driver = {
 -      .name = "fsl-msi",
 -      .match_table = fsl_of_msi_ids,
 +      .driver = {
 +              .name = "fsl-msi",
 +              .owner = THIS_MODULE,
 +              .of_match_table = fsl_of_msi_ids,
 +      },
        .probe = fsl_of_msi_probe,
+       .remove = fsl_of_msi_remove,
  };
  
  static __init int fsl_of_msi_init(void)