Garrett, I'm trying to port xenbus drivers onto Solaris HVM and hence I need to 
get to the register space of the platform PCI device which xen emulates for 
each VM. So any help in this regard would be very helpful. I'm attaching the 
sample code which I picked up from 
http://dsc.sun.com/solaris/developer/support/driver/faqs.html#QA3.17 and then 
modified.

In the attach routine I tried doing the ddi_regs_map_setup on BAR1 of the 
platform device but I keep getting 0xc000 as its virtual address. If I try 
writing anything to it the driver crashes the system. Then I decided to switch 
to devmap_devmem_setup but then on calling it the driver crashes the system.

Regards,
Bhaskar.


-----Original Message-----
From: Garrett D'Amore [mailto:garr...@damore.org] 
Sent: Wednesday, September 16, 2009 7:13 PM
To: Jayaraman, Bhaskar
Cc: opensolaris-code@opensolaris.org
Subject: Re: [osol-code] Doubt in ddi_regs_map_setup!

Jayaraman, Bhaskar wrote:
> Ok I changed the call to devmap_devmem_setup() but my driver is crashing. Any 
> idea why this could be happening? I'm calling it from the 'attach' routine 
> which I hope is allowed. Also all my callbacks do nothing and return 0 unless 
> they're void i.e. I'm not setting the pvtp pointers in the callbacks or 
> anything.
> Regards,
> Bhaskar.
>   

It doesn't sound like conceptually you are doing anything wrong.  I 
think we'd need to look at the crash dump and source code in order to 
understand why you're experiencing these crashes.

    - Garrett
> -----Original Message-----
> From: Garrett D'Amore [mailto:garr...@damore.org] 
> Sent: Tuesday, September 15, 2009 7:35 PM
> To: Jayaraman, Bhaskar
> Cc: opensolaris-code@opensolaris.org
> Subject: Re: [osol-code] Doubt in ddi_regs_map_setup!
>
> Jayaraman, Bhaskar wrote:
>   
>> Hi, I'm making this call on my driver's BAR1 which has a physical 
>> address 0xf2000008 written on it. So I'm assuming that when I call a 
>> hat_getpfnum(kas.a_hat, returned_address), I should get the physical 
>> page frame number.
>>
>> Instead I get 0xffffffff as its return value (which is definitely some 
>> error). Also the virtual address that ddi_regs_map_setup is returning 
>> 0xc000 as the virtual address for the physical address in the BAR1.
>>
>> Please note that hat_getpfnum returns proper values for other virtual 
>> addresses. Can someone help me understand what is going on in my case?
>>
>>     
>
> I'm not sure exactly why this is failing, but you do know that 
> hat_getkpfnum() is an obsolete interface, right? Its been obsolete for 
> quite a long time now. (I think maybe as far back as Solaris 8.)
>
> If you're using this for mmap(), you should try implementing a 
> devmap(9e) routine instead.
>
> -- Garrett
>   
>> Regards,
>>
>> Bhaskar.
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> opensolaris-code mailing list
>> opensolaris-code@opensolaris.org
>> http://mail.opensolaris.org/mailman/listinfo/opensolaris-code
>>   
>>     
>
>   

#include <sys/types.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <sys/open.h>
#include <sys/cred.h>
#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <sys/pci.h>
#include <sys/scsi/scsi.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/atomic.h>
#ifndef USE_GENERIC_AEN_FRAMEWORK
#include <sys/signal.h>
#endif

#define FALSE 0
#define TRUE (!FALSE)

#define PLATFORM_NAME            "platform"

#define PLATFORM_DIDNODES        0x04
#define PLATFORM_DIDZALLOC       0x08


static int platform_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
static int platform_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
static int platform_open(dev_t *devp, int flag, int otyp, cred_t *cred);
static int platform_close(dev_t dev, int flag, int otyp, cred_t *cred);
static int platform_read(dev_t dev, struct uio *uiop, cred_t *credp);
static int platform_write(dev_t dev, struct uio *uiop, cred_t *credp);
static int platform_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
        void **resultp);
static int platform_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
        cred_t *credp, int *rvalp);
static unsigned int platform_handler(char *ctx);

/* ----- Device Access cb_ops Structure [start] -----
 *
 *         The data structure (cb_ops(9S)) MUST be provided and initialized
 *                 correctly.
 *
 *                 */
static struct cb_ops platform_cb_ops = {
        platform_open,
        platform_close,
        nodev,
        nodev,
        nodev,
        platform_read,
        platform_write,
        platform_ioctl,
        nodev,
        nodev,
        nodev,
        nochpoll,
        ddi_prop_op,
        NULL,
        D_NEW | D_MP
};
/* ----- Device Access cb_ops Structure [end] ----- */

/* ----- Autoconfiguration Structure [start] -----
 *
 *         The data structures (modlinkage(9S),modldrv(9S),mod_driverops
 *         and
 *                 dev_ops(9S)) MUST be provided and initialized correctly.
 *
 *                 */
static struct dev_ops platform_ops = {
        DEVO_REV,
        0,                      /* reference count */
        platform_getinfo,
        nulldev,
        nulldev,
        platform_attach,
        platform_detach,
        nodev,
        &platform_cb_ops,
        (struct bus_ops *)NULL
};

