Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | /* * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. * Copyright (C) 2004 Christoph Hellwig. * Released under GPL v2. * * Support functions for the HUB ASIC - mostly PIO mapping related. */ #include <linux/bitops.h> #include <linux/string.h> #include <linux/mmzone.h> #include <asm/sn/addrs.h> #include <asm/sn/arch.h> #include <asm/sn/hub.h> static int force_fire_and_forget = 1; /** * hub_pio_map - establish a HUB PIO mapping * * @hub: hub to perform PIO mapping on * @widget: widget ID to perform PIO mapping for * @xtalk_addr: xtalk_address that needs to be mapped * @size: size of the PIO mapping * **/ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, unsigned long xtalk_addr, size_t size) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); unsigned i; /* use small-window mapping if possible */ if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" " too big (%ld)\n", nasid, widget, xtalk_addr, size); return 0; } xtalk_addr &= ~(BWIN_SIZE-1); for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { if (test_and_set_bit(i, hub_data(cnode)->h_bigwin_used)) continue; /* * The code below does a PIO write to setup an ITTE entry. * * We need to prevent other CPUs from seeing our updated * memory shadow of the ITTE (in the piomap) until the ITTE * entry is actually set up; otherwise, another CPU might * attempt a PIO prematurely. * * Also, the only way we can know that an entry has been * received by the hub and can be used by future PIO reads/ * writes is by reading back the ITTE entry after writing it. * * For these two reasons, we PIO read back the ITTE entry * after we write it. */ IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); (void) HUB_L(IIO_ITTE_GET(nasid, i)); return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); } printk(KERN_WARNING "unable to establish PIO mapping for at" " hub %d widget %d addr 0x%lx\n", nasid, widget, xtalk_addr); return 0; } /* * hub_setup_prb(nasid, prbnum, credits, conveyor) * * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, * put it into conveyor belt mode with the specified number of credits. */ static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) { iprb_t prb; int prb_offset; /* * Get the current register value. */ prb_offset = IIO_IOPRB(prbnum); prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); /* * Clear out some fields. */ prb.iprb_ovflow = 1; prb.iprb_bnakctr = 0; prb.iprb_anakctr = 0; /* * Enable or disable fire-and-forget mode. */ prb.iprb_ff = force_fire_and_forget ? 1 : 0; /* * Set the appropriate number of PIO cresits for the widget. */ prb.iprb_xtalkctr = credits; /* * Store the new value to the register. */ REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); } /** * hub_set_piomode - set pio mode for a given hub * * @nasid: physical node ID for the hub in question * * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. * To do this, we have to make absolutely sure that no PIOs are in progress * so we turn off access to all widgets for the duration of the function. * * XXX - This code should really check what kind of widget we're talking * to. Bridges can only handle three requests, but XG will do more. * How many can crossbow handle to widget 0? We're assuming 1. * * XXX - There is a bug in the crossbow that link reset PIOs do not * return write responses. The easiest solution to this problem is to * leave widget 0 (xbow) in fire-and-forget mode at all times. This * only affects pio's to xbow registers, which should be rare. **/ static void hub_set_piomode(nasid_t nasid) { hubreg_t ii_iowa; hubii_wcr_t ii_wcr; unsigned i; ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); if (ii_wcr.iwcr_dir_con) { /* * Assume a bridge here. */ hub_setup_prb(nasid, 0, 3); } else { /* * Assume a crossbow here. */ hub_setup_prb(nasid, 0, 1); } /* * XXX - Here's where we should take the widget type into * when account assigning credits. */ for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) hub_setup_prb(nasid, i, 3); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); } /* * hub_pio_init - PIO-related hub initialization * * @hub: hubinfo structure for our hub */ void hub_pio_init(cnodeid_t cnode) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); unsigned i; /* initialize big window piomaps for this hub */ bitmap_zero(hub_data(cnode)->h_bigwin_used, HUB_NUM_BIG_WINDOW); for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) IIO_ITTE_DISABLE(nasid, i); hub_set_piomode(nasid); } |