<commit_before>/*
 * Broadcom specific AMBA
 * PCI Core in hostmode
 *
 * Copyright 2005 - 2011, Broadcom Corporation
 * Copyright 2006, 2007, <NAME> <<EMAIL>>
 * Copyright 2011, 2012, <NAME> <<EMAIL>>
 *
 * Licensed under the GNU/GPL. See COPYING for details.
 */

#include "bcma_private.h"
#include <linux/pci.h>
#include <linux/export.h>
#include <linux/bcma/bcma.h>
#include <asm/paccess.h>

/* Probe a 32bit value on the bus and catch bus exceptions.
 * Returns nonzero on a bus exception.
 * This is MIPS specific */
#define mips_busprobe32(val, addr)	get_dbe((val), ((u32 *)(addr)))

/* Assume one-hot slot wiring */
#define BCMA_PCI_SLOT_MAX	16
#define	PCI_CONFIG_SPACE_SIZE	256

bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
{
	struct bcma_bus *bus = pc->core->bus;
	u16 chipid_top;
	u32 tmp;

	chipid_top = (bus->chipinfo.id & 0xFF00);
	if (chipid_top != 0x4700 &&
	    chipid_top != 0x5300)
		return false;

	if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
		pr_info("This PCI core is disabled and not working\n");
		return false;
	}

	bcma_core_enable(pc->core, 0);

	return !mips_busprobe32(tmp, pc->core->io_addr);
}

static u32 bcma_pcie_read_config(struct bcma_drv_pci *pc, u32 address)
{
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
	pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
	return pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_DATA);
}

static void bcma_pcie_write_config(struct bcma_drv_pci *pc, u32 address,
				   u32 data)
{
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
	pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_DATA, data);
}

static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
			     unsigned int func, unsigned int off)
{
	u32 addr = 0;

	/* Issue config commands only when the data link is up (atleast
	 * one external pcie device is present).
	 */
	if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
			  & BCMA_CORE_PCI_DLLP_LSREG_LINKUP))
		goto out;

	/* Type 0 transaction */
	/* Slide the PCI window to the appropriate slot */
	pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
	/* Calculate the address */
	addr = pc->host_controller->host_cfg_addr;
	addr |= (dev << BCMA_CORE_PCI_CFG_SLOT_SHIFT);
	addr |= (func << BCMA_CORE_PCI_CFG_FUN_SHIFT);
	addr |= (off & ~3);

out:
	return addr;
}

static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
				  unsigned int func, unsigned int off,
				  void *buf, int len)
{
	int err = -EINVAL;
	u32 addr, val;
	void __iomem *mmio = 0;

	WARN_ON(!pc->hostmode);
	if (unlikely(len != 1 && len != 2 && len != 4))
		goto out;
	if (dev == 0) {
		/* we support only two functions on device 0 */
		if (func > 1)
			return -EINVAL;

		/* accesses to config registers with offsets >= 256
		 * requires indirect access.
		 */
		if (off >= PCI_CONFIG_SPACE_SIZE) {
			addr = (func << 12);
			addr |= (off & 0x0FFF);
			val = bcma_pcie_read_config(pc, addr);
		} else {
			addr = BCMA_CORE_PCI_PCICFG0;
			addr |= (func << 8);
			addr |= (off & 0xfc);
			val = pcicore_read32(pc, addr);
		}
	} else {
		addr = bcma_get_cfgspace_addr(pc, dev, func, off);
		if (unlikely(!addr))
			goto out;
		err = -ENOMEM;
		mmio = ioremap_nocache(addr, len);
		if (!mmio)
			goto out;

		if (mips_busprobe32(val, mmio)) {
			val = 0xffffffff;
			goto unmap;
		}

		val = readl(mmio);
	}
	val >>= (8 * (off & 3));

	switch (len) {
	case 1:
		*((u8 *)buf) = (u8)val;
		break;
	case 2:
		*((u16 *)buf) = (u16)val;
		break;
	case 4:
		*((u32 *)buf) = (u32)val;
		break;
	}
	err = 0;
unmap:
	if (mmio)
		iounmap(mmio);
out:
	return err;
}

static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
				   unsigned int func, unsigned int off,
				   const void *buf, int len)
{
	int err = -EINVAL;
	u32 addr = 0, val = 0;
	void __iomem *mmio = 0;
	u16 chipid = pc->core->bus->chipinfo.id;

	WARN_ON(!pc->hostmode);
	if (unlikely(len != 1 && len != 2 && len != 4))
		goto out;
	if (dev == 0) {
		/* accesses to config registers with offsets >= 256
		 * requires indirect access.
		 */
		if (off < PCI_CONFIG_SPACE_SIZE) {
			addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
			addr |= (func << 8);
			addr |= (off & 0xfc);
			mmio = ioremap_nocache(addr, len);
			if (!mmio)
				goto out;
		}
	} else {
		addr = bcma_get_cfgspace_addr(pc, dev, func, off);
		if (unlikely(!addr))
			goto out;
		err = -ENOMEM;
		mmio = ioremap_nocache(addr, len);
		if (!mmio)
			goto out;

		if (mips_busprobe32(val, mmio)) {
			val = 0xffffffff;
			goto unmap;
		}
	}

	switch (len) {
	case 1:
		val = readl(mmio);
		val &= ~(0xFF << (8 * (off & 3)));
		val |= *((const u8 *)buf) << (8 * (off & 3));
		break;
	case 2:<commit_msg>bcma: reads/writes are always 4 bytes, so always map 4 bytes<commit_after>/*
 * Broadcom specific AMBA
 * PCI Core in hostmode
 *
 * Copyright 2005 - 2011, Broadcom Corporation
 * Copyright 2006, 2007, <NAME> <<EMAIL>>
 * Copyright 2011, 2012, <NAME> <<EMAIL>>
 *
 * Licensed under the GNU/GPL. See COPYING for details.
 */

#include "bcma_private.h"
#include <linux/pci.h>
#include <linux/export.h>
#include <linux/bcma/bcma.h>
#include <asm/paccess.h>

/* Probe a 32bit value on the bus and catch bus exceptions.
 * Returns nonzero on a bus exception.
 * This is MIPS specific */
#define mips_busprobe32(val, addr)	get_dbe((val), ((u32 *)(addr)))

/* Assume one-hot slot wiring */
#define BCMA_PCI_SLOT_MAX	16
#define	PCI_CONFIG_SPACE_SIZE	256

bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
{
	struct bcma_bus *bus = pc->core->bus;
	u16 chipid_top;
	u32 tmp;

	chipid_top = (bus->chipinfo.id & 0xFF00);
	if (chipid_top != 0x4700 &&
	    chipid_top != 0x5300)
		return false;

	if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
		pr_info("This PCI core is disabled and not working\n");
		return false;
	}

	bcma_core_enable(pc->core, 0);

	return !mips_busprobe32(tmp, pc->core->io_addr);
}

static u32 bcma_pcie_read_config(struct bcma_drv_pci *pc, u32 address)
{
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
	pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
	return pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_DATA);
}

