1 /* $Id: hubcounters.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc.
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <asm/types.h>
13 #include <asm/sn/io.h>
14 #include <asm/sn/nodepda.h>
15 #include <asm/sn/iograph.h>
16 #include <asm/sn/sn_cpuid.h>
17 #include <asm/sn/router.h>
18 #include <asm/sn/snconfig.h>
19 #include <asm/sn/slotnum.h>
20 #include <asm/sn/clksupport.h>
21 #include <asm/sn/sndrv.h>
23 extern void hubni_error_handler(char *, int); /* huberror.c */
25 static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
26 struct file_operations hub_mon_fops = {
27 ioctl: hubstats_ioctl,
30 #define HUB_CAPTURE_TICKS (2 * HZ)
32 #define HUB_ERR_THRESH 500
33 #define USEC_PER_SEC 1000000
34 #define NSEC_PER_SEC USEC_PER_SEC*1000
36 volatile int hub_print_usecs = 600 * USEC_PER_SEC;
38 /* Return success if the hub's crosstalk link is working */
40 hub_xtalk_link_up(nasid_t nasid)
44 /* Read the IO LLP control status register */
45 llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
47 /* Check if the xtalk link is working */
48 if (llp_csr_reg & IIO_LLP_CSR_IS_UP)
56 static char *error_flag_to_type(unsigned char error_flag)
59 case 0x1: return ("NI retries");
60 case 0x2: return ("NI SN errors");
61 case 0x4: return ("NI CB errors");
62 case 0x8: return ("II CB errors");
63 case 0x10: return ("II SN errors");
64 default: return ("Errors");
69 print_hub_error(hubstat_t *hsp, hubreg_t reg,
70 int64_t delta, unsigned char error_flag)
74 reg *= hsp->hs_per_minute; /* Convert to minutes */
77 if (rate > HUB_ERR_THRESH) {
79 if(hsp->hs_maint & error_flag)
81 printk( "Excessive %s (%ld/min) on %s",
82 error_flag_to_type(error_flag), rate, hsp->hs_name);
86 hsp->hs_maint |= error_flag;
87 printk( "Excessive %s (%ld/min) on %s",
88 error_flag_to_type(error_flag), rate, hsp->hs_name);
98 check_hub_error_rates(hubstat_t *hsp)
100 int64_t delta = hsp->hs_timestamp - hsp->hs_timebase;
103 printed += print_hub_error(hsp, hsp->hs_ni_retry_errors,
107 printed += print_hub_error(hsp, hsp->hs_ni_sn_errors,
111 printed += print_hub_error(hsp, hsp->hs_ni_cb_errors,
115 /* If the hub's xtalk link is not working there is
116 * no need to print the "Excessive..." warning
119 if (!hub_xtalk_link_up(hsp->hs_nasid))
123 printed += print_hub_error(hsp, hsp->hs_ii_cb_errors,
126 printed += print_hub_error(hsp, hsp->hs_ii_sn_errors,
134 capture_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda)
137 hubstat_t *hsp = &(npda->hubstats);
144 * If our link wasn't up at boot time, don't worry about error rates.
146 if (!(hsp->hs_ni_port_status & NPS_LINKUP_MASK)) {
147 printk("capture_hub_stats: cnode=%d hs_ni_port_status=0x%016lx : link is not up\n",
148 cnodeid, hsp->hs_ni_port_status);
152 nasid = COMPACT_TO_NASID_NODEID(cnodeid);
154 hsp->hs_timestamp = GET_RTC_COUNTER();
156 port_error = REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR);
157 count = ((port_error & NPE_RETRYCOUNT_MASK) >> NPE_RETRYCOUNT_SHFT);
158 hsp->hs_ni_retry_errors += count;
159 if (count == NPE_COUNT_MAX)
161 count = ((port_error & NPE_SNERRCOUNT_MASK) >> NPE_SNERRCOUNT_SHFT);
162 hsp->hs_ni_sn_errors += count;
163 if (count == NPE_COUNT_MAX)
165 count = ((port_error & NPE_CBERRCOUNT_MASK) >> NPE_CBERRCOUNT_SHFT);
166 hsp->hs_ni_cb_errors += count;
167 if (overflow || count == NPE_COUNT_MAX)
168 hsp->hs_ni_overflows++;
170 if (port_error & NPE_FATAL_ERRORS) {
172 hubni_error_handler("capture_hub_stats", 1);
174 printk("Error: hubni_error_handler in capture_hub_stats");
178 illr.ii_illr_regval = REMOTE_HUB_L(nasid, IIO_LLP_LOG);
179 REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0);
181 hsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt;
182 hsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt;
183 if ((illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) ||
184 (illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX))
185 hsp->hs_ii_overflows++;
188 if (check_hub_error_rates(hsp)) {
189 hsp->hs_last_print = GET_RTC_COUNTER();
193 if ((GET_RTC_COUNTER() -
194 hsp->hs_last_print) > hub_print_usecs)
198 npda->hubticks = HUB_CAPTURE_TICKS;
203 init_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda)
205 hubstat_t *hsp = &(npda->hubstats);
206 nasid_t nasid = cnodeid_to_nasid(cnodeid);
207 bzero(&(npda->hubstats), sizeof(hubstat_t));
209 hsp->hs_version = HUBSTAT_VERSION;
210 hsp->hs_cnode = cnodeid;
211 hsp->hs_nasid = nasid;
212 hsp->hs_timebase = GET_RTC_COUNTER();
213 hsp->hs_ni_port_status = REMOTE_HUB_L(nasid, NI_PORT_STATUS);
215 /* Clear the II error counts. */
216 REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0);
218 /* Clear the NI counts. */
219 REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR);
221 hsp->hs_per_minute = (long long)RTC_CYCLES_PER_SEC * 60LL;
223 npda->hubticks = HUB_CAPTURE_TICKS;
225 /* XX should use kmem_alloc_node */
226 hsp->hs_name = (char *)kmalloc(MAX_HUB_PATH, GFP_KERNEL);
227 ASSERT_ALWAYS(hsp->hs_name);
229 sprintf(hsp->hs_name, "/dev/hw/" EDGE_LBL_MODULE "/%03d/"
230 EDGE_LBL_NODE "/" EDGE_LBL_HUB,
233 hsp->hs_last_print = 0;
236 hub_print_usecs = hub_print_usecs;
239 printk("init_hub_stats: cnode=%d nasid=%d hs_version=%d hs_ni_port_status=0x%016lx\n",
240 cnodeid, nasid, hsp->hs_version, hsp->hs_ni_port_status);
245 hubstats_ioctl(struct inode *inode, struct file *file,
246 unsigned int cmd, unsigned long arg)
253 if ((d = devfs_get_handle_from_inode(inode)) == NULL)
255 cnode = (cnodeid_t)hwgraph_fastinfo_get(d);
256 npdap = NODEPDA(cnode);
258 if (npdap->hubstats.hs_version != HUBSTAT_VERSION) {
259 init_hub_stats(cnode, npdap);
263 case SNDRV_GET_INFOSIZE:
264 longarg = sizeof(hubstat_t);
265 if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) {
270 case SNDRV_GET_HUBINFO:
271 /* refresh npda->hubstats */
272 capture_hub_stats(cnode, npdap);
273 if (copy_to_user((void *)arg, &npdap->hubstats, sizeof(hubstat_t))) {