extern struct mod_ops mod_driverops;

static struct modldrv md = {
        &mod_driverops, /* Type of module. This is a driver */
        "platform driver",  /* Name of the module */
        &platform_ops,
};

static struct modlinkage ml = {
        MODREV_1,
        &md,
        NULL
};
/* ----- Autoconfiguration Structure [end] ----- */

/* ----- State Pointer [start] -----
 *
 *         The driver MUST provide a state pointer, which is used by the
 *         soft
 *                 state system to create the list of memory items.
 *                 */

struct platform_state {
        int instance;           /* instance number */
        dev_info_t *dip;        /* dev_info structure */
};

ddi_acc_handle_t pci_handle;
static void *statep;
ddi_iblock_cookie_t plat_iblock_cookie;

int plat_devmap_map(devmap_cookie_t dhp, dev_t dev, unsigned int flags, 
                offset_t off, size_t len, void **pvtp)
{
        return 0; 
}

int plat_devmap_access(devmap_cookie_t dhp, void *pvtp, offset_t off, 
                        size_t len, unsigned int type, unsigned int rw)
{
        return 0;
}

int plat_devmap_dup(devmap_cookie_t dhp, void *pvtp, 
                devmap_cookie_t new_dhp, void **new_pvtp)
{
        return 0;
}

void plat_devmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, 
                        size_t len, devmap_cookie_t new_dhp1, 
                        void **new_pvtp1, devmap_cookie_t new_dhp2, 
                        void **new_pvtp2)
{
        ;
}

devmap_cookie_t devmap_cook;
struct devmap_callback_ctl devmap_cb = {
                DEVMAP_OPS_REV,
                plat_devmap_map,
                plat_devmap_access,
                plat_devmap_dup,
                plat_devmap_unmap,
        };

unsigned int devmap_flags = 0;

static struct ddi_device_acc_attr endian_attr = {
        DDI_DEVICE_ATTR_V0,
        DDI_STRUCTURE_LE_ACC,
        DDI_STRICTORDER_ACC
};
/* ----- State Pointer [end] ----- */

/* ----- Loadable Module Routines [start] -----
 *
 *         All drivers MUST implement the _init(9E),_fini(9E) and _info(9E)
 *                 entry points to load,unload and report information about the
 *                         driver module.
 *                         */

static int
_init(void)
{
        int     error;

        error = ddi_soft_state_init(&statep, sizeof(struct platform_state),
1);
        if (error)
                return error;

        error = mod_install(&ml);

        if (error) {
                ddi_soft_state_fini(&statep);
                return error;
        }
        return 0;
}

static int
_info(struct modinfo *modinfop)
{
        return mod_info(&ml, modinfop);
}

static int
_fini(void)
{
        int     error;

        error = mod_remove(&ml);
        if (error)
                return error;

        ddi_soft_state_fini(&statep);
        return 0;
}
/* ----- Loadable Module Routines [end] ----- */

/* ----- Autoconfiguration Entry Point [start] ----- */
static int
platform_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
        int     instance, status;
        struct platform_state *bs;
        char *ourmem;
        int             flags, intNum, vendor_id, device_id, subsysid, 
