pci.c

来自「linux 内核源代码」· C语言 代码 · 共 741 行 · 第 1/2 页

C
741
字号
	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);	for (i = 0; i < 4; i++) {		v = in[SPOFF(SSB_SPROM2_CCODE) + i];		*(((__le16 *)out->country_str) + i) = cpu_to_le16(v);	}}static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in){	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;	out->ofdmapo <<= 16;	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;	out->ofdmalpo <<= 16;	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;	out->ofdmahpo <<= 16;	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,	     SSB_SPROM3_GPIOLDC_ON_SHIFT);	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,	     SSB_SPROM3_CCKPO_2M_SHIFT);	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,	     SSB_SPROM3_CCKPO_55M_SHIFT);	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,	     SSB_SPROM3_CCKPO_11M_SHIFT);	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;	out->ofdmgpo <<= 16;	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;}static int sprom_extract(struct ssb_bus *bus,			 struct ssb_sprom *out, const u16 *in){	memset(out, 0, sizeof(*out));	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,	     SSB_SPROM_REVISION_CRC_SHIFT);	if ((bus->chip_id & 0xFF00) == 0x4400) {		/* Workaround: The BCM44XX chip has a stupid revision		 * number stored in the SPROM.		 * Always extract r1. */		sprom_extract_r1(&out->r1, in);	} else {		if (out->revision == 0)			goto unsupported;		if (out->revision >= 1 && out->revision <= 3)			sprom_extract_r1(&out->r1, in);		if (out->revision >= 2 && out->revision <= 3)			sprom_extract_r2(&out->r2, in);		if (out->revision == 3)			sprom_extract_r3(&out->r3, in);		if (out->revision >= 4)			goto unsupported;	}	return 0;unsupported:	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "		   "detected. Will extract v1\n", out->revision);	sprom_extract_r1(&out->r1, in);	return 0;}static int ssb_pci_sprom_get(struct ssb_bus *bus,			     struct ssb_sprom *sprom){	int err = -ENOMEM;	u16 *buf;	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);	if (!buf)		goto out;	sprom_do_read(bus, buf);	err = sprom_check_crc(buf);	if (err) {		ssb_printk(KERN_WARNING PFX			   "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");	}	err = sprom_extract(bus, sprom, buf);	kfree(buf);out:	return err;}static void ssb_pci_get_boardinfo(struct ssb_bus *bus,				  struct ssb_boardinfo *bi){	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,			     &bi->vendor);	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,			     &bi->type);	pci_read_config_word(bus->host_pci, PCI_REVISION_ID,			     &bi->rev);}int ssb_pci_get_invariants(struct ssb_bus *bus,			   struct ssb_init_invariants *iv){	int err;	err = ssb_pci_sprom_get(bus, &iv->sprom);	if (err)		goto out;	ssb_pci_get_boardinfo(bus, &iv->boardinfo);out:	return err;}#ifdef CONFIG_SSB_DEBUGstatic int ssb_pci_assert_buspower(struct ssb_bus *bus){	if (likely(bus->powered_up))		return 0;	printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "	       "while accessing PCI MMIO space\n");	if (bus->power_warn_count <= 10) {		bus->power_warn_count++;		dump_stack();	}	return -ENODEV;}#else /* DEBUG */static inline int ssb_pci_assert_buspower(struct ssb_bus *bus){	return 0;}#endif /* DEBUG */static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset){	struct ssb_bus *bus = dev->bus;	if (unlikely(ssb_pci_assert_buspower(bus)))		return 0xFFFF;	if (unlikely(bus->mapped_device != dev)) {		if (unlikely(ssb_pci_switch_core(bus, dev)))			return 0xFFFF;	}	return ioread16(bus->mmio + offset);}static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset){	struct ssb_bus *bus = dev->bus;	if (unlikely(ssb_pci_assert_buspower(bus)))		return 0xFFFFFFFF;	if (unlikely(bus->mapped_device != dev)) {		if (unlikely(ssb_pci_switch_core(bus, dev)))			return 0xFFFFFFFF;	}	return ioread32(bus->mmio + offset);}static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value){	struct ssb_bus *bus = dev->bus;	if (unlikely(ssb_pci_assert_buspower(bus)))		return;	if (unlikely(bus->mapped_device != dev)) {		if (unlikely(ssb_pci_switch_core(bus, dev)))			return;	}	iowrite16(value, bus->mmio + offset);}static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value){	struct ssb_bus *bus = dev->bus;	if (unlikely(ssb_pci_assert_buspower(bus)))		return;	if (unlikely(bus->mapped_device != dev)) {		if (unlikely(ssb_pci_switch_core(bus, dev)))			return;	}	iowrite32(value, bus->mmio + offset);}/* Not "static", as it's used in main.c */const struct ssb_bus_ops ssb_pci_ops = {	.read16		= ssb_pci_read16,	.read32		= ssb_pci_read32,	.write16	= ssb_pci_write16,	.write32	= ssb_pci_write32,};static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len){	int i, pos = 0;	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {		pos += snprintf(buf + pos, buf_len - pos - 1,				"%04X", swab16(sprom[i]) & 0xFFFF);	}	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");	return pos + 1;}static int hex2sprom(u16 *sprom, const char *dump, size_t len){	char tmp[5] = { 0 };	int cnt = 0;	unsigned long parsed;	if (len < SSB_SPROMSIZE_BYTES * 2)		return -EINVAL;	while (cnt < SSB_SPROMSIZE_WORDS) {		memcpy(tmp, dump, 4);		dump += 4;		parsed = simple_strtoul(tmp, NULL, 16);		sprom[cnt++] = swab16((u16)parsed);	}	return 0;}static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,				       struct device_attribute *attr,				       char *buf){	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);	struct ssb_bus *bus;	u16 *sprom;	int err = -ENODEV;	ssize_t count = 0;	bus = ssb_pci_dev_to_bus(pdev);	if (!bus)		goto out;	err = -ENOMEM;	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);	if (!sprom)		goto out;	/* Use interruptible locking, as the SPROM write might	 * be holding the lock for several seconds. So allow userspace	 * to cancel operation. */	err = -ERESTARTSYS;	if (mutex_lock_interruptible(&bus->pci_sprom_mutex))		goto out_kfree;	sprom_do_read(bus, sprom);	mutex_unlock(&bus->pci_sprom_mutex);	count = sprom2hex(sprom, buf, PAGE_SIZE);	err = 0;out_kfree:	kfree(sprom);out:	return err ? err : count;}static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,					struct device_attribute *attr,					const char *buf, size_t count){	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);	struct ssb_bus *bus;	u16 *sprom;	int res = 0, err = -ENODEV;	bus = ssb_pci_dev_to_bus(pdev);	if (!bus)		goto out;	err = -ENOMEM;	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);	if (!sprom)		goto out;	err = hex2sprom(sprom, buf, count);	if (err) {		err = -EINVAL;		goto out_kfree;	}	err = sprom_check_crc(sprom);	if (err) {		err = -EINVAL;		goto out_kfree;	}	/* Use interruptible locking, as the SPROM write might	 * be holding the lock for several seconds. So allow userspace	 * to cancel operation. */	err = -ERESTARTSYS;	if (mutex_lock_interruptible(&bus->pci_sprom_mutex))		goto out_kfree;	err = ssb_devices_freeze(bus);	if (err == -EOPNOTSUPP) {		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "			   "No suspend support. Is CONFIG_PM enabled?\n");		goto out_unlock;	}	if (err) {		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");		goto out_unlock;	}	res = sprom_do_write(bus, sprom);	err = ssb_devices_thaw(bus);	if (err)		ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");out_unlock:	mutex_unlock(&bus->pci_sprom_mutex);out_kfree:	kfree(sprom);out:	if (res)		return res;	return err ? err : count;}static DEVICE_ATTR(ssb_sprom, 0600,		   ssb_pci_attr_sprom_show,		   ssb_pci_attr_sprom_store);void ssb_pci_exit(struct ssb_bus *bus){	struct pci_dev *pdev;	if (bus->bustype != SSB_BUSTYPE_PCI)		return;	pdev = bus->host_pci;	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);}int ssb_pci_init(struct ssb_bus *bus){	struct pci_dev *pdev;	int err;	if (bus->bustype != SSB_BUSTYPE_PCI)		return 0;	pdev = bus->host_pci;	mutex_init(&bus->pci_sprom_mutex);	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);	if (err)		goto out;out:	return err;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?