Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / sparc64 / kernel / pci_schizo.c
index 5753175..7fe4de0 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/upa.h>
+#include <asm/pstate.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -242,8 +243,8 @@ static unsigned char schizo_pil_table[] = {
 /*0x0c*/0, 0, 0, 0,    /* PCI slot 3  Int A, B, C, D   */
 /*0x10*/0, 0, 0, 0,    /* PCI slot 4  Int A, B, C, D   */
 /*0x14*/0, 0, 0, 0,    /* PCI slot 5  Int A, B, C, D   */
-/*0x18*/4,             /* SCSI                         */
-/*0x19*/4,             /* second SCSI                  */
+/*0x18*/5,             /* SCSI                         */
+/*0x19*/5,             /* second SCSI                  */
 /*0x1a*/0,             /* UNKNOWN                      */
 /*0x1b*/0,             /* UNKNOWN                      */
 /*0x1c*/8,             /* Parallel                     */
@@ -253,7 +254,7 @@ static unsigned char schizo_pil_table[] = {
 /*0x20*/13,            /* Audio Record                 */
 /*0x21*/14,            /* Audio Playback               */
 /*0x22*/12,            /* Serial                       */
-/*0x23*/4,             /* EBUS I2C                     */
+/*0x23*/5,             /* EBUS I2C                     */
 /*0x24*/10,            /* RTC Clock                    */
 /*0x25*/11,            /* Floppy                       */
 /*0x26*/0,             /* UNKNOWN                      */
@@ -284,7 +285,7 @@ static unsigned char schizo_pil_table[] = {
 /*0x3f*/0,             /* Reserved for NewLink         */
 };
 
-static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
 {
        int ret;
 
@@ -295,11 +296,11 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
 
        ret = schizo_pil_table[ino];
        if (ret == 0 && pdev == NULL) {
-               ret = 4;
+               ret = 5;
        } else if (ret == 0) {
                switch ((pdev->class >> 16) & 0xff) {
                case PCI_BASE_CLASS_STORAGE:
-                       ret = 4;
+                       ret = 5;
                        break;
 
                case PCI_BASE_CLASS_NETWORK:
@@ -318,7 +319,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
                        break;
 
                default:
-                       ret = 4;
+                       ret = 5;
                        break;
                };
        }
@@ -326,6 +327,44 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
        return ret;
 }
 
+static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
+{
+       unsigned long sync_reg = (unsigned long) _arg2;
+       u64 mask = 1UL << (__irq_ino(__irq(bucket)) & IMAP_INO);
+       u64 val;
+       int limit;
+
+       schizo_write(sync_reg, mask);
+
+       limit = 100000;
+       val = 0;
+       while (--limit) {
+               val = schizo_read(sync_reg);
+               if (!(val & mask))
+                       break;
+       }
+       if (limit <= 0) {
+               printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
+                      val, mask);
+       }
+
+       if (_arg1) {
+               static unsigned char cacheline[64]
+                       __attribute__ ((aligned (64)));
+
+               __asm__ __volatile__("rd %%fprs, %0\n\t"
+                                    "or %0, %4, %1\n\t"
+                                    "wr %1, 0x0, %%fprs\n\t"
+                                    "stda %%f0, [%5] %6\n\t"
+                                    "wr %0, 0x0, %%fprs\n\t"
+                                    "membar #Sync"
+                                    : "=&r" (mask), "=&r" (val)
+                                    : "0" (mask), "1" (val),
+                                    "i" (FPRS_FEF), "r" (&cacheline[0]),
+                                    "i" (ASI_BLK_COMMIT_P));
+       }
+}
+
 static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
                                     struct pci_dev *pdev,
                                     unsigned int ino)
@@ -369,6 +408,15 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
        bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap));
        bucket->flags |= IBF_PCI;
 
+       if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+               struct irq_desc *p = bucket->irq_info;
+
+               p->pre_handler = tomatillo_wsync_handler;
+               p->pre_handler_arg1 = ((pbm->chip_version <= 4) ?
+                                      (void *) 1 : (void *) 0);
+               p->pre_handler_arg2 = (void *) pbm->sync_reg;
+       }
+
        return __irq(bucket);
 }
 
@@ -885,6 +933,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
 
 #define SCHIZO_PCI_CTRL                (0x2000UL)
 #define SCHIZO_PCICTRL_BUS_UNUS        (1UL << 63UL) /* Safari */
+#define SCHIZO_PCICTRL_DTO_INT (1UL << 61UL) /* Tomatillo */
 #define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */
 #define SCHIZO_PCICTRL_ESLCK   (1UL << 51UL) /* Safari */
 #define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) /* Safari */
@@ -1172,7 +1221,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *
  * PCI bus units of the same Tomatillo.  I still have not really
  * figured this out...
  */
