diff options
Diffstat (limited to 'drivers/char/tpm/tpm-interface.c')
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 181 |
1 files changed, 12 insertions, 169 deletions
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6ae41d337630..0b9e9ca05ef3 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c | |||
@@ -312,23 +312,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { | |||
312 | TPM_MEDIUM, | 312 | TPM_MEDIUM, |
313 | }; | 313 | }; |
314 | 314 | ||
315 | static void user_reader_timeout(unsigned long ptr) | ||
316 | { | ||
317 | struct tpm_chip *chip = (struct tpm_chip *) ptr; | ||
318 | |||
319 | schedule_work(&chip->work); | ||
320 | } | ||
321 | |||
322 | static void timeout_work(struct work_struct *work) | ||
323 | { | ||
324 | struct tpm_chip *chip = container_of(work, struct tpm_chip, work); | ||
325 | |||
326 | mutex_lock(&chip->buffer_mutex); | ||
327 | atomic_set(&chip->data_pending, 0); | ||
328 | memset(chip->data_buffer, 0, TPM_BUFSIZE); | ||
329 | mutex_unlock(&chip->buffer_mutex); | ||
330 | } | ||
331 | |||
332 | /* | 315 | /* |
333 | * Returns max number of jiffies to wait | 316 | * Returns max number of jiffies to wait |
334 | */ | 317 | */ |
@@ -355,8 +338,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); | |||
355 | /* | 338 | /* |
356 | * Internal kernel interface to transmit TPM commands | 339 | * Internal kernel interface to transmit TPM commands |
357 | */ | 340 | */ |
358 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 341 | ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |
359 | size_t bufsiz) | 342 | size_t bufsiz) |
360 | { | 343 | { |
361 | ssize_t rc; | 344 | ssize_t rc; |
362 | u32 count, ordinal; | 345 | u32 count, ordinal; |
@@ -1151,127 +1134,6 @@ again: | |||
1151 | return -ETIME; | 1134 | return -ETIME; |
1152 | } | 1135 | } |
1153 | EXPORT_SYMBOL_GPL(wait_for_tpm_stat); | 1136 | EXPORT_SYMBOL_GPL(wait_for_tpm_stat); |
1154 | /* | ||
1155 | * Device file system interface to the TPM | ||
1156 | * | ||
1157 | * It's assured that the chip will be opened just once, | ||
1158 | * by the check of is_open variable, which is protected | ||
1159 | * by driver_lock. | ||
1160 | */ | ||
1161 | int tpm_open(struct inode *inode, struct file *file) | ||
1162 | { | ||
1163 | struct miscdevice *misc = file->private_data; | ||
1164 | struct tpm_chip *chip = container_of(misc, struct tpm_chip, | ||
1165 | vendor.miscdev); | ||
1166 | |||
1167 | if (test_and_set_bit(0, &chip->is_open)) { | ||
1168 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | ||
1169 | return -EBUSY; | ||
1170 | } | ||
1171 | |||
1172 | chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); | ||
1173 | if (chip->data_buffer == NULL) { | ||
1174 | clear_bit(0, &chip->is_open); | ||
1175 | return -ENOMEM; | ||
1176 | } | ||
1177 | |||
1178 | atomic_set(&chip->data_pending, 0); | ||
1179 | |||
1180 | file->private_data = chip; | ||
1181 | get_device(chip->dev); | ||
1182 | return 0; | ||
1183 | } | ||
1184 | EXPORT_SYMBOL_GPL(tpm_open); | ||
1185 | |||
1186 | /* | ||
1187 | * Called on file close | ||
1188 | */ | ||
1189 | int tpm_release(struct inode *inode, struct file *file) | ||
1190 | { | ||
1191 | struct tpm_chip *chip = file->private_data; | ||
1192 | |||
1193 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1194 | flush_work(&chip->work); | ||
1195 | file->private_data = NULL; | ||
1196 | atomic_set(&chip->data_pending, 0); | ||
1197 | kzfree(chip->data_buffer); | ||
1198 | clear_bit(0, &chip->is_open); | ||
1199 | put_device(chip->dev); | ||
1200 | return 0; | ||
1201 | } | ||
1202 | EXPORT_SYMBOL_GPL(tpm_release); | ||
1203 | |||
1204 | ssize_t tpm_write(struct file *file, const char __user *buf, | ||
1205 | size_t size, loff_t *off) | ||
1206 | { | ||
1207 | struct tpm_chip *chip = file->private_data; | ||
1208 | size_t in_size = size; | ||
1209 | ssize_t out_size; | ||
1210 | |||
1211 | /* cannot perform a write until the read has cleared | ||
1212 | either via tpm_read or a user_read_timer timeout. | ||
1213 | This also prevents splitted buffered writes from blocking here. | ||
1214 | */ | ||
1215 | if (atomic_read(&chip->data_pending) != 0) | ||
1216 | return -EBUSY; | ||
1217 | |||
1218 | if (in_size > TPM_BUFSIZE) | ||
1219 | return -E2BIG; | ||
1220 | |||
1221 | mutex_lock(&chip->buffer_mutex); | ||
1222 | |||
1223 | if (copy_from_user | ||
1224 | (chip->data_buffer, (void __user *) buf, in_size)) { | ||
1225 | mutex_unlock(&chip->buffer_mutex); | ||
1226 | return -EFAULT; | ||
1227 | } | ||
1228 | |||
1229 | /* atomic tpm command send and result receive */ | ||
1230 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); | ||
1231 | if (out_size < 0) { | ||
1232 | mutex_unlock(&chip->buffer_mutex); | ||
1233 | return out_size; | ||
1234 | } | ||
1235 | |||
1236 | atomic_set(&chip->data_pending, out_size); | ||
1237 | mutex_unlock(&chip->buffer_mutex); | ||
1238 | |||
1239 | /* Set a timeout by which the reader must come claim the result */ | ||
1240 | mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); | ||
1241 | |||
1242 | return in_size; | ||
1243 | } | ||
1244 | EXPORT_SYMBOL_GPL(tpm_write); | ||
1245 | |||
1246 | ssize_t tpm_read(struct file *file, char __user *buf, | ||
1247 | size_t size, loff_t *off) | ||
1248 | { | ||
1249 | struct tpm_chip *chip = file->private_data; | ||
1250 | ssize_t ret_size; | ||
1251 | int rc; | ||
1252 | |||
1253 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1254 | flush_work(&chip->work); | ||
1255 | ret_size = atomic_read(&chip->data_pending); | ||
1256 | if (ret_size > 0) { /* relay data */ | ||
1257 | ssize_t orig_ret_size = ret_size; | ||
1258 | if (size < ret_size) | ||
1259 | ret_size = size; | ||
1260 | |||
1261 | mutex_lock(&chip->buffer_mutex); | ||
1262 | rc = copy_to_user(buf, chip->data_buffer, ret_size); | ||
1263 | memset(chip->data_buffer, 0, orig_ret_size); | ||
1264 | if (rc) | ||
1265 | ret_size = -EFAULT; | ||
1266 | |||
1267 | mutex_unlock(&chip->buffer_mutex); | ||
1268 | } | ||
1269 | |||
1270 | atomic_set(&chip->data_pending, 0); | ||
1271 | |||
1272 | return ret_size; | ||
1273 | } | ||
1274 | EXPORT_SYMBOL_GPL(tpm_read); | ||
1275 | 1137 | ||
1276 | void tpm_remove_hardware(struct device *dev) | 1138 | void tpm_remove_hardware(struct device *dev) |
1277 | { | 1139 | { |
@@ -1287,7 +1149,7 @@ void tpm_remove_hardware(struct device *dev) | |||
1287 | spin_unlock(&driver_lock); | 1149 | spin_unlock(&driver_lock); |
1288 | synchronize_rcu(); | 1150 | synchronize_rcu(); |
1289 | 1151 | ||
1290 | misc_deregister(&chip->vendor.miscdev); | 1152 | tpm_dev_del_device(chip); |
1291 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1153 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1292 | tpm_remove_ppi(&dev->kobj); | 1154 | tpm_remove_ppi(&dev->kobj); |
1293 | tpm_bios_log_teardown(chip->bios_dir); | 1155 | tpm_bios_log_teardown(chip->bios_dir); |
@@ -1448,7 +1310,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | |||
1448 | * Once all references to platform device are down to 0, | 1310 | * Once all references to platform device are down to 0, |
1449 | * release all allocated structures. | 1311 | * release all allocated structures. |
1450 | */ | 1312 | */ |
1451 | void tpm_dev_release(struct device *dev) | 1313 | static void tpm_dev_release(struct device *dev) |
1452 | { | 1314 | { |
1453 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1315 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1454 | 1316 | ||
@@ -1460,7 +1322,6 @@ void tpm_dev_release(struct device *dev) | |||
1460 | chip->release(dev); | 1322 | chip->release(dev); |
1461 | kfree(chip); | 1323 | kfree(chip); |
1462 | } | 1324 | } |
1463 | EXPORT_SYMBOL_GPL(tpm_dev_release); | ||
1464 | 1325 | ||
1465 | /* | 1326 | /* |
1466 | * Called from tpm_<specific>.c probe function only for devices | 1327 | * Called from tpm_<specific>.c probe function only for devices |
@@ -1480,15 +1341,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1480 | if (chip == NULL) | 1341 | if (chip == NULL) |
1481 | return NULL; | 1342 | return NULL; |
1482 | 1343 | ||
1483 | mutex_init(&chip->buffer_mutex); | ||
1484 | mutex_init(&chip->tpm_mutex); | 1344 | mutex_init(&chip->tpm_mutex); |
1485 | INIT_LIST_HEAD(&chip->list); | 1345 | INIT_LIST_HEAD(&chip->list); |
1486 | 1346 | ||
1487 | INIT_WORK(&chip->work, timeout_work); | ||
1488 | |||
1489 | setup_timer(&chip->user_read_timer, user_reader_timeout, | ||
1490 | (unsigned long)chip); | ||
1491 | |||
1492 | memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); | 1347 | memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); |
1493 | 1348 | ||
1494 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); | 1349 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); |
@@ -1496,40 +1351,26 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1496 | if (chip->dev_num >= TPM_NUM_DEVICES) { | 1351 | if (chip->dev_num >= TPM_NUM_DEVICES) { |
1497 | dev_err(dev, "No available tpm device numbers\n"); | 1352 | dev_err(dev, "No available tpm device numbers\n"); |
1498 | goto out_free; | 1353 | goto out_free; |
1499 | } else if (chip->dev_num == 0) | 1354 | } |
1500 | chip->vendor.miscdev.minor = TPM_MINOR; | ||
1501 | else | ||
1502 | chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; | ||
1503 | 1355 | ||
1504 | set_bit(chip->dev_num, dev_mask); | 1356 | set_bit(chip->dev_num, dev_mask); |
1505 | 1357 | ||
1506 | scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", | 1358 | scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", |
1507 | chip->dev_num); | 1359 | chip->dev_num); |
1508 | chip->vendor.miscdev.name = chip->devname; | ||
1509 | 1360 | ||
1510 | chip->vendor.miscdev.parent = dev; | ||
1511 | chip->dev = get_device(dev); | 1361 | chip->dev = get_device(dev); |
1512 | chip->release = dev->release; | 1362 | chip->release = dev->release; |
1513 | dev->release = tpm_dev_release; | 1363 | dev->release = tpm_dev_release; |
1514 | dev_set_drvdata(dev, chip); | 1364 | dev_set_drvdata(dev, chip); |
1515 | 1365 | ||
1516 | if (misc_register(&chip->vendor.miscdev)) { | 1366 | if (tpm_dev_add_device(chip)) |
1517 | dev_err(chip->dev, | ||
1518 | "unable to misc_register %s, minor %d\n", | ||
1519 | chip->vendor.miscdev.name, | ||
1520 | chip->vendor.miscdev.minor); | ||
1521 | goto put_device; | 1367 | goto put_device; |
1522 | } | ||
1523 | 1368 | ||
1524 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1369 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) |
1525 | misc_deregister(&chip->vendor.miscdev); | 1370 | goto del_misc; |
1526 | goto put_device; | ||
1527 | } | ||
1528 | 1371 | ||
1529 | if (tpm_add_ppi(&dev->kobj)) { | 1372 | if (tpm_add_ppi(&dev->kobj)) |
1530 | misc_deregister(&chip->vendor.miscdev); | 1373 | goto del_misc; |
1531 | goto put_device; | ||
1532 | } | ||
1533 | 1374 | ||
1534 | chip->bios_dir = tpm_bios_log_setup(chip->devname); | 1375 | chip->bios_dir = tpm_bios_log_setup(chip->devname); |
1535 | 1376 | ||
@@ -1540,6 +1381,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1540 | 1381 | ||
1541 | return chip; | 1382 | return chip; |
1542 | 1383 | ||
1384 | del_misc: | ||
1385 | tpm_dev_del_device(chip); | ||
1543 | put_device: | 1386 | put_device: |
1544 | put_device(chip->dev); | 1387 | put_device(chip->dev); |
1545 | out_free: | 1388 | out_free: |