1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "config.h"
25 
26 #include <libudev.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #include <syslog.h>
33 #include "i915_drm.h"
34 #include "intel_l3_parity.h"
35 
36 #ifndef I915_L3_PARITY_UEVENT
37 #define I915_L3_PARITY_UEVENT "L3_PARITY_ERROR"
38 #endif
39 
l3_uevent_setup(struct l3_parity * par)40 int l3_uevent_setup(struct l3_parity *par)
41 {
42 	struct udev *udev;
43 	struct udev_monitor *uevent_monitor;
44 	fd_set fdset;
45 	int fd, ret = -1;
46 
47 	udev = udev_new();
48 	if (!udev) {
49 		return -1;
50 	}
51 
52 	uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
53 	if (!uevent_monitor)
54 		goto err_out;
55 
56 	ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor, "drm", "drm_minor");
57 	if (ret < 0)
58 		goto err_out;
59 
60 	ret = udev_monitor_enable_receiving(uevent_monitor);
61 	if (ret < 0)
62 		goto err_out;
63 
64 	fd = udev_monitor_get_fd(uevent_monitor);
65 	FD_ZERO(&fdset);
66 	FD_SET(fd, &fdset);
67 
68 	par->udev = udev;
69 	par->fd = fd;
70 	par->fdset = fdset;
71 	par->uevent_monitor = uevent_monitor;
72 	return 0;
73 
74 err_out:
75 	udev_unref(udev);
76 	return ret;
77 }
78 
l3_listen(struct l3_parity * par,bool daemon,struct l3_location * loc)79 int l3_listen(struct l3_parity *par, bool daemon, struct l3_location *loc)
80 {
81 	struct udev_device *udev_dev;
82 	const char *parity_status;
83 	char *err_msg;
84 	int ret;
85 
86 again:
87 	ret = select(par->fd + 1, &par->fdset, NULL, NULL, NULL);
88 	/* Number of bits set is returned, must be >= 1 */
89 	if (ret <= 0) {
90 		return ret;
91 	}
92 
93 	assert(FD_ISSET(par->fd, &par->fdset));
94 
95 	udev_dev = udev_monitor_receive_device(par->uevent_monitor);
96 	if (!udev_dev)
97 		return -1;
98 
99 	parity_status = udev_device_get_property_value(udev_dev, I915_L3_PARITY_UEVENT);
100 	if (strncmp(parity_status, "1", 1))
101 		goto again;
102 
103 	loc->slice = atoi(udev_device_get_property_value(udev_dev, "SLICE"));
104 	loc->row = atoi(udev_device_get_property_value(udev_dev, "ROW"));
105 	loc->bank = atoi(udev_device_get_property_value(udev_dev, "BANK"));
106 	loc->subbank = atoi(udev_device_get_property_value(udev_dev, "SUBBANK"));
107 
108 	udev_device_unref(udev_dev);
109 
110 	assert(asprintf(&err_msg, "Parity error detected on: %d,%d,%d,%d. "
111 			"Try to run intel_l3_parity -r %d -b %d -s %d -w %d -d",
112 			loc->slice, loc->row, loc->bank, loc->subbank,
113 			loc->row, loc->bank, loc->subbank, loc->slice) != -1);
114 	if (daemon) {
115 		syslog(LOG_INFO, "%s\n", err_msg);
116 		goto again;
117 	}
118 
119 	fprintf(stderr, "%s\n", err_msg);
120 
121 	free(err_msg);
122 
123 	return 0;
124 }
125