-static void __init tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_controller_info *p)
 {
        struct pci_pbm_info *pbm;
        unsigned int irq;
@@ -1310,7 +1359,7 @@ static void __init tomatillo_register_error_handlers(struct pci_controller_info
                     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
-static void __init schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_controller_info *p)
 {
        struct pci_pbm_info *pbm;
        unsigned int irq;
@@ -1456,7 +1505,7 @@ static void __init schizo_register_error_handlers(struct pci_controller_info *p)
                     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
-static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+static void pbm_config_busmastering(struct pci_pbm_info *pbm)
 {
        u8 *addr;
 
@@ -1473,10 +1522,10 @@ static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init pbm_scan_bus(struct pci_controller_info *p,
-                               struct pci_pbm_info *pbm)
+static void pbm_scan_bus(struct pci_controller_info *p,
+                        struct pci_pbm_info *pbm)
 {
-       struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+       struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
 
        if (!cookie) {
                prom_printf("%s: Critical allocation failure.\n", pbm->name);
@@ -1484,7 +1533,6 @@ static void __init pbm_scan_bus(struct pci_controller_info *p,
        }
 
        /* All we care about is the PBM. */
-       memset(cookie, 0, sizeof(*cookie));
        cookie->pbm = pbm;
 
        pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
@@ -1501,8 +1549,8 @@ static void __init pbm_scan_bus(struct pci_controller_info *p,
        pci_setup_busmastering(pbm, pbm->pci_bus);
 }
 
-static void __init __schizo_scan_bus(struct pci_controller_info *p,
-                                    int chip_type)
+static void __schizo_scan_bus(struct pci_controller_info *p,
+                             int chip_type)
 {
        if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) {
                printk("PCI: Only one PCI bus module of controller found.\n");
@@ -1528,17 +1576,17 @@ static void __init __schizo_scan_bus(struct pci_controller_info *p,
                schizo_register_error_handlers(p);
 }
 
-static void __init schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_controller_info *p)
 {
        __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);
 }
 
-static void __init tomatillo_scan_bus(struct pci_controller_info *p)
+static void tomatillo_scan_bus(struct pci_controller_info *p)
 {
        __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);
 }
 
-static void __init schizo_base_address_update(struct pci_dev *pdev, int resource)
+static void schizo_base_address_update(struct pci_dev *pdev, int resource)
 {
        struct pcidev_cookie *pcp = pdev->sysdata;
        struct pci_pbm_info *pbm = pcp->pbm;
@@ -1583,9 +1631,9 @@ static void __init schizo_base_address_update(struct pci_dev *pdev, int resource
                pci_write_config_dword(pdev, where + 4, 0);
 }
 
-static void __init schizo_resource_adjust(struct pci_dev *pdev,
-                                         struct resource *res,
-                                         struct resource *root)
+static void schizo_resource_adjust(struct pci_dev *pdev,
+                                  struct resource *res,
+                                  struct resource *root)
 {
        res->start += root->start;
        res->end += root->start;
@@ -1653,8 +1701,8 @@ static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm)
               pbm->mem_space.start);
 }
 
-static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
-                                                  struct pci_pbm_info *pbm)
+static void pbm_register_toplevel_resources(struct pci_controller_info *p,
+                                           struct pci_pbm_info *pbm)
 {
        pbm->io_space.name = pbm->mem_space.name = pbm->name;
 
@@ -1716,7 +1764,7 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
 static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
        struct pci_iommu *iommu = pbm->iommu;
-       unsigned long tsbbase, i, tagbase, database, order;
+       unsigned long i, tagbase, database;
        u32 vdma[2], dma_mask;
        u64 control;
        int err, tsbsize;
@@ -1751,10 +1799,6 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
                        prom_halt();
        };
 
-       /* Setup initial software IOMMU state. */
-       spin_lock_init(&iommu->lock);
-       iommu->ctx_lowest_free = 1;
-
        /* Register addresses, SCHIZO has iommu ctx flushing. */
        iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
        iommu->iommu_tsbbase  = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
@@ -1783,56 +1827,9 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        /* Leave diag mode enabled for full-flushing done
         * in pci_iommu.c
         */
+       pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
 
-       iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0);
-       if (!iommu->dummy_page) {
-               prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n");
-               prom_halt();
-       }
-       memset((void *)iommu->dummy_page, 0, PAGE_SIZE);
-       iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page);
-
-       /* Using assumed page size 8K with 128K entries we need 1MB iommu page
-        * table (128K ioptes * 8 bytes per iopte).  This is
-        * page order 7 on UltraSparc.
-        */
-       order = get_order(tsbsize * 8 * 1024);
-       tsbbase = __get_free_pages(GFP_KERNEL, order);
-       if (!tsbbase) {
-               prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name);
-               prom_halt();
-       }
-
-       iommu->page_table = (iopte_t *)tsbbase;
-       iommu->page_table_map_base = vdma[0];
-       iommu->dma_addr_mask = dma_mask;
-       pci_iommu_table_init(iommu, PAGE_SIZE << order);
-
-       switch (tsbsize) {
-       case 64:
-               iommu->page_table_sz_bits = 16;
-               break;
-
-       case 128:
-               iommu->page_table_sz_bits = 17;
-               break;
-
-       default:
-               prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
-               prom_halt();
-               break;
-       };
-
-       /* We start with no consistent mappings. */
-       iommu->lowest_consistent_map =
-               1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS);
-
-       for (i = 0; i < PBM_NCLUSTERS; i++) {
-               iommu->alloc_info[i].flush = 0;
-               iommu->alloc_info[i].next = 0;
-       }
-
-       schizo_write(iommu->iommu_tsbbase, __pa(tsbbase));
+       schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
 
        control = schizo_read(iommu->iommu_control);
        control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
