aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2008-12-21 04:54:27 -0500
committerGrant Likely <grant.likely@secretlab.ca>2008-12-21 04:54:27 -0500
commit622882455aa718cfbd6785cc5fbc479f1d976095 (patch)
tree6c8fe006241810845419f17a80b4e82dc03aed11
parentdd952cbb3dae9ea2dc47cc902b796e1e2bf806f0 (diff)
powerpc/mpc5200: Bugfix on handling variable sized buffer descriptors
The buffer descriptors for the ATA BestComm task are larger than the current definition for bcom_bd. This causes problems because the various bcom_... functions dereference the buffer descriptor pointer by using the array operator which doesn't work when the buffer descriptors are a different size. This patch adds the bcom_get_bd() function which uses the value in bcom_task.bd_size to calculate the offset into the BD table. This patch also changes the definition of bcom_bd to specify a data size of 0 instead of 1 so that it will never work if anyone attempts to dereference the bd list as an array (as opposed to something that might work even though it is wrong). Finally, this patch moves the definition of bcom_bd up in the file to eliminate a forward declaration. Based on patch originally written by Tim Yamin. Signed-off-by: Tim Yamin <plasm@roo.me.uk> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r--arch/powerpc/sysdev/bestcomm/bestcomm.h61
1 files changed, 42 insertions, 19 deletions
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
index c960a8b49655..23a95f80dfdb 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.h
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
@@ -16,8 +16,19 @@
16#ifndef __BESTCOMM_H__ 16#ifndef __BESTCOMM_H__
17#define __BESTCOMM_H__ 17#define __BESTCOMM_H__
18 18
19struct bcom_bd; /* defined later on ... */ 19/**
20 20 * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
21 * @status: The current status of this buffer. Exact meaning depends on the
22 * task type
23 * @data: An array of u32 extra data. Size of array is task dependant.
24 *
25 * Note: Don't dereference a bcom_bd pointer as an array. The size of the
26 * bcom_bd is variable. Use bcom_get_bd() instead.
27 */
28struct bcom_bd {
29 u32 status;
30 u32 data[0]; /* variable payload size */
31};
21 32
22/* ======================================================================== */ 33/* ======================================================================== */
23/* Generic task management */ 34/* Generic task management */
@@ -84,17 +95,6 @@ bcom_get_task_irq(struct bcom_task *tsk) {
84/* BD based tasks helpers */ 95/* BD based tasks helpers */
85/* ======================================================================== */ 96/* ======================================================================== */
86 97
87/**
88 * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
89 * @status: The current status of this buffer. Exact meaning depends on the
90 * task type
91 * @data: An array of u32 whose meaning depends on the task type.
92 */
93struct bcom_bd {
94 u32 status;
95 u32 data[1]; /* variable, but at least 1 */
96};
97
98#define BCOM_BD_READY 0x40000000ul 98#define BCOM_BD_READY 0x40000000ul
99 99
100/** _bcom_next_index - Get next input index. 100/** _bcom_next_index - Get next input index.
@@ -140,15 +140,31 @@ bcom_queue_full(struct bcom_task *tsk)
140} 140}
141 141
142/** 142/**
143 * bcom_get_bd - Get a BD from the queue
144 * @tsk: The BestComm task structure
145 * index: Index of the BD to fetch
146 */
147static inline struct bcom_bd
148*bcom_get_bd(struct bcom_task *tsk, unsigned int index)
149{
150 /* A cast to (void*) so the address can be incremented by the
151 * real size instead of by sizeof(struct bcom_bd) */
152 return ((void *)tsk->bd) + (index * tsk->bd_size);
153}
154
155/**
143 * bcom_buffer_done - Checks if a BestComm 156 * bcom_buffer_done - Checks if a BestComm
144 * @tsk: The BestComm task structure 157 * @tsk: The BestComm task structure
145 */ 158 */
146static inline int 159static inline int
147bcom_buffer_done(struct bcom_task *tsk) 160bcom_buffer_done(struct bcom_task *tsk)
148{ 161{
162 struct bcom_bd *bd;
149 if (bcom_queue_empty(tsk)) 163 if (bcom_queue_empty(tsk))
150 return 0; 164 return 0;
151 return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); 165
166 bd = bcom_get_bd(tsk, tsk->outdex);
167 return !(bd->status & BCOM_BD_READY);
152} 168}
153 169
154/** 170/**
@@ -160,16 +176,21 @@ bcom_buffer_done(struct bcom_task *tsk)
160static inline struct bcom_bd * 176static inline struct bcom_bd *
161bcom_prepare_next_buffer(struct bcom_task *tsk) 177bcom_prepare_next_buffer(struct bcom_task *tsk)
162{ 178{
163 tsk->bd[tsk->index].status = 0; /* cleanup last status */ 179 struct bcom_bd *bd;
164 return &tsk->bd[tsk->index]; 180
181 bd = bcom_get_bd(tsk, tsk->index);
182 bd->status = 0; /* cleanup last status */
183 return bd;
165} 184}
166 185
167static inline void 186static inline void
168bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) 187bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
169{ 188{
189 struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
190
170 tsk->cookie[tsk->index] = cookie; 191 tsk->cookie[tsk->index] = cookie;
171 mb(); /* ensure the bd is really up-to-date */ 192 mb(); /* ensure the bd is really up-to-date */
172 tsk->bd[tsk->index].status |= BCOM_BD_READY; 193 bd->status |= BCOM_BD_READY;
173 tsk->index = _bcom_next_index(tsk); 194 tsk->index = _bcom_next_index(tsk);
174 if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) 195 if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
175 bcom_enable(tsk); 196 bcom_enable(tsk);
@@ -179,10 +200,12 @@ static inline void *
179bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) 200bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
180{ 201{
181 void *cookie = tsk->cookie[tsk->outdex]; 202 void *cookie = tsk->cookie[tsk->outdex];
203 struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
204
182 if (p_status) 205 if (p_status)
183 *p_status = tsk->bd[tsk->outdex].status; 206 *p_status = bd->status;
184 if (p_bd) 207 if (p_bd)
185 *p_bd = &tsk->bd[tsk->outdex]; 208 *p_bd = bd;
186 tsk->outdex = _bcom_next_outdex(tsk); 209 tsk->outdex = _bcom_next_outdex(tsk);
187 return cookie; 210 return cookie;
188} 211}