Arnd and Greg,
I'm working on a TTY driver for a virtual device that we call "byte channels".
This are likes pipes, but they go through an ePAPR hypervisor.
The hypervisor declares byte channels as nodes in a device tree. Each byte
channel has a unique 32-bit number called a "handle", and this handle is
specified in the node for that device tree. Applications are expected to scan
the device tree to look for the node they want, and then extract the handle from
that node.
The problem I have is that the handles are, from Linux's perspective, arbitrary
and sparsely assigned. For example, we could have four byte channels with
handles of 2, 8, 73, and 74.
What I would like is for the minor number for each tty device to be the byte
channel handle. Or the byte channel could be in the /dev name. Either way,
applications can figure out which /dev entry to open in order to communicate
with a given byte channel.
Unfortunately, the only way I know how to do this is to create a separate tty
driver instance for each byte channel. This is because of this code in
tty_register_driver:
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
}
The 'index' passed to tty_register_device() is added to minor_start to create
the /dev entry, and it's added to name_base to create the name. If I specify a
very large number for driver->num, then tty_register_driver will create a large
but sparsely-populated array.
Would you be okay with creating a separate driver for each byte channel, or is
there a better way to do what I want?
--
Timur Tabi
Linux kernel developer at Freescale
--
Why would you need this mapping? Just do a first-come-first serve assignment of tty minor devices like all other subsystems do (usb, serial, acm, etc.) sysfs will show the representation between your ePAPR device "handle" and the tty device minor just fine, as it does today for those other types of devices. Bonus being that udev will create a persistant device id for your tty device based on that handle so you can just open that if you want to, no need to get the kernel involved in sparse minor mappings at all. Hope this helps, greg k-h --
It's a specification for an interface between the boot loader and the operating system. It's based on the device tree model that exists on PowerPC today. ePAPR defines a bunch of extensions, including one for hypervisors. The byte Without some kind of mapping, there's no way for an application to know which I don't see how. A byte channel node defines several properties, one of which could be a text string that acts as a label. So if an application is looking for the "channel-to-partition-two" byte channel, it can search for that string in the device tree. Once it finds the matching node, it can extract the byte channel handle. At this point, the application will want to open a /dev entry that corresponds to that byte channel handle. This is the piece I'm missing with the tty layer. If I want to create a regular character device, I can do this: bc->dev_id = MKDEV(MAJOR(dev_id), MINOR(dev_id) + i); device_create(ehv_bc_class, NULL, bc->dev_id, bc, "bc%u", bc->handle); Here, I control the name of the /dev entry via "bc%u". I want something similar I'm not sure I understand that. In order for udev to do this, I need to tell it what the byte channel handle actually is. How do I do that using the tty layer? -- Timur Tabi Linux kernel developer at Freescale --
No, you want to have a tty device attached to your "byte channel device". That will give you the correct mapping here. Your tty device number is sequencial and has nothing in its name to do with your "byte channel device number" just like ttyS1 has nothing in its pci device id You just create your tty device and assign the parent of it to be your "byte channel device". Just like we do for PCI, USB, and all other bus device types. I think you are forgetting that your byte channel devices must be "devices" in the system here, right? There is a 'struct bus_id" for your bus that these devices live on. Then you create a tty device in your tty driver that attaches to the byte channel that shows up as a tty device on your bus. Does that help explain things a bit better? thanks, greg k-h --
Do you mean "struct bus_type"? I don't have any concept of a "bus" in my driver. I didn't know I needed to create one, and I'm not sure how, either. I guess my real problem is that I'm not really sure what I should be doing. I already have a plain character driver that creates devices for each byte channel. First I call alloc_chrdev_region() to get a started dev_id. Then I iterate over the byte channels and call device_create() for each one, with NULL for the parent. At the end, I call cdev_init() and cdev_add(). Now I'm trying to register these byte channels as tty devices, because I'd like to use them for the system console, and not just plain character devices. My plan was to just call tty_register_device() instead of device_create(), so I Are you saying that when I call tty_register_device(), the third parameter should be the return value from the previous call to device_create(), like this: bc->dev_id = MKDEV(MAJOR(dev_id), MINOR(dev_id) + i); bc->dev = device_create(ehv_bc_class, NULL, bc->dev_id, bc, "bc%u", bc->handle); tty_register_device(ehv_bc_driver, MINOR(bc->dev_id), bc->dev); -- Timur Tabi Linux kernel developer at Freescale --
You need to create one as you really have a "bus" here, as you Ick, no. Please take a step back and go to your original message where you described something like "we have a bus and devices we discover on the bus and they have ids". Because of that, you should just create a bus, create the devices on the bus, and then, attach specific types of drivers to those devices (like your tty driver.) And your bus is automatically discoverable, right? So you don't need any interface for userspace to "create" devices, so you should be fine. If it's not discoverable, go kick some firmware programmers butt and make it so, as that is unforgivable in this age. Seriously, that's flat out broken and wrong, get it fixed first. thanks, greg k-h --
What about the fact that it's an Open Firmware driver? My driver gets probed for each byte channel node in the device tree. I'm still not sure why you think I have a bus. I don't see where the UART drivers register a bus, and there's not a whole lot different between a byte I never said we have a bus. There is no entity that conglomerates the byte channels. -- Timur Tabi Linux kernel developer at Freescale --
Why not? It sounds like there should be, right? That would make things much easier for you in the end from what I can tell. thanks, greg k-h --
Well, sure. A byte channel is just a software concept. You can send data, receive data, and poll a byte channel. You can't set the baud rate, or send break signals or even do flow control. I debated making the driver act like a fake serial device, which probably would have been easier but not "correct". Unfortunately, I seem to lack some fundamental understanding of tty drivers that is making my life difficult. I've been reading all the documentation that I can get my hands on, as well as studying a lot of source code, but I still can't find any example to base *my* code on. I just don't know if what I'm doing is right. I still don't know how to connect the byte channel handle with the /dev entry. I'm not so sure. Like I said, I still don't see where there's a bus. I have a single driver that has multiple devices. It sounds to me like one call to tty_register_driver() and multiple calls to tty_register_device() would be sufficient. For instance, there is no code in drivers/char/ that makes a call to bus_register(), so I don't see any precedent for a tty driver to register a bus first. Also, this is an Open Firmware driver. I already have a mechanism whereby I get probed for each instance of a byte channel. Isn't that my "bus"? I'm really trying to do the right thing here, Greg, but every time I try to solve one problem, I'm being told that I need to make things way more complicated first. -- Timur Tabi Linux kernel developer at Freescale --
Ok, I think I'm getting totally confused here. If all you want is a tty driver, then just write a tty driver. No need for character device nodes or any of that other stuff. Just assign minor numbers to the device, create it, attach it to the tty core, and away you go. I think you are going to have to show code here to get any kind of a better response out of me as I don't think we are understanding each other here, sorry. greg k-h --
What I would like to do is have some control over the name or minor number of I'll have to email it to you directly, since it's not authorized for public distribution just quite yet. -- Timur Tabi Linux kernel developer at Freescale --
Why? Again, it doesn't matter, and no other tty driver does it.
Actually you do have control over it, if you really want it, but again,
Sorry, I can't do code review, or accept code that is not allowed to be
sent to the public, as, surprise, I'm public :)
So you just sent me an illegal file, great, should I expect to hear from
your lawyers now?
{sigh}
I deal enough with lawyers as it is, please don't do this...
greg k-h
--
Because the only way to know which byte channel tty you want is via the byte channel handle. Think of the situation where you have two serial ports on the back of your computer. One of them is /dev/ttyS0, and the other is /dev/ttyS1. But which one is which? The only way to find out is try one and see if it works. Now that might be acceptable for serial ports that are fixed physically. But byte channels handles are completely arbitrary and easily change with even the slightest re-configuration of the partitions under the hypervisor. I need to Well, ok. I didn't want to spam the mailing list with something that only you asked for, but here it is: /* ePAPR hypervisor byte channel device driver * * Copyright 2009-2010 Freescale Semiconductor, Inc. * * Author: Timur Tabi <timur@freescale.com> * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. * * This driver support four distinct interfaces, all of which are related to * ePAPR hypervisor byte channels. * * 1) An early-console (udbg) driver. This provides early console output * through a byte channel. The byte channel handle must be specified in a * Kconfig option. * * 2) A normal console driver. Output is sent to the byte channel designated * for stdout in the device tree. * * 3) A tty driver. * * 4) A byte channel character driver. This driver creates a /dev/bcXX * character device for each byte channel. The "XX" is the byte channel * handle. */ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/poll.h> #include <asm/epapr_hcalls.h> #include <linux/of.h> #include <linux/cdev.h> #include <linux/console.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <asm/udbg.h> /* Byte channel handle for stdout (and stdin), taken from device tree ...
No, you can use the /dev/serial/ links to determine exactly which is which depending on the pci id, and other unique identifiers (serial Is this somehow not public code? What just changed in the past 15 minutes? confused, greg k-h --
I just booted a Linux kernel with the driver I just emailed you, and there's no /dev/serial/ directory. The only directories under /dev/ are 'shm' and 'pts', both of which are empty. I'm also running a Fedora 13 x86 system, just to see if I need a full modern OS to see these files. Again, there is no /dev/serial/, even though I have serial ports. Also not that since I'm not registering the byte channels as serial devices, I wouldn't expect anything in /dev/serial/ to reference them. What does my driver need to do in order for these /dev/xxxx/ entries to contain Sorry, when I said "not public", I didn't mean it in a legal sense. Now that I think about it, I guess that doesn't make much sense. -- Timur Tabi Linux kernel developer at Freescale --
Then plug in a serial port device and see what happens. You didn't hook everything up in your driver correctly it seems, do your devices show up Yes, it didn't :) --
If I delete the call to device_create() in ehv_bc_init() (so that it creates the
TTY devices only, and not the character devices), I get this:
# ls -l /sys/class/tty/ttyEHV*
lrwxrwxrwx 1 root root 0 Jan 1 00:04 /sys/class/tty/ttyEHV0
-> ../../devices/virtual/tty/ttyEHV0
lrwxrwxrwx 1 root root 0 Jan 1 00:04 /sys/class/tty/ttyEHV1
-> ../../devices/virtual/tty/ttyEHV1
lrwxrwxrwx 1 root root 0 Jan 1 00:04 /sys/class/tty/ttyEHV2
udev rules still need some way for the driver to tell user-space that
/dev/ttyEHV0 is associated with byte channel handle 73. I still don't know what
mechanism my driver is supposed to use to make that information available to
user space.
I could fake it by doing this:
for (i = 0; i < num_byte_channels; i++) {
bc->handle = get_the_byte_channel_handle(i);
ehv_bc_driver->name_base = bc->handle - i;
tty_register_device(ehv_bc_driver, i, NULL);
}
This actually works and does what I want, but I seriously doubt it's acceptable.
When I do this, I get:
# ls -l /dev/ttyEH*
crw-rw---- 1 root uucp 253, 0 Jan 1 00:00 /dev/ttyEHV73
crw-rw---- 1 root uucp 253, 1 Jan 1 00:00 /dev/ttyEHV76
crw-rw---- 1 root uucp 253, 2 Jan 1 00:00 /dev/ttyEHV79
--
Timur Tabi
Linux kernel developer at Freescale
--
Why are you not setting up a parent device of your tty device? That Does that work for you? Looks fine to me :) But again, you really should get the driver model portion right... thanks, greg k-h --
I'll do that. One last question. If I create multiple TTY devices, how do I tell the kernel which one should be used for the console? -- Timur Tabi Linux kernel developer at Freescale --
Is there a way to do it in the driver itself? Getting the boot loader to identify the specific byte channel for stdout isn't trivial. It'd be nice if the driver could tell the tty layer, "BTW, this use this for the default console". -- Timur Tabi Linux kernel developer at Freescale --
On Thu, 18 Nov 2010 14:43:17 -0600 You can - provide the required method in your console driver and it'll get used by /dev/console. Funnily enough a lot of other platform and consoles need that too. Alan --
Never mind .. I got it working. For some reason, it took a while for me to get add_preferred_console() working. -- Timur Tabi Linux kernel developer at Freescale --
Can you elaborate on that? What is the "required method"? My driver is mostly working now, but I have to supply the command-line "console=ttyEHV73" in order for the login prompt to show up. Unfortunately, there's no way for the boot loader to know that the primary byte channel for stdout is #73, so I need a way for the driver to tell the kernel this. Also, if I have a /dev/ttyEHV76 entry for a byte channel that's not the primary stdout tty, is the following supposed to work: cat > /dev/ttyEHV76 That is, should I be able to use a TTY device as a normal character device, where I can just write and read characters? -- Timur Tabi Linux kernel developer at Freescale --
Your console driver provides a device method (see kernel/printk.c). When /dev/console is opened the kernel iterates the console list looking for one with ->device and then calls that method. On success it expects the passed int * to contain the minor number to use. I suspect in your case you probably want to attach the primary byte channel to minor 0 in the driver (and reserve it for that), or some Sort of - processing gets done but you can disable the processing easily enough. If you have channels that are not tty related you may want to tap them directly to avoid the overhead of the tty layer if they are high data rate. Alan --
Are you talking about this:
static struct tty_driver *ehv_bc_console_device(struct console *co, int *index)
{
*index = co->index;
return ehv_bc_driver;
}
I never really understood this function, but almost everyone does the same
thing, and it seems to work for me. Looking at console_device(), it appears
that all of the xxx_console_device functions are called in order until one of
them returns non-NULL.
How is this related to add_preferred_console()? When I call this function, I
also specify the same index and the name from the struct console device:
static struct console ehv_bc_console = {
.name = "ttyEHV",
.write = ehv_bc_console_write,
.device = ehv_bc_console_device,
.flags = CON_PRINTBUFFER | CON_ENABLED,
};
add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
Yes, that's a good idea. It does simplify things a lot.
--
Timur Tabi
Linux kernel developer at Freescale
--
*index is the minor number to use - so you can return whichever minor It's probably the cleanest and simplest solution and it fits the "natural" order of things. --
On Thu, 18 Nov 2010 10:03:12 -0600 The tty driver doesn't register the bus, but rather a driver for some type of device on that bus. The code to create the bus goes It would be if you actually had it -- but it looks like you just loop over the nodes. We should add a proper bus for the "handles" node. Then sysfs should show the link between the tty device and a device tree node -- which is s/make things way more complicated/use the existing infrastructure rather than reinvent the wheel/ And getting rid of the redundant chardev driver would be a simplification... -Scott --
Which code to create the bus? Are you saying that the driver should call Well, ok, but I can change that. If I drop the normal character driver registration and register the byte channels only as tty devices, then I can make it probe-able. The reason I don't do it now is because, for a normal character device, I need to call cdev_init() and cdev_add() after all devices have been registered, which can't be done in an OF driver since I don't get told when I agree there, but so far people have been telling me, "just do this!" without actually telling me how to do "this". -- Timur Tabi Linux kernel developer at Freescale --
On Thu, 18 Nov 2010 11:42:21 -0600 No, the bus code calls that (probably drivers/base/platform.c in this Pass the platform device pointer to tty_register_device. Then, in the sysfs node, "driver" should be a symlink to another sysfs node whose path looks lind of like an OF path. Unfortunately, it's not an exact match, and the fact that reg doesn't translate to a physical address means that AFAICT you'll currently get something like "byte-channel.nnn", where "nnn" is an arbitrary kernel-assigned number. It would be nice if platform devices that are created from device tree nodes included a link to the corresponding /proc/device-tree node in their sysfs node. Other than that, I guess you could add hv handle support to of_device_make_bus_id. -Scott --
It's not a link, but the OF path is in devspec, so you can work it out fairly easily. cheers
On Wed, 24 Nov 2010 21:23:47 +1100 Ah, didn't know about that. Still, might be nice to add support for Hmm, I see a "devspec" in PCI devices, but not in devtree-probed platform devices. of_bus_type_init isn't being called from anywhere but the ibmebus code. It looks like this was a casualty of merging of_platform with platform (commit eca3930163ba8884060ce9d9ff5ef0d9b7c7b00f). -Scott --
No, please never use that function, bad things will happen. thanks, greg k-h --
Why? The network & wireless code uses it, so presumably it can work? If
not please consider:
commit f470f680dfaad8731f079a033a50440082e20930
Author: Michael Ellerman <michael@ellerman.id.au>
Date: Thu Nov 25 09:41:28 2010 +1100
driver core: Document that device_rename() is not to be used
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 6ed6454..f1fac19 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1513,6 +1513,8 @@ EXPORT_SYMBOL_GPL(device_destroy);
* exclusion between two different calls of device_rename
* on the same device to ensure that new_name is valid and
* won't conflict with other devices.
+ *
+ * "Never use this function, bad things will happen" - gregkh
*/
int device_rename(struct device *dev, const char *new_name)
{
Nice, I like it :) I'll go queue this up. greg k-h --
I really don't want to get into it, but the networking code is the only thing that allows this due to the userspace "want" to rename devices because we can't create symlinks to network devices like we can for all other devices (as they use device nodes.) When this function is called, userspace had better know exactly what is going on as it can get confused due to the lack of uevents happening. thanks, greg k-h --
Thanks for the explanation, but I'm just concerned that you'll add a comment that says, "don't call this function". A quick grep will show that there are users of this function, and we'll have this exact conversation all over again. -- Timur Tabi Linux kernel developer at Freescale --
Sure, I'll take care of it tomorrow. -- Timur Tabi Linux kernel developer --
One question: why are uevents not happening? -- Timur Tabi Linux kernel developer at Freescale --
What uevent would describe this? Userspace asked for the rename to happen, so it better be aware that it did. We don't want to do a "remove" and then "add" sequence of events, that would confuse everyone. thanks, greg k-h --
A bit more details: First: never rename anything! :) It's racy at many levels, symlinks and other stuff are not replaced atomically, you get a "move" uevent", but it's not easy to connect the event to the old and new device. Device nodes are not renamed at all, there isn't even support for that in the kernel now. In the meantime during renaming, your target name might be taken by another driver, creating conflicts. Or the old name is taken directly after you renamed it -- then you get events for the same DEVPATH, before you even seet the "move" event. It's just a mess, and nothing new should ever rely on kernel device renaming. Besides that it's not even implemented now for other things than (driver-core wise very simple) network devices. We are currently about to change network renaming in udev to completely disallow renaming of devices in the same namespace as the kernel uses, because we can't solve the problems properly, that arise with swapping names of multiple interfaces without races. Means, renaming of eth[0-9]* will only be allowed to some other name than eth[0-9]*, for the mentioned reasons. Make up a "real" name in the driver before you register anything, or add some other attributes for userspace to find the device, or use udev to add symlinks -- but never rename kernel devices later, it's a complete mess. We don't even want to get into that and try to implement the missing pieces in the core. We really have other pieces to fix in the driver core mess. :) Kay --
Kay, thank you so much for this explanation. I wish every function in the kernel were described so thoroughly! My life would be so much easier. I put your text into a patch and posted it for review. -- Timur Tabi Linux kernel developer at Freescale --
Ah crud, yeah I was looking at an old kernel. That seems like a regression, but seemingly no one has complained so perhaps it doesn't matter in practice. It was certainly a nice feature though. cheers
On Wed, Nov 24, 2010 at 3:46 PM, Michael Ellerman Hmmm, I missed that when merging. Oops. devspec is easy enough to add back since there isn't a conflict. It can even be made system-wide (not just platform bus) since any device can have an of_node now. However, the modalias and name attributes are a lot harder since there are name conflicts. g. -- Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. --
[sorry for the resend, fixed the devtree list address] On Wed, 24 Nov 2010 21:23:47 +1100 Ah, didn't know about that. Still, might be nice to add support for Hmm, I see a "devspec" in PCI devices, but not in devtree-probed platform devices. of_bus_type_init isn't being called from anywhere but the ibmebus code. It looks like this was a casualty of merging of_platform with platform (commit eca3930163ba8884060ce9d9ff5ef0d9b7c7b00f). -Scott --
