@@ -59,25 +59,26 @@ static unvme_lock_t unvme_lock = 0; ///< session lock
59
59
*/
60
60
static unvme_desc_t * unvme_desc_get (unvme_queue_t * q )
61
61
{
62
+ static u32 id = 0 ;
62
63
unvme_desc_t * desc ;
63
64
64
65
if (q -> descfree ) {
65
66
desc = q -> descfree ;
66
67
LIST_DEL (q -> descfree , desc );
68
+
69
+ desc -> error = 0 ;
70
+ desc -> cidcount = 0 ;
71
+ u64 * cidmask = desc -> cidmask ;
72
+ int i = q -> masksize >> 3 ;
73
+ while (i -- ) * cidmask ++ = 0 ;
67
74
} else {
68
75
desc = zalloc (sizeof (unvme_desc_t ) + q -> masksize );
76
+ desc -> id = ++ id ;
69
77
desc -> q = q ;
70
78
}
71
79
LIST_ADD (q -> desclist , desc );
72
-
73
- if (desc == desc -> next ) {
74
- desc -> id = 1 ;
75
- q -> descnext = desc ;
76
- } else {
77
- desc -> id = desc -> prev -> id + 1 ;
78
- }
80
+ if (desc == desc -> next ) q -> descpend = desc ; // head of pending list
79
81
q -> desccount ++ ;
80
-
81
82
return desc ;
82
83
}
83
84
@@ -89,16 +90,14 @@ static void unvme_desc_put(unvme_desc_t* desc)
89
90
{
90
91
unvme_queue_t * q = desc -> q ;
91
92
92
- if (q -> descnext == desc ) {
93
- if (desc != desc -> next ) q -> descnext = desc -> next ;
94
- else q -> descnext = NULL ;
93
+ // check to change the pending head or clear the list
94
+ if (desc == q -> descpend ) {
95
+ if (desc != desc -> next ) q -> descpend = desc -> next ;
96
+ else q -> descpend = NULL ;
95
97
}
96
98
97
99
LIST_DEL (q -> desclist , desc );
98
- memset (desc , 0 , sizeof (unvme_desc_t ) + q -> masksize );
99
- desc -> q = q ;
100
100
LIST_ADD (q -> descfree , desc );
101
-
102
101
q -> desccount -- ;
103
102
}
104
103
@@ -116,19 +115,20 @@ static int unvme_check_completion(unvme_queue_t* q, int timeout, u32* cqe_cs)
116
115
u64 endtsc = 0 ;
117
116
do {
118
117
cid = nvme_check_completion (q -> nvmeq , & err , cqe_cs );
119
- if (cid >= 0 || timeout = = 0 ) break ;
118
+ if (timeout == 0 || cid > = 0 ) break ;
120
119
if (endtsc ) sched_yield ();
121
120
else endtsc = rdtsc () + timeout * q -> nvmeq -> dev -> rdtsec ;
122
121
} while (rdtsc () < endtsc );
122
+
123
123
if (cid < 0 ) return cid ;
124
124
125
125
// find the pending cid in the descriptor list to clear it
126
- unvme_desc_t * desc = q -> descnext ;
126
+ unvme_desc_t * desc = q -> descpend ;
127
127
int b = cid >> 6 ;
128
128
u64 mask = (u64 )1 << (cid & 63 );
129
129
while ((desc -> cidmask [b ] & mask ) == 0 ) {
130
130
desc = desc -> next ;
131
- if (desc == q -> descnext )
131
+ if (desc == q -> descpend )
132
132
FATAL ("pending cid %d not found" , cid );
133
133
}
134
134
if (err ) desc -> error = err ;
@@ -142,11 +142,11 @@ static int unvme_check_completion(unvme_queue_t* q, int timeout, u32* cqe_cs)
142
142
143
143
// check to advance next pending descriptor
144
144
if (q -> cidcount ) {
145
- while (q -> descnext -> cidcount == 0 ) q -> descnext = q -> descnext -> next ;
145
+ while (q -> descpend -> cidcount == 0 ) q -> descpend = q -> descpend -> next ;
146
146
}
147
147
PDEBUG ("# c q%d={%d %d %#lx} d={%d %d %#lx} @%d" ,
148
148
q -> nvmeq -> id , cid , q -> cidcount , * q -> cidmask ,
149
- desc -> id , desc -> cidcount , * desc -> cidmask , q -> descnext -> id );
149
+ desc -> id , desc -> cidcount , * desc -> cidmask , q -> descpend -> id );
150
150
return err ;
151
151
}
152
152
@@ -160,32 +160,31 @@ static u16 unvme_get_cid(unvme_desc_t* desc)
160
160
u16 cid ;
161
161
unvme_queue_t * q = desc -> q ;
162
162
int qsize = q -> size ;
163
- if ((q -> cidcount + 1 ) < qsize ) {
164
- cid = q -> cid ;
165
- while (q -> cidmask [cid >> 6 ] & ((u64 )1 << (cid & 63 ))) {
166
- if (++ cid >= qsize ) cid = 0 ;
167
- }
168
- q -> cid = cid ;
169
- } else {
170
- // if submission queue is full then process pending in descriptor
171
- unvme_desc_t * desc = q -> descnext ;
172
- while (desc -> cidcount ) {
173
- int err = unvme_check_completion (q , UNVME_TIMEOUT , NULL );
174
- if (err ) {
175
- if (err == -1 ) FATAL ("q%d timeout" , q -> nvmeq -> id );
176
- else ERROR ("q%d error %#x" , q -> nvmeq -> id , err );
177
- }
163
+
164
+ // if submission queue is full then process completion first
165
+ if ((q -> cidcount + 1 ) == qsize ) {
166
+ int err = unvme_check_completion (q , UNVME_TIMEOUT , NULL );
167
+ if (err ) {
168
+ if (err == -1 ) FATAL ("q%d timeout" , q -> nvmeq -> id );
169
+ else ERROR ("q%d error %#x" , q -> nvmeq -> id , err );
178
170
}
179
- cid = q -> cid ;
171
+ }
172
+
173
+ // get a free cid
174
+ cid = q -> cid ;
175
+ while (q -> cidmask [cid >> 6 ] & ((u64 )1L << (cid & 63 ))) {
176
+ if (++ cid >= qsize ) cid = 0 ;
180
177
}
181
178
182
179
// set cid bit used
183
180
int b = cid >> 6 ;
184
181
u64 mask = (u64 )1 << (cid & 63 );
185
- q -> cidmask [b ] |= mask ;
186
- q -> cidcount ++ ;
187
182
desc -> cidmask [b ] |= mask ;
188
183
desc -> cidcount ++ ;
184
+ q -> cidmask [b ] |= mask ;
185
+ q -> cidcount ++ ;
186
+ q -> cid = cid ;
187
+ if (++ q -> cid >= qsize ) q -> cid = 0 ;
189
188
190
189
return cid ;
191
190
}
@@ -654,7 +653,7 @@ int unvme_do_poll(unvme_desc_t* desc, int timeout, u32* cqe_cs)
654
653
while (desc -> cidcount ) {
655
654
if ((err = unvme_check_completion (desc -> q , timeout , cqe_cs )) != 0 ) break ;
656
655
}
657
- if (desc -> id != 0 && desc -> cidcount == 0 ) unvme_desc_put (desc );
656
+ if (desc -> cidcount == 0 ) unvme_desc_put (desc );
658
657
PDEBUG ("# q%d +%d" , desc -> q -> nvmeq -> id , desc -> q -> desccount );
659
658
660
659
return err ;
0 commit comments