Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
0004  * Copyright (C) 1999, 2000 Silcon Graphics, Inc.
0005  * Copyright (C) 2004 Christoph Hellwig.
0006  *
0007  * Generic XTALK initialization code
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/smp.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/platform_data/sgi-w1.h>
0014 #include <linux/platform_data/xtalk-bridge.h>
0015 #include <asm/sn/addrs.h>
0016 #include <asm/sn/types.h>
0017 #include <asm/sn/klconfig.h>
0018 #include <asm/pci/bridge.h>
0019 #include <asm/xtalk/xtalk.h>
0020 
0021 
0022 #define XBOW_WIDGET_PART_NUM    0x0
0023 #define XXBOW_WIDGET_PART_NUM   0xd000  /* Xbow in Xbridge */
0024 #define BASE_XBOW_PORT      8     /* Lowest external port */
0025 
0026 static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
0027 {
0028     struct xtalk_bridge_platform_data *bd;
0029     struct sgi_w1_platform_data *wd;
0030     struct platform_device *pdev;
0031     struct resource w1_res;
0032     unsigned long offset;
0033 
0034     offset = NODE_OFFSET(nasid);
0035 
0036     wd = kzalloc(sizeof(*wd), GFP_KERNEL);
0037     if (!wd)
0038         goto no_mem;
0039 
0040     snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
0041          offset + (widget << SWIN_SIZE_BITS));
0042 
0043     memset(&w1_res, 0, sizeof(w1_res));
0044     w1_res.start = offset + (widget << SWIN_SIZE_BITS) +
0045                 offsetof(struct bridge_regs, b_nic);
0046     w1_res.end = w1_res.start + 3;
0047     w1_res.flags = IORESOURCE_MEM;
0048 
0049     pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
0050     if (!pdev) {
0051         kfree(wd);
0052         goto no_mem;
0053     }
0054     platform_device_add_resources(pdev, &w1_res, 1);
0055     platform_device_add_data(pdev, wd, sizeof(*wd));
0056     /* platform_device_add_data() duplicates the data */
0057     kfree(wd);
0058     platform_device_add(pdev);
0059 
0060     bd = kzalloc(sizeof(*bd), GFP_KERNEL);
0061     if (!bd)
0062         goto no_mem;
0063     pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
0064     if (!pdev) {
0065         kfree(bd);
0066         goto no_mem;
0067     }
0068 
0069 
0070     bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
0071     bd->intr_addr   = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
0072     bd->nasid   = nasid;
0073     bd->masterwid   = masterwid;
0074 
0075     bd->mem.name    = "Bridge PCI MEM";
0076     bd->mem.start   = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
0077     bd->mem.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
0078     bd->mem.flags   = IORESOURCE_MEM;
0079     bd->mem_offset  = offset;
0080 
0081     bd->io.name = "Bridge PCI IO";
0082     bd->io.start    = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
0083     bd->io.end  = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
0084     bd->io.flags    = IORESOURCE_IO;
0085     bd->io_offset   = offset;
0086 
0087     platform_device_add_data(pdev, bd, sizeof(*bd));
0088     /* platform_device_add_data() duplicates the data */
0089     kfree(bd);
0090     platform_device_add(pdev);
0091     pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
0092     return;
0093 
0094 no_mem:
0095     pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
0096 }
0097 
0098 static int probe_one_port(nasid_t nasid, int widget, int masterwid)
0099 {
0100     widgetreg_t     widget_id;
0101     xwidget_part_num_t  partnum;
0102 
0103     widget_id = *(volatile widgetreg_t *)
0104         (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
0105     partnum = XWIDGET_PART_NUM(widget_id);
0106 
0107     switch (partnum) {
0108     case BRIDGE_WIDGET_PART_NUM:
0109     case XBRIDGE_WIDGET_PART_NUM:
0110         bridge_platform_create(nasid, widget, masterwid);
0111         break;
0112     default:
0113         pr_info("xtalk:n%d/%d unknown widget (0x%x)\n",
0114             nasid, widget, partnum);
0115         break;
0116     }
0117 
0118     return 0;
0119 }
0120 
0121 static int xbow_probe(nasid_t nasid)
0122 {
0123     lboard_t *brd;
0124     klxbow_t *xbow_p;
0125     unsigned masterwid, i;
0126 
0127     /*
0128      * found xbow, so may have multiple bridges
0129      * need to probe xbow
0130      */
0131     brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8);
0132     if (!brd)
0133         return -ENODEV;
0134 
0135     xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW);
0136     if (!xbow_p)
0137         return -ENODEV;
0138 
0139     /*
0140      * Okay, here's a xbow. Let's arbitrate and find
0141      * out if we should initialize it. Set enabled
0142      * hub connected at highest or lowest widget as
0143      * master.
0144      */
0145 #ifdef WIDGET_A
0146     i = HUB_WIDGET_ID_MAX + 1;
0147     do {
0148         i--;
0149     } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
0150          (!XBOW_PORT_IS_ENABLED(xbow_p, i)));
0151 #else
0152     i = HUB_WIDGET_ID_MIN - 1;
0153     do {
0154         i++;
0155     } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
0156          (!XBOW_PORT_IS_ENABLED(xbow_p, i)));
0157 #endif
0158 
0159     masterwid = i;
0160     if (nasid != XBOW_PORT_NASID(xbow_p, i))
0161         return 1;
0162 
0163     for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) {
0164         if (XBOW_PORT_IS_ENABLED(xbow_p, i) &&
0165             XBOW_PORT_TYPE_IO(xbow_p, i))
0166             probe_one_port(nasid, i, masterwid);
0167     }
0168 
0169     return 0;
0170 }
0171 
0172 static void xtalk_probe_node(nasid_t nasid)
0173 {
0174     volatile u64        hubreg;
0175     xwidget_part_num_t  partnum;
0176     widgetreg_t     widget_id;
0177 
0178     hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
0179 
0180     /* check whether the link is up */
0181     if (!(hubreg & IIO_LLP_CSR_IS_UP))
0182         return;
0183 
0184     widget_id = *(volatile widgetreg_t *)
0185                (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
0186     partnum = XWIDGET_PART_NUM(widget_id);
0187 
0188     switch (partnum) {
0189     case BRIDGE_WIDGET_PART_NUM:
0190         bridge_platform_create(nasid, 0x8, 0xa);
0191         break;
0192     case XBOW_WIDGET_PART_NUM:
0193     case XXBOW_WIDGET_PART_NUM:
0194         pr_info("xtalk:n%d/0 xbow widget\n", nasid);
0195         xbow_probe(nasid);
0196         break;
0197     default:
0198         pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
0199         break;
0200     }
0201 }
0202 
0203 static int __init xtalk_init(void)
0204 {
0205     nasid_t nasid;
0206 
0207     for_each_online_node(nasid)
0208         xtalk_probe_node(nasid);
0209 
0210     return 0;
0211 }
0212 arch_initcall(xtalk_init);