Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b8e087b authored by Dominik Brodowski's avatar Dominik Brodowski
Browse files

pcmcia: add locking to set_mem_map()



Protect the pccard_operations callback "set_mem_map" by a new
mutex ops_mutex. This mutex also protects the following values
in struct pcmcia_socket:

        pccard_mem_map          win[]
        pccard_mem_map          cis_mem
        void __iomem            *cis_virt

Tested-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent c6958fdb
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444);

void release_cis_mem(struct pcmcia_socket *s)
{
    mutex_lock(&s->ops_mutex);
    if (s->cis_mem.flags & MAP_ACTIVE) {
	s->cis_mem.flags &= ~MAP_ACTIVE;
	s->ops->set_mem_map(s, &s->cis_mem);
@@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s)
	iounmap(s->cis_virt);
	s->cis_virt = NULL;
    }
    mutex_unlock(&s->ops_mutex);
}

/*
@@ -88,11 +90,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
	pccard_mem_map *mem = &s->cis_mem;
	int ret;

	mutex_lock(&s->ops_mutex);
	if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
		mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
		if (mem->res == NULL) {
			dev_printk(KERN_NOTICE, &s->dev,
				   "cs: unable to map card memory!\n");
			mutex_unlock(&s->ops_mutex);
			return NULL;
		}
		s->cis_virt = NULL;
@@ -108,6 +112,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
	if (ret) {
		iounmap(s->cis_virt);
		s->cis_virt = NULL;
		mutex_unlock(&s->ops_mutex);
		return NULL;
	}

@@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
		s->cis_virt = ioremap(mem->static_start, s->map_size);
	}

	mutex_unlock(&s->ops_mutex);
	return s->cis_virt;
}

+1 −0
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
	init_completion(&socket->socket_released);
	init_completion(&socket->thread_done);
	mutex_init(&socket->skt_mutex);
	mutex_init(&socket->ops_mutex);
	spin_lock_init(&socket->thread_lock);

	if (socket->resource_ops->init) {
+15 −5
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
			memreq_t *req)
{
	struct pcmcia_socket *s = p_dev->socket;
	int ret;

	wh--;
	if (wh >= MAX_WIN)
@@ -231,12 +232,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
		dev_dbg(&s->dev, "failure: requested page is zero\n");
		return -EINVAL;
	}
	mutex_lock(&s->ops_mutex);
	s->win[wh].card_start = req->CardOffset;
	if (s->ops->set_mem_map(s, &s->win[wh]) != 0) {
		dev_dbg(&s->dev, "failed to set_mem_map\n");
		return -EIO;
	}
	return 0;
	ret = s->ops->set_mem_map(s, &s->win[wh]);
	if (ret)
		dev_warn(&s->dev, "failed to set_mem_map\n");
	mutex_unlock(&s->ops_mutex);
	return ret;
} /* pcmcia_map_mem_page */
EXPORT_SYMBOL(pcmcia_map_mem_page);

@@ -437,10 +439,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
	if (wh >= MAX_WIN)
		return -EINVAL;

	mutex_lock(&s->ops_mutex);
	win = &s->win[wh];

	if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) {
		dev_dbg(&s->dev, "not releasing unknown window\n");
		mutex_unlock(&s->ops_mutex);
		return -EINVAL;
	}

@@ -456,6 +460,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
		win->res = NULL;
	}
	p_dev->_win &= ~CLIENT_WIN_REQ(wh);
	mutex_unlock(&s->ops_mutex);

	return 0;
} /* pcmcia_release_window */
@@ -829,6 +834,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
		return -EINVAL;
	}

	mutex_lock(&s->ops_mutex);
	win = &s->win[w];

	if (!(s->features & SS_CAP_STATIC_MAP)) {
@@ -836,6 +842,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
						      (req->Attributes & WIN_MAP_BELOW_1MB), s);
		if (!win->res) {
			dev_dbg(&s->dev, "allocating mem region failed\n");
			mutex_unlock(&s->ops_mutex);
			return -EINVAL;
		}
	}
@@ -854,8 +861,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
	if (req->Attributes & WIN_USE_WAIT)
		win->flags |= MAP_USE_WAIT;
	win->card_start = 0;

	if (s->ops->set_mem_map(s, win) != 0) {
		dev_dbg(&s->dev, "failed to set memory mapping\n");
		mutex_unlock(&s->ops_mutex);
		return -EIO;
	}
	s->state |= SOCKET_WIN_REQ(w);
@@ -866,6 +875,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
	else
		req->Base = win->res->start;

	mutex_unlock(&s->ops_mutex);
	*wh = w + 1;

	return 0;
+8 −0
Original line number Diff line number Diff line
@@ -274,17 +274,21 @@ static int readable(struct pcmcia_socket *s, struct resource *res,
{
	int ret = -EINVAL;

	mutex_lock(&s->ops_mutex);
	s->cis_mem.res = res;
	s->cis_virt = ioremap(res->start, s->map_size);
	if (s->cis_virt) {
		mutex_unlock(&s->ops_mutex);
		/* as we're only called from pcmcia.c, we're safe */
		if (s->callback->validate)
			ret = s->callback->validate(s, count);
		/* invalidate mapping */
		mutex_lock(&s->ops_mutex);
		iounmap(s->cis_virt);
		s->cis_virt = NULL;
	}
	s->cis_mem.res = NULL;
	mutex_unlock(&s->ops_mutex);
	if ((ret) || (*count == 0))
		return -EINVAL;
	return 0;
@@ -300,6 +304,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
	int i, a = 0, b = -1, d;
	void __iomem *virt;

	mutex_lock(&s->ops_mutex);

	virt = ioremap(res->start, s->map_size);
	if (virt) {
		map.map = 0;
@@ -322,6 +328,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
		iounmap(virt);
	}

	mutex_unlock(&s->ops_mutex);

	if (b == -1)
		return -EINVAL;

+2 −0
Original line number Diff line number Diff line
@@ -203,6 +203,8 @@ struct pcmcia_socket {
	unsigned int			thread_events;
	/* protects socket h/w state */
	struct mutex			skt_mutex;
	/* protects PCMCIA state */
	struct mutex			ops_mutex;
	/* protects thread_events */
	spinlock_t			thread_lock;