Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.
0004  * Copyright (C) 2004 Christoph Hellwig.
0005  *
0006  * Support functions for the HUB ASIC - mostly PIO mapping related.
0007  */
0008 
0009 #include <linux/bitops.h>
0010 #include <linux/string.h>
0011 #include <linux/mmzone.h>
0012 #include <asm/sn/addrs.h>
0013 #include <asm/sn/arch.h>
0014 #include <asm/sn/agent.h>
0015 #include <asm/sn/io.h>
0016 #include <asm/xtalk/xtalk.h>
0017 
0018 
0019 static int force_fire_and_forget = 1;
0020 
0021 /**
0022  * hub_pio_map  -  establish a HUB PIO mapping
0023  *
0024  * @hub:    hub to perform PIO mapping on
0025  * @widget: widget ID to perform PIO mapping for
0026  * @xtalk_addr: xtalk_address that needs to be mapped
0027  * @size:   size of the PIO mapping
0028  *
0029  **/
0030 unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget,
0031               unsigned long xtalk_addr, size_t size)
0032 {
0033     unsigned i;
0034 
0035     /* use small-window mapping if possible */
0036     if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE)
0037         return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE);
0038 
0039     if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) {
0040         printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx"
0041                 " too big (%ld)\n",
0042                 nasid, widget, xtalk_addr, size);
0043         return 0;
0044     }
0045 
0046     xtalk_addr &= ~(BWIN_SIZE-1);
0047     for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) {
0048         if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used))
0049             continue;
0050 
0051         /*
0052          * The code below does a PIO write to setup an ITTE entry.
0053          *
0054          * We need to prevent other CPUs from seeing our updated
0055          * memory shadow of the ITTE (in the piomap) until the ITTE
0056          * entry is actually set up; otherwise, another CPU might
0057          * attempt a PIO prematurely.
0058          *
0059          * Also, the only way we can know that an entry has been
0060          * received  by the hub and can be used by future PIO reads/
0061          * writes is by reading back the ITTE entry after writing it.
0062          *
0063          * For these two reasons, we PIO read back the ITTE entry
0064          * after we write it.
0065          */
0066         IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
0067         __raw_readq(IIO_ITTE_GET(nasid, i));
0068 
0069         return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
0070     }
0071 
0072     printk(KERN_WARNING "unable to establish PIO mapping for at"
0073             " hub %d widget %d addr 0x%lx\n",
0074             nasid, widget, xtalk_addr);
0075     return 0;
0076 }
0077 
0078 
0079 /*
0080  * hub_setup_prb(nasid, prbnum, credits, conveyor)
0081  *
0082  *  Put a PRB into fire-and-forget mode if conveyor isn't set.  Otherwise,
0083  *  put it into conveyor belt mode with the specified number of credits.
0084  */
0085 static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
0086 {
0087     union iprb_u prb;
0088     int prb_offset;
0089 
0090     /*
0091      * Get the current register value.
0092      */
0093     prb_offset = IIO_IOPRB(prbnum);
0094     prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset);
0095 
0096     /*
0097      * Clear out some fields.
0098      */
0099     prb.iprb_ovflow = 1;
0100     prb.iprb_bnakctr = 0;
0101     prb.iprb_anakctr = 0;
0102 
0103     /*
0104      * Enable or disable fire-and-forget mode.
0105      */
0106     prb.iprb_ff = force_fire_and_forget ? 1 : 0;
0107 
0108     /*
0109      * Set the appropriate number of PIO credits for the widget.
0110      */
0111     prb.iprb_xtalkctr = credits;
0112 
0113     /*
0114      * Store the new value to the register.
0115      */
0116     REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval);
0117 }
0118 
0119 /**
0120  * hub_set_piomode  -  set pio mode for a given hub
0121  *
0122  * @nasid:  physical node ID for the hub in question
0123  *
0124  * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode.
0125  * To do this, we have to make absolutely sure that no PIOs are in progress
0126  * so we turn off access to all widgets for the duration of the function.
0127  *
0128  * XXX - This code should really check what kind of widget we're talking
0129  * to.  Bridges can only handle three requests, but XG will do more.
0130  * How many can crossbow handle to widget 0?  We're assuming 1.
0131  *
0132  * XXX - There is a bug in the crossbow that link reset PIOs do not
0133  * return write responses.  The easiest solution to this problem is to
0134  * leave widget 0 (xbow) in fire-and-forget mode at all times.  This
0135  * only affects pio's to xbow registers, which should be rare.
0136  **/
0137 static void hub_set_piomode(nasid_t nasid)
0138 {
0139     u64 ii_iowa;
0140     union hubii_wcr_u ii_wcr;
0141     unsigned i;
0142 
0143     ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
0144     REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0);
0145 
0146     ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR);
0147 
0148     if (ii_wcr.iwcr_dir_con) {
0149         /*
0150          * Assume a bridge here.
0151          */
0152         hub_setup_prb(nasid, 0, 3);
0153     } else {
0154         /*
0155          * Assume a crossbow here.
0156          */
0157         hub_setup_prb(nasid, 0, 1);
0158     }
0159 
0160     /*
0161      * XXX - Here's where we should take the widget type into
0162      * when account assigning credits.
0163      */
0164     for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++)
0165         hub_setup_prb(nasid, i, 3);
0166 
0167     REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
0168 }
0169 
0170 /*
0171  * hub_pio_init  -  PIO-related hub initialization
0172  *
0173  * @hub:    hubinfo structure for our hub
0174  */
0175 void hub_pio_init(nasid_t nasid)
0176 {
0177     unsigned i;
0178 
0179     /* initialize big window piomaps for this hub */
0180     bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW);
0181     for (i = 0; i < HUB_NUM_BIG_WINDOW; i++)
0182         IIO_ITTE_DISABLE(nasid, i);
0183 
0184     hub_set_piomode(nasid);
0185 }