howto provide io memory to PCI card
Charles Brown
charles.brown at sensis.com
Tue Apr 27 18:43:46 UTC 2010
OK - here's the code, I've snipped out a lot of my debug cruft
First off, my driver load script examines /proc/iomem, the figure out
where I can allocate some IO memory, and it passes me a start address
and length
/** start address for iomem block to allocate for read space */
unsigned long iomstart = 0, iomlength = 0;
module_param(iomstart,ulong,0);
module_param(iomlength,ulong,0);
-------------------
Next, on module initialization, I reserve the io memory, and allocate a
slice to each of the cards - there will be several evantually.
void
alt_onInit(void)
{
int i, status = 0;
struct resource * resource = NULL;
/* request IO memory for incoming data */
resource = request_mem_region(iomstart, iomlength, DEVNAME);
MDDEBUG( "Requesting IO Mem: start = 0x%lX, length = 0x%lX... %s\n",
iomstart, iomlength, ((resource==NULL) ? "failed" : "ok") );
/* initialize that no boards are detected, yet. */
for( i=0 ; i < NUMBOARDS ; ++i )
{
alt_pci_dev[i].boardno = -1;
if ( NULL == resource )
{
alt_pci_dev[i].iomlength = 0;
alt_pci_dev[i].iomstart = 0;
}
else
{
alt_pci_dev[i].iomlength = iomlength / NUMBOARDS;
alt_pci_dev[i].iomstart = iomstart + alt_pci_dev[i].iomlength * i;
}
}
/* To register the struct pci_driver with the PCI core, a call to
* pci_register_driver is made with a pointer to the struct
pci_driver. This
* is traditionally done in the module initialization code for the PCI
* driver. Note that the pci_register_driver function either returns a
* negative error number or 0 if everything was registered
successfully. It
* does not return the number of devices that were bound to the
driver or an
* error number if no devices were bound to the driver.
*/
status = pci_register_driver(&pci_driver);
MDDEBUG( "PCI registration... %s\n", (status ? "failed" : "ok") );
}
---------------------------
Finally, the probe code enables a board, registers a IRQ handler, and
writes the IO memory physical address back into the BAR0 memory. The
hardware guy expects he'll pick the address up from there, and stick it
in the board's address translation table - for now, he's doing that
manually with a debugger.
/* The probe function in the PCI driver. */
int
alt_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int status = 0;
int boardno = 0;
struct pci_config * pci_config = (void*)0;
unsigned long start, end, flags, size;
unsigned char *dest = NULL;
struct alt_pci_dev *board = NULL;
/* save the device information for interrupt processing */
/* TODO: figure a better method to ID specific boards */
for( boardno=0 ; boardno < NUMBOARDS ; ++boardno )
if ( -1 == alt_pci_dev[boardno].boardno )
{
alt_pci_dev[boardno].boardno = boardno;
alt_pci_dev[boardno].dev = dev;
break;
}
if ( NUMBOARDS == boardno )
{
MDDEBUG( "Too many boards probed! Ignoring...\n" );
return -1;
}
MDDEBUG( "Probing board %d...\n", boardno );
board = &alt_pci_dev[boardno];
/* In the probe function for the PCI driver, before the driver can access
* any device resource (I/O region or interrupt) of the PCI device, the
* driver must call the pci_enable_device function. This function
actually
* enables the device. It wakes up the device and in some cases also
assigns
* its interrupt line and I/O regions.
*/
status = pci_enable_device(dev);
MDDEBUG( "PCI enabling board %d... %s\n", boardno, (status ? "failed"
: "ok") );
/* read the configuration space and dump it to the log */
MDDEBUG( "PCI Configuration Registers for board %d... \n", boardno );
...snip...
/* register an interrupt handler for the board */
alt_pci_dev[boardno].irq_status = request_irq(
alt_pci_dev[boardno].pci_config.irq_line, alt_irq_handler,
IRQF_SHARED | IRQF_SAMPLE_RANDOM, DEVNAME, &alt_pci_dev[boardno] );
MDDEBUG( "Requesting IRQ %d for board %d... %s\n",
alt_pci_dev[boardno].pci_config.irq_line, boardno,
(status ? "failed" : "ok") );
/* get board addresses */
start = pci_resource_start(board->dev, 0);
end = pci_resource_end(board->dev, 0);
flags = pci_resource_flags(board->dev, 0);
size = (end - start);
dest = (unsigned char *)ioremap( start, size );
/* set IO mem start, length and flag */
memcpy_toio( &dest[4], &board->iomstart, sizeof(board->iomstart) );
memcpy_toio( &dest[4+sizeof(board->iomstart)], &board->iomlength,
sizeof(board->iomlength) );
memcpy_toio( &dest[0], "RDY\0", 4 );
/* release io memory */
iounmap( dest );
MDDEBUG( "IO Mem for board %d: start = 0x%lx, len = 0x%lX.\n",
boardno, board->iomstart, board->iomlength );
return 0;
}
Peter M. Petrakis wrote:
> Charles,
>
> It would help to see your probe routine. Thanks
>
> Peter
>
> On 04/27/2010 02:07 PM, Charles Brown wrote:
> > All,
> >
> > Apologies for bothering you with this question. If you know of a
> > better place for me to ask such a question, please let me know.
> >
> > I'm trying to write a device driver under ubuntu for a PCI card, and
> > exchange information with the card.
> >
> > The hardware engineer has configured the card to support BAR0 for
> > data to the card, and linux allocates memory at kernel boot and I am
> > able to write data from the driver to the card.
> >
> > For data coming from the card to the driver, the hardware engineer
> > expects the driver to allocate IO memory when the driver loads, and to
> > provide the physical address of that memory to the card - which the card
> > will use with its address translation register to write data directly
> > into the provided I/O memory.
> >
> > Using information from LDD3 I've been able to allocate IO memory, but
> > I can't find any PCI/kernel functions that allow me to tell the kernel
> > about this memory for the PCI card, and there's no way to tell the card
> > about this memory, except through writing the physical address back into
> > the IO memory associated to BAR0.
> >
> > Any insights would be very helpful.
> >
> > --CB
> >
> >
> >
> > -
> > This message is intended only for the addressee and may contain
> information that is company confidential or privileged. Any technical
> data in this message may be exported only in accordance with the U.S.
> International Traffic in Arms Regulations (22 CFR Parts 120-130) or the
> Export Administration Regulations (15 CFR Parts 730-774). Unauthorized
> use is strictly prohibited and may be unlawful. If you are not the
> intended recipient, or the person responsible for delivering to the
> intended recipient, you should not read, copy, disclose or otherwise use
> this message. If you have received this email in error, please delete
> it, and advise the sender immediately.
> >
> -
> >
>
-
This message is intended only for the addressee and may contain information that is company confidential or privileged. Any technical data in this message may be exported only in accordance with the U.S. International Traffic in Arms Regulations (22 CFR Parts 120-130) or the Export Administration Regulations (15 CFR Parts 730-774). Unauthorized use is strictly prohibited and may be unlawful. If you are not the intended recipient, or the person responsible for delivering to the intended recipient, you should not read, copy, disclose or otherwise use this message. If you have received this email in error, please delete it, and advise the sender immediately.
-
More information about the kernel-team
mailing list