diff options
Diffstat (limited to 'drivers/tty/hvc/hvcs.c')
| -rw-r--r-- | drivers/tty/hvc/hvcs.c | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 3436436fe2d7..d56788c83974 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c | |||
| @@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); | |||
| 261 | 261 | ||
| 262 | /* One vty-server per hvcs_struct */ | 262 | /* One vty-server per hvcs_struct */ |
| 263 | struct hvcs_struct { | 263 | struct hvcs_struct { |
| 264 | struct tty_port port; | ||
| 264 | spinlock_t lock; | 265 | spinlock_t lock; |
| 265 | 266 | ||
| 266 | /* | 267 | /* |
| @@ -269,9 +270,6 @@ struct hvcs_struct { | |||
| 269 | */ | 270 | */ |
| 270 | unsigned int index; | 271 | unsigned int index; |
| 271 | 272 | ||
| 272 | struct tty_struct *tty; | ||
| 273 | int open_count; | ||
| 274 | |||
| 275 | /* | 273 | /* |
| 276 | * Used to tell the driver kernel_thread what operations need to take | 274 | * Used to tell the driver kernel_thread what operations need to take |
| 277 | * place upon this hvcs_struct instance. | 275 | * place upon this hvcs_struct instance. |
| @@ -290,12 +288,11 @@ struct hvcs_struct { | |||
| 290 | int chars_in_buffer; | 288 | int chars_in_buffer; |
| 291 | 289 | ||
| 292 | /* | 290 | /* |
| 293 | * Any variable below the kref is valid before a tty is connected and | 291 | * Any variable below is valid before a tty is connected and |
| 294 | * stays valid after the tty is disconnected. These shouldn't be | 292 | * stays valid after the tty is disconnected. These shouldn't be |
| 295 | * whacked until the kobject refcount reaches zero though some entries | 293 | * whacked until the kobject refcount reaches zero though some entries |
| 296 | * may be changed via sysfs initiatives. | 294 | * may be changed via sysfs initiatives. |
| 297 | */ | 295 | */ |
| 298 | struct kref kref; /* ref count & hvcs_struct lifetime */ | ||
| 299 | int connected; /* is the vty-server currently connected to a vty? */ | 296 | int connected; /* is the vty-server currently connected to a vty? */ |
| 300 | uint32_t p_unit_address; /* partner unit address */ | 297 | uint32_t p_unit_address; /* partner unit address */ |
| 301 | uint32_t p_partition_ID; /* partner partition ID */ | 298 | uint32_t p_partition_ID; /* partner partition ID */ |
| @@ -304,9 +301,6 @@ struct hvcs_struct { | |||
| 304 | struct vio_dev *vdev; | 301 | struct vio_dev *vdev; |
| 305 | }; | 302 | }; |
| 306 | 303 | ||
| 307 | /* Required to back map a kref to its containing object */ | ||
| 308 | #define from_kref(k) container_of(k, struct hvcs_struct, kref) | ||
| 309 | |||
| 310 | static LIST_HEAD(hvcs_structs); | 304 | static LIST_HEAD(hvcs_structs); |
| 311 | static DEFINE_SPINLOCK(hvcs_structs_lock); | 305 | static DEFINE_SPINLOCK(hvcs_structs_lock); |
| 312 | static DEFINE_MUTEX(hvcs_init_mutex); | 306 | static DEFINE_MUTEX(hvcs_init_mutex); |
| @@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut | |||
| 422 | 416 | ||
| 423 | spin_lock_irqsave(&hvcsd->lock, flags); | 417 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 424 | 418 | ||
| 425 | if (hvcsd->open_count > 0) { | 419 | if (hvcsd->port.count > 0) { |
| 426 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 420 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 427 | printk(KERN_INFO "HVCS: vterm state unchanged. " | 421 | printk(KERN_INFO "HVCS: vterm state unchanged. " |
| 428 | "The hvcs device node is still in use.\n"); | 422 | "The hvcs device node is still in use.\n"); |
| @@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) | |||
| 564 | static void hvcs_try_write(struct hvcs_struct *hvcsd) | 558 | static void hvcs_try_write(struct hvcs_struct *hvcsd) |
| 565 | { | 559 | { |
| 566 | uint32_t unit_address = hvcsd->vdev->unit_address; | 560 | uint32_t unit_address = hvcsd->vdev->unit_address; |
| 567 | struct tty_struct *tty = hvcsd->tty; | 561 | struct tty_struct *tty = hvcsd->port.tty; |
| 568 | int sent; | 562 | int sent; |
| 569 | 563 | ||
| 570 | if (hvcsd->todo_mask & HVCS_TRY_WRITE) { | 564 | if (hvcsd->todo_mask & HVCS_TRY_WRITE) { |
| @@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) | |||
| 602 | spin_lock_irqsave(&hvcsd->lock, flags); | 596 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 603 | 597 | ||
| 604 | unit_address = hvcsd->vdev->unit_address; | 598 | unit_address = hvcsd->vdev->unit_address; |
| 605 | tty = hvcsd->tty; | 599 | tty = hvcsd->port.tty; |
| 606 | 600 | ||
| 607 | hvcs_try_write(hvcsd); | 601 | hvcs_try_write(hvcsd); |
| 608 | 602 | ||
| @@ -701,10 +695,9 @@ static void hvcs_return_index(int index) | |||
| 701 | hvcs_index_list[index] = -1; | 695 | hvcs_index_list[index] = -1; |
| 702 | } | 696 | } |
| 703 | 697 | ||
| 704 | /* callback when the kref ref count reaches zero */ | 698 | static void hvcs_destruct_port(struct tty_port *p) |
| 705 | static void destroy_hvcs_struct(struct kref *kref) | ||
| 706 | { | 699 | { |
| 707 | struct hvcs_struct *hvcsd = from_kref(kref); | 700 | struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); |
| 708 | struct vio_dev *vdev; | 701 | struct vio_dev *vdev; |
| 709 | unsigned long flags; | 702 | unsigned long flags; |
| 710 | 703 | ||
| @@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref) | |||
| 741 | kfree(hvcsd); | 734 | kfree(hvcsd); |
| 742 | } | 735 | } |
| 743 | 736 | ||
| 737 | static const struct tty_port_operations hvcs_port_ops = { | ||
| 738 | .destruct = hvcs_destruct_port, | ||
| 739 | }; | ||
| 740 | |||
| 744 | static int hvcs_get_index(void) | 741 | static int hvcs_get_index(void) |
| 745 | { | 742 | { |
| 746 | int i; | 743 | int i; |
| @@ -789,10 +786,9 @@ static int __devinit hvcs_probe( | |||
| 789 | if (!hvcsd) | 786 | if (!hvcsd) |
| 790 | return -ENODEV; | 787 | return -ENODEV; |
| 791 | 788 | ||
| 792 | 789 | tty_port_init(&hvcsd->port); | |
| 790 | hvcsd->port.ops = &hvcs_port_ops; | ||
| 793 | spin_lock_init(&hvcsd->lock); | 791 | spin_lock_init(&hvcsd->lock); |
| 794 | /* Automatically incs the refcount the first time */ | ||
| 795 | kref_init(&hvcsd->kref); | ||
| 796 | 792 | ||
| 797 | hvcsd->vdev = dev; | 793 | hvcsd->vdev = dev; |
| 798 | dev_set_drvdata(&dev->dev, hvcsd); | 794 | dev_set_drvdata(&dev->dev, hvcsd); |
| @@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) | |||
| 852 | 848 | ||
| 853 | spin_lock_irqsave(&hvcsd->lock, flags); | 849 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 854 | 850 | ||
| 855 | tty = hvcsd->tty; | 851 | tty = hvcsd->port.tty; |
| 856 | 852 | ||
| 857 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 853 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 858 | 854 | ||
| @@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) | |||
| 860 | * Let the last holder of this object cause it to be removed, which | 856 | * Let the last holder of this object cause it to be removed, which |
| 861 | * would probably be tty_hangup below. | 857 | * would probably be tty_hangup below. |
| 862 | */ | 858 | */ |
| 863 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 859 | tty_port_put(&hvcsd->port); |
| 864 | 860 | ||
| 865 | /* | 861 | /* |
| 866 | * The hangup is a scheduled function which will auto chain call | 862 | * The hangup is a scheduled function which will auto chain call |
| @@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) | |||
| 1094 | list_for_each_entry(hvcsd, &hvcs_structs, next) { | 1090 | list_for_each_entry(hvcsd, &hvcs_structs, next) { |
| 1095 | spin_lock_irqsave(&hvcsd->lock, flags); | 1091 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1096 | if (hvcsd->index == index) { | 1092 | if (hvcsd->index == index) { |
| 1097 | kref_get(&hvcsd->kref); | 1093 | tty_port_get(&hvcsd->port); |
| 1098 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1094 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1099 | spin_unlock(&hvcs_structs_lock); | 1095 | spin_unlock(&hvcs_structs_lock); |
| 1100 | return hvcsd; | 1096 | return hvcsd; |
| @@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) | |||
| 1138 | if ((retval = hvcs_partner_connect(hvcsd))) | 1134 | if ((retval = hvcs_partner_connect(hvcsd))) |
| 1139 | goto error_release; | 1135 | goto error_release; |
| 1140 | 1136 | ||
| 1141 | hvcsd->open_count = 1; | 1137 | hvcsd->port.count = 1; |
| 1142 | hvcsd->tty = tty; | 1138 | hvcsd->port.tty = tty; |
| 1143 | tty->driver_data = hvcsd; | 1139 | tty->driver_data = hvcsd; |
| 1144 | 1140 | ||
| 1145 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); | 1141 | memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); |
| @@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) | |||
| 1160 | * and will grab the spinlock and free the connection if it fails. | 1156 | * and will grab the spinlock and free the connection if it fails. |
| 1161 | */ | 1157 | */ |
| 1162 | if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { | 1158 | if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { |
| 1163 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 1159 | tty_port_put(&hvcsd->port); |
| 1164 | printk(KERN_WARNING "HVCS: enable device failed.\n"); | 1160 | printk(KERN_WARNING "HVCS: enable device failed.\n"); |
| 1165 | return rc; | 1161 | return rc; |
| 1166 | } | 1162 | } |
| @@ -1171,8 +1167,8 @@ fast_open: | |||
| 1171 | hvcsd = tty->driver_data; | 1167 | hvcsd = tty->driver_data; |
| 1172 | 1168 | ||
| 1173 | spin_lock_irqsave(&hvcsd->lock, flags); | 1169 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1174 | kref_get(&hvcsd->kref); | 1170 | tty_port_get(&hvcsd->port); |
| 1175 | hvcsd->open_count++; | 1171 | hvcsd->port.count++; |
| 1176 | hvcsd->todo_mask |= HVCS_SCHED_READ; | 1172 | hvcsd->todo_mask |= HVCS_SCHED_READ; |
| 1177 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1173 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1178 | 1174 | ||
| @@ -1186,7 +1182,7 @@ open_success: | |||
| 1186 | 1182 | ||
| 1187 | error_release: | 1183 | error_release: |
| 1188 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1184 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1189 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 1185 | tty_port_put(&hvcsd->port); |
| 1190 | 1186 | ||
| 1191 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); | 1187 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); |
| 1192 | return retval; | 1188 | return retval; |
| @@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
| 1216 | hvcsd = tty->driver_data; | 1212 | hvcsd = tty->driver_data; |
| 1217 | 1213 | ||
| 1218 | spin_lock_irqsave(&hvcsd->lock, flags); | 1214 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1219 | if (--hvcsd->open_count == 0) { | 1215 | if (--hvcsd->port.count == 0) { |
| 1220 | 1216 | ||
| 1221 | vio_disable_interrupts(hvcsd->vdev); | 1217 | vio_disable_interrupts(hvcsd->vdev); |
| 1222 | 1218 | ||
| @@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
| 1225 | * execute any operations on the TTY even though it is obligated | 1221 | * execute any operations on the TTY even though it is obligated |
| 1226 | * to deliver any pending I/O to the hypervisor. | 1222 | * to deliver any pending I/O to the hypervisor. |
| 1227 | */ | 1223 | */ |
| 1228 | hvcsd->tty = NULL; | 1224 | hvcsd->port.tty = NULL; |
| 1229 | 1225 | ||
| 1230 | irq = hvcsd->vdev->irq; | 1226 | irq = hvcsd->vdev->irq; |
| 1231 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1227 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| @@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
| 1240 | tty->driver_data = NULL; | 1236 | tty->driver_data = NULL; |
| 1241 | 1237 | ||
| 1242 | free_irq(irq, hvcsd); | 1238 | free_irq(irq, hvcsd); |
| 1243 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 1239 | tty_port_put(&hvcsd->port); |
| 1244 | return; | 1240 | return; |
| 1245 | } else if (hvcsd->open_count < 0) { | 1241 | } else if (hvcsd->port.count < 0) { |
| 1246 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" | 1242 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" |
| 1247 | " is missmanaged.\n", | 1243 | " is missmanaged.\n", |
| 1248 | hvcsd->vdev->unit_address, hvcsd->open_count); | 1244 | hvcsd->vdev->unit_address, hvcsd->port.count); |
| 1249 | } | 1245 | } |
| 1250 | 1246 | ||
| 1251 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1247 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1252 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 1248 | tty_port_put(&hvcsd->port); |
| 1253 | } | 1249 | } |
| 1254 | 1250 | ||
| 1255 | static void hvcs_hangup(struct tty_struct * tty) | 1251 | static void hvcs_hangup(struct tty_struct * tty) |
| @@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
| 1261 | 1257 | ||
| 1262 | spin_lock_irqsave(&hvcsd->lock, flags); | 1258 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1263 | /* Preserve this so that we know how many kref refs to put */ | 1259 | /* Preserve this so that we know how many kref refs to put */ |
| 1264 | temp_open_count = hvcsd->open_count; | 1260 | temp_open_count = hvcsd->port.count; |
| 1265 | 1261 | ||
| 1266 | /* | 1262 | /* |
| 1267 | * Don't kref put inside the spinlock because the destruction | 1263 | * Don't kref put inside the spinlock because the destruction |
| @@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
| 1273 | hvcsd->todo_mask = 0; | 1269 | hvcsd->todo_mask = 0; |
| 1274 | 1270 | ||
| 1275 | /* I don't think the tty needs the hvcs_struct pointer after a hangup */ | 1271 | /* I don't think the tty needs the hvcs_struct pointer after a hangup */ |
| 1276 | hvcsd->tty->driver_data = NULL; | 1272 | tty->driver_data = NULL; |
| 1277 | hvcsd->tty = NULL; | 1273 | hvcsd->port.tty = NULL; |
| 1278 | 1274 | ||
| 1279 | hvcsd->open_count = 0; | 1275 | hvcsd->port.count = 0; |
| 1280 | 1276 | ||
| 1281 | /* This will drop any buffered data on the floor which is OK in a hangup | 1277 | /* This will drop any buffered data on the floor which is OK in a hangup |
| 1282 | * scenario. */ | 1278 | * scenario. */ |
| @@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty) | |||
| 1301 | * NOTE: If this hangup was signaled from user space then the | 1297 | * NOTE: If this hangup was signaled from user space then the |
| 1302 | * final put will never happen. | 1298 | * final put will never happen. |
| 1303 | */ | 1299 | */ |
| 1304 | kref_put(&hvcsd->kref, destroy_hvcs_struct); | 1300 | tty_port_put(&hvcsd->port); |
| 1305 | } | 1301 | } |
| 1306 | } | 1302 | } |
| 1307 | 1303 | ||
| @@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty, | |||
| 1347 | * the middle of a write operation? This is a crummy place to do this | 1343 | * the middle of a write operation? This is a crummy place to do this |
| 1348 | * but we want to keep it all in the spinlock. | 1344 | * but we want to keep it all in the spinlock. |
| 1349 | */ | 1345 | */ |
| 1350 | if (hvcsd->open_count <= 0) { | 1346 | if (hvcsd->port.count <= 0) { |
| 1351 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1347 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1352 | return -ENODEV; | 1348 | return -ENODEV; |
| 1353 | } | 1349 | } |
| @@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty) | |||
| 1421 | { | 1417 | { |
| 1422 | struct hvcs_struct *hvcsd = tty->driver_data; | 1418 | struct hvcs_struct *hvcsd = tty->driver_data; |
| 1423 | 1419 | ||
| 1424 | if (!hvcsd || hvcsd->open_count <= 0) | 1420 | if (!hvcsd || hvcsd->port.count <= 0) |
| 1425 | return 0; | 1421 | return 0; |
| 1426 | 1422 | ||
| 1427 | return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; | 1423 | return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; |
