vserver 2.0 rc7
[linux-2.6.git] / drivers / parisc / iosapic.c
index 7252d5c..91df0bf 100644 (file)
 
 
 #ifdef DEBUG_IOSAPIC
-static char assert_buf[128];
-
-static int
-assert_failed (char *a, char *f, int l)
-{
-        sprintf(assert_buf,
-                       "ASSERT(%s) failed!\nline %d in %s\n",
-                       a,      /* assertion text */
-                       l,      /* line number */
-                       f);     /* file name */
-        panic(assert_buf);
-       return 0;
-}
-
-#undef ASSERT
-#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); }
-
 #define DBG(x...) printk(x)
-
 #else /* DEBUG_IOSAPIC */
-
 #define DBG(x...)
-#undef ASSERT
-#define ASSERT(EX)
-
 #endif /* DEBUG_IOSAPIC */
 
 #ifdef DEBUG_IOSAPIC_IRT
@@ -191,6 +169,12 @@ assert_failed (char *a, char *f, int l)
 #define DBG_IRT(x...)
 #endif
 
+#ifdef CONFIG_64BIT
+#define COMPARE_IRTE_ADDR(irte, hpa)   ((irte)->dest_iosapic_addr == (hpa))
+#else
+#define COMPARE_IRTE_ADDR(irte, hpa)   \
+               ((irte)->dest_iosapic_addr == ((hpa) | 0xffffffff00000000ULL))
+#endif
 
 #define IOSAPIC_REG_SELECT              0x00
 #define IOSAPIC_REG_WINDOW              0x10
@@ -201,33 +185,18 @@ assert_failed (char *a, char *f, int l)
 #define IOSAPIC_IRDT_ENTRY(idx)                (0x10+(idx)*2)
 #define IOSAPIC_IRDT_ENTRY_HI(idx)     (0x11+(idx)*2)
 
-static inline unsigned int iosapic_read(unsigned long iosapic, unsigned int reg)
+static inline unsigned int iosapic_read(void __iomem *iosapic, unsigned int reg)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        return readl(iosapic + IOSAPIC_REG_WINDOW);
 }
 
-static inline void iosapic_write(unsigned long iosapic, unsigned int reg, u32 val)
+static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 val)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        writel(val, iosapic + IOSAPIC_REG_WINDOW);
 }
 
-/*
-**     GFP_KERNEL includes __GFP_WAIT flag and that may not
-**     be acceptable. Since this is boot time, we shouldn't have
-**     to wait ever and this code should (will?) never get called
-**     from the interrrupt context.
-*/
-#define        IOSAPIC_KALLOC(a_type, cnt) \
-                       (a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL)
-#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr)
-
-
-#define        IOSAPIC_LOCK(lck)       spin_lock_irqsave(lck, irqflags)
-#define        IOSAPIC_UNLOCK(lck)     spin_unlock_irqrestore(lck, irqflags)
-
-
 #define IOSAPIC_VERSION_MASK   0x000000ff
 #define        IOSAPIC_VERSION(ver)    ((int) (ver & IOSAPIC_VERSION_MASK))
 
@@ -265,52 +234,64 @@ static inline void iosapic_eoi(void __iomem *addr, unsigned int data)
 static struct irt_entry *irt_cell;
 static size_t irt_num_entry;
 
+static struct irt_entry *iosapic_alloc_irt(int num_entries)
+{
+       unsigned long a;
 
+       /* The IRT needs to be 8-byte aligned for the PDC call. 
+        * Normally kmalloc would guarantee larger alignment, but
+        * if CONFIG_DEBUG_SLAB is enabled, then we can get only
+        * 4-byte alignment on 32-bit kernels
+        */
+       a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL);
+       a = (a + 7) & ~7;
+       return (struct irt_entry *)a;
+}
 