static void bcma_pcie_write_config(struct bcma_drv_pci *pc, u32 address,
				   u32 data)
{
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
	pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
	pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_DATA, data);
}

static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
			     unsigned int func, unsigned int off)
{
	u32 addr = 0;

	/* Issue config commands only when the data link is up (atleast
	 * one external pcie device is present).
	 */
	if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
			  & BCMA_CORE_PCI_DLLP_LSREG_LINKUP))
		goto out;

	/* Type 0 transaction */
	/* Slide the PCI window to the appropriate slot */
	pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
	/* Calculate the address */
	addr = pc->host_controller->host_cfg_addr;
	addr |= (dev << BCMA_CORE_PCI_CFG_SLOT_SHIFT);
	addr |= (func << BCMA_CORE_PCI_CFG_FUN_SHIFT);
	addr |= (off & ~3);

out:
	return addr;
}

static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
				  unsigned int func, unsigned int off,
				  void *buf, int len)
{
	int err = -EINVAL;
	u32 addr, val;
	void __iomem *mmio = 0;

	WARN_ON(!pc->hostmode);
	if (unlikely(len != 1 && len != 2 && len != 4))
		goto out;
	if (dev == 0) {
		/* we support only two functions on device 0 */
		if (func > 1)
			return -EINVAL;

		/* accesses to config registers with offsets >= 256
		 * requires indirect access.
		 */
		if (off >= PCI_CONFIG_SPACE_SIZE) {
			addr = (func << 12);
			addr |= (off & 0x0FFF);
			val = bcma_pcie_read_config(pc, addr);
		} else {
			addr = BCMA_CORE_PCI_PCICFG0;
			addr |= (func << 8);
			addr |= (off & 0xfc);
			val = pcicore_read32(pc, addr);
		}
	} else {
		addr = bcma_get_cfgspace_addr(pc, dev, func, off);
		if (unlikely(!addr))
			goto out;
		err = -ENOMEM;
		mmio = ioremap_nocache(addr, sizeof(val));
		if (!mmio)
			goto out;

		if (mips_busprobe32(val, mmio)) {
			val = 0xffffffff;
			goto unmap;
		}

		val = readl(mmio);
	}
	val >>= (8 * (off & 3));

	switch (len) {
	case 1:
		*((u8 *)buf) = (u8)val;
		break;
	case 2:
		*((u16 *)buf) = (u16)val;
		break;
	case 4:
		*((u32 *)buf) = (u32)val;
		break;
	}
	err = 0;
unmap:
	if (mmio)
		iounmap(mmio);
out:
	return err;
}

static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
				   unsigned int func, unsigned int off,
				   const void *buf, int len)
{
	int err = -EINVAL;
	u32 addr = 0, val = 0;
	void __iomem *mmio = 0;
	u16 chipid = pc->core->bus->chipinfo.id;

	WARN_ON(!pc->hostmode);
	if (unlikely(len != 1 && len != 2 && len != 4))
		goto out;
	if (dev == 0) {
		/* accesses to config registers with offsets >= 256
		 * requires indirect access.
		 */
		if (off < PCI_CONFIG_SPACE_SIZE) {
			addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
			addr |= (func << 8);
			addr |= (off & 0xfc);
			mmio = ioremap_nocache(addr, sizeof(val));
			if (!mmio)
				goto out;
		}
	} else {
		addr = bcma_get_cfgspace_addr(pc, dev, func, off);
		if (unlikely(!addr))
			goto out;
		err = -ENOMEM;
		mmio = ioremap_nocache(addr, sizeof(val));
		if (!mmio)
			goto out;

		if (mips_busprobe32(val, mmio)) {
			val = 0xffffffff;
			goto unmap;
		}
	}

	switch (len) {
	case 1:
		val = readl(mmio);
		val &= ~(0xFF << (8 * (off & 3)));
		val |= *((const u8 *)buf) << (8 * (off & 3));
		break;
	case 2:
{'fraction_non_alphanumeric': 0.1375611787982922, 'fraction_numerical': 0.032489846922836615, 'mean_word_length': 3.684878048780488, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7223865', 'n_tokens_mistral': 4333, 'n_tokens_neox': 3834, 'n_words': 1001}