Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Sep 2018 14:04:38 -0300
From:      "Dr. Rolf Jansen" <rj@obsigna.com>
To:        freebsd-drivers@freebsd.org
Subject:   Re: Writing a PCIe-Driver
Message-ID:  <F9C8518D-E241-4BCF-8C38-A7386AD1B045@obsigna.com>
In-Reply-To: <0E9C0EFE-F2EE-47A3-B7E6-60E9404E3904@obsigna.com>
References:  <F756788B-591D-4B9D-B58B-B0C07FE4E233@obsigna.com> <CAFd4kYAuD1nDwQv-AtZnEqKJZ4wvo3ik1ERyOSjYp_kaOAS7fQ@mail.gmail.com> <0E9C0EFE-F2EE-47A3-B7E6-60E9404E3904@obsigna.com>

next in thread | previous in thread | raw e-mail | index | archive | help
I got it working. Actually, it was more easy than expected.

I was looking at the output of pciconf -lcbv and there I confused the =
card identifier (card=3D0x742f1093) with the chip identifier =
(chip=3D0xc4c41093) of the NI PCIe-6351 board, and in the first place I =
took the first one for the probe function of my driver, vendor =3D =
0x1093 (National Instruments) device =3D 0x742f (wrong). Looking closer =
at the respective output of the old PCI board NI PCI-6251, I saw, that =
this one doesn=E2=80=99t got a card ID assigned (0x00000000). I only =
need to use the corrected device ID 0xc4c4 in the probe routine of my =
driver, and now I got it attached:

   # kldload ./cydaq.ko; tail /var/log/messages
   ...
   Sep 26 12:39:25 CyStat-220 kernel: cydaq0: CyDAQ found DAQ-Board NI =
PCIe-6351; VendorID 0x1093, DeviceID 0xC4C4
   Sep 26 12:39:25 CyStat-220 kernel: cydaq0: <DAQ-Board NI PCIe-6351> =
mem 0xdf000000-0xdf03ffff irq 18 at device 0.0 on pci2
   Sep 26 12:39:25 CyStat-220 kernel: cydaq0: CyDAQ PCI device driver =
has been loaded

   # kldstat
   Id Refs Address            Size     Name
   ...
   14    1 0xffffffff827da000 1700     cydaq.ko

   # sysctl -a | grep cydaq
   cydaq.AO_dma_buffer_size: 50331648
   cydaq.AI_dma_buffer_size: 268435456
   dev.cydaq.0.%parent: pci2
   dev.cydaq.0.%pnpinfo: vendor=3D0x1093 device=3D0xc4c4 =
subvendor=3D0x1093 subdevice=3D0x742f class=3D0x118000
   dev.cydaq.0.%location: slot=3D0 function=3D0 dbsf=3Dpci0:2:0:0 =
handle=3D\_SB_.PCI0.RP11.PXSX
   dev.cydaq.0.%driver: cydaq
   dev.cydaq.0.%desc: DAQ-Board NI PCIe-6351
   dev.cydaq.%parent:=20

Everything looks good now. As I said already, the actual DAC/ADC/DIO is =
all controlled from user space. The driver only provides the base =
addresses of the DAQ board and of the reserved DMA ranges via respective =
ioctl calls. Some measurement tasks are very math intensive, and the =
kernel is anyway not the right place for doing this.

Best regards

Rolf

