aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux/ecc_sysfs.c
blob: 73ae3dc2b74b5b6ad5669fe9a74584409cf5591c (plain) (blame)
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
/*
 * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <nvgpu/ecc.h>
#include <nvgpu/gk20a.h>

#include "os_linux.h"

int nvgpu_ecc_sysfs_init(struct gk20a *g)
{
	struct device *dev = dev_from_gk20a(g);
	struct nvgpu_ecc *ecc = &g->ecc;
	struct dev_ext_attribute *attr;
	struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
	struct nvgpu_ecc_stat *stat;
	int i = 0, err;

	attr = nvgpu_kzalloc(g, sizeof(*attr) * ecc->stats_count);
	if (!attr)
		return -ENOMEM;

	nvgpu_list_for_each_entry(stat,
			&ecc->stats_list, nvgpu_ecc_stat, node) {
		if (i >= ecc->stats_count) {
			err = -EINVAL;
			nvgpu_err(g, "stats_list longer than stats_count %d",
					ecc->stats_count);
			break;
		}
		sysfs_attr_init(&attr[i].attr.attr);
		attr[i].attr.attr.name = stat->name;
		attr[i].attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
		attr[i].var =  &stat->counter;
		attr[i].attr.show = device_show_int;
		err = device_create_file(dev, &attr[i].attr);
		if (err) {
			nvgpu_err(g, "sysfs node create failed for %s\n",
					stat->name);
			break;
		}
		i++;
	}

	if (err) {
		while (i-- > 0)
			device_remove_file(dev, &attr[i].attr);
		nvgpu_kfree(g, attr);
		return err;
	}

	l->ecc_attrs = attr;

	return 0;
}

void nvgpu_ecc_sysfs_remove(struct gk20a *g)
{
	struct device *dev = dev_from_gk20a(g);
	struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
	struct nvgpu_ecc *ecc = &g->ecc;
	int i;

	for (i = 0; i < ecc->stats_count; i++)
		device_remove_file(dev, &l->ecc_attrs[i].attr);
	nvgpu_kfree(g, l->ecc_attrs);
	l->ecc_attrs = NULL;
}
an> int chEnd ); void dijkstra_main( void ); //int main( void ); void dijkstra_init( void ) { int i, k; volatile int x = 0; _Pragma( "loopbound min 100 max 100" ) for ( i = 0; i < NUM_NODES; i++ ) { _Pragma( "loopbound min 100 max 100" ) for ( k = 0; k < NUM_NODES; k++ ) { dijkstra_AdjMatrix[i][k] ^= x; } } dijkstra_queueCount = 0; dijkstra_queueNext = 0; dijkstra_queueHead = ( struct _QITEM * )0; dijkstra_checksum = 0; } int dijkstra_return( void ) { return ( ( dijkstra_checksum == 25 ) ? 0 : -1 ); } int dijkstra_enqueue( int node, int dist, int prev ) { struct _QITEM *newItem = &dijkstra_queueItems[dijkstra_queueNext]; struct _QITEM *last = dijkstra_queueHead; if ( ++dijkstra_queueNext >= QUEUE_SIZE ) return OUT_OF_MEMORY; newItem->node = node; newItem->dist = dist; newItem->prev = prev; newItem->next = 0; if ( !last ) dijkstra_queueHead = newItem; else { /* TODO: where does this magic loop bound come from? */ _Pragma( "loopbound min 0 max 313" ) while ( last->next ) last = last->next; last->next = newItem; } dijkstra_queueCount++; return 0; } void dijkstra_dequeue( int *node, int *dist, int *prev ) { if ( dijkstra_queueHead ) { *node = dijkstra_queueHead->node; *dist = dijkstra_queueHead->dist; *prev = dijkstra_queueHead->prev; dijkstra_queueHead = dijkstra_queueHead->next; dijkstra_queueCount--; } } int dijkstra_qcount( void ) { return ( dijkstra_queueCount ); } int dijkstra_find( int chStart, int chEnd ) { int ch; int prev, node; int cost, dist; int i; _Pragma( "loopbound min 100 max 100" ) for ( ch = 0; ch < NUM_NODES; ch++ ) { dijkstra_rgnNodes[ch].dist = NONE; dijkstra_rgnNodes[ch].prev = NONE; } if ( chStart == chEnd ) { } else { dijkstra_rgnNodes[chStart].dist = 0; dijkstra_rgnNodes[chStart].prev = NONE; if ( dijkstra_enqueue ( chStart, 0, NONE ) == OUT_OF_MEMORY ) return OUT_OF_MEMORY; /* TODO: where does this magic loop bound come from? */ _Pragma( "loopbound min 618 max 928" ) while ( dijkstra_qcount() > 0 ) { dijkstra_dequeue ( &node, &dist, &prev ); _Pragma( "loopbound min 100 max 100" ) for ( i = 0; i < NUM_NODES; i++ ) { if ( ( cost = dijkstra_AdjMatrix[node][i] ) != NONE ) { if ( ( NONE == dijkstra_rgnNodes[i].dist ) || ( dijkstra_rgnNodes[i].dist > ( cost + dist ) ) ) { dijkstra_rgnNodes[i].dist = dist + cost; dijkstra_rgnNodes[i].prev = node; if ( dijkstra_enqueue ( i, dist + cost, node ) == OUT_OF_MEMORY ) return OUT_OF_MEMORY; } } } } } return 0; } void _Pragma( "entrypoint" ) dijkstra_main( void ) { int i, j; /* finds 20 shortest paths between nodes */ _Pragma( "loopbound min 20 max 20" ) for ( i = 0, j = NUM_NODES / 2; i < 20; i++, j++ ) { j = j % NUM_NODES; if ( dijkstra_find( i, j ) == OUT_OF_MEMORY ) { dijkstra_checksum += OUT_OF_MEMORY; return; } else dijkstra_checksum += dijkstra_rgnNodes[j].dist; dijkstra_queueNext = 0; } } int main(int argc, char** argv ) { SET_UP for_each_job { dijkstra_init(); dijkstra_main(); } WRITE_TO_FILE return ( dijkstra_return() ); }