1 | /********************************************************************** |
2 | * Author: Cavium, Inc. |
3 | * |
4 | * Contact: support@cavium.com |
5 | * Please include "LiquidIO" in the subject. |
6 | * |
7 | * Copyright (c) 2003-2016 Cavium, Inc. |
8 | * |
9 | * This file is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License, Version 2, as |
11 | * published by the Free Software Foundation. |
12 | * |
13 | * This file is distributed in the hope that it will be useful, but |
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty |
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or |
16 | * NONINFRINGEMENT. See the GNU General Public License for more details. |
17 | ***********************************************************************/ |
18 | #include <linux/pci.h> |
19 | #include <linux/netdevice.h> |
20 | #include "liquidio_common.h" |
21 | #include "octeon_droq.h" |
22 | #include "octeon_iq.h" |
23 | #include "response_manager.h" |
24 | #include "octeon_device.h" |
25 | #include "octeon_main.h" |
26 | #include "octeon_mailbox.h" |
27 | #include "cn23xx_pf_device.h" |
28 | |
29 | /** |
30 | * octeon_mbox_read: |
31 | * @mbox: Pointer mailbox |
32 | * |
33 | * Reads the 8-bytes of data from the mbox register |
34 | * Writes back the acknowldgement inidcating completion of read |
35 | */ |
36 | int octeon_mbox_read(struct octeon_mbox *mbox) |
37 | { |
38 | union octeon_mbox_message msg; |
39 | int ret = 0; |
40 | |
41 | spin_lock(lock: &mbox->lock); |
42 | |
43 | msg.u64 = readq(addr: mbox->mbox_read_reg); |
44 | |
45 | if ((msg.u64 == OCTEON_PFVFACK) || (msg.u64 == OCTEON_PFVFSIG)) { |
46 | spin_unlock(lock: &mbox->lock); |
47 | return 0; |
48 | } |
49 | |
50 | if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVING) { |
51 | mbox->mbox_req.data[mbox->mbox_req.recv_len - 1] = msg.u64; |
52 | mbox->mbox_req.recv_len++; |
53 | } else { |
54 | if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVING) { |
55 | mbox->mbox_resp.data[mbox->mbox_resp.recv_len - 1] = |
56 | msg.u64; |
57 | mbox->mbox_resp.recv_len++; |
58 | } else { |
59 | if ((mbox->state & OCTEON_MBOX_STATE_IDLE) && |
60 | (msg.s.type == OCTEON_MBOX_REQUEST)) { |
61 | mbox->state &= ~OCTEON_MBOX_STATE_IDLE; |
62 | mbox->state |= |
63 | OCTEON_MBOX_STATE_REQUEST_RECEIVING; |
64 | mbox->mbox_req.msg.u64 = msg.u64; |
65 | mbox->mbox_req.q_no = mbox->q_no; |
66 | mbox->mbox_req.recv_len = 1; |
67 | } else { |
68 | if ((mbox->state & |
69 | OCTEON_MBOX_STATE_RESPONSE_PENDING) && |
70 | (msg.s.type == OCTEON_MBOX_RESPONSE)) { |
71 | mbox->state &= |
72 | ~OCTEON_MBOX_STATE_RESPONSE_PENDING; |
73 | mbox->state |= |
74 | OCTEON_MBOX_STATE_RESPONSE_RECEIVING |
75 | ; |
76 | mbox->mbox_resp.msg.u64 = msg.u64; |
77 | mbox->mbox_resp.q_no = mbox->q_no; |
78 | mbox->mbox_resp.recv_len = 1; |
79 | } else { |
80 | writeq(OCTEON_PFVFERR, |
81 | addr: mbox->mbox_read_reg); |
82 | mbox->state |= OCTEON_MBOX_STATE_ERROR; |
83 | spin_unlock(lock: &mbox->lock); |
84 | return 1; |
85 | } |
86 | } |
87 | } |
88 | } |
89 | |
90 | if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVING) { |
91 | if (mbox->mbox_req.recv_len < mbox->mbox_req.msg.s.len) { |
92 | ret = 0; |
93 | } else { |
94 | mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVING; |
95 | mbox->state |= OCTEON_MBOX_STATE_REQUEST_RECEIVED; |
96 | ret = 1; |
97 | } |
98 | } else { |
99 | if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVING) { |
100 | if (mbox->mbox_resp.recv_len < |
101 | mbox->mbox_resp.msg.s.len) { |
102 | ret = 0; |
103 | } else { |
104 | mbox->state &= |
105 | ~OCTEON_MBOX_STATE_RESPONSE_RECEIVING; |
106 | mbox->state |= |
107 | OCTEON_MBOX_STATE_RESPONSE_RECEIVED; |
108 | ret = 1; |
109 | } |
110 | } else { |
111 | WARN_ON(1); |
112 | } |
113 | } |
114 | |
115 | writeq(OCTEON_PFVFACK, addr: mbox->mbox_read_reg); |
116 | |
117 | spin_unlock(lock: &mbox->lock); |
118 | |
119 | return ret; |
120 | } |
121 | |
122 | /** |
123 | * octeon_mbox_write: |
124 | * @oct: Pointer Octeon Device |
125 | * @mbox_cmd: Cmd to send to mailbox. |
126 | * |
127 | * Populates the queue specific mbox structure |
128 | * with cmd information. |
129 | * Write the cmd to mbox register |
130 | */ |
131 | int octeon_mbox_write(struct octeon_device *oct, |
132 | struct octeon_mbox_cmd *mbox_cmd) |
133 | { |
134 | struct octeon_mbox *mbox = oct->mbox[mbox_cmd->q_no]; |
135 | u32 count, i, ret = OCTEON_MBOX_STATUS_SUCCESS; |
136 | long timeout = LIO_MBOX_WRITE_WAIT_TIME; |
137 | unsigned long flags; |
138 | |
139 | spin_lock_irqsave(&mbox->lock, flags); |
140 | |
141 | if ((mbox_cmd->msg.s.type == OCTEON_MBOX_RESPONSE) && |
142 | !(mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVED)) { |
143 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
144 | return OCTEON_MBOX_STATUS_FAILED; |
145 | } |
146 | |
147 | if ((mbox_cmd->msg.s.type == OCTEON_MBOX_REQUEST) && |
148 | !(mbox->state & OCTEON_MBOX_STATE_IDLE)) { |
149 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
150 | return OCTEON_MBOX_STATUS_BUSY; |
151 | } |
152 | |
153 | if (mbox_cmd->msg.s.type == OCTEON_MBOX_REQUEST) { |
154 | memcpy(&mbox->mbox_resp, mbox_cmd, |
155 | sizeof(struct octeon_mbox_cmd)); |
156 | mbox->state = OCTEON_MBOX_STATE_RESPONSE_PENDING; |
157 | } |
158 | |
159 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
160 | |
161 | count = 0; |
162 | |
163 | while (readq(addr: mbox->mbox_write_reg) != OCTEON_PFVFSIG) { |
164 | schedule_timeout_uninterruptible(timeout); |
165 | if (count++ == LIO_MBOX_WRITE_WAIT_CNT) { |
166 | ret = OCTEON_MBOX_STATUS_FAILED; |
167 | break; |
168 | } |
169 | } |
170 | |
171 | if (ret == OCTEON_MBOX_STATUS_SUCCESS) { |
172 | writeq(val: mbox_cmd->msg.u64, addr: mbox->mbox_write_reg); |
173 | for (i = 0; i < (u32)(mbox_cmd->msg.s.len - 1); i++) { |
174 | count = 0; |
175 | while (readq(addr: mbox->mbox_write_reg) != |
176 | OCTEON_PFVFACK) { |
177 | schedule_timeout_uninterruptible(timeout); |
178 | if (count++ == LIO_MBOX_WRITE_WAIT_CNT) { |
179 | ret = OCTEON_MBOX_STATUS_FAILED; |
180 | break; |
181 | } |
182 | } |
183 | if (ret == OCTEON_MBOX_STATUS_SUCCESS) |
184 | writeq(val: mbox_cmd->data[i], addr: mbox->mbox_write_reg); |
185 | else |
186 | break; |
187 | } |
188 | } |
189 | |
190 | spin_lock_irqsave(&mbox->lock, flags); |
191 | if (mbox_cmd->msg.s.type == OCTEON_MBOX_RESPONSE) { |
192 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
193 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
194 | } else { |
195 | if ((!mbox_cmd->msg.s.resp_needed) || |
196 | (ret == OCTEON_MBOX_STATUS_FAILED)) { |
197 | mbox->state &= ~OCTEON_MBOX_STATE_RESPONSE_PENDING; |
198 | if (!(mbox->state & |
199 | (OCTEON_MBOX_STATE_REQUEST_RECEIVING | |
200 | OCTEON_MBOX_STATE_REQUEST_RECEIVED))) |
201 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
202 | } |
203 | } |
204 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
205 | |
206 | return ret; |
207 | } |
208 | |
209 | static void get_vf_stats(struct octeon_device *oct, |
210 | struct oct_vf_stats *stats) |
211 | { |
212 | int i; |
213 | |
214 | for (i = 0; i < oct->num_iqs; i++) { |
215 | if (!oct->instr_queue[i]) |
216 | continue; |
217 | stats->tx_packets += oct->instr_queue[i]->stats.tx_done; |
218 | stats->tx_bytes += oct->instr_queue[i]->stats.tx_tot_bytes; |
219 | } |
220 | |
221 | for (i = 0; i < oct->num_oqs; i++) { |
222 | if (!oct->droq[i]) |
223 | continue; |
224 | stats->rx_packets += oct->droq[i]->stats.rx_pkts_received; |
225 | stats->rx_bytes += oct->droq[i]->stats.rx_bytes_received; |
226 | } |
227 | } |
228 | |
229 | /** |
230 | * octeon_mbox_process_cmd: |
231 | * @mbox: Pointer mailbox |
232 | * @mbox_cmd: Pointer to command received |
233 | * |
234 | * Process the cmd received in mbox |
235 | */ |
236 | static int octeon_mbox_process_cmd(struct octeon_mbox *mbox, |
237 | struct octeon_mbox_cmd *mbox_cmd) |
238 | { |
239 | struct octeon_device *oct = mbox->oct_dev; |
240 | |
241 | switch (mbox_cmd->msg.s.cmd) { |
242 | case OCTEON_VF_ACTIVE: |
243 | dev_dbg(&oct->pci_dev->dev, "got vfactive sending data back\n" ); |
244 | mbox_cmd->msg.s.type = OCTEON_MBOX_RESPONSE; |
245 | mbox_cmd->msg.s.resp_needed = 1; |
246 | mbox_cmd->msg.s.len = 2; |
247 | mbox_cmd->data[0] = 0; /* VF version is in mbox_cmd->data[0] */ |
248 | ((struct lio_version *)&mbox_cmd->data[0])->major = |
249 | LIQUIDIO_BASE_MAJOR_VERSION; |
250 | ((struct lio_version *)&mbox_cmd->data[0])->minor = |
251 | LIQUIDIO_BASE_MINOR_VERSION; |
252 | ((struct lio_version *)&mbox_cmd->data[0])->micro = |
253 | LIQUIDIO_BASE_MICRO_VERSION; |
254 | memcpy(mbox_cmd->msg.s.params, (uint8_t *)&oct->pfvf_hsword, 6); |
255 | /* Sending core cofig info to the corresponding active VF.*/ |
256 | octeon_mbox_write(oct, mbox_cmd); |
257 | break; |
258 | |
259 | case OCTEON_VF_FLR_REQUEST: |
260 | dev_info(&oct->pci_dev->dev, |
261 | "got a request for FLR from VF that owns DPI ring %u\n" , |
262 | mbox->q_no); |
263 | pcie_flr(dev: oct->sriov_info.dpiring_to_vfpcidev_lut[mbox->q_no]); |
264 | break; |
265 | |
266 | case OCTEON_PF_CHANGED_VF_MACADDR: |
267 | if (OCTEON_CN23XX_VF(oct)) |
268 | octeon_pf_changed_vf_macaddr(oct, |
269 | mac: mbox_cmd->msg.s.params); |
270 | break; |
271 | |
272 | case OCTEON_GET_VF_STATS: |
273 | dev_dbg(&oct->pci_dev->dev, "Got VF stats request. Sending data back\n" ); |
274 | mbox_cmd->msg.s.type = OCTEON_MBOX_RESPONSE; |
275 | mbox_cmd->msg.s.resp_needed = 1; |
276 | mbox_cmd->msg.s.len = 1 + |
277 | sizeof(struct oct_vf_stats) / sizeof(u64); |
278 | get_vf_stats(oct, stats: (struct oct_vf_stats *)mbox_cmd->data); |
279 | octeon_mbox_write(oct, mbox_cmd); |
280 | break; |
281 | default: |
282 | break; |
283 | } |
284 | return 0; |
285 | } |
286 | |
287 | /** |
288 | * octeon_mbox_process_message |
289 | * @mbox: mailbox |
290 | * |
291 | * Process the received mbox message. |
292 | */ |
293 | int octeon_mbox_process_message(struct octeon_mbox *mbox) |
294 | { |
295 | struct octeon_mbox_cmd mbox_cmd; |
296 | unsigned long flags; |
297 | |
298 | spin_lock_irqsave(&mbox->lock, flags); |
299 | |
300 | if (mbox->state & OCTEON_MBOX_STATE_ERROR) { |
301 | if (mbox->state & (OCTEON_MBOX_STATE_RESPONSE_PENDING | |
302 | OCTEON_MBOX_STATE_RESPONSE_RECEIVING)) { |
303 | memcpy(&mbox_cmd, &mbox->mbox_resp, |
304 | sizeof(struct octeon_mbox_cmd)); |
305 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
306 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
307 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
308 | mbox_cmd.recv_status = 1; |
309 | if (mbox_cmd.fn) |
310 | mbox_cmd.fn(mbox->oct_dev, &mbox_cmd, |
311 | mbox_cmd.fn_arg); |
312 | return 0; |
313 | } |
314 | |
315 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
316 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
317 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
318 | return 0; |
319 | } |
320 | |
321 | if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVED) { |
322 | memcpy(&mbox_cmd, &mbox->mbox_resp, |
323 | sizeof(struct octeon_mbox_cmd)); |
324 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
325 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
326 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
327 | mbox_cmd.recv_status = 0; |
328 | if (mbox_cmd.fn) |
329 | mbox_cmd.fn(mbox->oct_dev, &mbox_cmd, mbox_cmd.fn_arg); |
330 | return 0; |
331 | } |
332 | |
333 | if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVED) { |
334 | memcpy(&mbox_cmd, &mbox->mbox_req, |
335 | sizeof(struct octeon_mbox_cmd)); |
336 | if (!mbox_cmd.msg.s.resp_needed) { |
337 | mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVED; |
338 | if (!(mbox->state & |
339 | OCTEON_MBOX_STATE_RESPONSE_PENDING)) |
340 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
341 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
342 | } |
343 | |
344 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
345 | octeon_mbox_process_cmd(mbox, mbox_cmd: &mbox_cmd); |
346 | return 0; |
347 | } |
348 | |
349 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
350 | WARN_ON(1); |
351 | |
352 | return 0; |
353 | } |
354 | |
355 | int octeon_mbox_cancel(struct octeon_device *oct, int q_no) |
356 | { |
357 | struct octeon_mbox *mbox = oct->mbox[q_no]; |
358 | struct octeon_mbox_cmd *mbox_cmd; |
359 | unsigned long flags = 0; |
360 | |
361 | spin_lock_irqsave(&mbox->lock, flags); |
362 | mbox_cmd = &mbox->mbox_resp; |
363 | |
364 | if (!(mbox->state & OCTEON_MBOX_STATE_RESPONSE_PENDING)) { |
365 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
366 | return 1; |
367 | } |
368 | |
369 | mbox->state = OCTEON_MBOX_STATE_IDLE; |
370 | memset(mbox_cmd, 0, sizeof(*mbox_cmd)); |
371 | writeq(OCTEON_PFVFSIG, addr: mbox->mbox_read_reg); |
372 | spin_unlock_irqrestore(lock: &mbox->lock, flags); |
373 | |
374 | return 0; |
375 | } |
376 | |