Skip to content

Commit

Permalink
Staging: vme: add VME Location Monitor management mechanism
Browse files Browse the repository at this point in the history
Extend the image and DMA channel resource management methods to control the
location monitor resource. The location monitor should be controlled as it can
only be used at a single location at a time.

Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Martyn Welch authored and Greg Kroah-Hartman committed Sep 15, 2009
1 parent 400822f commit 42fb503
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 78 deletions.
36 changes: 18 additions & 18 deletions drivers/staging/vme/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -331,44 +331,44 @@ monitor.
Location Monitor Management
---------------------------

TODO: Provide a mechanism to request use of the location monitor. The location
monitors can be moved and we only want one driver to be able to do that
at a time! We also need to be able to free the location monitor for
others to use.
The following functions are provided to request the use of a block of location
monitors and to free them after they are no longer required:

struct vme_resource * vme_request_lm(struct device *dev);
struct vme_resource * vme_lm_request(struct device *dev);

void vme_free_lm(struct vme_resource * res);
void vme_lm_free(struct vme_resource * res);

Each block may provide a number of location monitors, monitoring adjacent
locations. The following function can be used to determine how many locations
are provided:

int vme_lm_count(struct vme_resource * res);


Location Monitor Configuration
------------------------------

TODO: Change to struct "vme_resource *res" rather than "struct device *dev".
Once a bank of location monitors has been allocated, the following functions
are provided to configure the location and mode of the location monitor:

The following functions are provided to configure the location and mode of the
location monitor:

int vme_lm_set(struct device *dev, unsigned long long base,
int vme_lm_set(struct vme_resource *res, unsigned long long base,
vme_address_t aspace, vme_cycle_t cycle);

int vme_lm_get(struct device *dev, unsigned long long *base,
int vme_lm_get(struct vme_resource *res, unsigned long long *base,
vme_address_t *aspace, vme_cycle_t *cycle);


Location Monitor Use
--------------------

TODO: Change to struct "vme_resource *res" rather than "struct device *dev".

The following functions allow a callback to be attached and detached from each
location monitor location. The API currently supports 4 location monitors,
monitoring 4 adjacent locations:
location monitor location. Each location monitor can monitor a number of
adjacent locations:

int vme_lm_attach(struct device *dev, int num,
int vme_lm_attach(struct vme_resource *res, int num,
void (*callback)(int));

int vme_lm_detach(struct device *dev, int num);
int vme_lm_detach(struct vme_resource *res, int num);

The callback function is declared as follows.

Expand Down
69 changes: 44 additions & 25 deletions drivers/staging/vme/bridges/vme_tsi148.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ int tsi148_dma_list_add (struct vme_dma_list *, struct vme_dma_attr *,
int tsi148_dma_list_exec(struct vme_dma_list *);
int tsi148_dma_list_empty(struct vme_dma_list *);
int tsi148_generate_irq(int, int);
int tsi148_lm_set(unsigned long long, vme_address_t, vme_cycle_t);
int tsi148_lm_get(unsigned long long *, vme_address_t *, vme_cycle_t *);
int tsi148_lm_attach(int, void (*callback)(int));
int tsi148_lm_detach(int);
int tsi148_slot_get(void);

/* Modue parameter */
Expand All @@ -82,7 +78,6 @@ struct mutex vme_int; /*
* generated at a time, provide locking
*/
struct mutex vme_irq; /* Locking for VME irq callback configuration */
struct mutex vme_lm; /* Locking for location monitor operations */


static char driver_name[] = "vme_tsi148";
Expand Down Expand Up @@ -1985,18 +1980,18 @@ int tsi148_dma_list_empty(struct vme_dma_list *list)
* This does not enable the LM monitor - that should be done when the first
* callback is attached and disabled when the last callback is removed.
*/
int tsi148_lm_set(unsigned long long lm_base, vme_address_t aspace,
vme_cycle_t cycle)
int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
vme_address_t aspace, vme_cycle_t cycle)
{
u32 lm_base_high, lm_base_low, lm_ctl = 0;
int i;

mutex_lock(&(vme_lm));
mutex_lock(&(lm->mtx));

/* If we already have a callback attached, we can't move it! */
for (i = 0; i < 4; i++) {
for (i = 0; i < lm->monitors; i++) {
if(lm_callback[i] != NULL) {
mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));
printk("Location monitor callback attached, can't "
"reset\n");
return -EBUSY;
Expand All @@ -2017,7 +2012,7 @@ int tsi148_lm_set(unsigned long long lm_base, vme_address_t aspace,
lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
break;
default:
mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));
printk("Invalid address space\n");
return -EINVAL;
break;
Expand All @@ -2038,20 +2033,20 @@ int tsi148_lm_set(unsigned long long lm_base, vme_address_t aspace,
iowrite32be(lm_base_low, tsi148_bridge->base + TSI148_LCSR_LMBAL);
iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);

mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));

return 0;
}

/* Get configuration of the callback monitor and return whether it is enabled
* or disabled.
*/
int tsi148_lm_get(unsigned long long *lm_base, vme_address_t *aspace,
vme_cycle_t *cycle)
int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
vme_address_t *aspace, vme_cycle_t *cycle)
{
u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;

mutex_lock(&(vme_lm));
mutex_lock(&(lm->mtx));

lm_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAU);
lm_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAL);
Expand Down Expand Up @@ -2084,7 +2079,7 @@ int tsi148_lm_get(unsigned long long *lm_base, vme_address_t *aspace,
if (lm_ctl & TSI148_LCSR_LMAT_DATA)
*cycle |= VME_DATA;

mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));