-/*
-** iosapic_load_irt
-**
-** The "Get PCI INT Routing Table Size" option returns the number of 
-** entries in the PCI interrupt routing table for the cell specified 
-** in the cell_number argument.  The cell number must be for a cell 
-** within the caller's protection domain.
-**
-** The "Get PCI INT Routing Table" option returns, for the cell 
-** specified in the cell_number argument, the PCI interrupt routing 
-** table in the caller allocated memory pointed to by mem_addr.
-** We assume the IRT only contains entries for I/O SAPIC and
-** calculate the size based on the size of I/O sapic entries.
-**
-** The PCI interrupt routing table entry format is derived from the
-** IA64 SAL Specification 2.4.   The PCI interrupt routing table defines
-** the routing of PCI interrupt signals between the PCI device output
-** "pins" and the IO SAPICs' input "lines" (including core I/O PCI
-** devices).  This table does NOT include information for devices/slots
-** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
-** for the architected method of routing of IRQ's behind PPB's.
-*/
+/**
+ * iosapic_load_irt - Fill in the interrupt routing table
+ * @cell_num: The cell number of the CPU we're currently executing on
+ * @irt: The address to place the new IRT at
+ * @return The number of entries found
+ *
+ * The "Get PCI INT Routing Table Size" option returns the number of 
+ * entries in the PCI interrupt routing table for the cell specified 
+ * in the cell_number argument.  The cell number must be for a cell 
+ * within the caller's protection domain.
+ *
+ * The "Get PCI INT Routing Table" option returns, for the cell 
+ * specified in the cell_number argument, the PCI interrupt routing 
+ * table in the caller allocated memory pointed to by mem_addr.
+ * We assume the IRT only contains entries for I/O SAPIC and
+ * calculate the size based on the size of I/O sapic entries.
+ *
+ * The PCI interrupt routing table entry format is derived from the
+ * IA64 SAL Specification 2.4.   The PCI interrupt routing table defines
+ * the routing of PCI interrupt signals between the PCI device output
+ * "pins" and the IO SAPICs' input "lines" (including core I/O PCI
+ * devices).  This table does NOT include information for devices/slots
+ * behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
+ * for the architected method of routing of IRQ's behind PPB's.
+ */
 
 
-static int __init /* return number of entries as success/fail flag */
+static int __init
 iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
 {
        long status;              /* PDC return value status */
        struct irt_entry *table;  /* start of interrupt routing tbl */
        unsigned long num_entries = 0UL;
 
-       ASSERT(NULL != irt);
+       BUG_ON(!irt);
 
        if (is_pdc_pat()) {
-
                /* Use pat pdc routine to get interrupt routing table size */
                DBG("calling get_irt_size (cell %ld)\n", cell_num);
                status = pdc_pat_get_irt_size(&num_entries, cell_num);
                DBG("get_irt_size: %ld\n", status);
 
-               ASSERT(status == PDC_OK);
-
-               /* save the number of entries in the table */
-               ASSERT(0UL != num_entries);
+               BUG_ON(status != PDC_OK);
+               BUG_ON(num_entries == 0);
 
                /*
                ** allocate memory for interrupt routing table
@@ -318,45 +299,47 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
                ** the contents of the table are exclusively
                ** for I/O sapic devices.
                */
-               table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
+               table = iosapic_alloc_irt(num_entries);
                if (table == NULL) {
-                       printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+                       printk(KERN_WARNING MODULE_NAME ": read_irt : can "
+                                       "not alloc mem for IRT\n");
                        return 0;
                }
 
                /* get PCI INT routing table */
                status = pdc_pat_get_irt(table, cell_num);
                DBG("pdc_pat_get_irt: %ld\n", status);
-               ASSERT(status == PDC_OK);
+               WARN_ON(status != PDC_OK);
        } else {
                /*
                ** C3000/J5000 (and similar) platforms with Sprockets PDC
                ** will return exactly one IRT for all iosapics.
                ** So if we have one, don't need to get it again.
                */
-               if (NULL != irt_cell)
+               if (irt_cell)
                        return 0;
 
                /* Should be using the Elroy's HPA, but it's ignored anyway */
                status = pdc_pci_irt_size(&num_entries, 0);
                DBG("pdc_pci_irt_size: %ld\n", status);
 
-               if (PDC_OK != status) {
+               if (status != PDC_OK) {
                        /* Not a "legacy" system with I/O SAPIC either */
                        return 0;
                }
 
-               ASSERT(0UL != num_entries);
+               BUG_ON(num_entries == 0);
 
-               table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
-               if (table == NULL) {
-                       printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+               table = iosapic_alloc_irt(num_entries);
+               if (!table) {
+                       printk(KERN_WARNING MODULE_NAME ": read_irt : can "
+                                       "not alloc mem for IRT\n");
                        return 0;
                }
 
                /* HPA ignored by this call too. */
                status = pdc_pci_irt(num_entries, 0, table);
-               ASSERT(PDC_OK == status);
+               BUG_ON(status != PDC_OK);
        }
 
        /* return interrupt table address */
@@ -390,16 +373,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
 
 
 
-void __init
-iosapic_init(void)
+void __init iosapic_init(void)
 {
        unsigned long cell = 0;
 
-       /* init global data */
-       spin_lock_init(&iosapic_lock);
-        iosapic_list = (struct iosapic_info *) NULL;
-       iosapic_count = 0;
-
        DBG("iosapic_init()\n");
 
 #ifdef __LP64__
@@ -414,11 +391,9 @@ iosapic_init(void)
        }
 #endif
 
-       /*
-       **  get IRT for this cell.
-       */
-       irt_num_entry =  iosapic_load_irt(cell, &irt_cell);
-       if (0 == irt_num_entry)
+       /* get interrupt routing table for this cell */
+       irt_num_entry = iosapic_load_irt(cell, &irt_cell);
+       if (irt_num_entry == 0)
                irt_cell = NULL;        /* old PDC w/o iosapic */
 }
 
@@ -459,10 +434,7 @@ irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin)
                        continue;
                }
 
