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

Commit 6bbc321a authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

b43: Add debugfs files for random SHM access



This adds debugfs files for random SHM access.
This is needed in order to implement firmware and driver debugging
scripts in userspace.

Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8bd463f4
Loading
Loading
Loading
Loading
+178 −0
Original line number Diff line number Diff line
@@ -74,6 +74,168 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
	} while (0)


/* The biggest address values for SHM access from the debugfs files. */
#define B43_MAX_SHM_ROUTING	4
#define B43_MAX_SHM_ADDR	0xFFFF

static ssize_t shm16read__read_file(struct b43_wldev *dev,
				    char *buf, size_t bufsize)
{
	ssize_t count = 0;
	unsigned int routing, addr;
	u16 val;

	routing = dev->dfsentry->shm16read_routing_next;
	addr = dev->dfsentry->shm16read_addr_next;
	if ((routing > B43_MAX_SHM_ROUTING) ||
	    (addr > B43_MAX_SHM_ADDR))
		return -EDESTADDRREQ;

	val = b43_shm_read16(dev, routing, addr);
	fappend("0x%04X\n", val);

	return count;
}

static int shm16read__write_file(struct b43_wldev *dev,
				 const char *buf, size_t count)
{
	unsigned int routing, addr;
	int res;

	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
	if (res != 2)
		return -EINVAL;
	if (routing > B43_MAX_SHM_ROUTING)
		return -EADDRNOTAVAIL;
	if (addr > B43_MAX_SHM_ADDR)
		return -EADDRNOTAVAIL;
	if (routing == B43_SHM_SHARED) {
		if ((addr % 2) != 0)
			return -EADDRNOTAVAIL;
	}

	dev->dfsentry->shm16read_routing_next = routing;
	dev->dfsentry->shm16read_addr_next = addr;

	return 0;
}

static int shm16write__write_file(struct b43_wldev *dev,
				  const char *buf, size_t count)
{
	unsigned int routing, addr, mask, set;
	u16 val;
	int res;
	unsigned long flags;

	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
		     &routing, &addr, &mask, &set);
	if (res != 4)
		return -EINVAL;
	if (routing > B43_MAX_SHM_ROUTING)
		return -EADDRNOTAVAIL;
	if (addr > B43_MAX_SHM_ADDR)
		return -EADDRNOTAVAIL;
	if (routing == B43_SHM_SHARED) {
		if ((addr % 2) != 0)
			return -EADDRNOTAVAIL;
	}
	if ((mask > 0xFFFF) || (set > 0xFFFF))
		return -E2BIG;

	spin_lock_irqsave(&dev->wl->shm_lock, flags);
	if (mask == 0)
		val = 0;
	else
		val = __b43_shm_read16(dev, routing, addr);
	val &= mask;
	val |= set;
	__b43_shm_write16(dev, routing, addr, val);
	spin_unlock_irqrestore(&dev->wl->shm_lock, flags);

	return 0;
}

static ssize_t shm32read__read_file(struct b43_wldev *dev,
				    char *buf, size_t bufsize)
{
	ssize_t count = 0;
	unsigned int routing, addr;
	u32 val;

	routing = dev->dfsentry->shm32read_routing_next;
	addr = dev->dfsentry->shm32read_addr_next;
	if ((routing > B43_MAX_SHM_ROUTING) ||
	    (addr > B43_MAX_SHM_ADDR))
		return -EDESTADDRREQ;

	val = b43_shm_read32(dev, routing, addr);
	fappend("0x%08X\n", val);

	return count;
}

static int shm32read__write_file(struct b43_wldev *dev,
				 const char *buf, size_t count)
{
	unsigned int routing, addr;
	int res;

	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
	if (res != 2)
		return -EINVAL;
	if (routing > B43_MAX_SHM_ROUTING)
		return -EADDRNOTAVAIL;
	if (addr > B43_MAX_SHM_ADDR)
		return -EADDRNOTAVAIL;
	if (routing == B43_SHM_SHARED) {
		if ((addr % 2) != 0)
			return -EADDRNOTAVAIL;
	}

	dev->dfsentry->shm32read_routing_next = routing;
	dev->dfsentry->shm32read_addr_next = addr;

	return 0;
}

static int shm32write__write_file(struct b43_wldev *dev,
				  const char *buf, size_t count)
{
	unsigned int routing, addr, mask, set;
	u32 val;
	int res;
	unsigned long flags;

	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
		     &routing, &addr, &mask, &set);
	if (res != 4)
		return -EINVAL;
	if (routing > B43_MAX_SHM_ROUTING)
		return -EADDRNOTAVAIL;
	if (addr > B43_MAX_SHM_ADDR)
		return -EADDRNOTAVAIL;
	if (routing == B43_SHM_SHARED) {
		if ((addr % 2) != 0)
			return -EADDRNOTAVAIL;
	}
	if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
		return -E2BIG;

	spin_lock_irqsave(&dev->wl->shm_lock, flags);
	if (mask == 0)
		val = 0;
	else
		val = __b43_shm_read32(dev, routing, addr);
	val &= mask;
	val |= set;
	__b43_shm_write32(dev, routing, addr, val);
	spin_unlock_irqrestore(&dev->wl->shm_lock, flags);

	return 0;
}

/* The biggest MMIO address that we allow access to from the debugfs files. */
#define B43_MAX_MMIO_ACCESS	(0xF00 - 1)

@@ -605,6 +767,10 @@ static ssize_t b43_debugfs_write(struct file *file,
		.take_irqlock	= _take_irqlock,		\
	}