> Am 24.09.2018 um 15:30 schrieb Dr. Rolf Jansen <rj@obsigna.com>:
>=20
> Farhan,
>=20
> Thank you very much for sharing your findings. I will also look into =
the code, and I started with checking out the FreeBSD source tree to my =
development machine, so examine the code of the various drivers is more =
easy. Anyway, the outline which you revealed is already a good starting =
point, and it will help me a lot to find my way in the jungle.
>=20
> Best regards
>=20
> Rolf
>=20
>> Am 24.09.2018 um 01:53 schrieb Farhan Khan <khanzf@gmail.com>:
>>=20
>> Hi Rolf,
>>=20
>> I have been reading up on this code myself. I do not claim expertise,
>> so hopefully others can chim in here if I make a mistake. On the WiFi
>> side of things, I've pretty consistently I've seen the following
>> routine:
>>=20
>> A call to pci_find_cap(9), typically as follows from the WiFi code
>> I've looked into:
>> pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off);
>>=20
>> A write to clear the PCI Retry timeout, by writing 0x41 to the device
>> with pci_write_config(9):
>> pci_write_config(dev, 0x41, 0, 1);
>>=20
>> Obtain the base address registers using PCIR_BAR(), an abstraction of
>> bus_alloc_resource(), and store that value.
>> rid =3D PCIR_BAR(0)
>>=20
>> Allocate IO DMA memory to the device:
>> sc->sc_mem =3D bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, =
RF_ACTIVE);
>> Most drivers check this return value and return ENXIO if the value is =
NULL.
>>=20
>> I do not fully understand what rman_get_bustag(9) does, but I see =
this
>> called on all drivers I've looked at as follows:
>> sc->sc_st =3D rman_get_bustag(sc->sc_mem);
>> sc->sc_sh =3D rman_get_bushandle(sc->sc_mem);
>>=20
>> Typically I see Interrupt handler code setup here. In the case of
>> rtwn(4) and iwm(4). This might not be relevant to your driver,
>> depending on what it does. I see a call to pci_alloc_msi as follows:
>> rid =3D 1;
>> if (pci_alloc_msi(dev, &rid) =3D=3D 0)
>> rid =3D 1;
>> else
>> rid =3D 0;
>> pci->irq =3D bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE =
|
>> (rid !=3D 0 ? 0 : RF_SHAREABLE));
>>=20
>> Then assign an interrupt handler function as follows so you know to
>> read from the DMA.
>> error =3D bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | =
INTR_MPSAFE,
>> NULL, your_function_here, sc, &sc->sc_ih);
>>=20
>> Capture the DMA tag as follows:
>> sc->sc_dmat =3D bus_get_dma_tag(sc->sc_dev);
>>=20
>> =46rom here, I see the following sequence:
>> 1. bus_dma_tag_create(), where the first argument is the DMA tag
>> (sc->sc_dmat), and the last argument is the memory it is mapped to.
>> 2. bus_dmamem_alloc()
>> 3. bus_dmamap_load()
>> 4. bus_dmamap_sync()
>>=20
>> At this point, you may need to initialize the interrupts, depending =
on
>> your hardware. If/when the interrupt arrives, you need to determine
>> what type it is and read from the DMA memory, as allocated in the DMA
>> sequence. On every assign and allocation you should also do
>> error-checking on all return values.
>>=20
>> That is my understanding. Again, someone else can jump in if I made a
>> mistake. I read rtwn(4), iwm(4) and iwi(4) while writing this and =
they
>> are excellent references.
>>=20
>> Hope this helps!
>> --
>> Farhan Khan
>> PGP Fingerprint: B28D 2726 E2BC A97E 3854 5ABE 9A9F 00BC D525 16EE
>>=20
>>=20
>> On Sun, Sep 23, 2018 at 10:46 PM Dr. Rolf Jansen <rj@obsigna.com> =
wrote:
>>>=20
>>> Hello,
>>>=20
>>> A couple of years ago, with the valuable help of people on this =
list, I managed to write a PCI driver for the National Instruments DAQ =
card, NI PCI-6251. The driver was kept very simple, only map the BAR=E2=80=
=99s and some DMA memory into the user space. The DAC/ADC and DIO is =
then all controlled from user space by writing command codes to certain =
offsets from the mapped BAR=E2=80=99s, and reading data from the mapped =
DMA memory and/or from other given offsets.
>>>=20
>>> See: How to map device addresses into user space
>>> =
https://lists.freebsd.org/pipermail/freebsd-drivers/2013-January/thread.ht=
ml
>>>=20
>>>=20
>>> Now, I need to do exactly the same for a PCIe card, namely the NI =
PCIe-6351. However, I even cannot see where to start. For PCI cards, the =
respective chapter 11 in the FreeBSD Architecture Handbook was quite =
helpful, for getting started, in no time, I got the PCI card probed and =
attached.
>>>=20
>>> =
https://www.freebsd.org/doc/en_US.ISO8859-1/books/arch-handbook/pci.html
>>>=20
>>> The dumb approach, probing the device ID and attaching the PCI(e) =
driver to the PCIe device in a similar fashion didn=E2=80=99t work - I =
didn=E2=80=99t expect this either, however, where would I start? How do =
I attach my driver to a PCIe card on FreeBSD 11 or 12?
>>>=20
>>> Please can somebody push me into the right direction. Once I got the =
driver attached to the card, I guess, I would be able to adapt the =
mem-mapping code of my old driver for the new card.
>>>=20
>>> Best regards
>>>=20
>>> Rolf
>>> _______________________________________________
>>> freebsd-drivers@freebsd.org mailing list
>>> https://lists.freebsd.org/mailman/listinfo/freebsd-drivers
>>> To unsubscribe, send any mail to =
"freebsd-drivers-unsubscribe@freebsd.org"
>=20
> _______________________________________________
> freebsd-drivers@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-drivers
> To unsubscribe, send any mail to =
"freebsd-drivers-unsubscribe@freebsd.org"




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?F9C8518D-E241-4BCF-8C38-A7386AD1B045>