kernelnewbies.kernelnewbies.org archive mirror
 help / color / mirror / Atom feed
* Remote I/O bus
@ 2019-10-04 11:04 Luca Ceresoli
  2019-10-04 13:22 ` Greg KH
  0 siblings, 1 reply; 10+ messages in thread
From: Luca Ceresoli @ 2019-10-04 11:04 UTC (permalink / raw)
  To: kernelnewbies

Hi,

on an embedded system I currently have a standard platform device:

.-----.  data  .--------.
| CPU |--------| DEVICE |
'-----'   bus  '--------'

The driver is a standard platform driver that uses ioread32() and
iowrite32() to access registers.

So far, so good.

Now in a new design I have the same device in an FPGA, external to the
SoC. The external FPGA is not reachable via an I/O bus, but via SPI (or
I2C). A microprocessor in the FPGA acts as a bridge: as an SPI client it
receives register read/write requests from the CPU, forwards them to the
devices on the in-FPGA data bus as a master, then sends back the replies
over SPI.

                       SoC <- | -> FPGA

.-----.  data   .---------.       .--------.  data   .--------.
| CPU |---------| SPI CTL |-------| BRIDGE |---------| DEVICE |
'-----'  bus A  '---------'  SPI  '--------'  bus B  '--------'


What would be a proper way to model this in the Linux kernel?

Of course I can hack the drivers to hijack them on SPI, but I'm trying
to solve the problem in a better way. IMO "a proper way" implies that
the platform driver does not need to be aware of the existence of the
bridge.

Note: in the real case there is more than one device to handle.

At first sight I think this should be modeled with a "bridge" device that:

 * is a SPI device
 * implements a "platform bus" where regular platform devices can be
   instantiated, similar to a "simple-bus"

In device tree terms:

&amba { /* data bus A in picture */

    spi0: spi@42000000 {
        reg = <0x42000000 0x1000>;
        #address-cells = <1>;

        io-over-spi-bridge@1 { /* data bus B */
            reg = <1>; /* slave select pin 1 */
            compatible = "linux,io-over-spi-bridge";
            #address-cells = <1>;
            #size-cells = <1>;

            mydevice@4000 {
                /* 1 kB I/O space at 0x4000 on bus B */
                reg = <0x4000 0x1000>;
            };
        };
    };
};

The io-over-spi driver is supposed to request allocation of a virtual
memory area that:
 1. is as large as the address space on bus B
 2. is __iomem (non cached, etc)
 3. is not mapped on the physical CPU address space (bus A)
 4. page faults at every read/write access, triggering a callback
    that starts an SPI transaction, waits for the result and returns

After some research I haven't found how this could be implemented,
mostly due to my newbieness about kernel memory management. Also, as
drivers might access the bus in IRQ handlers, I suspect there is no way
to do an SPI transaction in IRQ context, but this could be handled
differently (threaded IRQ...).

Does this look like a good approach to handle the problem?
If it does, how would you implement the iomem access and handle IRQ context?
Otherwise, which way would you suggest?

Many thanks in advance,
-- 
Luca

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-10-07  7:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-04 11:04 Remote I/O bus Luca Ceresoli
2019-10-04 13:22 ` Greg KH
2019-10-04 14:08   ` Luca Ceresoli
2019-10-04 14:54     ` Greg KH
2019-10-04 15:08       ` Luca Ceresoli
2019-10-04 21:51         ` Valdis Klētnieks
2019-10-05 22:29           ` Luca Ceresoli
2019-10-06  0:19             ` Valdis Klētnieks
2019-10-06  9:18             ` Greg KH
2019-10-07  7:48               ` Luca Ceresoli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).