subsysvid, base0, base1;

        switch(cmd) {
        case DDI_ATTACH:
                instance= ddi_get_instance(dip);
                        /* Setup the PCI configuration space handles */
                        if (pci_config_setup(dip, &pci_handle) != DDI_SUCCESS) {
                                cmn_err(CE_WARN, "platform%d: pci config setup 
failed ", instance);
                                pci_config_teardown(&pci_handle);
                                return DDI_FAILURE;
                        }
                        vendor_id = pci_config_get16(pci_handle, 
PCI_CONF_VENID);
                        device_id = pci_config_get16(pci_handle, 
PCI_CONF_DEVID);
                
                        subsysvid = pci_config_get16(pci_handle, 
PCI_CONF_SUBVENID);
                        subsysid = pci_config_get16(pci_handle, 
PCI_CONF_SUBSYSID);
                        base0 = pci_config_get32(pci_handle, PCI_CONF_BASE0);
                        base1 = pci_config_get32(pci_handle, PCI_CONF_BASE1);
                        cmn_err(CE_NOTE, "platform: vendor %x, device %x, 
subsysid %x, subsysvid %x, base0 %x, base1 %x\n", vendor_id, device_id, 
subsysid, subsysvid, base0, base1);
#if 0
                        pci_config_put32(pci_handle, PCI_CONF_BASE0, 
0x3fffd000);
                        pci_config_put32(pci_handle, PCI_CONF_BASE1, 
0x3fffd000);

                        ddi_regs_map_setup(dip, 1, &ourmem, 0, 0, &endian_attr, 
&pci_handle);
                        ourmem[0xffd000] = 0xa;
                        ourmem[0xffd001] = 0xb;
                        ourmem[0xffd002] = 0xc;
                        ourmem[0xffd003] = 0xd;
                        ourmem[0xffd004] = 0xe;
                        ourmem[0xffd005] = 0xf;
#endif
                if (devmap_devmem_setup(devmap_cook, dip, 
                        &devmap_cb, 1, 0, 4096, PROT_ALL, 
                        IOMEM_DATA_CACHED, &endian_attr) <
                        0) {
                        cmn_err(CE_NOTE, "platform: couldn't map base1 reg");
                }

                        base0 = pci_config_get32(pci_handle, PCI_CONF_BASE0);
                        base1 = pci_config_get32(pci_handle, PCI_CONF_BASE1);
                        cmn_err(CE_NOTE, "platform: vendor %x, device %x, 
subsysid %x, subsysvid %x, base0 %x, base1 %x\n", vendor_id, device_id, 
subsysid, subsysvid, base0, base1);
                        cmn_err(CE_NOTE, "platform: The address mapped at pfn 
%x virtual address %x\n", (unsigned long)hat_getpfnum(kas.a_hat, ourmem), 
ourmem);
                
                if (ddi_soft_state_zalloc(statep, instance) !=
DDI_SUCCESS) {
                        pci_config_teardown(&pci_handle);
                        return DDI_FAILURE;
                }

                flags = 0;

                bs = ddi_get_soft_state(statep, instance);
                if (bs == NULL) {
                        goto out;
                }

                flags |= PLATFORM_DIDZALLOC;

                if (ddi_create_minor_node(dip, "0", S_IFCHR, instance, 
                        DDI_PSEUDO,0) != DDI_SUCCESS) {
                        goto out;
                }

                flags |= PLATFORM_DIDNODES;

                ddi_set_driver_private(dip, (caddr_t)flags);
                ddi_dev_nintrs(dip, &intNum);
                ddi_get_iblock_cookie(dip, intNum, &plat_iblock_cookie);
#if 0
                status = ddi_add_intr(dip, intNum, &plat_iblock_cookie, NULL, 
platform_handler, NULL);
                if (status != DDI_SUCCESS)
                {
                cmn_err(CE_WARN, "ddi_add_intr() is not successful, Error: 
%d\n", status);
                }
#endif
                ddi_report_dev(dip);
        
                return DDI_SUCCESS;
        default:
                return DDI_FAILURE;
        }
out:    /* Undo */
        ddi_set_driver_private(dip, (caddr_t)flags);
        cmn_err(CE_WARN, "Platform: ddi_dev_nintrs(): %d\n", intNum);
        platform_detach(dip, DDI_DETACH);
        return DDI_FAILURE;
}

static unsigned int
platform_handler(char *ctx)
{
        cmn_err(CE_WARN, "Dummy handler");
        return(DDI_INTR_CLAIMED);
}
        
static int
platform_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
        int             instance, flags, intNum;
        struct platform_state *bs;

        switch(cmd) {
        case DDI_DETACH:
                instance = ddi_get_instance(dip);
                bs = ddi_get_soft_state(statep, instance);
                if (bs == NULL) {
                        return DDI_FAILURE;
                }

                flags = (int)ddi_get_driver_private(dip);

                if (flags & PLATFORM_DIDNODES)
                        ddi_remove_minor_node(dip, NULL);
                if (flags & PLATFORM_DIDZALLOC)
                ddi_soft_state_free(statep, instance);
#if 0
                ddi_dev_nintrs(dip, &intNum);
                ddi_remove_intr(dip, intNum, plat_iblock_cookie);
#endif
                pci_config_teardown(&pci_handle);

                return DDI_SUCCESS;
        default:
                return DDI_FAILURE;
        }
}

static int
platform_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void
**resultp)
{
        dev_t   dev;
        int             instance, rval = DDI_FAILURE;
        struct platform_state *bs;

        switch(cmd) {
        case DDI_INFO_DEVT2DEVINFO:     /* seek device's dev_info
pointer */
                dev = (dev_t)arg;
                instance = getminor(dev);
                bs = ddi_get_soft_state(statep, instance);
                if (bs != NULL) {
                        *resultp = bs->dip;
                        rval = DDI_SUCCESS;
                } else {
                        *resultp = NULL;
                }
                break;
        case DDI_INFO_DEVT2INSTANCE:    /* seek device's instance number
*/
                dev = (dev_t)arg;
                instance = getminor(dev);
                *resultp = (void *)instance;
                rval = DDI_SUCCESS;
                break;
        default:
                break;
        }
        return rval;
}
/* ----- Autoconfiguration Entry Point [end] ----- */

/* ----- Character Driver Entry Point [start] ----- */
static int
platform_open(dev_t *devp, int flag, int otyp, cred_t *cred)
{
        return 0;
}

static int
platform_close(dev_t dev, int flag, int otyp, cred_t *cred)
{
        return 0;
}

static int
platform_read(dev_t dev, struct uio *uiop, cred_t *credp)
{
        return 0;
}

static int
platform_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
        return 0;
}

static int
platform_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
        cred_t *credp, int *rvalp)
{
        return 0;
}
/* ----- Character Driver Entry Point [end] ----- */

_______________________________________________
opensolaris-code mailing list
opensolaris-code@opensolaris.org
http://mail.opensolaris.org/mailman/listinfo/opensolaris-code

Reply via email to