1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Function Control Protocol (IEC 61883-1) helper functions
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/device.h>
9*4882a593Smuzhiyun #include <linux/firewire.h>
10*4882a593Smuzhiyun #include <linux/firewire-constants.h>
11*4882a593Smuzhiyun #include <linux/list.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/sched.h>
15*4882a593Smuzhiyun #include <linux/spinlock.h>
16*4882a593Smuzhiyun #include <linux/wait.h>
17*4882a593Smuzhiyun #include <linux/delay.h>
18*4882a593Smuzhiyun #include "fcp.h"
19*4882a593Smuzhiyun #include "lib.h"
20*4882a593Smuzhiyun #include "amdtp-stream.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define CTS_AVC 0x00
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define ERROR_RETRIES 3
25*4882a593Smuzhiyun #define ERROR_DELAY_MS 5
26*4882a593Smuzhiyun #define FCP_TIMEOUT_MS 125
27*4882a593Smuzhiyun
avc_general_set_sig_fmt(struct fw_unit * unit,unsigned int rate,enum avc_general_plug_dir dir,unsigned short pid)28*4882a593Smuzhiyun int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate,
29*4882a593Smuzhiyun enum avc_general_plug_dir dir,
30*4882a593Smuzhiyun unsigned short pid)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun unsigned int sfc;
33*4882a593Smuzhiyun u8 *buf;
34*4882a593Smuzhiyun bool flag;
35*4882a593Smuzhiyun int err;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun flag = false;
38*4882a593Smuzhiyun for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
39*4882a593Smuzhiyun if (amdtp_rate_table[sfc] == rate) {
40*4882a593Smuzhiyun flag = true;
41*4882a593Smuzhiyun break;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun if (!flag)
45*4882a593Smuzhiyun return -EINVAL;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun buf = kzalloc(8, GFP_KERNEL);
48*4882a593Smuzhiyun if (buf == NULL)
49*4882a593Smuzhiyun return -ENOMEM;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun buf[0] = 0x00; /* AV/C CONTROL */
52*4882a593Smuzhiyun buf[1] = 0xff; /* UNIT */
53*4882a593Smuzhiyun if (dir == AVC_GENERAL_PLUG_DIR_IN)
54*4882a593Smuzhiyun buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
55*4882a593Smuzhiyun else
56*4882a593Smuzhiyun buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
57*4882a593Smuzhiyun buf[3] = 0xff & pid; /* plug id */
58*4882a593Smuzhiyun buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
59*4882a593Smuzhiyun buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */
60*4882a593Smuzhiyun buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used)*/
61*4882a593Smuzhiyun buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* do transaction and check buf[1-5] are the same against command */
64*4882a593Smuzhiyun err = fcp_avc_transaction(unit, buf, 8, buf, 8,
65*4882a593Smuzhiyun BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
66*4882a593Smuzhiyun if (err < 0)
67*4882a593Smuzhiyun ;
68*4882a593Smuzhiyun else if (err < 8)
69*4882a593Smuzhiyun err = -EIO;
70*4882a593Smuzhiyun else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
71*4882a593Smuzhiyun err = -ENOSYS;
72*4882a593Smuzhiyun else if (buf[0] == 0x0a) /* REJECTED */
73*4882a593Smuzhiyun err = -EINVAL;
74*4882a593Smuzhiyun if (err < 0)
75*4882a593Smuzhiyun goto end;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun err = 0;
78*4882a593Smuzhiyun end:
79*4882a593Smuzhiyun kfree(buf);
80*4882a593Smuzhiyun return err;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun EXPORT_SYMBOL(avc_general_set_sig_fmt);
83*4882a593Smuzhiyun
avc_general_get_sig_fmt(struct fw_unit * unit,unsigned int * rate,enum avc_general_plug_dir dir,unsigned short pid)84*4882a593Smuzhiyun int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate,
85*4882a593Smuzhiyun enum avc_general_plug_dir dir,
86*4882a593Smuzhiyun unsigned short pid)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun unsigned int sfc;
89*4882a593Smuzhiyun u8 *buf;
90*4882a593Smuzhiyun int err;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun buf = kzalloc(8, GFP_KERNEL);
93*4882a593Smuzhiyun if (buf == NULL)
94*4882a593Smuzhiyun return -ENOMEM;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun buf[0] = 0x01; /* AV/C STATUS */
97*4882a593Smuzhiyun buf[1] = 0xff; /* Unit */
98*4882a593Smuzhiyun if (dir == AVC_GENERAL_PLUG_DIR_IN)
99*4882a593Smuzhiyun buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
100*4882a593Smuzhiyun else
101*4882a593Smuzhiyun buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
102*4882a593Smuzhiyun buf[3] = 0xff & pid; /* plug id */
103*4882a593Smuzhiyun buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
104*4882a593Smuzhiyun buf[5] = 0xff; /* FDF-hi. AM824, frequency */
105*4882a593Smuzhiyun buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */
106*4882a593Smuzhiyun buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* do transaction and check buf[1-4] are the same against command */
109*4882a593Smuzhiyun err = fcp_avc_transaction(unit, buf, 8, buf, 8,
110*4882a593Smuzhiyun BIT(1) | BIT(2) | BIT(3) | BIT(4));
111*4882a593Smuzhiyun if (err < 0)
112*4882a593Smuzhiyun ;
113*4882a593Smuzhiyun else if (err < 8)
114*4882a593Smuzhiyun err = -EIO;
115*4882a593Smuzhiyun else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
116*4882a593Smuzhiyun err = -ENOSYS;
117*4882a593Smuzhiyun else if (buf[0] == 0x0a) /* REJECTED */
118*4882a593Smuzhiyun err = -EINVAL;
119*4882a593Smuzhiyun else if (buf[0] == 0x0b) /* IN TRANSITION */
120*4882a593Smuzhiyun err = -EAGAIN;
121*4882a593Smuzhiyun if (err < 0)
122*4882a593Smuzhiyun goto end;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* check sfc field and pick up rate */
125*4882a593Smuzhiyun sfc = 0x07 & buf[5];
126*4882a593Smuzhiyun if (sfc >= CIP_SFC_COUNT) {
127*4882a593Smuzhiyun err = -EAGAIN; /* also in transition */
128*4882a593Smuzhiyun goto end;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun *rate = amdtp_rate_table[sfc];
132*4882a593Smuzhiyun err = 0;
133*4882a593Smuzhiyun end:
134*4882a593Smuzhiyun kfree(buf);
135*4882a593Smuzhiyun return err;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun EXPORT_SYMBOL(avc_general_get_sig_fmt);
138*4882a593Smuzhiyun
avc_general_get_plug_info(struct fw_unit * unit,unsigned int subunit_type,unsigned int subunit_id,unsigned int subfunction,u8 info[AVC_PLUG_INFO_BUF_BYTES])139*4882a593Smuzhiyun int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type,
140*4882a593Smuzhiyun unsigned int subunit_id, unsigned int subfunction,
141*4882a593Smuzhiyun u8 info[AVC_PLUG_INFO_BUF_BYTES])
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun u8 *buf;
144*4882a593Smuzhiyun int err;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* extended subunit in spec.4.2 is not supported */
147*4882a593Smuzhiyun if ((subunit_type == 0x1E) || (subunit_id == 5))
148*4882a593Smuzhiyun return -EINVAL;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun buf = kzalloc(8, GFP_KERNEL);
151*4882a593Smuzhiyun if (buf == NULL)
152*4882a593Smuzhiyun return -ENOMEM;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun buf[0] = 0x01; /* AV/C STATUS */
155*4882a593Smuzhiyun /* UNIT or Subunit, Functionblock */
156*4882a593Smuzhiyun buf[1] = ((subunit_type & 0x1f) << 3) | (subunit_id & 0x7);
157*4882a593Smuzhiyun buf[2] = 0x02; /* PLUG INFO */
158*4882a593Smuzhiyun buf[3] = 0xff & subfunction;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2));
161*4882a593Smuzhiyun if (err < 0)
162*4882a593Smuzhiyun ;
163*4882a593Smuzhiyun else if (err < 8)
164*4882a593Smuzhiyun err = -EIO;
165*4882a593Smuzhiyun else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
166*4882a593Smuzhiyun err = -ENOSYS;
167*4882a593Smuzhiyun else if (buf[0] == 0x0a) /* REJECTED */
168*4882a593Smuzhiyun err = -EINVAL;
169*4882a593Smuzhiyun else if (buf[0] == 0x0b) /* IN TRANSITION */
170*4882a593Smuzhiyun err = -EAGAIN;
171*4882a593Smuzhiyun if (err < 0)
172*4882a593Smuzhiyun goto end;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun info[0] = buf[4];
175*4882a593Smuzhiyun info[1] = buf[5];
176*4882a593Smuzhiyun info[2] = buf[6];
177*4882a593Smuzhiyun info[3] = buf[7];
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun err = 0;
180*4882a593Smuzhiyun end:
181*4882a593Smuzhiyun kfree(buf);
182*4882a593Smuzhiyun return err;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun EXPORT_SYMBOL(avc_general_get_plug_info);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun static DEFINE_SPINLOCK(transactions_lock);
187*4882a593Smuzhiyun static LIST_HEAD(transactions);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun enum fcp_state {
190*4882a593Smuzhiyun STATE_PENDING,
191*4882a593Smuzhiyun STATE_BUS_RESET,
192*4882a593Smuzhiyun STATE_COMPLETE,
193*4882a593Smuzhiyun STATE_DEFERRED,
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun struct fcp_transaction {
197*4882a593Smuzhiyun struct list_head list;
198*4882a593Smuzhiyun struct fw_unit *unit;
199*4882a593Smuzhiyun void *response_buffer;
200*4882a593Smuzhiyun unsigned int response_size;
201*4882a593Smuzhiyun unsigned int response_match_bytes;
202*4882a593Smuzhiyun enum fcp_state state;
203*4882a593Smuzhiyun wait_queue_head_t wait;
204*4882a593Smuzhiyun bool deferrable;
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun * fcp_avc_transaction - send an AV/C command and wait for its response
209*4882a593Smuzhiyun * @unit: a unit on the target device
210*4882a593Smuzhiyun * @command: a buffer containing the command frame; must be DMA-able
211*4882a593Smuzhiyun * @command_size: the size of @command
212*4882a593Smuzhiyun * @response: a buffer for the response frame
213*4882a593Smuzhiyun * @response_size: the maximum size of @response
214*4882a593Smuzhiyun * @response_match_bytes: a bitmap specifying the bytes used to detect the
215*4882a593Smuzhiyun * correct response frame
216*4882a593Smuzhiyun *
217*4882a593Smuzhiyun * This function sends a FCP command frame to the target and waits for the
218*4882a593Smuzhiyun * corresponding response frame to be returned.
219*4882a593Smuzhiyun *
220*4882a593Smuzhiyun * Because it is possible for multiple FCP transactions to be active at the
221*4882a593Smuzhiyun * same time, the correct response frame is detected by the value of certain
222*4882a593Smuzhiyun * bytes. These bytes must be set in @response before calling this function,
223*4882a593Smuzhiyun * and the corresponding bits must be set in @response_match_bytes.
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun * @command and @response can point to the same buffer.
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun * Returns the actual size of the response frame, or a negative error code.
228*4882a593Smuzhiyun */
fcp_avc_transaction(struct fw_unit * unit,const void * command,unsigned int command_size,void * response,unsigned int response_size,unsigned int response_match_bytes)229*4882a593Smuzhiyun int fcp_avc_transaction(struct fw_unit *unit,
230*4882a593Smuzhiyun const void *command, unsigned int command_size,
231*4882a593Smuzhiyun void *response, unsigned int response_size,
232*4882a593Smuzhiyun unsigned int response_match_bytes)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun struct fcp_transaction t;
235*4882a593Smuzhiyun int tcode, ret, tries = 0;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun t.unit = unit;
238*4882a593Smuzhiyun t.response_buffer = response;
239*4882a593Smuzhiyun t.response_size = response_size;
240*4882a593Smuzhiyun t.response_match_bytes = response_match_bytes;
241*4882a593Smuzhiyun t.state = STATE_PENDING;
242*4882a593Smuzhiyun init_waitqueue_head(&t.wait);
243*4882a593Smuzhiyun t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun spin_lock_irq(&transactions_lock);
246*4882a593Smuzhiyun list_add_tail(&t.list, &transactions);
247*4882a593Smuzhiyun spin_unlock_irq(&transactions_lock);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun for (;;) {
250*4882a593Smuzhiyun tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST
251*4882a593Smuzhiyun : TCODE_WRITE_BLOCK_REQUEST;
252*4882a593Smuzhiyun ret = snd_fw_transaction(t.unit, tcode,
253*4882a593Smuzhiyun CSR_REGISTER_BASE + CSR_FCP_COMMAND,
254*4882a593Smuzhiyun (void *)command, command_size, 0);
255*4882a593Smuzhiyun if (ret < 0)
256*4882a593Smuzhiyun break;
257*4882a593Smuzhiyun deferred:
258*4882a593Smuzhiyun wait_event_timeout(t.wait, t.state != STATE_PENDING,
259*4882a593Smuzhiyun msecs_to_jiffies(FCP_TIMEOUT_MS));
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (t.state == STATE_DEFERRED) {
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * 'AV/C General Specification' define no time limit
264*4882a593Smuzhiyun * on command completion once an INTERIM response has
265*4882a593Smuzhiyun * been sent. but we promise to finish this function
266*4882a593Smuzhiyun * for a caller. Here we use FCP_TIMEOUT_MS for next
267*4882a593Smuzhiyun * interval. This is not in the specification.
268*4882a593Smuzhiyun */
269*4882a593Smuzhiyun t.state = STATE_PENDING;
270*4882a593Smuzhiyun goto deferred;
271*4882a593Smuzhiyun } else if (t.state == STATE_COMPLETE) {
272*4882a593Smuzhiyun ret = t.response_size;
273*4882a593Smuzhiyun break;
274*4882a593Smuzhiyun } else if (t.state == STATE_BUS_RESET) {
275*4882a593Smuzhiyun msleep(ERROR_DELAY_MS);
276*4882a593Smuzhiyun } else if (++tries >= ERROR_RETRIES) {
277*4882a593Smuzhiyun dev_err(&t.unit->device, "FCP command timed out\n");
278*4882a593Smuzhiyun ret = -EIO;
279*4882a593Smuzhiyun break;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun spin_lock_irq(&transactions_lock);
284*4882a593Smuzhiyun list_del(&t.list);
285*4882a593Smuzhiyun spin_unlock_irq(&transactions_lock);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun return ret;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun EXPORT_SYMBOL(fcp_avc_transaction);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /**
292*4882a593Smuzhiyun * fcp_bus_reset - inform the target handler about a bus reset
293*4882a593Smuzhiyun * @unit: the unit that might be used by fcp_avc_transaction()
294*4882a593Smuzhiyun *
295*4882a593Smuzhiyun * This function must be called from the driver's .update handler to inform
296*4882a593Smuzhiyun * the FCP transaction handler that a bus reset has happened. Any pending FCP
297*4882a593Smuzhiyun * transactions are retried.
298*4882a593Smuzhiyun */
fcp_bus_reset(struct fw_unit * unit)299*4882a593Smuzhiyun void fcp_bus_reset(struct fw_unit *unit)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun struct fcp_transaction *t;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun spin_lock_irq(&transactions_lock);
304*4882a593Smuzhiyun list_for_each_entry(t, &transactions, list) {
305*4882a593Smuzhiyun if (t->unit == unit &&
306*4882a593Smuzhiyun (t->state == STATE_PENDING ||
307*4882a593Smuzhiyun t->state == STATE_DEFERRED)) {
308*4882a593Smuzhiyun t->state = STATE_BUS_RESET;
309*4882a593Smuzhiyun wake_up(&t->wait);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun spin_unlock_irq(&transactions_lock);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun EXPORT_SYMBOL(fcp_bus_reset);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /* checks whether the response matches the masked bytes in response_buffer */
is_matching_response(struct fcp_transaction * transaction,const void * response,size_t length)317*4882a593Smuzhiyun static bool is_matching_response(struct fcp_transaction *transaction,
318*4882a593Smuzhiyun const void *response, size_t length)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun const u8 *p1, *p2;
321*4882a593Smuzhiyun unsigned int mask, i;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun p1 = response;
324*4882a593Smuzhiyun p2 = transaction->response_buffer;
325*4882a593Smuzhiyun mask = transaction->response_match_bytes;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun for (i = 0; ; ++i) {
328*4882a593Smuzhiyun if ((mask & 1) && p1[i] != p2[i])
329*4882a593Smuzhiyun return false;
330*4882a593Smuzhiyun mask >>= 1;
331*4882a593Smuzhiyun if (!mask)
332*4882a593Smuzhiyun return true;
333*4882a593Smuzhiyun if (--length == 0)
334*4882a593Smuzhiyun return false;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
fcp_response(struct fw_card * card,struct fw_request * request,int tcode,int destination,int source,int generation,unsigned long long offset,void * data,size_t length,void * callback_data)338*4882a593Smuzhiyun static void fcp_response(struct fw_card *card, struct fw_request *request,
339*4882a593Smuzhiyun int tcode, int destination, int source,
340*4882a593Smuzhiyun int generation, unsigned long long offset,
341*4882a593Smuzhiyun void *data, size_t length, void *callback_data)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun struct fcp_transaction *t;
344*4882a593Smuzhiyun unsigned long flags;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC)
347*4882a593Smuzhiyun return;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun spin_lock_irqsave(&transactions_lock, flags);
350*4882a593Smuzhiyun list_for_each_entry(t, &transactions, list) {
351*4882a593Smuzhiyun struct fw_device *device = fw_parent_device(t->unit);
352*4882a593Smuzhiyun if (device->card != card ||
353*4882a593Smuzhiyun device->generation != generation)
354*4882a593Smuzhiyun continue;
355*4882a593Smuzhiyun smp_rmb(); /* node_id vs. generation */
356*4882a593Smuzhiyun if (device->node_id != source)
357*4882a593Smuzhiyun continue;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (t->state == STATE_PENDING &&
360*4882a593Smuzhiyun is_matching_response(t, data, length)) {
361*4882a593Smuzhiyun if (t->deferrable && *(const u8 *)data == 0x0f) {
362*4882a593Smuzhiyun t->state = STATE_DEFERRED;
363*4882a593Smuzhiyun } else {
364*4882a593Smuzhiyun t->state = STATE_COMPLETE;
365*4882a593Smuzhiyun t->response_size = min_t(unsigned int, length,
366*4882a593Smuzhiyun t->response_size);
367*4882a593Smuzhiyun memcpy(t->response_buffer, data,
368*4882a593Smuzhiyun t->response_size);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun wake_up(&t->wait);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun spin_unlock_irqrestore(&transactions_lock, flags);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun static struct fw_address_handler response_register_handler = {
377*4882a593Smuzhiyun .length = 0x200,
378*4882a593Smuzhiyun .address_callback = fcp_response,
379*4882a593Smuzhiyun };
380*4882a593Smuzhiyun
fcp_module_init(void)381*4882a593Smuzhiyun static int __init fcp_module_init(void)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun static const struct fw_address_region response_register_region = {
384*4882a593Smuzhiyun .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
385*4882a593Smuzhiyun .end = CSR_REGISTER_BASE + CSR_FCP_END,
386*4882a593Smuzhiyun };
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun fw_core_add_address_handler(&response_register_handler,
389*4882a593Smuzhiyun &response_register_region);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
fcp_module_exit(void)394*4882a593Smuzhiyun static void __exit fcp_module_exit(void)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun WARN_ON(!list_empty(&transactions));
397*4882a593Smuzhiyun fw_core_remove_address_handler(&response_register_handler);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun module_init(fcp_module_init);
401*4882a593Smuzhiyun module_exit(fcp_module_exit);
402