xref: /linux/drivers/gpu/drm/imagination/pvr_ccb.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1cc1aeedbSSarah Walker // SPDX-License-Identifier: GPL-2.0-only OR MIT
2cc1aeedbSSarah Walker /* Copyright (c) 2023 Imagination Technologies Ltd. */
3cc1aeedbSSarah Walker 
4cc1aeedbSSarah Walker #include "pvr_ccb.h"
5cc1aeedbSSarah Walker #include "pvr_device.h"
6cc1aeedbSSarah Walker #include "pvr_drv.h"
7*6eedddabSSarah Walker #include "pvr_free_list.h"
8cc1aeedbSSarah Walker #include "pvr_fw.h"
9cc1aeedbSSarah Walker #include "pvr_gem.h"
10cc1aeedbSSarah Walker #include "pvr_power.h"
11cc1aeedbSSarah Walker 
12cc1aeedbSSarah Walker #include <drm/drm_managed.h>
13cc1aeedbSSarah Walker #include <linux/compiler.h>
14cc1aeedbSSarah Walker #include <linux/delay.h>
15cc1aeedbSSarah Walker #include <linux/jiffies.h>
16cc1aeedbSSarah Walker #include <linux/kernel.h>
17cc1aeedbSSarah Walker #include <linux/mutex.h>
18cc1aeedbSSarah Walker #include <linux/types.h>
19cc1aeedbSSarah Walker #include <linux/workqueue.h>
20cc1aeedbSSarah Walker 
21cc1aeedbSSarah Walker #define RESERVE_SLOT_TIMEOUT (1 * HZ) /* 1s */
22cc1aeedbSSarah Walker #define RESERVE_SLOT_MIN_RETRIES 10
23cc1aeedbSSarah Walker 
24cc1aeedbSSarah Walker static void
ccb_ctrl_init(void * cpu_ptr,void * priv)25cc1aeedbSSarah Walker ccb_ctrl_init(void *cpu_ptr, void *priv)
26cc1aeedbSSarah Walker {
27cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = cpu_ptr;
28cc1aeedbSSarah Walker 	struct pvr_ccb *pvr_ccb = priv;
29cc1aeedbSSarah Walker 
30cc1aeedbSSarah Walker 	ctrl->write_offset = 0;
31cc1aeedbSSarah Walker 	ctrl->read_offset = 0;
32cc1aeedbSSarah Walker 	ctrl->wrap_mask = pvr_ccb->num_cmds - 1;
33cc1aeedbSSarah Walker 	ctrl->cmd_size = pvr_ccb->cmd_size;
34cc1aeedbSSarah Walker }
35cc1aeedbSSarah Walker 
36cc1aeedbSSarah Walker /**
37cc1aeedbSSarah Walker  * pvr_ccb_init() - Initialise a CCB
38cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
39cc1aeedbSSarah Walker  * @pvr_ccb: Pointer to CCB structure to initialise.
40cc1aeedbSSarah Walker  * @num_cmds_log2: Log2 of number of commands in this CCB.
41cc1aeedbSSarah Walker  * @cmd_size: Command size for this CCB.
42cc1aeedbSSarah Walker  *
43cc1aeedbSSarah Walker  * Return:
44cc1aeedbSSarah Walker  *  * Zero on success, or
45cc1aeedbSSarah Walker  *  * Any error code returned by pvr_fw_object_create_and_map().
46cc1aeedbSSarah Walker  */
47cc1aeedbSSarah Walker static int
pvr_ccb_init(struct pvr_device * pvr_dev,struct pvr_ccb * pvr_ccb,u32 num_cmds_log2,size_t cmd_size)48cc1aeedbSSarah Walker pvr_ccb_init(struct pvr_device *pvr_dev, struct pvr_ccb *pvr_ccb,
49cc1aeedbSSarah Walker 	     u32 num_cmds_log2, size_t cmd_size)
50cc1aeedbSSarah Walker {
51cc1aeedbSSarah Walker 	u32 num_cmds = 1 << num_cmds_log2;
52cc1aeedbSSarah Walker 	u32 ccb_size = num_cmds * cmd_size;
53cc1aeedbSSarah Walker 	int err;
54cc1aeedbSSarah Walker 
55cc1aeedbSSarah Walker 	pvr_ccb->num_cmds = num_cmds;
56cc1aeedbSSarah Walker 	pvr_ccb->cmd_size = cmd_size;
57cc1aeedbSSarah Walker 
58cc1aeedbSSarah Walker 	err = drmm_mutex_init(from_pvr_device(pvr_dev), &pvr_ccb->lock);
59cc1aeedbSSarah Walker 	if (err)
60cc1aeedbSSarah Walker 		return err;
61cc1aeedbSSarah Walker 
62cc1aeedbSSarah Walker 	/*
63cc1aeedbSSarah Walker 	 * Map CCB and control structure as uncached, so we don't have to flush
64cc1aeedbSSarah Walker 	 * CPU cache repeatedly when polling for space.
65cc1aeedbSSarah Walker 	 */
66cc1aeedbSSarah Walker 	pvr_ccb->ctrl = pvr_fw_object_create_and_map(pvr_dev, sizeof(*pvr_ccb->ctrl),
67cc1aeedbSSarah Walker 						     PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
68cc1aeedbSSarah Walker 						     ccb_ctrl_init, pvr_ccb, &pvr_ccb->ctrl_obj);
69cc1aeedbSSarah Walker 	if (IS_ERR(pvr_ccb->ctrl))
70cc1aeedbSSarah Walker 		return PTR_ERR(pvr_ccb->ctrl);
71cc1aeedbSSarah Walker 
72cc1aeedbSSarah Walker 	pvr_ccb->ccb = pvr_fw_object_create_and_map(pvr_dev, ccb_size,
73cc1aeedbSSarah Walker 						    PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
74cc1aeedbSSarah Walker 						    NULL, NULL, &pvr_ccb->ccb_obj);
75cc1aeedbSSarah Walker 	if (IS_ERR(pvr_ccb->ccb)) {
76cc1aeedbSSarah Walker 		err = PTR_ERR(pvr_ccb->ccb);
77cc1aeedbSSarah Walker 		goto err_free_ctrl;
78cc1aeedbSSarah Walker 	}
79cc1aeedbSSarah Walker 
80cc1aeedbSSarah Walker 	pvr_fw_object_get_fw_addr(pvr_ccb->ctrl_obj, &pvr_ccb->ctrl_fw_addr);
81cc1aeedbSSarah Walker 	pvr_fw_object_get_fw_addr(pvr_ccb->ccb_obj, &pvr_ccb->ccb_fw_addr);
82cc1aeedbSSarah Walker 
83cc1aeedbSSarah Walker 	WRITE_ONCE(pvr_ccb->ctrl->write_offset, 0);
84cc1aeedbSSarah Walker 	WRITE_ONCE(pvr_ccb->ctrl->read_offset, 0);
85cc1aeedbSSarah Walker 	WRITE_ONCE(pvr_ccb->ctrl->wrap_mask, num_cmds - 1);
86cc1aeedbSSarah Walker 	WRITE_ONCE(pvr_ccb->ctrl->cmd_size, cmd_size);
87cc1aeedbSSarah Walker 
88cc1aeedbSSarah Walker 	return 0;
89cc1aeedbSSarah Walker 
90cc1aeedbSSarah Walker err_free_ctrl:
91cc1aeedbSSarah Walker 	pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj);
92cc1aeedbSSarah Walker 
93cc1aeedbSSarah Walker 	return err;
94cc1aeedbSSarah Walker }
95cc1aeedbSSarah Walker 
96cc1aeedbSSarah Walker /**
97cc1aeedbSSarah Walker  * pvr_ccb_fini() - Release CCB structure
98cc1aeedbSSarah Walker  * @pvr_ccb: CCB to release.
99cc1aeedbSSarah Walker  */
100cc1aeedbSSarah Walker void
pvr_ccb_fini(struct pvr_ccb * pvr_ccb)101cc1aeedbSSarah Walker pvr_ccb_fini(struct pvr_ccb *pvr_ccb)
102cc1aeedbSSarah Walker {
103cc1aeedbSSarah Walker 	pvr_fw_object_unmap_and_destroy(pvr_ccb->ccb_obj);
104cc1aeedbSSarah Walker 	pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj);
105cc1aeedbSSarah Walker }
106cc1aeedbSSarah Walker 
107cc1aeedbSSarah Walker /**
108cc1aeedbSSarah Walker  * pvr_ccb_slot_available_locked() - Test whether any slots are available in CCB
109cc1aeedbSSarah Walker  * @pvr_ccb: CCB to test.
110cc1aeedbSSarah Walker  * @write_offset: Address to store number of next available slot. May be %NULL.
111cc1aeedbSSarah Walker  *
112cc1aeedbSSarah Walker  * Caller must hold @pvr_ccb->lock.
113cc1aeedbSSarah Walker  *
114cc1aeedbSSarah Walker  * Return:
115cc1aeedbSSarah Walker  *  * %true if a slot is available, or
116cc1aeedbSSarah Walker  *  * %false if no slot is available.
117cc1aeedbSSarah Walker  */
118cc1aeedbSSarah Walker static __always_inline bool
pvr_ccb_slot_available_locked(struct pvr_ccb * pvr_ccb,u32 * write_offset)119cc1aeedbSSarah Walker pvr_ccb_slot_available_locked(struct pvr_ccb *pvr_ccb, u32 *write_offset)
120cc1aeedbSSarah Walker {
121cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl;
122cc1aeedbSSarah Walker 	u32 next_write_offset = (READ_ONCE(ctrl->write_offset) + 1) & READ_ONCE(ctrl->wrap_mask);
123cc1aeedbSSarah Walker 
124cc1aeedbSSarah Walker 	lockdep_assert_held(&pvr_ccb->lock);
125cc1aeedbSSarah Walker 
126cc1aeedbSSarah Walker 	if (READ_ONCE(ctrl->read_offset) != next_write_offset) {
127cc1aeedbSSarah Walker 		if (write_offset)
128cc1aeedbSSarah Walker 			*write_offset = next_write_offset;
129cc1aeedbSSarah Walker 		return true;
130cc1aeedbSSarah Walker 	}
131cc1aeedbSSarah Walker 
132cc1aeedbSSarah Walker 	return false;
133cc1aeedbSSarah Walker }
134cc1aeedbSSarah Walker 
135cc1aeedbSSarah Walker static void
process_fwccb_command(struct pvr_device * pvr_dev,struct rogue_fwif_fwccb_cmd * cmd)136cc1aeedbSSarah Walker process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *cmd)
137cc1aeedbSSarah Walker {
138cc1aeedbSSarah Walker 	switch (cmd->cmd_type) {
139cc1aeedbSSarah Walker 	case ROGUE_FWIF_FWCCB_CMD_REQUEST_GPU_RESTART:
140cc1aeedbSSarah Walker 		pvr_power_reset(pvr_dev, false);
141cc1aeedbSSarah Walker 		break;
142cc1aeedbSSarah Walker 
143*6eedddabSSarah Walker 	case ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION:
144*6eedddabSSarah Walker 		pvr_free_list_process_reconstruct_req(pvr_dev,
145*6eedddabSSarah Walker 						      &cmd->cmd_data.cmd_freelists_reconstruction);
146*6eedddabSSarah Walker 		break;
147*6eedddabSSarah Walker 
148*6eedddabSSarah Walker 	case ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW:
149*6eedddabSSarah Walker 		pvr_free_list_process_grow_req(pvr_dev, &cmd->cmd_data.cmd_free_list_gs);
150*6eedddabSSarah Walker 		break;
151*6eedddabSSarah Walker 
152cc1aeedbSSarah Walker 	default:
153cc1aeedbSSarah Walker 		drm_info(from_pvr_device(pvr_dev), "Received unknown FWCCB command %x\n",
154cc1aeedbSSarah Walker 			 cmd->cmd_type);
155cc1aeedbSSarah Walker 		break;
156cc1aeedbSSarah Walker 	}
157cc1aeedbSSarah Walker }
158cc1aeedbSSarah Walker 
159cc1aeedbSSarah Walker /**
160cc1aeedbSSarah Walker  * pvr_fwccb_process() - Process any pending FWCCB commands
161cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
162cc1aeedbSSarah Walker  */
pvr_fwccb_process(struct pvr_device * pvr_dev)163cc1aeedbSSarah Walker void pvr_fwccb_process(struct pvr_device *pvr_dev)
164cc1aeedbSSarah Walker {
165cc1aeedbSSarah Walker 	struct rogue_fwif_fwccb_cmd *fwccb = pvr_dev->fwccb.ccb;
166cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->fwccb.ctrl;
167cc1aeedbSSarah Walker 	u32 read_offset;
168cc1aeedbSSarah Walker 
169cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->fwccb.lock);
170cc1aeedbSSarah Walker 
171cc1aeedbSSarah Walker 	while ((read_offset = READ_ONCE(ctrl->read_offset)) != READ_ONCE(ctrl->write_offset)) {
172cc1aeedbSSarah Walker 		struct rogue_fwif_fwccb_cmd cmd = fwccb[read_offset];
173cc1aeedbSSarah Walker 
174cc1aeedbSSarah Walker 		WRITE_ONCE(ctrl->read_offset, (read_offset + 1) & READ_ONCE(ctrl->wrap_mask));
175cc1aeedbSSarah Walker 
176cc1aeedbSSarah Walker 		/* Drop FWCCB lock while we process command. */
177cc1aeedbSSarah Walker 		mutex_unlock(&pvr_dev->fwccb.lock);
178cc1aeedbSSarah Walker 
179cc1aeedbSSarah Walker 		process_fwccb_command(pvr_dev, &cmd);
180cc1aeedbSSarah Walker 
181cc1aeedbSSarah Walker 		mutex_lock(&pvr_dev->fwccb.lock);
182cc1aeedbSSarah Walker 	}
183cc1aeedbSSarah Walker 
184cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->fwccb.lock);
185cc1aeedbSSarah Walker }
186cc1aeedbSSarah Walker 
187cc1aeedbSSarah Walker /**
188cc1aeedbSSarah Walker  * pvr_kccb_capacity() - Returns the maximum number of usable KCCB slots.
189cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
190cc1aeedbSSarah Walker  *
191cc1aeedbSSarah Walker  * Return:
192cc1aeedbSSarah Walker  *  * The maximum number of active slots.
193cc1aeedbSSarah Walker  */
pvr_kccb_capacity(struct pvr_device * pvr_dev)194cc1aeedbSSarah Walker static u32 pvr_kccb_capacity(struct pvr_device *pvr_dev)
195cc1aeedbSSarah Walker {
196cc1aeedbSSarah Walker 	/* Capacity is the number of slot minus one to cope with the wrapping
197cc1aeedbSSarah Walker 	 * mechanisms. If we were to use all slots, we might end up with
198cc1aeedbSSarah Walker 	 * read_offset == write_offset, which the FW considers as a KCCB-is-empty
199cc1aeedbSSarah Walker 	 * condition.
200cc1aeedbSSarah Walker 	 */
201cc1aeedbSSarah Walker 	return pvr_dev->kccb.slot_count - 1;
202cc1aeedbSSarah Walker }
203cc1aeedbSSarah Walker 
204cc1aeedbSSarah Walker /**
205cc1aeedbSSarah Walker  * pvr_kccb_used_slot_count_locked() - Get the number of used slots
206cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
207cc1aeedbSSarah Walker  *
208cc1aeedbSSarah Walker  * KCCB lock must be held.
209cc1aeedbSSarah Walker  *
210cc1aeedbSSarah Walker  * Return:
211cc1aeedbSSarah Walker  *  * The number of slots currently used.
212cc1aeedbSSarah Walker  */
213cc1aeedbSSarah Walker static u32
pvr_kccb_used_slot_count_locked(struct pvr_device * pvr_dev)214cc1aeedbSSarah Walker pvr_kccb_used_slot_count_locked(struct pvr_device *pvr_dev)
215cc1aeedbSSarah Walker {
216cc1aeedbSSarah Walker 	struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb;
217cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl;
218cc1aeedbSSarah Walker 	u32 wr_offset = READ_ONCE(ctrl->write_offset);
219cc1aeedbSSarah Walker 	u32 rd_offset = READ_ONCE(ctrl->read_offset);
220cc1aeedbSSarah Walker 	u32 used_count;
221cc1aeedbSSarah Walker 
222cc1aeedbSSarah Walker 	lockdep_assert_held(&pvr_ccb->lock);
223cc1aeedbSSarah Walker 
224cc1aeedbSSarah Walker 	if (wr_offset >= rd_offset)
225cc1aeedbSSarah Walker 		used_count = wr_offset - rd_offset;
226cc1aeedbSSarah Walker 	else
227cc1aeedbSSarah Walker 		used_count = wr_offset + pvr_dev->kccb.slot_count - rd_offset;
228cc1aeedbSSarah Walker 
229cc1aeedbSSarah Walker 	return used_count;
230cc1aeedbSSarah Walker }
231cc1aeedbSSarah Walker 
232cc1aeedbSSarah Walker /**
233cc1aeedbSSarah Walker  * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref
234cc1aeedbSSarah Walker  * held and a slot pre-reserved
235cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
236cc1aeedbSSarah Walker  * @cmd: Command to sent.
237cc1aeedbSSarah Walker  * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
238cc1aeedbSSarah Walker  */
239cc1aeedbSSarah Walker void
pvr_kccb_send_cmd_reserved_powered(struct pvr_device * pvr_dev,struct rogue_fwif_kccb_cmd * cmd,u32 * kccb_slot)240cc1aeedbSSarah Walker pvr_kccb_send_cmd_reserved_powered(struct pvr_device *pvr_dev,
241cc1aeedbSSarah Walker 				   struct rogue_fwif_kccb_cmd *cmd,
242cc1aeedbSSarah Walker 				   u32 *kccb_slot)
243cc1aeedbSSarah Walker {
244cc1aeedbSSarah Walker 	struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb;
245cc1aeedbSSarah Walker 	struct rogue_fwif_kccb_cmd *kccb = pvr_ccb->ccb;
246cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl;
247cc1aeedbSSarah Walker 	u32 old_write_offset;
248cc1aeedbSSarah Walker 	u32 new_write_offset;
249cc1aeedbSSarah Walker 
250cc1aeedbSSarah Walker 	WARN_ON(pvr_dev->lost);
251cc1aeedbSSarah Walker 
252cc1aeedbSSarah Walker 	mutex_lock(&pvr_ccb->lock);
253cc1aeedbSSarah Walker 
254cc1aeedbSSarah Walker 	if (WARN_ON(!pvr_dev->kccb.reserved_count))
255cc1aeedbSSarah Walker 		goto out_unlock;
256cc1aeedbSSarah Walker 
257cc1aeedbSSarah Walker 	old_write_offset = READ_ONCE(ctrl->write_offset);
258cc1aeedbSSarah Walker 
259cc1aeedbSSarah Walker 	/* We reserved the slot, we should have one available. */
260cc1aeedbSSarah Walker 	if (WARN_ON(!pvr_ccb_slot_available_locked(pvr_ccb, &new_write_offset)))
261cc1aeedbSSarah Walker 		goto out_unlock;
262cc1aeedbSSarah Walker 
263cc1aeedbSSarah Walker 	memcpy(&kccb[old_write_offset], cmd,
264cc1aeedbSSarah Walker 	       sizeof(struct rogue_fwif_kccb_cmd));
265cc1aeedbSSarah Walker 	if (kccb_slot) {
266cc1aeedbSSarah Walker 		*kccb_slot = old_write_offset;
267cc1aeedbSSarah Walker 		/* Clear return status for this slot. */
268cc1aeedbSSarah Walker 		WRITE_ONCE(pvr_dev->kccb.rtn[old_write_offset],
269cc1aeedbSSarah Walker 			   ROGUE_FWIF_KCCB_RTN_SLOT_NO_RESPONSE);
270cc1aeedbSSarah Walker 	}
271cc1aeedbSSarah Walker 	mb(); /* memory barrier */
272cc1aeedbSSarah Walker 	WRITE_ONCE(ctrl->write_offset, new_write_offset);
273cc1aeedbSSarah Walker 	pvr_dev->kccb.reserved_count--;
274cc1aeedbSSarah Walker 
275cc1aeedbSSarah Walker 	/* Kick MTS */
276cc1aeedbSSarah Walker 	pvr_fw_mts_schedule(pvr_dev,
277cc1aeedbSSarah Walker 			    PVR_FWIF_DM_GP & ~ROGUE_CR_MTS_SCHEDULE_DM_CLRMSK);
278cc1aeedbSSarah Walker 
279cc1aeedbSSarah Walker out_unlock:
280cc1aeedbSSarah Walker 	mutex_unlock(&pvr_ccb->lock);
281cc1aeedbSSarah Walker }
282cc1aeedbSSarah Walker 
283cc1aeedbSSarah Walker /**
284cc1aeedbSSarah Walker  * pvr_kccb_try_reserve_slot() - Try to reserve a KCCB slot
285cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
286cc1aeedbSSarah Walker  *
287cc1aeedbSSarah Walker  * Return:
288cc1aeedbSSarah Walker  *  * true if a KCCB slot was reserved, or
289cc1aeedbSSarah Walker  *  * false otherwise.
290cc1aeedbSSarah Walker  */
pvr_kccb_try_reserve_slot(struct pvr_device * pvr_dev)291cc1aeedbSSarah Walker static bool pvr_kccb_try_reserve_slot(struct pvr_device *pvr_dev)
292cc1aeedbSSarah Walker {
293cc1aeedbSSarah Walker 	bool reserved = false;
294cc1aeedbSSarah Walker 	u32 used_count;
295cc1aeedbSSarah Walker 
296cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->kccb.ccb.lock);
297cc1aeedbSSarah Walker 
298cc1aeedbSSarah Walker 	used_count = pvr_kccb_used_slot_count_locked(pvr_dev);
299cc1aeedbSSarah Walker 	if (pvr_dev->kccb.reserved_count < pvr_kccb_capacity(pvr_dev) - used_count) {
300cc1aeedbSSarah Walker 		pvr_dev->kccb.reserved_count++;
301cc1aeedbSSarah Walker 		reserved = true;
302cc1aeedbSSarah Walker 	}
303cc1aeedbSSarah Walker 
304cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->kccb.ccb.lock);
305cc1aeedbSSarah Walker 
306cc1aeedbSSarah Walker 	return reserved;
307cc1aeedbSSarah Walker }
308cc1aeedbSSarah Walker 
309cc1aeedbSSarah Walker /**
310cc1aeedbSSarah Walker  * pvr_kccb_reserve_slot_sync() - Try to reserve a slot synchronously
311cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
312cc1aeedbSSarah Walker  *
313cc1aeedbSSarah Walker  * Return:
314cc1aeedbSSarah Walker  *  * 0 on success, or
315cc1aeedbSSarah Walker  *  * -EBUSY if no slots were reserved after %RESERVE_SLOT_TIMEOUT, with a minimum of
316cc1aeedbSSarah Walker  *    %RESERVE_SLOT_MIN_RETRIES retries.
317cc1aeedbSSarah Walker  */
pvr_kccb_reserve_slot_sync(struct pvr_device * pvr_dev)318cc1aeedbSSarah Walker static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev)
319cc1aeedbSSarah Walker {
320cc1aeedbSSarah Walker 	unsigned long start_timestamp = jiffies;
321cc1aeedbSSarah Walker 	bool reserved = false;
322cc1aeedbSSarah Walker 	u32 retries = 0;
323cc1aeedbSSarah Walker 
324cc1aeedbSSarah Walker 	while ((jiffies - start_timestamp) < (u32)RESERVE_SLOT_TIMEOUT ||
325cc1aeedbSSarah Walker 	       retries < RESERVE_SLOT_MIN_RETRIES) {
326cc1aeedbSSarah Walker 		reserved = pvr_kccb_try_reserve_slot(pvr_dev);
327cc1aeedbSSarah Walker 		if (reserved)
328cc1aeedbSSarah Walker 			break;
329cc1aeedbSSarah Walker 
330cc1aeedbSSarah Walker 		usleep_range(1, 50);
331cc1aeedbSSarah Walker 
332cc1aeedbSSarah Walker 		if (retries < U32_MAX)
333cc1aeedbSSarah Walker 			retries++;
334cc1aeedbSSarah Walker 	}
335cc1aeedbSSarah Walker 
336cc1aeedbSSarah Walker 	return reserved ? 0 : -EBUSY;
337cc1aeedbSSarah Walker }
338cc1aeedbSSarah Walker 
339cc1aeedbSSarah Walker /**
340cc1aeedbSSarah Walker  * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held
341cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
342cc1aeedbSSarah Walker  * @cmd: Command to sent.
343cc1aeedbSSarah Walker  * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
344cc1aeedbSSarah Walker  *
345cc1aeedbSSarah Walker  * Returns:
346cc1aeedbSSarah Walker  *  * Zero on success, or
347cc1aeedbSSarah Walker  *  * -EBUSY if timeout while waiting for a free KCCB slot.
348cc1aeedbSSarah Walker  */
349cc1aeedbSSarah Walker int
pvr_kccb_send_cmd_powered(struct pvr_device * pvr_dev,struct rogue_fwif_kccb_cmd * cmd,u32 * kccb_slot)350cc1aeedbSSarah Walker pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd,
351cc1aeedbSSarah Walker 			  u32 *kccb_slot)
352cc1aeedbSSarah Walker {
353cc1aeedbSSarah Walker 	int err;
354cc1aeedbSSarah Walker 
355cc1aeedbSSarah Walker 	err = pvr_kccb_reserve_slot_sync(pvr_dev);
356cc1aeedbSSarah Walker 	if (err)
357cc1aeedbSSarah Walker 		return err;
358cc1aeedbSSarah Walker 
359cc1aeedbSSarah Walker 	pvr_kccb_send_cmd_reserved_powered(pvr_dev, cmd, kccb_slot);
360cc1aeedbSSarah Walker 	return 0;
361cc1aeedbSSarah Walker }
362cc1aeedbSSarah Walker 
363cc1aeedbSSarah Walker /**
364cc1aeedbSSarah Walker  * pvr_kccb_send_cmd() - Send command to the KCCB
365cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
366cc1aeedbSSarah Walker  * @cmd: Command to sent.
367cc1aeedbSSarah Walker  * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
368cc1aeedbSSarah Walker  *
369cc1aeedbSSarah Walker  * Returns:
370cc1aeedbSSarah Walker  *  * Zero on success, or
371cc1aeedbSSarah Walker  *  * -EBUSY if timeout while waiting for a free KCCB slot.
372cc1aeedbSSarah Walker  */
373cc1aeedbSSarah Walker int
pvr_kccb_send_cmd(struct pvr_device * pvr_dev,struct rogue_fwif_kccb_cmd * cmd,u32 * kccb_slot)374cc1aeedbSSarah Walker pvr_kccb_send_cmd(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd,
375cc1aeedbSSarah Walker 		  u32 *kccb_slot)
376cc1aeedbSSarah Walker {
377cc1aeedbSSarah Walker 	int err;
378cc1aeedbSSarah Walker 
379cc1aeedbSSarah Walker 	err = pvr_power_get(pvr_dev);
380cc1aeedbSSarah Walker 	if (err)
381cc1aeedbSSarah Walker 		return err;
382cc1aeedbSSarah Walker 
383cc1aeedbSSarah Walker 	err = pvr_kccb_send_cmd_powered(pvr_dev, cmd, kccb_slot);
384cc1aeedbSSarah Walker 
385cc1aeedbSSarah Walker 	pvr_power_put(pvr_dev);
386cc1aeedbSSarah Walker 
387cc1aeedbSSarah Walker 	return err;
388cc1aeedbSSarah Walker }
389cc1aeedbSSarah Walker 
390cc1aeedbSSarah Walker /**
391cc1aeedbSSarah Walker  * pvr_kccb_wait_for_completion() - Wait for a KCCB command to complete
392cc1aeedbSSarah Walker  * @pvr_dev: Device pointer.
393cc1aeedbSSarah Walker  * @slot_nr: KCCB slot to wait on.
394cc1aeedbSSarah Walker  * @timeout: Timeout length (in jiffies).
395cc1aeedbSSarah Walker  * @rtn_out: Location to store KCCB command result. May be %NULL.
396cc1aeedbSSarah Walker  *
397cc1aeedbSSarah Walker  * Returns:
398cc1aeedbSSarah Walker  *  * Zero on success, or
399cc1aeedbSSarah Walker  *  * -ETIMEDOUT on timeout.
400cc1aeedbSSarah Walker  */
401cc1aeedbSSarah Walker int
pvr_kccb_wait_for_completion(struct pvr_device * pvr_dev,u32 slot_nr,u32 timeout,u32 * rtn_out)402cc1aeedbSSarah Walker pvr_kccb_wait_for_completion(struct pvr_device *pvr_dev, u32 slot_nr,
403cc1aeedbSSarah Walker 			     u32 timeout, u32 *rtn_out)
404cc1aeedbSSarah Walker {
405cc1aeedbSSarah Walker 	int ret = wait_event_timeout(pvr_dev->kccb.rtn_q, READ_ONCE(pvr_dev->kccb.rtn[slot_nr]) &
406cc1aeedbSSarah Walker 				     ROGUE_FWIF_KCCB_RTN_SLOT_CMD_EXECUTED, timeout);
407cc1aeedbSSarah Walker 
408cc1aeedbSSarah Walker 	if (ret && rtn_out)
409cc1aeedbSSarah Walker 		*rtn_out = READ_ONCE(pvr_dev->kccb.rtn[slot_nr]);
410cc1aeedbSSarah Walker 
411cc1aeedbSSarah Walker 	return ret ? 0 : -ETIMEDOUT;
412cc1aeedbSSarah Walker }
413cc1aeedbSSarah Walker 
414cc1aeedbSSarah Walker /**
415cc1aeedbSSarah Walker  * pvr_kccb_is_idle() - Returns whether the device's KCCB is idle
416cc1aeedbSSarah Walker  * @pvr_dev: Device pointer
417cc1aeedbSSarah Walker  *
418cc1aeedbSSarah Walker  * Returns:
419cc1aeedbSSarah Walker  *  * %true if the KCCB is idle (contains no commands), or
420cc1aeedbSSarah Walker  *  * %false if the KCCB contains pending commands.
421cc1aeedbSSarah Walker  */
422cc1aeedbSSarah Walker bool
pvr_kccb_is_idle(struct pvr_device * pvr_dev)423cc1aeedbSSarah Walker pvr_kccb_is_idle(struct pvr_device *pvr_dev)
424cc1aeedbSSarah Walker {
425cc1aeedbSSarah Walker 	struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->kccb.ccb.ctrl;
426cc1aeedbSSarah Walker 	bool idle;
427cc1aeedbSSarah Walker 
428cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->kccb.ccb.lock);
429cc1aeedbSSarah Walker 
430cc1aeedbSSarah Walker 	idle = (READ_ONCE(ctrl->write_offset) == READ_ONCE(ctrl->read_offset));
431cc1aeedbSSarah Walker 
432cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->kccb.ccb.lock);
433cc1aeedbSSarah Walker 
434cc1aeedbSSarah Walker 	return idle;
435cc1aeedbSSarah Walker }
436cc1aeedbSSarah Walker 
437cc1aeedbSSarah Walker static const char *
pvr_kccb_fence_get_driver_name(struct dma_fence * f)438cc1aeedbSSarah Walker pvr_kccb_fence_get_driver_name(struct dma_fence *f)
439cc1aeedbSSarah Walker {
440cc1aeedbSSarah Walker 	return PVR_DRIVER_NAME;
441cc1aeedbSSarah Walker }
442cc1aeedbSSarah Walker 
443cc1aeedbSSarah Walker static const char *
pvr_kccb_fence_get_timeline_name(struct dma_fence * f)444cc1aeedbSSarah Walker pvr_kccb_fence_get_timeline_name(struct dma_fence *f)
445cc1aeedbSSarah Walker {
446cc1aeedbSSarah Walker 	return "kccb";
447cc1aeedbSSarah Walker }
448cc1aeedbSSarah Walker 
449cc1aeedbSSarah Walker static const struct dma_fence_ops pvr_kccb_fence_ops = {
450cc1aeedbSSarah Walker 	.get_driver_name = pvr_kccb_fence_get_driver_name,
451cc1aeedbSSarah Walker 	.get_timeline_name = pvr_kccb_fence_get_timeline_name,
452cc1aeedbSSarah Walker };
453cc1aeedbSSarah Walker 
454cc1aeedbSSarah Walker /**
455cc1aeedbSSarah Walker  * struct pvr_kccb_fence - Fence object used to wait for a KCCB slot
456cc1aeedbSSarah Walker  */
457cc1aeedbSSarah Walker struct pvr_kccb_fence {
458cc1aeedbSSarah Walker 	/** @base: Base dma_fence object. */
459cc1aeedbSSarah Walker 	struct dma_fence base;
460cc1aeedbSSarah Walker 
461cc1aeedbSSarah Walker 	/** @node: Node used to insert the fence in the pvr_device::kccb::waiters list. */
462cc1aeedbSSarah Walker 	struct list_head node;
463cc1aeedbSSarah Walker };
464cc1aeedbSSarah Walker 
465cc1aeedbSSarah Walker /**
466cc1aeedbSSarah Walker  * pvr_kccb_wake_up_waiters() - Check the KCCB waiters
467cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
468cc1aeedbSSarah Walker  *
469cc1aeedbSSarah Walker  * Signal as many KCCB fences as we have slots available.
470cc1aeedbSSarah Walker  */
pvr_kccb_wake_up_waiters(struct pvr_device * pvr_dev)471cc1aeedbSSarah Walker void pvr_kccb_wake_up_waiters(struct pvr_device *pvr_dev)
472cc1aeedbSSarah Walker {
473cc1aeedbSSarah Walker 	struct pvr_kccb_fence *fence, *tmp_fence;
474cc1aeedbSSarah Walker 	u32 used_count, available_count;
475cc1aeedbSSarah Walker 
476cc1aeedbSSarah Walker 	/* Wake up those waiting for KCCB slot execution. */
477cc1aeedbSSarah Walker 	wake_up_all(&pvr_dev->kccb.rtn_q);
478cc1aeedbSSarah Walker 
479cc1aeedbSSarah Walker 	/* Then iterate over all KCCB fences and signal as many as we can. */
480cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->kccb.ccb.lock);
481cc1aeedbSSarah Walker 	used_count = pvr_kccb_used_slot_count_locked(pvr_dev);
482cc1aeedbSSarah Walker 
483cc1aeedbSSarah Walker 	if (WARN_ON(used_count + pvr_dev->kccb.reserved_count > pvr_kccb_capacity(pvr_dev)))
484cc1aeedbSSarah Walker 		goto out_unlock;
485cc1aeedbSSarah Walker 
486cc1aeedbSSarah Walker 	available_count = pvr_kccb_capacity(pvr_dev) - used_count - pvr_dev->kccb.reserved_count;
487cc1aeedbSSarah Walker 	list_for_each_entry_safe(fence, tmp_fence, &pvr_dev->kccb.waiters, node) {
488cc1aeedbSSarah Walker 		if (!available_count)
489cc1aeedbSSarah Walker 			break;
490cc1aeedbSSarah Walker 
491cc1aeedbSSarah Walker 		list_del(&fence->node);
492cc1aeedbSSarah Walker 		pvr_dev->kccb.reserved_count++;
493cc1aeedbSSarah Walker 		available_count--;
494cc1aeedbSSarah Walker 		dma_fence_signal(&fence->base);
495cc1aeedbSSarah Walker 		dma_fence_put(&fence->base);
496cc1aeedbSSarah Walker 	}
497cc1aeedbSSarah Walker 
498cc1aeedbSSarah Walker out_unlock:
499cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->kccb.ccb.lock);
500cc1aeedbSSarah Walker }
501cc1aeedbSSarah Walker 
502cc1aeedbSSarah Walker /**
503cc1aeedbSSarah Walker  * pvr_kccb_fini() - Cleanup device KCCB
504cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
505cc1aeedbSSarah Walker  */
pvr_kccb_fini(struct pvr_device * pvr_dev)506cc1aeedbSSarah Walker void pvr_kccb_fini(struct pvr_device *pvr_dev)
507cc1aeedbSSarah Walker {
508cc1aeedbSSarah Walker 	pvr_ccb_fini(&pvr_dev->kccb.ccb);
509cc1aeedbSSarah Walker 	WARN_ON(!list_empty(&pvr_dev->kccb.waiters));
510cc1aeedbSSarah Walker 	WARN_ON(pvr_dev->kccb.reserved_count);
511cc1aeedbSSarah Walker }
512cc1aeedbSSarah Walker 
513cc1aeedbSSarah Walker /**
514cc1aeedbSSarah Walker  * pvr_kccb_init() - Initialise device KCCB
515cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
516cc1aeedbSSarah Walker  *
517cc1aeedbSSarah Walker  * Returns:
518cc1aeedbSSarah Walker  *  * 0 on success, or
519cc1aeedbSSarah Walker  *  * Any error returned by pvr_ccb_init().
520cc1aeedbSSarah Walker  */
521cc1aeedbSSarah Walker int
pvr_kccb_init(struct pvr_device * pvr_dev)522cc1aeedbSSarah Walker pvr_kccb_init(struct pvr_device *pvr_dev)
523cc1aeedbSSarah Walker {
524cc1aeedbSSarah Walker 	pvr_dev->kccb.slot_count = 1 << ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT;
525cc1aeedbSSarah Walker 	INIT_LIST_HEAD(&pvr_dev->kccb.waiters);
526cc1aeedbSSarah Walker 	pvr_dev->kccb.fence_ctx.id = dma_fence_context_alloc(1);
527cc1aeedbSSarah Walker 	spin_lock_init(&pvr_dev->kccb.fence_ctx.lock);
528cc1aeedbSSarah Walker 
529cc1aeedbSSarah Walker 	return pvr_ccb_init(pvr_dev, &pvr_dev->kccb.ccb,
530cc1aeedbSSarah Walker 			    ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT,
531cc1aeedbSSarah Walker 			    sizeof(struct rogue_fwif_kccb_cmd));
532cc1aeedbSSarah Walker }
533cc1aeedbSSarah Walker 
534cc1aeedbSSarah Walker /**
535cc1aeedbSSarah Walker  * pvr_kccb_fence_alloc() - Allocate a pvr_kccb_fence object
536cc1aeedbSSarah Walker  *
537cc1aeedbSSarah Walker  * Return:
538cc1aeedbSSarah Walker  *  * NULL if the allocation fails, or
539cc1aeedbSSarah Walker  *  * A valid dma_fence pointer otherwise.
540cc1aeedbSSarah Walker  */
pvr_kccb_fence_alloc(void)541cc1aeedbSSarah Walker struct dma_fence *pvr_kccb_fence_alloc(void)
542cc1aeedbSSarah Walker {
543cc1aeedbSSarah Walker 	struct pvr_kccb_fence *kccb_fence;
544cc1aeedbSSarah Walker 
545cc1aeedbSSarah Walker 	kccb_fence = kzalloc(sizeof(*kccb_fence), GFP_KERNEL);
546cc1aeedbSSarah Walker 	if (!kccb_fence)
547cc1aeedbSSarah Walker 		return NULL;
548cc1aeedbSSarah Walker 
549cc1aeedbSSarah Walker 	return &kccb_fence->base;
550cc1aeedbSSarah Walker }
551cc1aeedbSSarah Walker 
552cc1aeedbSSarah Walker /**
553cc1aeedbSSarah Walker  * pvr_kccb_fence_put() - Drop a KCCB fence reference
554cc1aeedbSSarah Walker  * @fence: The fence to drop the reference on.
555cc1aeedbSSarah Walker  *
556cc1aeedbSSarah Walker  * If the fence hasn't been initialized yet, dma_fence_free() is called. This
557cc1aeedbSSarah Walker  * way we have a single function taking care of both cases.
558cc1aeedbSSarah Walker  */
pvr_kccb_fence_put(struct dma_fence * fence)559cc1aeedbSSarah Walker void pvr_kccb_fence_put(struct dma_fence *fence)
560cc1aeedbSSarah Walker {
561cc1aeedbSSarah Walker 	if (!fence)
562cc1aeedbSSarah Walker 		return;
563cc1aeedbSSarah Walker 
564cc1aeedbSSarah Walker 	if (!fence->ops) {
565cc1aeedbSSarah Walker 		dma_fence_free(fence);
566cc1aeedbSSarah Walker 	} else {
567cc1aeedbSSarah Walker 		WARN_ON(fence->ops != &pvr_kccb_fence_ops);
568cc1aeedbSSarah Walker 		dma_fence_put(fence);
569cc1aeedbSSarah Walker 	}
570cc1aeedbSSarah Walker }
571cc1aeedbSSarah Walker 
572cc1aeedbSSarah Walker /**
573cc1aeedbSSarah Walker  * pvr_kccb_reserve_slot() - Reserve a KCCB slot for later use
574cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
575cc1aeedbSSarah Walker  * @f: KCCB fence object previously allocated with pvr_kccb_fence_alloc()
576cc1aeedbSSarah Walker  *
577cc1aeedbSSarah Walker  * Try to reserve a KCCB slot, and if there's no slot available,
578cc1aeedbSSarah Walker  * initializes the fence object and queue it to the waiters list.
579cc1aeedbSSarah Walker  *
580cc1aeedbSSarah Walker  * If NULL is returned, that means the slot is reserved. In that case,
581cc1aeedbSSarah Walker  * the @f is freed and shouldn't be accessed after that point.
582cc1aeedbSSarah Walker  *
583cc1aeedbSSarah Walker  * Return:
584cc1aeedbSSarah Walker  *  * NULL if a slot was available directly, or
585cc1aeedbSSarah Walker  *  * A valid dma_fence object to wait on if no slot was available.
586cc1aeedbSSarah Walker  */
587cc1aeedbSSarah Walker struct dma_fence *
pvr_kccb_reserve_slot(struct pvr_device * pvr_dev,struct dma_fence * f)588cc1aeedbSSarah Walker pvr_kccb_reserve_slot(struct pvr_device *pvr_dev, struct dma_fence *f)
589cc1aeedbSSarah Walker {
590cc1aeedbSSarah Walker 	struct pvr_kccb_fence *fence = container_of(f, struct pvr_kccb_fence, base);
591cc1aeedbSSarah Walker 	struct dma_fence *out_fence = NULL;
592cc1aeedbSSarah Walker 	u32 used_count;
593cc1aeedbSSarah Walker 
594cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->kccb.ccb.lock);
595cc1aeedbSSarah Walker 
596cc1aeedbSSarah Walker 	used_count = pvr_kccb_used_slot_count_locked(pvr_dev);
597cc1aeedbSSarah Walker 	if (pvr_dev->kccb.reserved_count >= pvr_kccb_capacity(pvr_dev) - used_count) {
598cc1aeedbSSarah Walker 		dma_fence_init(&fence->base, &pvr_kccb_fence_ops,
599cc1aeedbSSarah Walker 			       &pvr_dev->kccb.fence_ctx.lock,
600cc1aeedbSSarah Walker 			       pvr_dev->kccb.fence_ctx.id,
601cc1aeedbSSarah Walker 			       atomic_inc_return(&pvr_dev->kccb.fence_ctx.seqno));
602cc1aeedbSSarah Walker 		out_fence = dma_fence_get(&fence->base);
603cc1aeedbSSarah Walker 		list_add_tail(&fence->node, &pvr_dev->kccb.waiters);
604cc1aeedbSSarah Walker 	} else {
605cc1aeedbSSarah Walker 		pvr_kccb_fence_put(f);
606cc1aeedbSSarah Walker 		pvr_dev->kccb.reserved_count++;
607cc1aeedbSSarah Walker 	}
608cc1aeedbSSarah Walker 
609cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->kccb.ccb.lock);
610cc1aeedbSSarah Walker 
611cc1aeedbSSarah Walker 	return out_fence;
612cc1aeedbSSarah Walker }
613cc1aeedbSSarah Walker 
614cc1aeedbSSarah Walker /**
615cc1aeedbSSarah Walker  * pvr_kccb_release_slot() - Release a KCCB slot reserved with
616cc1aeedbSSarah Walker  * pvr_kccb_reserve_slot()
617cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
618cc1aeedbSSarah Walker  *
619cc1aeedbSSarah Walker  * Should only be called if something failed after the
620cc1aeedbSSarah Walker  * pvr_kccb_reserve_slot() call and you know you won't call
621cc1aeedbSSarah Walker  * pvr_kccb_send_cmd_reserved().
622cc1aeedbSSarah Walker  */
pvr_kccb_release_slot(struct pvr_device * pvr_dev)623cc1aeedbSSarah Walker void pvr_kccb_release_slot(struct pvr_device *pvr_dev)
624cc1aeedbSSarah Walker {
625cc1aeedbSSarah Walker 	mutex_lock(&pvr_dev->kccb.ccb.lock);
626cc1aeedbSSarah Walker 	if (!WARN_ON(!pvr_dev->kccb.reserved_count))
627cc1aeedbSSarah Walker 		pvr_dev->kccb.reserved_count--;
628cc1aeedbSSarah Walker 	mutex_unlock(&pvr_dev->kccb.ccb.lock);
629cc1aeedbSSarah Walker }
630cc1aeedbSSarah Walker 
631cc1aeedbSSarah Walker /**
632cc1aeedbSSarah Walker  * pvr_fwccb_init() - Initialise device FWCCB
633cc1aeedbSSarah Walker  * @pvr_dev: Target PowerVR device
634cc1aeedbSSarah Walker  *
635cc1aeedbSSarah Walker  * Returns:
636cc1aeedbSSarah Walker  *  * 0 on success, or
637cc1aeedbSSarah Walker  *  * Any error returned by pvr_ccb_init().
638cc1aeedbSSarah Walker  */
639cc1aeedbSSarah Walker int
pvr_fwccb_init(struct pvr_device * pvr_dev)640cc1aeedbSSarah Walker pvr_fwccb_init(struct pvr_device *pvr_dev)
641cc1aeedbSSarah Walker {
642cc1aeedbSSarah Walker 	return pvr_ccb_init(pvr_dev, &pvr_dev->fwccb,
643cc1aeedbSSarah Walker 			    ROGUE_FWIF_FWCCB_NUMCMDS_LOG2,
644cc1aeedbSSarah Walker 			    sizeof(struct rogue_fwif_fwccb_cmd));
645cc1aeedbSSarah Walker }
646