return enabled;
}
Expand All @@ -2094,23 +2089,24 @@ int tsi148_lm_get(unsigned long long *lm_base, vme_address_t *aspace,
*
* Callback will be passed the monitor triggered.
*/
int tsi148_lm_attach(int monitor, void (*callback)(int))
int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
void (*callback)(int))
{
u32 lm_ctl, tmp;

mutex_lock(&(vme_lm));
mutex_lock(&(lm->mtx));

/* Ensure that the location monitor is configured - need PGM or DATA */
lm_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));
printk("Location monitor not properly configured\n");
return -EINVAL;
}

/* Check that a callback isn't already attached */
if (lm_callback[monitor] != NULL) {
mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));
printk("Existing callback attached\n");
return -EBUSY;
}
Expand All @@ -2133,19 +2129,19 @@ int tsi148_lm_attach(int monitor, void (*callback)(int))
iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);
}

mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));

return 0;
}

/*
* Detach a callback function forn a specific location monitor.
*/
int tsi148_lm_detach(int monitor)
int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
{
u32 lm_en, tmp;

mutex_lock(&(vme_lm));
mutex_lock(&(lm->mtx));

/* Disable Location Monitor and ensure previous interrupts are clear */
lm_en = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
Expand All @@ -2170,7 +2166,7 @@ int tsi148_lm_detach(int monitor)
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_LMAT);
}

mutex_unlock(&(vme_lm));
mutex_unlock(&(lm->mtx));

return 0;
}
Expand Down Expand Up @@ -2285,6 +2281,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
struct vme_lm_resource *lm;

/* If we want to support more than one of each bridge, we need to
* dynamically generate this so we get one per device
Expand Down Expand Up @@ -2338,7 +2335,6 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&(vme_int));
mutex_init(&(vme_irq));
mutex_init(&(vme_rmw));
mutex_init(&(vme_lm));

tsi148_bridge->parent = &(pdev->dev);
strcpy(tsi148_bridge->name, driver_name);
Expand Down Expand Up @@ -2459,6 +2455,22 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
&(tsi148_bridge->dma_resources));
}

/* Add location monitor to list */
INIT_LIST_HEAD(&(tsi148_bridge->lm_resources));
lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
if (lm == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for "
"location monitor resource structure\n");
retval = -ENOMEM;
goto err_lm;
}
lm->parent = tsi148_bridge;
mutex_init(&(lm->mtx));
lm->locked = 0;
lm->number = 1;
lm->monitors = 4;
list_add_tail(&(lm->list), &(tsi148_bridge->lm_resources));

tsi148_bridge->slave_get = tsi148_slave_get;
tsi148_bridge->slave_set = tsi148_slave_set;
tsi148_bridge->master_get = tsi148_master_get;
Expand Down Expand Up @@ -2513,6 +2525,13 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_reg:
tsi148_crcsr_exit(pdev);
err_crcsr:
err_lm:
/* resources are stored in link list */
list_for_each(pos, &(tsi148_bridge->lm_resources)) {
lm = list_entry(pos, struct vme_lm_resource, list);
list_del(pos);
kfree(lm);
}
err_dma:
/* resources are stored in link list */
list_for_each(pos, &(tsi148_bridge->dma_resources)) {
Expand Down
Loading

0 comments on commit 42fb503

Please sign in to comment.