aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/csr1212.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ieee1394/csr1212.c')
-rw-r--r--drivers/ieee1394/csr1212.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index d08166bda1c5..e8122def164d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -218,12 +218,10 @@ static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
218 if (!kv) 218 if (!kv)
219 return NULL; 219 return NULL;
220 220
221 atomic_set(&kv->refcnt, 1);
221 kv->key.type = type; 222 kv->key.type = type;
222 kv->key.id = key; 223 kv->key.id = key;
223
224 kv->associate = NULL; 224 kv->associate = NULL;
225 kv->refcnt = 1;
226
227 kv->next = NULL; 225 kv->next = NULL;
228 kv->prev = NULL; 226 kv->prev = NULL;
229 kv->offset = 0; 227 kv->offset = 0;
@@ -326,12 +324,13 @@ void csr1212_associate_keyval(struct csr1212_keyval *kv,
326 if (kv->associate) 324 if (kv->associate)
327 csr1212_release_keyval(kv->associate); 325 csr1212_release_keyval(kv->associate);
328 326
329 associate->refcnt++; 327 csr1212_keep_keyval(associate);
330 kv->associate = associate; 328 kv->associate = associate;
331} 329}
332 330
333int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, 331static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
334 struct csr1212_keyval *kv) 332 struct csr1212_keyval *kv,
333 bool keep_keyval)
335{ 334{
336 struct csr1212_dentry *dentry; 335 struct csr1212_dentry *dentry;
337 336
@@ -341,10 +340,10 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
341 if (!dentry) 340 if (!dentry)
342 return -ENOMEM; 341 return -ENOMEM;
343 342
343 if (keep_keyval)
344 csr1212_keep_keyval(kv);
344 dentry->kv = kv; 345 dentry->kv = kv;
345 346
346 kv->refcnt++;
347
348 dentry->next = NULL; 347 dentry->next = NULL;
349 dentry->prev = dir->value.directory.dentries_tail; 348 dentry->prev = dir->value.directory.dentries_tail;
350 349
@@ -358,6 +357,12 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
358 return CSR1212_SUCCESS; 357 return CSR1212_SUCCESS;
359} 358}
360 359
360int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
361 struct csr1212_keyval *kv)
362{
363 return __csr1212_attach_keyval_to_directory(dir, kv, true);
364}
365
361#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ 366#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
362 (&((kv)->value.leaf.data[1])) 367 (&((kv)->value.leaf.data[1]))
363 368
@@ -483,15 +488,18 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
483 488
484/* This function is used to free the memory taken by a keyval. If the given 489/* This function is used to free the memory taken by a keyval. If the given
485 * keyval is a directory type, then any keyvals contained in that directory 490 * keyval is a directory type, then any keyvals contained in that directory
486 * will be destroyed as well if their respective refcnts are 0. By means of 491 * will be destroyed as well if noone holds a reference on them. By means of
487 * list manipulation, this routine will descend a directory structure in a 492 * list manipulation, this routine will descend a directory structure in a
488 * non-recursive manner. */ 493 * non-recursive manner. */
489static void csr1212_destroy_keyval(struct csr1212_keyval *kv) 494void csr1212_release_keyval(struct csr1212_keyval *kv)
490{ 495{
491 struct csr1212_keyval *k, *a; 496 struct csr1212_keyval *k, *a;
492 struct csr1212_dentry dentry; 497 struct csr1212_dentry dentry;
493 struct csr1212_dentry *head, *tail; 498 struct csr1212_dentry *head, *tail;
494 499
500 if (!atomic_dec_and_test(&kv->refcnt))
501 return;
502
495 dentry.kv = kv; 503 dentry.kv = kv;
496 dentry.next = NULL; 504 dentry.next = NULL;
497 dentry.prev = NULL; 505 dentry.prev = NULL;
@@ -503,9 +511,8 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
503 k = head->kv; 511 k = head->kv;
504 512
505 while (k) { 513 while (k) {
506 k->refcnt--; 514 /* must not dec_and_test kv->refcnt again */
507 515 if (k != kv && !atomic_dec_and_test(&k->refcnt))
508 if (k->refcnt > 0)
509 break; 516 break;
510 517
511 a = k->associate; 518 a = k->associate;
@@ -536,14 +543,6 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
536 } 543 }
537} 544}
538 545
539void csr1212_release_keyval(struct csr1212_keyval *kv)
540{
541 if (kv->refcnt > 1)
542 kv->refcnt--;
543 else
544 csr1212_destroy_keyval(kv);
545}
546
547void csr1212_destroy_csr(struct csr1212_csr *csr) 546void csr1212_destroy_csr(struct csr1212_csr *csr)
548{ 547{
549 struct csr1212_csr_rom_cache *c, *oc; 548 struct csr1212_csr_rom_cache *c, *oc;
@@ -1126,6 +1125,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1126 int ret = CSR1212_SUCCESS; 1125 int ret = CSR1212_SUCCESS;
1127 struct csr1212_keyval *k = NULL; 1126 struct csr1212_keyval *k = NULL;
1128 u32 offset; 1127 u32 offset;
1128 bool keep_keyval = true;
1129 1129
1130 switch (CSR1212_KV_KEY_TYPE(ki)) { 1130 switch (CSR1212_KV_KEY_TYPE(ki)) {
1131 case CSR1212_KV_TYPE_IMMEDIATE: 1131 case CSR1212_KV_TYPE_IMMEDIATE:
@@ -1135,8 +1135,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1135 ret = -ENOMEM; 1135 ret = -ENOMEM;
1136 goto out; 1136 goto out;
1137 } 1137 }
1138 1138 /* Don't keep local reference when parsing. */
1139 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1139 keep_keyval = false;
1140 break; 1140 break;
1141 1141
1142 case CSR1212_KV_TYPE_CSR_OFFSET: 1142 case CSR1212_KV_TYPE_CSR_OFFSET:
@@ -1146,7 +1146,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1146 ret = -ENOMEM; 1146 ret = -ENOMEM;
1147 goto out; 1147 goto out;
1148 } 1148 }
1149 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1149 /* Don't keep local reference when parsing. */
1150 keep_keyval = false;
1150 break; 1151 break;
1151 1152
1152 default: 1153 default:
@@ -1174,8 +1175,10 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1174 ret = -ENOMEM; 1175 ret = -ENOMEM;
1175 goto out; 1176 goto out;
1176 } 1177 }
1177 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1178 /* Don't keep local reference when parsing. */
1178 k->valid = 0; /* Contents not read yet so it's not valid. */ 1179 keep_keyval = false;
1180 /* Contents not read yet so it's not valid. */
1181 k->valid = 0;
1179 k->offset = offset; 1182 k->offset = offset;
1180 1183
1181 k->prev = dir; 1184 k->prev = dir;
@@ -1183,7 +1186,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1183 dir->next->prev = k; 1186 dir->next->prev = k;
1184 dir->next = k; 1187 dir->next = k;
1185 } 1188 }
1186 ret = csr1212_attach_keyval_to_directory(dir, k); 1189 ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
1187out: 1190out:
1188 if (ret != CSR1212_SUCCESS && k != NULL) 1191 if (ret != CSR1212_SUCCESS && k != NULL)
1189 free_keyval(k); 1192 free_keyval(k);