Add version to PATCH_LOG and LAST_LOG.
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / sn1 / hubcounters.c
1 /* $Id: hubcounters.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
2  *
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
5  * for more details.
6  *
7  * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc.
8  * All rights reserved.
9  */
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>
22
23 extern void hubni_error_handler(char *, int); /* huberror.c */
24
25 static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
26 struct file_operations hub_mon_fops = {
27         ioctl:          hubstats_ioctl,
28 };
29
30 #define HUB_CAPTURE_TICKS       (2 * HZ)
31
32 #define HUB_ERR_THRESH          500
33 #define USEC_PER_SEC            1000000
34 #define NSEC_PER_SEC            USEC_PER_SEC*1000
35
36 volatile int hub_print_usecs = 600 * USEC_PER_SEC;
37
38 /* Return success if the hub's crosstalk link is working */
39 int
40 hub_xtalk_link_up(nasid_t nasid)
41 {
42         hubreg_t        llp_csr_reg;
43
44         /* Read the IO LLP control status register */
45         llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
46
47         /* Check if the xtalk link is working */
48         if (llp_csr_reg & IIO_LLP_CSR_IS_UP) 
49                 return(1);
50
51         return(0);
52
53         
54 }
55
56 static char *error_flag_to_type(unsigned char error_flag)
57 {
58     switch(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");
65     }
66 }
67
68 int
69 print_hub_error(hubstat_t *hsp, hubreg_t reg,
70                 int64_t delta, unsigned char error_flag)
71 {
72         int64_t rate;
73
74         reg *= hsp->hs_per_minute;      /* Convert to minutes */
75         rate = reg / delta;
76
77         if (rate > HUB_ERR_THRESH) {
78                 
79                 if(hsp->hs_maint & error_flag) 
80                 {
81                 printk( "Excessive %s (%ld/min) on %s",
82                         error_flag_to_type(error_flag), rate, hsp->hs_name); 
83                 }
84                 else 
85                 {
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); 
89                 }
90                 return 1;
91         } else {
92                 return 0;
93         }
94 }
95
96
97 int
98 check_hub_error_rates(hubstat_t *hsp)
99 {
100         int64_t delta = hsp->hs_timestamp - hsp->hs_timebase;
101         int printed = 0;
102
103         printed += print_hub_error(hsp, hsp->hs_ni_retry_errors,
104                                    delta, 0x1);
105
106 #if 0
107         printed += print_hub_error(hsp, hsp->hs_ni_sn_errors,
108                                    delta, 0x2);
109 #endif
110
111         printed += print_hub_error(hsp, hsp->hs_ni_cb_errors,
112                                    delta, 0x4);
113
114
115         /* If the hub's xtalk link is not working there is 
116          * no need to print the "Excessive..." warning 
117          * messages
118          */
119         if (!hub_xtalk_link_up(hsp->hs_nasid))
120                 return(printed);
121
122
123         printed += print_hub_error(hsp, hsp->hs_ii_cb_errors,
124                                    delta, 0x8);
125
126         printed += print_hub_error(hsp, hsp->hs_ii_sn_errors,
127                                    delta, 0x10);
128
129         return printed;
130 }
131
132
133 void
134 capture_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda)
135 {
136         nasid_t nasid;
137         hubstat_t *hsp = &(npda->hubstats);
138         hubreg_t port_error;
139         ii_illr_u_t illr;
140         int count;
141         int overflow = 0;
142
143         /*
144          * If our link wasn't up at boot time, don't worry about error rates.
145          */
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);
149                 return;
150         }
151
152         nasid = COMPACT_TO_NASID_NODEID(cnodeid);
153
154         hsp->hs_timestamp = GET_RTC_COUNTER();
155
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)
160                 overflow = 1;
161         count = ((port_error & NPE_SNERRCOUNT_MASK) >> NPE_SNERRCOUNT_SHFT);
162         hsp->hs_ni_sn_errors += count;
163         if (count == NPE_COUNT_MAX)
164                 overflow = 1;
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++;
169
170         if (port_error & NPE_FATAL_ERRORS) {
171 #ifdef ajm
172                 hubni_error_handler("capture_hub_stats", 1);
173 #else
174                 printk("Error: hubni_error_handler in capture_hub_stats");
175 #endif
176         }
177
178         illr.ii_illr_regval = REMOTE_HUB_L(nasid, IIO_LLP_LOG);
179         REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0);
180
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++;
186
187         if (hsp->hs_print) {
188                 if (check_hub_error_rates(hsp)) {
189                         hsp->hs_last_print = GET_RTC_COUNTER();
190                         hsp->hs_print = 0;
191                 }
192         } else {
193                 if ((GET_RTC_COUNTER() -
194                     hsp->hs_last_print) > hub_print_usecs)
195                         hsp->hs_print = 1;
196         }
197                 
198         npda->hubticks = HUB_CAPTURE_TICKS;
199 }
200
201
202 void
203 init_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda)
204 {
205         hubstat_t *hsp = &(npda->hubstats);
206         nasid_t nasid = cnodeid_to_nasid(cnodeid);
207         bzero(&(npda->hubstats), sizeof(hubstat_t));
208
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);
214
215         /* Clear the II error counts. */
216         REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0);
217
218         /* Clear the NI counts. */
219         REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR);
220
221         hsp->hs_per_minute = (long long)RTC_CYCLES_PER_SEC * 60LL;
222
223         npda->hubticks = HUB_CAPTURE_TICKS;
224
225         /* XX should use kmem_alloc_node */
226         hsp->hs_name = (char *)kmalloc(MAX_HUB_PATH, GFP_KERNEL);
227         ASSERT_ALWAYS(hsp->hs_name);
228
229         sprintf(hsp->hs_name, "/dev/hw/" EDGE_LBL_MODULE "/%03d/"
230                 EDGE_LBL_NODE "/" EDGE_LBL_HUB,
231                 npda->module_id);
232
233         hsp->hs_last_print = 0;
234         hsp->hs_print = 1;
235
236         hub_print_usecs = hub_print_usecs;
237
238 #if 0
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);
241 #endif
242 }
243
244 static int
245 hubstats_ioctl(struct inode *inode, struct file *file,
246         unsigned int cmd, unsigned long arg)
247 {
248         cnodeid_t       cnode;
249         nodepda_t       *npdap;
250         uint64_t        longarg;
251         devfs_handle_t  d;
252
253         if ((d = devfs_get_handle_from_inode(inode)) == NULL)
254                 return -ENODEV;
255         cnode = (cnodeid_t)hwgraph_fastinfo_get(d);
256         npdap = NODEPDA(cnode);
257
258         if (npdap->hubstats.hs_version != HUBSTAT_VERSION) {
259                 init_hub_stats(cnode, npdap);
260         }
261
262         switch (cmd) {
263         case SNDRV_GET_INFOSIZE:
264                 longarg = sizeof(hubstat_t);
265                 if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) {
266                     return -EFAULT;
267                 }
268                 break;
269
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))) {
274                     return -EFAULT;
275                 }
276                 break;
277
278         default:
279                 return -EINVAL;
280         }
281
282         return 0;
283 }