aboutsummaryrefslogtreecommitdiffstats
blob: ce99b54495e82dda257a12d1bac0d47ecd9cfb17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * Hardware queues handle header
 *
 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
 *
 * Contact: Prabhu Kuttiyam <pkuttiyam@ti.com>
 *	    Cyril Chemparathy <cyril@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __HWQUEUE_HWQUEUE_H
#define __HWQUEUE_HWQUEUE_H

#include <linux/device.h>
#include <linux/wait.h>
#include <linux/hwqueue.h>


struct hwqueue_instance {
	struct list_head	 handles;
	struct hwqueue_device	*hdev;
	struct timer_list	 poll_timer;
	wait_queue_head_t	 wait;
	void			*priv;
	char			 name[32];
	atomic_t		 num_notifiers;
	struct hwqueue_inst_ops	*ops;
};

struct hwqueue_device_ops {
	/*
	 * Return a match quotient (0 = best .. UINT_MAX-1) for a set of
	 * option flags.  Negative error values imply "do not allocate"
	 */
	int	 (*match)(struct hwqueue_instance *inst, unsigned flags);

	/* Initialize a queue inst when opened for the first time */
	int	 (*open)(struct hwqueue_instance *inst, unsigned flags);

	/* Close a queue inst when closed by the last user */
	void	 (*close)(struct hwqueue_instance *inst);

	/* Enable or disable notification */
	void	 (*set_notify)(struct hwqueue_instance *inst, bool enabled);

	/* Get a hardware identifier for a queue */
	int	 (*get_hw_id)(struct hwqueue_instance *inst);
};

struct hwqueue_inst_ops {
	/* Push something into the queue */
	int	 (*push)(struct hwqueue_instance *inst, dma_addr_t dma,
			 unsigned size, unsigned flags);

	/* Pop something from the queue */
	dma_addr_t (*pop)(struct hwqueue_instance *inst, unsigned *size,
			  unsigned flags);

	/* Flush a queue */
	int	 (*flush)(struct hwqueue_instance *inst);

	/* Poll number of elements on the queue */
	int	 (*get_count)(struct hwqueue_instance *inst);
	
	/* Perform DMA mapping on objects to be pushed */
	int	 (*map)(struct hwqueue_instance *inst, void *data,
			unsigned size, dma_addr_t *dma_ptr, unsigned *size_ptr);
	
	/* Perform DMA unmapping on objects that have been pulled */
	void	*(*unmap)(struct hwqueue_instance *inst, dma_addr_t dma,
			unsigned desc_size);
};

struct hwqueue_device {
	unsigned			 base_id;
	unsigned			 num_queues;
	unsigned			 inst_shift;
	void				*instances;
	struct hwqueue_device_ops	*ops;

	unsigned			 priv_size;
	struct list_head		 list;
	struct device			*dev;
};

static inline int hwqueue_inst_to_id(struct hwqueue_instance *inst)
{
	struct hwqueue_device *hdev = inst->hdev;
	int offset = (void *)inst - hdev->instances;
	int inst_size = 1 << hdev->inst_shift;

	BUG_ON(offset & (inst_size - 1));
	return offset >> hdev->inst_shift;
}

static inline struct hwqueue_instance *
hwqueue_id_to_inst(struct hwqueue_device *hdev, unsigned id)
{
	return hdev->instances + (id <<  hdev->inst_shift);
}

static inline void *hwqueue_inst_to_priv(struct hwqueue_instance *inst)
{
	return (void *)(inst + 1);
}

static inline struct hwqueue *rcu_to_handle(struct rcu_head *rcu)
{
	return container_of(rcu, struct hwqueue, rcu);
}

int hwqueue_device_register(struct hwqueue_device *dev);
int hwqueue_device_unregister(struct hwqueue_device *dev);
void hwqueue_notify(struct hwqueue_instance *inst);
void hwqueue_set_poll(struct hwqueue_instance *inst, bool enabled);

#endif /* __HWQUEUE_HWQUEUE_H */