summaryrefslogtreecommitdiff
path: root/drivers/usb/host/whci/whcd.h
blob: c80c7d93bc4ac63019f40b8e6107f34a650226b1 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
 * Wireless Host Controller (WHC) private header.
 *
 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
#ifndef __WHCD_H
#define __WHCD_H

#include <linux/uwb/whci.h>
#include <linux/uwb/umc.h>
#include <linux/workqueue.h>

#include "whci-hc.h"

/* Generic command timeout. */
#define WHC_GENCMD_TIMEOUT_MS 100

struct whc_dbg;

struct whc {
	struct wusbhc wusbhc;
	struct umc_dev *umc;

	resource_size_t base_phys;
	void __iomem *base;
	int irq;

	u8 n_devices;
	u8 n_keys;
	u8 n_mmc_ies;

	u64 *pz_list;
	struct dn_buf_entry *dn_buf;
	struct di_buf_entry *di_buf;
	dma_addr_t pz_list_dma;
	dma_addr_t dn_buf_dma;
	dma_addr_t di_buf_dma;

	spinlock_t   lock;
	struct mutex mutex;

	void *            gen_cmd_buf;
	dma_addr_t        gen_cmd_buf_dma;
	wait_queue_head_t cmd_wq;

	struct workqueue_struct *workqueue;
	struct work_struct       dn_work;

	struct dma_pool *qset_pool;

	struct list_head async_list;
	struct list_head async_removed_list;
	wait_queue_head_t async_list_wq;
	struct work_struct async_work;

	struct list_head periodic_list[5];
	struct list_head periodic_removed_list;
	wait_queue_head_t periodic_list_wq;
	struct work_struct periodic_work;

	struct whc_dbg *dbg;
};

#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))

/**
 * struct whc_std - a software TD.
 * @urb: the URB this sTD is for.
 * @offset: start of the URB's data for this TD.
 * @len: the length of data in the associated TD.
 * @ntds_remaining: number of TDs (starting from this one) in this transfer.
 *
 * @bounce_buf: a bounce buffer if the std was from an urb with a sg
 * list that could not be mapped to qTDs directly.
 * @bounce_sg: the first scatterlist element bounce_buf is for.
 * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
 *
 * Queued URBs may require more TDs than are available in a qset so we
 * use a list of these "software TDs" (sTDs) to hold per-TD data.
 */
struct whc_std {
	struct urb *urb;
	size_t len;
	int    ntds_remaining;
	struct whc_qtd *qtd;

	struct list_head list_node;
	int num_pointers;
	dma_addr_t dma_addr;
	struct whc_page_list_entry *pl_virt;

	void *bounce_buf;
	struct scatterlist *bounce_sg;
	unsigned bounce_offset;
};

/**
 * struct whc_urb - per URB host controller structure.
 * @urb: the URB this struct is for.
 * @qset: the qset associated to the URB.
 * @dequeue_work: the work to remove the URB when dequeued.
 * @is_async: the URB belongs to async sheduler or not.
 * @status: the status to be returned when calling wusbhc_giveback_urb.
 */
struct whc_urb {
	struct urb *urb;
	struct whc_qset *qset;
	struct work_struct dequeue_work;
	bool is_async;
	int status;
};

/**
 * whc_std_last - is this sTD the URB's last?
 * @std: the sTD to check.
 */
static inline bool whc_std_last(struct whc_std *std)
{
	return std->ntds_remaining <= 1;
}

enum whc_update {
	WHC_UPDATE_ADDED   = 0x01,
	WHC_UPDATE_REMOVED = 0x02,
	WHC_UPDATE_UPDATED = 0x04,
};

/* init.c */
int whc_init(struct whc *whc);
void whc_clean_up(struct whc *whc);

/* hw.c */
void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
void whc_hw_error(struct whc *whc, const char *reason);

/* wusb.c */
int whc_wusbhc_start(struct wusbhc *wusbhc);
void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
		  u8 handle, struct wuie_hdr *wuie);
int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
		const void *ptk, size_t key_size);
int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
		const void *gtk, size_t key_size);
int whc_set_cluster_id(struct whc *whc, u8 bcid);

/* int.c */
irqreturn_t whc_int_handler(struct usb_hcd *hcd);
void whc_dn_work(struct work_struct *work);

/* asl.c */
void asl_start(struct whc *whc);
void asl_stop(struct whc *whc);
int  asl_init(struct whc *whc);
void asl_clean_up(struct whc *whc);
int  asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
int  asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
void scan_async_work(struct work_struct *work);

/* pzl.c */
int  pzl_init(struct whc *whc);
void pzl_clean_up(struct whc *whc);
void pzl_start(struct whc *whc);
void pzl_stop(struct whc *whc);
int  pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
int  pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
void scan_periodic_work(struct work_struct *work);

/* qset.c */
struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
void qset_free(struct whc *whc, struct whc_qset *qset);
struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
void qset_delete(struct whc *whc, struct whc_qset *qset);
void qset_clear(struct whc *whc, struct whc_qset *qset);
void qset_reset(struct whc *whc, struct whc_qset *qset);
int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
		 gfp_t mem_flags);
void qset_free_std(struct whc *whc, struct whc_std *std);
void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
			    struct urb *urb, int status);
void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
			       struct whc_qtd *qtd);
void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
				 struct whc_qtd *qtd);
enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
void pzl_update(struct whc *whc, uint32_t wusbcmd);
void asl_update(struct whc *whc, uint32_t wusbcmd);

/* debug.c */
void whc_dbg_init(struct whc *whc);
void whc_dbg_clean_up(struct whc *whc);

#endif /* #ifndef __WHCD_H */