-               /*
-               ** Compare: dest_iosapic_addr, src_bus_irq_devno
-               */
-               if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))
+               if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa))
                        continue;
 
                if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)
@@ -506,10 +478,10 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
 
        pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
 
-       DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n",
-               PCI_SLOT(pcidev->devfn), intr_pin);
+       DBG_IRT("iosapic_xlate_pin(%s) SLOT %d pin %d\n",
+               pcidev->slot_name, PCI_SLOT(pcidev->devfn), intr_pin);
 
-       if (0 == intr_pin) {
+       if (intr_pin == 0) {
                /* The device does NOT support/use IRQ lines.  */
                return NULL;
        }
@@ -606,7 +578,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
 {
        u32 mode = 0;
        struct irt_entry *p = vi->irte;
-       ASSERT(NULL != vi->irte);
 
        if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
                mode |= IOSAPIC_IRDT_PO_LOW;
@@ -619,7 +590,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
        ** PA doesn't support EXTINT or LPRIO bits.
        */
 
-       ASSERT(vi->txn_data);
        *dp0 = mode | (u32) vi->txn_data;
 
        /*
@@ -802,22 +772,23 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
 
        vi->irte = irte;
 
-       /* Allocate processor IRQ */
-       vi->txn_irq = txn_alloc_irq();
-
        /*
+        * Allocate processor IRQ
+        *
         * XXX/FIXME The txn_alloc_irq() code and related code should be
         * moved to enable_irq(). That way we only allocate processor IRQ
         * bits for devices that actually have drivers claiming them.
         * Right now we assign an IRQ to every PCI device present,
         * regardless of whether it's used or not.
         */
+       vi->txn_irq = txn_alloc_irq(8);
+
        if (vi->txn_irq < 0)
                panic("I/O sapic: couldn't get TXN IRQ\n");
 
        /* enable_irq() will use txn_* to program IRdT */
        vi->txn_addr = txn_alloc_addr(vi->txn_irq);
-       vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
+       vi->txn_data = txn_alloc_data(vi->txn_irq);
 
        vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
        vi->eoi_data = cpu_to_le32(vi->txn_data);
@@ -841,10 +812,7 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
 static unsigned int
 iosapic_rd_version(struct iosapic_info *isi)
 {
-       ASSERT(isi);
-       ASSERT(isi->isi_hpa);
-
-       return iosapic_read(isi->isi_hpa, IOSAPIC_REG_VERSION);
+       return iosapic_read(isi->addr, IOSAPIC_REG_VERSION);
 }
 
 
@@ -866,44 +834,38 @@ void *iosapic_register(unsigned long hpa)
        int cnt;        /* track how many entries we've looked at */
 
        /*
-       ** Astro based platforms can't support PCI OLARD if they
-       ** implement the legacy PDC (not PAT). Though Legacy PDC
-       ** supports an IRT, LBA's with no device under them
-       ** are *not* listed in the IRT.
-       ** Search the IRT and ignore iosapic's which aren't
-       ** in the IRT.
-       */
-       ASSERT(NULL != irte);   /* always have built-in devices */
+        * Astro based platforms can only support PCI OLARD if they implement
+        * PAT PDC.  Legacy PDC omits LBAs with no PCI devices from the IRT.
+        * Search the IRT and ignore iosapic's which aren't in the IRT.
+        */
        for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
-               ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type);
-               /*
-               ** We need sign extension of the hpa on 32-bit kernels.
-               ** The address in the IRT is *always* 64 bit and really
-               ** is an unsigned quantity (like all physical addresses).
-               */ 
-               if (irte->dest_iosapic_addr == (s64) ((long) hpa))
+               WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type);
+               if (COMPARE_IRTE_ADDR(irte, hpa))
                        break;
        }
 
