From: David Daney <hidden> Date: 2011-03-17 01:27:35
I wanted to get some feedback on my attempts to control my serial
device registration with device tree data.
It was suggested by Grant Likely that I could use of_serial.c for my
purposes. However I think it is simpler to do my own registration
code, because I need to set my own device type, required port flags,
and I/O functions, instead of using general purpose ones. Adding this
to of_serial.c would be quite ugly, so I would like to keep it with my
chip/board code.
This leads to a problem: You cannot call serial8250_register_port()
until the 8250.c driver is registered. of_serial.c is lucky that it
comes after 8250.c in the make file so that the device initcall order
is correct. When I put the code in my board's serial.c file, I am not
so lucky. To get the initialization order correct, I add a notifier
chain to 8250.c
What say you all to this approach?
David Daney (2):
serial: 8250: Add a notifier chain for driver registration.
MIPS: Octeon: Use device tree to register serial ports.
arch/mips/cavium-octeon/serial.c | 140 ++++++++++++++++----------------------
drivers/tty/serial/8250.c | 20 ++++++
include/linux/serial_8250.h | 21 ++++++
3 files changed, 101 insertions(+), 80 deletions(-)
--
1.7.2.3
From: David Daney <hidden> Date: 2011-03-17 01:26:49
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized, so we add a notifier chain just for this driver. When the
SERIAL8250_DRIVER_ADD notifier is called, we know it is safe to call
serial8250_register_port(), and we can add our devices.
Signed-off-by: David Daney <redacted>
---
drivers/tty/serial/8250.c | 20 ++++++++++++++++++++
include/linux/serial_8250.h | 21 +++++++++++++++++++++
2 files changed, 41 insertions(+), 0 deletions(-)
From: David Daney <hidden> Date: 2011-03-17 01:27:47
Switch to using the device tree to register serial ports.
After the serial8250 driver indicates that it is initialized, add all
the ports with compatible = "cavium,octeon-3860-uart". Octeon serial
ports have their own device type, required port flags, and I/O
functions, so using of_serial.c is not indicated.
Signed-off-by: David Daney <redacted>
---
arch/mips/cavium-octeon/serial.c | 140 ++++++++++++++++----------------------
1 files changed, 60 insertions(+), 80 deletions(-)
@@ -43,95 +43,75 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)cvmx_write_csr((uint64_t)(up->membase+(offset<<3)),(u8)value);}-/*-*Allocatedin.bss,soitisallzeroed.-*/-#define OCTEON_MAX_UARTS 3-staticstructplat_serial8250_portocteon_uart8250_data[OCTEON_MAX_UARTS+1];-staticstructplatform_deviceocteon_uart8250_device={-.name="serial8250",-.id=PLAT8250_DEV_PLATFORM,-.dev={-.platform_data=octeon_uart8250_data,-},-};--staticvoid__initocteon_uart_set_common(structplat_serial8250_port*p)+staticint__devinitocteon_serial_probe(structplatform_device*pdev){-p->flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;-p->type=PORT_OCTEON;-p->iotype=UPIO_MEM;-p->regshift=3;/* I/O addresses are every 8 bytes */+intirq,res;+structresource*res_mem;+structuart_portport;++/* All adaptors have an irq. */+irq=platform_get_irq(pdev,0);+if(irq<0)+returnirq;++memset(&port,0,sizeof(port));++port.flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;+port.type=PORT_OCTEON;+port.iotype=UPIO_MEM;+port.regshift=3;+port.dev=&pdev->dev;+if(octeon_is_simulation())/* Make simulator output fast*/-p->uartclk=115200*16;+port.uartclk=115200*16;else-p->uartclk=octeon_get_io_clock_rate();-p->serial_in=octeon_serial_in;-p->serial_out=octeon_serial_out;-}+port.uartclk=octeon_get_io_clock_rate();-staticint__initocteon_serial_init(void)-{-intenable_uart0;-intenable_uart1;-intenable_uart2;-structplat_serial8250_port*p;+port.serial_in=octeon_serial_in;+port.serial_out=octeon_serial_out;+port.irq=irq;-#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL-/*-*Ifweareconfiguredtorunasthesecondoftwokernels,-*disableuart0andenableuart1.Uart0isownedbythefirst-*kernel-*/-enable_uart0=0;-enable_uart1=1;-#else-/*-*Weareconfiguredforthefirstkernel.We'llenableuart0-*ifthebootloadertoldustouse0,otherwisewillenable-*uart1.-*/-enable_uart0=(octeon_get_boot_uart()==0);-enable_uart1=(octeon_get_boot_uart()==1);-#ifdef CONFIG_KGDB-enable_uart1=1;-#endif-#endif--/* Right now CN52XX is the only chip with a third uart */-enable_uart2=OCTEON_IS_MODEL(OCTEON_CN52XX);--p=octeon_uart8250_data;-if(enable_uart0){-/* Add a ttyS device for hardware uart 0 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(0);-p->mapbase=CVMX_MIO_UARTX_RBR(0)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART0;-p++;+res_mem=platform_get_resource(pdev,IORESOURCE_MEM,0);+if(res_mem==NULL){+dev_err(&pdev->dev,"found no memory resource\n");+return-ENXIO;}+port.mapbase=res_mem->start;+port.membase=ioremap(res_mem->start,resource_size(res_mem));-if(enable_uart1){-/* Add a ttyS device for hardware uart 1 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(1);-p->mapbase=CVMX_MIO_UARTX_RBR(1)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART1;-p++;-}-if(enable_uart2){-/* Add a ttyS device for hardware uart 2 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UART2_RBR;-p->mapbase=CVMX_MIO_UART2_RBR&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART2;-p++;-}+res=serial8250_register_port(&port);++returnres>=0?0:res;+}++staticstructof_device_idocteon_serial_match[]={+{+.compatible="cavium,octeon-3860-uart",+},+{},+};+MODULE_DEVICE_TABLE(of,octeon_serial_match);-BUG_ON(p>&octeon_uart8250_data[OCTEON_MAX_UARTS]);+staticstructplatform_driverocteon_serial_driver={+.probe=octeon_serial_probe,+.driver={+.owner=THIS_MODULE,+.name="octeon_serial",+.of_match_table=octeon_serial_match,+},+};-returnplatform_device_register(&octeon_uart8250_device);+staticintocteon_serial_register_driver(structnotifier_block*nb,+unsignedlongcode,void*arg)+{+if(code==SERIAL8250_DRIVER_ADD)+platform_driver_register(&octeon_serial_driver);+returnNOTIFY_OK;}-device_initcall(octeon_serial_init);+staticint__initocteon_serial_init(void)+{+returnserial8250_notifier(octeon_serial_register_driver,0);+}+arch_initcall(octeon_serial_init);
is correct. When I put the code in my board's serial.c file, I am not
so lucky. To get the initialization order correct, I add a notifier
chain to 8250.c
Can't you use a late_initcall ? or indeed we could make the 8250 core
functionality only init first ?
Alan
On Wed, 16 Mar 2011 18:26:06 -0700
David Daney [off-list ref] wrote:
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized
I've had a bigger dig into this. I think the correct answer is probably
"always go via platform devices or similar". That *is* the notifier in
the kernel of today. serial8250_register_port ultimately should I think
ultimatly become an internal helper.
Alan
From: David Daney <hidden> Date: 2011-03-17 16:42:44
On 03/17/2011 05:18 AM, Alan Cox wrote:
On Wed, 16 Mar 2011 18:26:06 -0700
David Daney[off-list ref] wrote:
quoted
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized
I've had a bigger dig into this. I think the correct answer is probably
"always go via platform devices or similar". That *is* the notifier in
the kernel of today. serial8250_register_port ultimately should I think
ultimatly become an internal helper.
That was kind of my thought too. However we have all sorts of things
calling serial8250_register_port(). Things like:
8250_pci.c
of_serial.c
8250_acorn.c
8250_gsc.c
.
.
.
The resulting view of the drivers in sysfs is that the little stub code
that calls serial8250_register_port() is shown as the driver rather than
serial8250. But I suppose that is a matter of aesthetics more than
function.
All those 'stub drivers' are relying on the ordering of module_init
calls caused indirectly by the Makefile layout. The path of least
resistance is your suggestion that I use late_initcall() in my driver
stub. I actually tried that before hacking up this patch, but didn't
like the idea of relying on *_initcall() ordering being necessary for
correct initialization.
David Daney
From: Grant Likely <hidden> Date: 2011-03-17 18:25:16
On Thu, Mar 17, 2011 at 12:18:49PM +0000, Alan Cox wrote:
On Wed, 16 Mar 2011 18:26:06 -0700
David Daney [off-list ref] wrote:
quoted
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized
I've had a bigger dig into this. I think the correct answer is probably
"always go via platform devices or similar". That *is* the notifier in
the kernel of today. serial8250_register_port ultimately should I think
ultimatly become an internal helper.
+1
Depending on serial8250_register_port() definitely the wrong thing to
do for platform support code. It would be better to figure out how to
get the dt bits you need into 8250.c or of_serial.c.
g.
From: Grant Likely <hidden> Date: 2011-03-17 18:28:59
On Wed, Mar 16, 2011 at 06:26:07PM -0700, David Daney wrote:
Switch to using the device tree to register serial ports.
After the serial8250 driver indicates that it is initialized, add all
the ports with compatible = "cavium,octeon-3860-uart". Octeon serial
ports have their own device type, required port flags, and I/O
functions, so using of_serial.c is not indicated.
What specifically is the list extra settings needed to make of_serial
work? From what I can see in this driver, nothing looks particularly
troublesome to handle.
g.
@@ -43,95 +43,75 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)cvmx_write_csr((uint64_t)(up->membase+(offset<<3)),(u8)value);}-/*-*Allocatedin.bss,soitisallzeroed.-*/-#define OCTEON_MAX_UARTS 3-staticstructplat_serial8250_portocteon_uart8250_data[OCTEON_MAX_UARTS+1];-staticstructplatform_deviceocteon_uart8250_device={-.name="serial8250",-.id=PLAT8250_DEV_PLATFORM,-.dev={-.platform_data=octeon_uart8250_data,-},-};--staticvoid__initocteon_uart_set_common(structplat_serial8250_port*p)+staticint__devinitocteon_serial_probe(structplatform_device*pdev){-p->flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;-p->type=PORT_OCTEON;-p->iotype=UPIO_MEM;-p->regshift=3;/* I/O addresses are every 8 bytes */+intirq,res;+structresource*res_mem;+structuart_portport;++/* All adaptors have an irq. */+irq=platform_get_irq(pdev,0);+if(irq<0)+returnirq;++memset(&port,0,sizeof(port));++port.flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;+port.type=PORT_OCTEON;+port.iotype=UPIO_MEM;+port.regshift=3;+port.dev=&pdev->dev;+if(octeon_is_simulation())/* Make simulator output fast*/-p->uartclk=115200*16;+port.uartclk=115200*16;else-p->uartclk=octeon_get_io_clock_rate();-p->serial_in=octeon_serial_in;-p->serial_out=octeon_serial_out;-}+port.uartclk=octeon_get_io_clock_rate();-staticint__initocteon_serial_init(void)-{-intenable_uart0;-intenable_uart1;-intenable_uart2;-structplat_serial8250_port*p;+port.serial_in=octeon_serial_in;+port.serial_out=octeon_serial_out;+port.irq=irq;-#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL-/*-*Ifweareconfiguredtorunasthesecondoftwokernels,-*disableuart0andenableuart1.Uart0isownedbythefirst-*kernel-*/-enable_uart0=0;-enable_uart1=1;-#else-/*-*Weareconfiguredforthefirstkernel.We'llenableuart0-*ifthebootloadertoldustouse0,otherwisewillenable-*uart1.-*/-enable_uart0=(octeon_get_boot_uart()==0);-enable_uart1=(octeon_get_boot_uart()==1);-#ifdef CONFIG_KGDB-enable_uart1=1;-#endif-#endif--/* Right now CN52XX is the only chip with a third uart */-enable_uart2=OCTEON_IS_MODEL(OCTEON_CN52XX);--p=octeon_uart8250_data;-if(enable_uart0){-/* Add a ttyS device for hardware uart 0 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(0);-p->mapbase=CVMX_MIO_UARTX_RBR(0)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART0;-p++;+res_mem=platform_get_resource(pdev,IORESOURCE_MEM,0);+if(res_mem==NULL){+dev_err(&pdev->dev,"found no memory resource\n");+return-ENXIO;}+port.mapbase=res_mem->start;+port.membase=ioremap(res_mem->start,resource_size(res_mem));-if(enable_uart1){-/* Add a ttyS device for hardware uart 1 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(1);-p->mapbase=CVMX_MIO_UARTX_RBR(1)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART1;-p++;-}-if(enable_uart2){-/* Add a ttyS device for hardware uart 2 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UART2_RBR;-p->mapbase=CVMX_MIO_UART2_RBR&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART2;-p++;-}+res=serial8250_register_port(&port);++returnres>=0?0:res;+}++staticstructof_device_idocteon_serial_match[]={+{+.compatible="cavium,octeon-3860-uart",+},+{},+};+MODULE_DEVICE_TABLE(of,octeon_serial_match);-BUG_ON(p>&octeon_uart8250_data[OCTEON_MAX_UARTS]);+staticstructplatform_driverocteon_serial_driver={+.probe=octeon_serial_probe,+.driver={+.owner=THIS_MODULE,+.name="octeon_serial",+.of_match_table=octeon_serial_match,+},+};-returnplatform_device_register(&octeon_uart8250_device);+staticintocteon_serial_register_driver(structnotifier_block*nb,+unsignedlongcode,void*arg)+{+if(code==SERIAL8250_DRIVER_ADD)+platform_driver_register(&octeon_serial_driver);+returnNOTIFY_OK;}-device_initcall(octeon_serial_init);+staticint__initocteon_serial_init(void)+{+returnserial8250_notifier(octeon_serial_register_driver,0);+}+arch_initcall(octeon_serial_init);
From: David Daney <hidden> Date: 2011-03-17 18:35:24
On 03/17/2011 11:28 AM, Grant Likely wrote:
On Wed, Mar 16, 2011 at 06:26:07PM -0700, David Daney wrote:
quoted
Switch to using the device tree to register serial ports.
After the serial8250 driver indicates that it is initialized, add all
the ports with compatible = "cavium,octeon-3860-uart". Octeon serial
ports have their own device type, required port flags, and I/O
functions, so using of_serial.c is not indicated.
What specifically is the list extra settings needed to make of_serial
work? From what I can see in this driver, nothing looks particularly
troublesome to handle.
Specifically:
+ port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ port.type = PORT_OCTEON;
+ port.serial_in = octeon_serial_in;
+ port.serial_out = octeon_serial_out;
This one is iffy:
+ port.uartclk = octeon_get_io_clock_rate();
Those octeon_serial_in() and octeon_serial_out() are chip specific code
that does not belong in a generic driver file like of_serial.c
David Daney
@@ -43,95 +43,75 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)cvmx_write_csr((uint64_t)(up->membase+(offset<<3)),(u8)value);}-/*-*Allocatedin.bss,soitisallzeroed.-*/-#define OCTEON_MAX_UARTS 3-staticstructplat_serial8250_portocteon_uart8250_data[OCTEON_MAX_UARTS+1];-staticstructplatform_deviceocteon_uart8250_device={-.name="serial8250",-.id=PLAT8250_DEV_PLATFORM,-.dev={-.platform_data=octeon_uart8250_data,-},-};--staticvoid__initocteon_uart_set_common(structplat_serial8250_port*p)+staticint__devinitocteon_serial_probe(structplatform_device*pdev){-p->flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;-p->type=PORT_OCTEON;-p->iotype=UPIO_MEM;-p->regshift=3;/* I/O addresses are every 8 bytes */+intirq,res;+structresource*res_mem;+structuart_portport;++/* All adaptors have an irq. */+irq=platform_get_irq(pdev,0);+if(irq<0)+returnirq;++memset(&port,0,sizeof(port));++port.flags=ASYNC_SKIP_TEST|UPF_SHARE_IRQ|UPF_FIXED_TYPE;+port.type=PORT_OCTEON;+port.iotype=UPIO_MEM;+port.regshift=3;+port.dev=&pdev->dev;+if(octeon_is_simulation())/* Make simulator output fast*/-p->uartclk=115200*16;+port.uartclk=115200*16;else-p->uartclk=octeon_get_io_clock_rate();-p->serial_in=octeon_serial_in;-p->serial_out=octeon_serial_out;-}+port.uartclk=octeon_get_io_clock_rate();-staticint__initocteon_serial_init(void)-{-intenable_uart0;-intenable_uart1;-intenable_uart2;-structplat_serial8250_port*p;+port.serial_in=octeon_serial_in;+port.serial_out=octeon_serial_out;+port.irq=irq;-#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL-/*-*Ifweareconfiguredtorunasthesecondoftwokernels,-*disableuart0andenableuart1.Uart0isownedbythefirst-*kernel-*/-enable_uart0=0;-enable_uart1=1;-#else-/*-*Weareconfiguredforthefirstkernel.We'llenableuart0-*ifthebootloadertoldustouse0,otherwisewillenable-*uart1.-*/-enable_uart0=(octeon_get_boot_uart()==0);-enable_uart1=(octeon_get_boot_uart()==1);-#ifdef CONFIG_KGDB-enable_uart1=1;-#endif-#endif--/* Right now CN52XX is the only chip with a third uart */-enable_uart2=OCTEON_IS_MODEL(OCTEON_CN52XX);--p=octeon_uart8250_data;-if(enable_uart0){-/* Add a ttyS device for hardware uart 0 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(0);-p->mapbase=CVMX_MIO_UARTX_RBR(0)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART0;-p++;+res_mem=platform_get_resource(pdev,IORESOURCE_MEM,0);+if(res_mem==NULL){+dev_err(&pdev->dev,"found no memory resource\n");+return-ENXIO;}+port.mapbase=res_mem->start;+port.membase=ioremap(res_mem->start,resource_size(res_mem));-if(enable_uart1){-/* Add a ttyS device for hardware uart 1 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UARTX_RBR(1);-p->mapbase=CVMX_MIO_UARTX_RBR(1)&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART1;-p++;-}-if(enable_uart2){-/* Add a ttyS device for hardware uart 2 */-octeon_uart_set_common(p);-p->membase=(void*)CVMX_MIO_UART2_RBR;-p->mapbase=CVMX_MIO_UART2_RBR&((1ull<<49)-1);-p->irq=OCTEON_IRQ_UART2;-p++;-}+res=serial8250_register_port(&port);++returnres>=0?0:res;+}++staticstructof_device_idocteon_serial_match[]={+{+.compatible="cavium,octeon-3860-uart",+},+{},+};+MODULE_DEVICE_TABLE(of,octeon_serial_match);-BUG_ON(p>&octeon_uart8250_data[OCTEON_MAX_UARTS]);+staticstructplatform_driverocteon_serial_driver={+.probe=octeon_serial_probe,+.driver={+.owner=THIS_MODULE,+.name="octeon_serial",+.of_match_table=octeon_serial_match,+},+};-returnplatform_device_register(&octeon_uart8250_device);+staticintocteon_serial_register_driver(structnotifier_block*nb,+unsignedlongcode,void*arg)+{+if(code==SERIAL8250_DRIVER_ADD)+platform_driver_register(&octeon_serial_driver);+returnNOTIFY_OK;}-device_initcall(octeon_serial_init);+staticint__initocteon_serial_init(void)+{+returnserial8250_notifier(octeon_serial_register_driver,0);+}+arch_initcall(octeon_serial_init);--
From: David Daney <hidden> Date: 2011-03-17 18:42:27
On 03/17/2011 11:25 AM, Grant Likely wrote:
On Thu, Mar 17, 2011 at 12:18:49PM +0000, Alan Cox wrote:
quoted
On Wed, 16 Mar 2011 18:26:06 -0700
David Daney[off-list ref] wrote:
quoted
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized
I've had a bigger dig into this. I think the correct answer is probably
"always go via platform devices or similar". That *is* the notifier in
the kernel of today. serial8250_register_port ultimately should I think
ultimatly become an internal helper.
+1
Depending on serial8250_register_port() definitely the wrong thing to
do for platform support code. It would be better to figure out how to
get the dt bits you need into 8250.c or of_serial.c.
IMHO, of_serial.c is no better than my board/chip specific code that
calls serial8250_register_port().
Really what would be ideal would be a hook to add a dev.platform_data
pointer to the appropriate struct plat_serial8250_port when the platform
device is created. It is possible that the platform bus notifiers could
be used for this. We would also want to have a way to add an
of_device_id to those recognized by 8250.c
If we did that, serial8250_probe() would automatically do the right thing.
David Daney
From: Grant Likely <hidden> Date: 2011-03-17 18:47:28
On Thu, Mar 17, 2011 at 11:42:19AM -0700, David Daney wrote:
On 03/17/2011 11:25 AM, Grant Likely wrote:
quoted
On Thu, Mar 17, 2011 at 12:18:49PM +0000, Alan Cox wrote:
quoted
On Wed, 16 Mar 2011 18:26:06 -0700
David Daney[off-list ref] wrote:
quoted
The 8250 driver is a bit weird in that in addition to supporting
platform devices, extra devices can be added by calling
serial8250_register_port().
The problem is that if we call serial8250_register_port() before the
driver is initialized Bad Things happen (we dereference NULL
pointers).
There doesn't seem to be a general way to know if a driver has been
initialized
I've had a bigger dig into this. I think the correct answer is probably
"always go via platform devices or similar". That *is* the notifier in
the kernel of today. serial8250_register_port ultimately should I think
ultimatly become an internal helper.
+1
Depending on serial8250_register_port() definitely the wrong thing to
do for platform support code. It would be better to figure out how to
get the dt bits you need into 8250.c or of_serial.c.
IMHO, of_serial.c is no better than my board/chip specific code that
calls serial8250_register_port().
Really what would be ideal would be a hook to add a
dev.platform_data pointer to the appropriate struct
plat_serial8250_port when the platform device is created. It is
possible that the platform bus notifiers could be used for this. We
would also want to have a way to add an of_device_id to those
recognized by 8250.c
If we did that, serial8250_probe() would automatically do the right thing.
Take a look at the way arch/powerpc/platforms/512x/pdm360ng.c uses a
notifier for amending a platform_device with additional data..
g.
If we did that, serial8250_probe() would automatically do the right thing.
Take a look at the way arch/powerpc/platforms/512x/pdm360ng.c uses a
notifier for amending a platform_device with additional data..
I tend to view arch specific embedded code as rather like very dubious
parties. What goes on in other peoples' house out of sight is none of my
business.
The 8250 however is core code so it should keep its clothers on and behave
in a manner befitting its status.
What part of the problem can't be solved by doing it properly using the
device registration interfaces we have today ?
Alan
From: Grant Likely <hidden> Date: 2011-03-17 19:31:55
On Thu, Mar 17, 2011 at 07:24:41PM +0000, Alan Cox wrote:
quoted
quoted
If we did that, serial8250_probe() would automatically do the right thing.
Take a look at the way arch/powerpc/platforms/512x/pdm360ng.c uses a
notifier for amending a platform_device with additional data..
I tend to view arch specific embedded code as rather like very dubious
parties. What goes on in other peoples' house out of sight is none of my
business.
The 8250 however is core code so it should keep its clothers on and behave
in a manner befitting its status.
What part of the problem can't be solved by doing it properly using the
device registration interfaces we have today ?
Device registration isn't the problem. The problem is supplying
machine-specific callbacks from the board support code to the
drivers. When devices are sourced from a device tree, it is easy to
get data about the device out of the tree, but it is really hard to
get callback pointers. To make it all work without this fiddling
about, the octeon serial_{in,out} implementation would need to be
rolled into of_serial.c (which FWIW, I have absolutely no problem
with).
g.
From: David Daney <hidden> Date: 2011-03-17 20:13:52
On 03/17/2011 12:31 PM, Grant Likely wrote:
On Thu, Mar 17, 2011 at 07:24:41PM +0000, Alan Cox wrote:
quoted
quoted
quoted
If we did that, serial8250_probe() would automatically do the right thing.
Take a look at the way arch/powerpc/platforms/512x/pdm360ng.c uses a
notifier for amending a platform_device with additional data..
I tend to view arch specific embedded code as rather like very dubious
parties. What goes on in other peoples' house out of sight is none of my
business.
The 8250 however is core code so it should keep its clothers on and behave
in a manner befitting its status.
What part of the problem can't be solved by doing it properly using the
device registration interfaces we have today ?
Device registration isn't the problem. The problem is supplying
machine-specific callbacks from the board support code to the
drivers. When devices are sourced from a device tree, it is easy to
get data about the device out of the tree, but it is really hard to
get callback pointers. To make it all work without this fiddling
about, the octeon serial_{in,out} implementation would need to be
rolled into of_serial.c (which FWIW, I have absolutely no problem
with).
The only problem I have with that is that it ends up moving chip
specific erratum workarounds into drivers/tty/serial instead of
arch/mips/cavium-octeon.
I will think about this more.
David Daney
From: Grant Likely <hidden> Date: 2011-03-17 20:32:00
On Thu, Mar 17, 2011 at 01:13:06PM -0700, David Daney wrote:
On 03/17/2011 12:31 PM, Grant Likely wrote:
quoted
On Thu, Mar 17, 2011 at 07:24:41PM +0000, Alan Cox wrote:
quoted
quoted
quoted
If we did that, serial8250_probe() would automatically do the right thing.
Take a look at the way arch/powerpc/platforms/512x/pdm360ng.c uses a
notifier for amending a platform_device with additional data..
I tend to view arch specific embedded code as rather like very dubious
parties. What goes on in other peoples' house out of sight is none of my
business.
The 8250 however is core code so it should keep its clothers on and behave
in a manner befitting its status.
What part of the problem can't be solved by doing it properly using the
device registration interfaces we have today ?
Device registration isn't the problem. The problem is supplying
machine-specific callbacks from the board support code to the
drivers. When devices are sourced from a device tree, it is easy to
get data about the device out of the tree, but it is really hard to
get callback pointers. To make it all work without this fiddling
about, the octeon serial_{in,out} implementation would need to be
rolled into of_serial.c (which FWIW, I have absolutely no problem
with).
The only problem I have with that is that it ends up moving chip
specific erratum workarounds into drivers/tty/serial instead of
arch/mips/cavium-octeon.
I will think about this more.
arch/mips/cavium-octeon/serial.c appears to be void of any
chip-specific errata at the moment. :-)
g.
Device registration isn't the problem. The problem is supplying
machine-specific callbacks from the board support code to the
drivers. When devices are sourced from a device tree, it is easy to
get data about the device out of the tree, but it is really hard to
get callback pointers. To make it all work without this fiddling
about, the octeon serial_{in,out} implementation would need to be
rolled into of_serial.c (which FWIW, I have absolutely no problem
with).
Disagree - the arch code needs to register I/O method descriptions with
the of_serial code they don't neccessarily need to be in it.
Ie you'd have something like
of_serial8250_register_ops("dt-op-type-name-blah", &ops);
in the early boot code, and the ops can be in the arch, providing the ops
has a module owner field the rest can even work modular. Sure the stuff
should be able to describe standard forms directly without extra methods
being registered but for the special stuff I think that is the right
approach
Funnily enough I'm in the middle of trying to rip the rm9k, au and other
crap out of 8250.c by doing this for the UPIO_xxx ids and once you have
an ops struct you can also then go and boot out the resource claim crap
and package it all nicely.
From: Grant Likely <hidden> Date: 2011-03-18 05:18:54
On Thu, Mar 17, 2011 at 11:48:14PM +0000, Alan Cox wrote:
quoted
Device registration isn't the problem. The problem is supplying
machine-specific callbacks from the board support code to the
drivers. When devices are sourced from a device tree, it is easy to
get data about the device out of the tree, but it is really hard to
get callback pointers. To make it all work without this fiddling
about, the octeon serial_{in,out} implementation would need to be
rolled into of_serial.c (which FWIW, I have absolutely no problem
with).
Disagree - the arch code needs to register I/O method descriptions with
the of_serial code they don't neccessarily need to be in it.
Ie you'd have something like
of_serial8250_register_ops("dt-op-type-name-blah", &ops);
in the early boot code, and the ops can be in the arch, providing the ops
has a module owner field the rest can even work modular. Sure the stuff
should be able to describe standard forms directly without extra methods
being registered but for the special stuff I think that is the right
approach
Yeah, okay. That's nice and clean. I like it.
Funnily enough I'm in the middle of trying to rip the rm9k, au and other
crap out of 8250.c by doing this for the UPIO_xxx ids and once you have
an ops struct you can also then go and boot out the resource claim crap
and package it all nicely.