Commit | Line | Data |
---|---|---|
800f879a AT |
1 | /* |
2 | * Copyright 2010-2017 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License, version 2, | |
6 | * as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * Disclaimer: The codes contained in these modules may be specific to | |
14 | * the Intel Software Development Platform codenamed Knights Ferry, | |
15 | * and the Intel product codenamed Knights Corner, and are not backward | |
16 | * compatible with other Intel products. Additionally, Intel will NOT | |
17 | * support the codes or instruction set in future products. | |
18 | * | |
19 | * Intel offers no warranty of any kind regarding the code. This code is | |
20 | * licensed on an "AS IS" basis and Intel is not obligated to provide | |
21 | * any support, assistance, installation, training, or other services | |
22 | * of any kind. Intel is also not obligated to provide any updates, | |
23 | * enhancements or extensions. Intel specifically disclaims any warranty | |
24 | * of merchantability, non-infringement, fitness for any particular | |
25 | * purpose, and any other warranty. | |
26 | * | |
27 | * Further, Intel disclaims all liability of any kind, including but | |
28 | * not limited to liability for infringement of any proprietary rights, | |
29 | * relating to the use of the code, even if Intel is notified of the | |
30 | * possibility of such liability. Except as expressly stated in an Intel | |
31 | * license agreement provided with this code and agreed upon with Intel, | |
32 | * no license, express or implied, by estoppel or otherwise, to any | |
33 | * intellectual property rights is granted herein. | |
34 | */ | |
35 | ||
36 | #include <linux/string.h> | |
37 | #include <linux/module.h> | |
38 | #include <linux/kernel.h> | |
39 | #include <linux/err.h> | |
40 | #include <micint.h> | |
41 | ||
42 | #include <scif.h> | |
43 | #include <mic_common.h> | |
44 | ||
45 | #define ACPT_BACKLOG 120 | |
46 | #define ACPT_POLL_MS 2000 | |
47 | ||
48 | #define ACPT_BOOTED 1 | |
49 | #define ACPT_BOOT_ACK 2 | |
50 | #define ACPT_NACK_VERSION 3 | |
51 | #define ACPT_REQUEST_TIME 4 | |
52 | #define ACPT_TIME_DATA 5 | |
53 | ||
54 | #define ACPT_VERSION 1 | |
55 | ||
56 | static acptboot_data_t *acptboot_data; | |
57 | ||
58 | ||
59 | void acptboot_getconn(struct work_struct *work) | |
60 | { | |
61 | mic_ctx_t *node_ctx; | |
62 | struct scif_portID data; | |
63 | scif_epd_t conn_epd; | |
64 | struct timespec tod; | |
65 | int proto; | |
66 | int version; | |
67 | int err; | |
68 | ||
69 | if ((err = scif_accept(acptboot_data->listen_epd, &data, &conn_epd, | |
70 | SCIF_ACCEPT_SYNC))) { | |
71 | pr_debug("ACPTBOOT: scif_accept_failed %d\n", err); | |
72 | return; | |
73 | ||
74 | //goto requeue_accept; | |
75 | } | |
76 | ||
77 | if (!data.node) { | |
78 | printk(KERN_ERR "ACPTBOOT: connect received from invalid dev %d\n", | |
79 | -EINVAL); | |
80 | goto close_epd; | |
81 | } | |
82 | ||
83 | if ((err = scif_recv(conn_epd, &version, sizeof(version), SCIF_RECV_BLOCK)) != sizeof(version)) { | |
84 | printk(KERN_ERR "ACPTBOOT: failed to recieve version number err %d\n", err); | |
85 | goto close_epd; | |
86 | } | |
87 | ||
88 | if ((err = scif_recv(conn_epd, &proto, sizeof(proto), SCIF_RECV_BLOCK)) != sizeof(proto)) { | |
89 | printk(KERN_ERR "ACPTBOOT: failed to recieve proto id %d\n", err); | |
90 | goto close_epd; | |
91 | } | |
92 | ||
93 | switch (proto) { | |
94 | case ACPT_BOOTED: | |
95 | node_ctx = get_per_dev_ctx(data.node - 1); | |
96 | mic_setstate(node_ctx, MIC_ONLINE); | |
97 | node_ctx->boot_count++; | |
98 | ||
99 | proto = ACPT_BOOT_ACK; | |
100 | scif_send(conn_epd, &proto, sizeof(proto), SCIF_SEND_BLOCK); | |
101 | break; | |
102 | ||
103 | case ACPT_REQUEST_TIME: | |
104 | getnstimeofday(&tod); | |
105 | proto = ACPT_TIME_DATA; | |
106 | scif_send(conn_epd, &proto, sizeof(proto), SCIF_SEND_BLOCK); | |
107 | scif_send(conn_epd, &tod, sizeof(tod), SCIF_SEND_BLOCK); | |
108 | break; | |
109 | } | |
110 | ||
111 | close_epd: | |
112 | if ((err = scif_close(conn_epd))) | |
113 | printk(KERN_ERR "ACPTBOOT: scif_close failed %d\n", err); | |
114 | ||
115 | //requeue_accept: | |
116 | queue_work(acptboot_data->acptbootwq, &acptboot_data->acptbootwork); | |
117 | } | |
118 | ||
119 | void acptboot_exit(void) | |
120 | { | |
121 | int err = 0; | |
122 | if (acptboot_data) { | |
123 | if (acptboot_data->listen_epd) | |
124 | if ((err = scif_close(acptboot_data->listen_epd)) < 0) | |
125 | pr_debug("scif_close failed %d\n", err); | |
126 | destroy_workqueue(acptboot_data->acptbootwq); | |
127 | ||
128 | kfree(acptboot_data); | |
129 | } | |
130 | } | |
131 | ||
132 | int | |
133 | acptboot_init(void) | |
134 | { | |
135 | int err, ret; | |
136 | ||
137 | acptboot_data = (acptboot_data_t *)kzalloc(sizeof(*acptboot_data), GFP_KERNEL); | |
138 | ||
139 | if (!acptboot_data) { | |
140 | printk(KERN_ERR "ACPTBOOT: memory allocation failure\n"); | |
141 | return -ENOMEM; | |
142 | } | |
143 | ||
144 | acptboot_data->listen_epd = scif_open(); | |
145 | ||
146 | if (!acptboot_data->listen_epd) { | |
147 | printk(KERN_ERR "ACPTBOOT: scif_open() failed!\n"); | |
148 | err = -ENOMEM; | |
149 | goto error; | |
150 | } | |
151 | ||
152 | err = scif_bind(acptboot_data->listen_epd, MIC_NOTIFY); | |
153 | if (err < 0) { | |
154 | pr_debug("ACPTBOOT: scif_bind() failed! %d\n", err); | |
155 | goto error; | |
156 | } | |
157 | ||
158 | acptboot_data->acptboot_pn = err; | |
159 | ||
160 | err = scif_listen(acptboot_data->listen_epd, ACPT_BACKLOG); | |
161 | if (err < 0) { | |
162 | pr_debug("scif_listen() failed! %d\n", err); | |
163 | goto error; | |
164 | ||
165 | } | |
166 | ||
167 | pr_debug("ACPT endpoint listening port %d\n", | |
168 | acptboot_data->acptboot_pn); | |
169 | ||
170 | // Create workqueue | |
171 | acptboot_data->acptbootwq = __mic_create_singlethread_workqueue( | |
172 | "ACPTBOOT_WQ"); | |
173 | ||
174 | if (!acptboot_data->acptbootwq) { | |
175 | printk(KERN_ERR "%s %d wq creation failed!\n", __func__, __LINE__); | |
176 | goto error; | |
177 | } | |
178 | ||
179 | INIT_WORK(&acptboot_data->acptbootwork, acptboot_getconn); | |
180 | queue_work(acptboot_data->acptbootwq, | |
181 | &acptboot_data->acptbootwork); | |
182 | return 0; | |
183 | ||
184 | error: | |
185 | ||
186 | if (acptboot_data->listen_epd) | |
187 | if ((ret = scif_close(acptboot_data->listen_epd)) < 0) | |
188 | pr_debug("ACPTBOOT: scif_close() failed! %d\n", ret); | |
189 | ||
190 | kfree(acptboot_data); | |
191 | ||
192 | return err; | |
193 | } | |
194 |