@@ -1883,41 +1880,31 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 #define TOMATILLO_PCI_IOC_TDIAG                (0x2250UL)
 #define TOMATILLO_PCI_IOC_DDIAG                (0x2290UL)
 
-static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm)
+static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
        u64 tmp;
 
-       /* Set IRQ retry to infinity. */
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY,
-                    SCHIZO_IRQ_RETRY_INF);
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
 
-       /* Enable arbiter for all PCI slots.  Also, disable PCI interval
-        * timer so that DTO (Discard TimeOuts) are not reported because
-        * some Schizo revisions report them erroneously.
-        */
        tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
-       if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS &&
-           pbm->chip_version == 0x5 &&
-           pbm->chip_revision == 0x1)
-               tmp |= 0x0f;
-       else
-               tmp |= 0xff;
 
-       tmp &= ~SCHIZO_PCICTRL_PTO;
+       /* Enable arbiter for all PCI slots.  */
+       tmp |= 0xff;
+
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
            pbm->chip_version >= 0x2)
                tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
-       else
-               tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
        if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
                tmp |= SCHIZO_PCICTRL_PARK;
+       else
+               tmp &= ~SCHIZO_PCICTRL_PARK;
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
            pbm->chip_version <= 0x1)
-               tmp |= (1UL << 61);
+               tmp |= SCHIZO_PCICTRL_DTO_INT;
        else
-               tmp &= ~(1UL << 61);
+               tmp &= ~SCHIZO_PCICTRL_DTO_INT;
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
                tmp |= (SCHIZO_PCICTRL_MRM_PREF |
@@ -1947,9 +1934,9 @@ static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm)
        }
 }
 
-static void __init schizo_pbm_init(struct pci_controller_info *p,
-                                  int prom_node, u32 portid,
-                                  int chip_type)
+static void schizo_pbm_init(struct pci_controller_info *p,
+                           int prom_node, u32 portid,
+                           int chip_type)
 {
        struct linux_prom64_registers pr_regs[4];
        unsigned int busrange[2];
@@ -2015,6 +2002,9 @@ static void __init schizo_pbm_init(struct pci_controller_info *p,
        pbm->pbm_regs = pr_regs[0].phys_addr;
        pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
 
+       if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+               pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
+
        sprintf(pbm->name,
                (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
                 "TOMATILLO%d PBM%c" :
@@ -2103,7 +2093,7 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static void __init __schizo_init(int node, char *model_name, int chip_type)
+static void __schizo_init(int node, char *model_name, int chip_type)
 {
        struct pci_controller_info *p;
        struct pci_iommu *iommu;
@@ -2129,27 +2119,24 @@ static void __init __schizo_init(int node, char *model_name, int chip_type)
                }
        }
 
-       p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
        if (!p) {
                prom_printf("SCHIZO: Fatal memory allocation error.\n");
                prom_halt();
        }
-       memset(p, 0, sizeof(*p));
 
-       iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+       iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
        if (!iommu) {
                prom_printf("SCHIZO: Fatal memory allocation error.\n");
                prom_halt();
        }
-       memset(iommu, 0, sizeof(*iommu));
        p->pbm_A.iommu = iommu;
 
-       iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+       iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
        if (!iommu) {
                prom_printf("SCHIZO: Fatal memory allocation error.\n");
                prom_halt();
        }
-       memset(iommu, 0, sizeof(*iommu));
        p->pbm_B.iommu = iommu;
 
        p->next = pci_controller_root;
@@ -2171,17 +2158,17 @@ static void __init __schizo_init(int node, char *model_name, int chip_type)
        schizo_pbm_init(p, node, portid, chip_type);
 }
 
-void __init schizo_init(int node, char *model_name)
+void schizo_init(int node, char *model_name)
 {
        __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
 }
 
-void __init schizo_plus_init(int node, char *model_name)
+void schizo_plus_init(int node, char *model_name)
 {
        __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
 }
 
-void __init tomatillo_init(int node, char *model_name)
+void tomatillo_init(int node, char *model_name)
 {
        __schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
 }