B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
@@ -699,6 +865,10 @@ void b43_debugfs_add_device(struct b43_wldev *dev)

	e->mmio16read_next = 0xFFFF; /* invalid address */
	e->mmio32read_next = 0xFFFF; /* invalid address */
	e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
	e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
	e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
	e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */

#define ADD_FILE(name, mode)	\
	do {							\
@@ -712,6 +882,10 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
	} while (0)


	ADD_FILE(shm16read, 0600);
	ADD_FILE(shm16write, 0200);
	ADD_FILE(shm32read, 0600);
	ADD_FILE(shm32write, 0200);
	ADD_FILE(mmio16read, 0600);
	ADD_FILE(mmio16write, 0200);
	ADD_FILE(mmio32read, 0600);
@@ -740,6 +914,10 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
		return;
	b43_remove_dynamic_debug(dev);

	debugfs_remove(e->file_shm16read.dentry);
	debugfs_remove(e->file_shm16write.dentry);
	debugfs_remove(e->file_shm32read.dentry);
	debugfs_remove(e->file_shm32write.dentry);
	debugfs_remove(e->file_mmio16read.dentry);
	debugfs_remove(e->file_mmio16write.dentry);
	debugfs_remove(e->file_mmio32read.dentry);
+11 −0
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@ struct b43_dfsentry {
	struct b43_wldev *dev;
	struct dentry *subdir;

	struct b43_dfs_file file_shm16read;
	struct b43_dfs_file file_shm16write;
	struct b43_dfs_file file_shm32read;
	struct b43_dfs_file file_shm32write;
	struct b43_dfs_file file_mmio16read;
	struct b43_dfs_file file_mmio16write;
	struct b43_dfs_file file_mmio32read;
@@ -55,6 +59,13 @@ struct b43_dfsentry {
	/* The cached address for the next mmio32read file read */
	u16 mmio32read_next;

	/* The cached address for the next shm16read file read */
	u32 shm16read_routing_next;
	u32 shm16read_addr_next;
	/* The cached address for the next shm32read file read */
	u32 shm32read_routing_next;
	u32 shm32read_addr_next;

	/* Enabled/Disabled list for the dynamic debugging features. */
	u32 dyn_debug[__B43_NR_DYNDBG];
	/* Dentries for the dynamic debugging entries. */
+41 −17
Original line number Diff line number Diff line
@@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
	b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
}

u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
{
	struct b43_wl *wl = dev->wl;
	unsigned long flags;
	u32 ret;

	spin_lock_irqsave(&wl->shm_lock, flags);
	if (routing == B43_SHM_SHARED) {
		B43_WARN_ON(offset & 0x0001);
		if (offset & 0x0003) {
@@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
	b43_shm_control_word(dev, routing, offset);
	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
out:
	spin_unlock_irqrestore(&wl->shm_lock, flags);

	return ret;
}

u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
{
	struct b43_wl *wl = dev->wl;
	unsigned long flags;
	u16 ret;
	u32 ret;

	spin_lock_irqsave(&wl->shm_lock, flags);
	ret = __b43_shm_read32(dev, routing, offset);
	spin_unlock_irqrestore(&wl->shm_lock, flags);

	return ret;
}

u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
{
	u16 ret;

	if (routing == B43_SHM_SHARED) {
		B43_WARN_ON(offset & 0x0001);
		if (offset & 0x0003) {
@@ -423,17 +428,24 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
	b43_shm_control_word(dev, routing, offset);
	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
out:
	spin_unlock_irqrestore(&wl->shm_lock, flags);

	return ret;
}

void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
{
	struct b43_wl *wl = dev->wl;
	unsigned long flags;
	u16 ret;

	spin_lock_irqsave(&wl->shm_lock, flags);
	ret = __b43_shm_read16(dev, routing, offset);
	spin_unlock_irqrestore(&wl->shm_lock, flags);

	return ret;
}

void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
{
	if (routing == B43_SHM_SHARED) {
		B43_WARN_ON(offset & 0x0001);
		if (offset & 0x0003) {
@@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
				    (value >> 16) & 0xffff);
			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
			goto out;
			return;
		}
		offset >>= 2;
	}
	b43_shm_control_word(dev, routing, offset);
	b43_write32(dev, B43_MMIO_SHM_DATA, value);
out:
	spin_unlock_irqrestore(&wl->shm_lock, flags);
}

void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
{
	struct b43_wl *wl = dev->wl;
	unsigned long flags;

	spin_lock_irqsave(&wl->shm_lock, flags);
	__b43_shm_write32(dev, routing, offset, value);
	spin_unlock_irqrestore(&wl->shm_lock, flags);
}

void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
{
	if (routing == B43_SHM_SHARED) {
		B43_WARN_ON(offset & 0x0001);
		if (offset & 0x0003) {
			/* Unaligned access */
			b43_shm_control_word(dev, routing, offset >> 2);
			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
			goto out;
			return;
		}
		offset >>= 2;
	}
	b43_shm_control_word(dev, routing, offset);
	b43_write16(dev, B43_MMIO_SHM_DATA, value);
out:
}

void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
{
	struct b43_wl *wl = dev->wl;
	unsigned long flags;

	spin_lock_irqsave(&wl->shm_lock, flags);
	__b43_shm_write16(dev, routing, offset, value);
	spin_unlock_irqrestore(&wl->shm_lock, flags);
}

+4 −0
Original line number Diff line number Diff line
@@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
void b43_tsf_write(struct b43_wldev *dev, u64 tsf);

u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);

u64 b43_hf_read(struct b43_wldev *dev);
void b43_hf_write(struct b43_wldev *dev, u64 value);