18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. 48c2ecf20Sopenharmony_ci * Copyright (C) 2004 Christoph Hellwig. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Support functions for the HUB ASIC - mostly PIO mapping related. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/mmzone.h> 128c2ecf20Sopenharmony_ci#include <asm/sn/addrs.h> 138c2ecf20Sopenharmony_ci#include <asm/sn/arch.h> 148c2ecf20Sopenharmony_ci#include <asm/sn/agent.h> 158c2ecf20Sopenharmony_ci#include <asm/sn/io.h> 168c2ecf20Sopenharmony_ci#include <asm/xtalk/xtalk.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int force_fire_and_forget = 1; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/** 228c2ecf20Sopenharmony_ci * hub_pio_map - establish a HUB PIO mapping 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * @hub: hub to perform PIO mapping on 258c2ecf20Sopenharmony_ci * @widget: widget ID to perform PIO mapping for 268c2ecf20Sopenharmony_ci * @xtalk_addr: xtalk_address that needs to be mapped 278c2ecf20Sopenharmony_ci * @size: size of the PIO mapping 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci **/ 308c2ecf20Sopenharmony_ciunsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget, 318c2ecf20Sopenharmony_ci unsigned long xtalk_addr, size_t size) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci unsigned i; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* use small-window mapping if possible */ 368c2ecf20Sopenharmony_ci if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) 378c2ecf20Sopenharmony_ci return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { 408c2ecf20Sopenharmony_ci printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" 418c2ecf20Sopenharmony_ci " too big (%ld)\n", 428c2ecf20Sopenharmony_ci nasid, widget, xtalk_addr, size); 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci xtalk_addr &= ~(BWIN_SIZE-1); 478c2ecf20Sopenharmony_ci for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { 488c2ecf20Sopenharmony_ci if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used)) 498c2ecf20Sopenharmony_ci continue; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* 528c2ecf20Sopenharmony_ci * The code below does a PIO write to setup an ITTE entry. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * We need to prevent other CPUs from seeing our updated 558c2ecf20Sopenharmony_ci * memory shadow of the ITTE (in the piomap) until the ITTE 568c2ecf20Sopenharmony_ci * entry is actually set up; otherwise, another CPU might 578c2ecf20Sopenharmony_ci * attempt a PIO prematurely. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Also, the only way we can know that an entry has been 608c2ecf20Sopenharmony_ci * received by the hub and can be used by future PIO reads/ 618c2ecf20Sopenharmony_ci * writes is by reading back the ITTE entry after writing it. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * For these two reasons, we PIO read back the ITTE entry 648c2ecf20Sopenharmony_ci * after we write it. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); 678c2ecf20Sopenharmony_ci __raw_readq(IIO_ITTE_GET(nasid, i)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci printk(KERN_WARNING "unable to establish PIO mapping for at" 738c2ecf20Sopenharmony_ci " hub %d widget %d addr 0x%lx\n", 748c2ecf20Sopenharmony_ci nasid, widget, xtalk_addr); 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * hub_setup_prb(nasid, prbnum, credits, conveyor) 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, 838c2ecf20Sopenharmony_ci * put it into conveyor belt mode with the specified number of credits. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic void hub_setup_prb(nasid_t nasid, int prbnum, int credits) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci union iprb_u prb; 888c2ecf20Sopenharmony_ci int prb_offset; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Get the current register value. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci prb_offset = IIO_IOPRB(prbnum); 948c2ecf20Sopenharmony_ci prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * Clear out some fields. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci prb.iprb_ovflow = 1; 1008c2ecf20Sopenharmony_ci prb.iprb_bnakctr = 0; 1018c2ecf20Sopenharmony_ci prb.iprb_anakctr = 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * Enable or disable fire-and-forget mode. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci prb.iprb_ff = force_fire_and_forget ? 1 : 0; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * Set the appropriate number of PIO credits for the widget. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci prb.iprb_xtalkctr = credits; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * Store the new value to the register. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/** 1208c2ecf20Sopenharmony_ci * hub_set_piomode - set pio mode for a given hub 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * @nasid: physical node ID for the hub in question 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. 1258c2ecf20Sopenharmony_ci * To do this, we have to make absolutely sure that no PIOs are in progress 1268c2ecf20Sopenharmony_ci * so we turn off access to all widgets for the duration of the function. 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * XXX - This code should really check what kind of widget we're talking 1298c2ecf20Sopenharmony_ci * to. Bridges can only handle three requests, but XG will do more. 1308c2ecf20Sopenharmony_ci * How many can crossbow handle to widget 0? We're assuming 1. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * XXX - There is a bug in the crossbow that link reset PIOs do not 1338c2ecf20Sopenharmony_ci * return write responses. The easiest solution to this problem is to 1348c2ecf20Sopenharmony_ci * leave widget 0 (xbow) in fire-and-forget mode at all times. This 1358c2ecf20Sopenharmony_ci * only affects pio's to xbow registers, which should be rare. 1368c2ecf20Sopenharmony_ci **/ 1378c2ecf20Sopenharmony_cistatic void hub_set_piomode(nasid_t nasid) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci u64 ii_iowa; 1408c2ecf20Sopenharmony_ci union hubii_wcr_u ii_wcr; 1418c2ecf20Sopenharmony_ci unsigned i; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); 1448c2ecf20Sopenharmony_ci REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (ii_wcr.iwcr_dir_con) { 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * Assume a bridge here. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci hub_setup_prb(nasid, 0, 3); 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * Assume a crossbow here. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci hub_setup_prb(nasid, 0, 1); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * XXX - Here's where we should take the widget type into 1628c2ecf20Sopenharmony_ci * when account assigning credits. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) 1658c2ecf20Sopenharmony_ci hub_setup_prb(nasid, i, 3); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * hub_pio_init - PIO-related hub initialization 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * @hub: hubinfo structure for our hub 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_civoid hub_pio_init(nasid_t nasid) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci unsigned i; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* initialize big window piomaps for this hub */ 1808c2ecf20Sopenharmony_ci bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW); 1818c2ecf20Sopenharmony_ci for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) 1828c2ecf20Sopenharmony_ci IIO_ITTE_DISABLE(nasid, i); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci hub_set_piomode(nasid); 1858c2ecf20Sopenharmony_ci} 186