-       if (cnt  >= irt_num_entry)
-               return (NULL);
+       if (cnt >= irt_num_entry) {
+               DBG("iosapic_register() ignoring 0x%lx (NOT FOUND)\n", hpa);
+               return NULL;
+       }
 
-       if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) {
+       isi = (struct iosapic_info *)kmalloc(sizeof(struct iosapic_info), GFP_KERNEL);
+       if (!isi) {
                BUG();
-               return (NULL);
+               return NULL;
        }
 
        memset(isi, 0, sizeof(struct iosapic_info));
 
-       isi->isi_hpa         = hpa;
-       isi->isi_version     = iosapic_rd_version(isi);
+       isi->addr = ioremap(hpa, 4096);
+       isi->isi_hpa = hpa;
+       isi->isi_version = iosapic_rd_version(isi);
        isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
 
-       vip = isi->isi_vector =
-                IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors);
-
+       vip = isi->isi_vector = (struct vector_info *)
+               kmalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
        if (vip == NULL) {
-               IOSAPIC_FREE(isi, struct iosapic_info, 1);
+               kfree(isi);
                return NULL;
        }
 
@@ -924,7 +886,6 @@ iosapic_prt_irt(void *irt, long num_entry)
 {
        unsigned int i, *irp = (unsigned int *) irt;
 
-       ASSERT(NULL != irt);
 
        printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry);
 
@@ -938,8 +899,6 @@ iosapic_prt_irt(void *irt, long num_entry)
 static void
 iosapic_prt_vi(struct vector_info *vi)
 {
-       ASSERT(NULL != vi);
-
        printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
        printk(KERN_DEBUG "\t\tstatus:   %.4x\n", vi->status);
        printk(KERN_DEBUG "\t\ttxn_irq:  %d\n",  vi->txn_irq);
@@ -953,10 +912,9 @@ iosapic_prt_vi(struct vector_info *vi)
 static void
 iosapic_prt_isi(struct iosapic_info *isi)
 {
-       ASSERT(NULL != isi);
        printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
        printk(KERN_DEBUG "\t\tisi_hpa:       %lx\n", isi->isi_hpa);
-       printk(KERN_DEBUG "\t\tisi_status:     %x\n", isi->isi_status);
+       printk(KERN_DEBUG "\t\tisi_status:    %x\n", isi->isi_status);
        printk(KERN_DEBUG "\t\tisi_version:   %x\n", isi->isi_version);
        printk(KERN_DEBUG "\t\tisi_vector:    %p\n", isi->isi_vector);
 }