⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shpchp_hpc.c

📁 audio driver for hotplug pci on linux 2.6.27
💻 C
📖 第 1 页 / 共 2 页
字号:
	shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON);}static void hpc_set_green_led_off(struct slot *slot){	shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF);}static void hpc_set_green_led_blink(struct slot *slot){	shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK);}static void hpc_release_ctlr(struct controller *ctrl){	int i;	u32 slot_reg, serr_int;	/*	 * Mask event interrupts and SERRs of all slots	 */	for (i = 0; i < ctrl->num_slots; i++) {		slot_reg = shpc_readl(ctrl, SLOT_REG(i));		slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |			     BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |			     CON_PFAULT_INTR_MASK   | MRL_CHANGE_SERR_MASK |			     CON_PFAULT_SERR_MASK);		slot_reg &= ~SLOT_REG_RSVDZ_MASK;		shpc_writel(ctrl, SLOT_REG(i), slot_reg);	}	cleanup_slots(ctrl);	/*	 * Mask SERR and System Interrupt generation	 */	serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);	serr_int |= (GLOBAL_INTR_MASK  | GLOBAL_SERR_MASK |		     COMMAND_INTR_MASK | ARBITER_SERR_MASK);	serr_int &= ~SERR_INTR_RSVDZ_MASK;	shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);	if (shpchp_poll_mode)		del_timer(&ctrl->poll_timer);	else {		free_irq(ctrl->pci_dev->irq, ctrl);		pci_disable_msi(ctrl->pci_dev);	}	iounmap(ctrl->creg);	release_mem_region(ctrl->mmio_base, ctrl->mmio_size);	/*	 * If this is the last controller to be released, destroy the	 * shpchpd work queue	 */	if (atomic_dec_and_test(&shpchp_num_controllers))		destroy_workqueue(shpchp_wq);}static int hpc_power_on_slot(struct slot * slot){	int retval;	retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);	if (retval)		err("%s: Write command failed!\n", __func__);	return retval;}static int hpc_slot_enable(struct slot * slot){	int retval;	/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */	retval = shpc_write_cmd(slot, slot->hp_slot,			SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);	if (retval)		err("%s: Write command failed!\n", __func__);	return retval;}static int hpc_slot_disable(struct slot * slot){	int retval;	/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */	retval = shpc_write_cmd(slot, slot->hp_slot,			SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);	if (retval)		err("%s: Write command failed!\n", __func__);	return retval;}static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value){	int retval;	struct controller *ctrl = slot->ctrl;	u8 pi, cmd;	pi = shpc_readb(ctrl, PROG_INTERFACE);	if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))		return -EINVAL;	switch (value) {	case PCI_SPEED_33MHz:		cmd = SETA_PCI_33MHZ;		break;	case PCI_SPEED_66MHz:		cmd = SETA_PCI_66MHZ;		break;	case PCI_SPEED_66MHz_PCIX:		cmd = SETA_PCIX_66MHZ;		break;	case PCI_SPEED_100MHz_PCIX:		cmd = SETA_PCIX_100MHZ;		break;	case PCI_SPEED_133MHz_PCIX:		cmd = SETA_PCIX_133MHZ;		break;	case PCI_SPEED_66MHz_PCIX_ECC:		cmd = SETB_PCIX_66MHZ_EM;		break;	case PCI_SPEED_100MHz_PCIX_ECC:		cmd = SETB_PCIX_100MHZ_EM;		break;	case PCI_SPEED_133MHz_PCIX_ECC:		cmd = SETB_PCIX_133MHZ_EM;		break;	case PCI_SPEED_66MHz_PCIX_266:		cmd = SETB_PCIX_66MHZ_266;		break;	case PCI_SPEED_100MHz_PCIX_266:		cmd = SETB_PCIX_100MHZ_266;		break;	case PCI_SPEED_133MHz_PCIX_266:		cmd = SETB_PCIX_133MHZ_266;		break;	case PCI_SPEED_66MHz_PCIX_533:		cmd = SETB_PCIX_66MHZ_533;		break;	case PCI_SPEED_100MHz_PCIX_533:		cmd = SETB_PCIX_100MHZ_533;		break;	case PCI_SPEED_133MHz_PCIX_533:		cmd = SETB_PCIX_133MHZ_533;		break;	default:		return -EINVAL;	}	retval = shpc_write_cmd(slot, 0, cmd);	if (retval)		err("%s: Write command failed!\n", __func__);	return retval;}static irqreturn_t shpc_isr(int irq, void *dev_id){	struct controller *ctrl = (struct controller *)dev_id;	u32 serr_int, slot_reg, intr_loc, intr_loc2;	int hp_slot;	/* Check to see if it was our interrupt */	intr_loc = shpc_readl(ctrl, INTR_LOC);	if (!intr_loc)		return IRQ_NONE;	dbg("%s: intr_loc = %x\n",__func__, intr_loc);	if(!shpchp_poll_mode) {		/*		 * Mask Global Interrupt Mask - see implementation		 * note on p. 139 of SHPC spec rev 1.0		 */		serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);		serr_int |= GLOBAL_INTR_MASK;		serr_int &= ~SERR_INTR_RSVDZ_MASK;		shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);		intr_loc2 = shpc_readl(ctrl, INTR_LOC);		dbg("%s: intr_loc2 = %x\n",__func__, intr_loc2);	}	if (intr_loc & CMD_INTR_PENDING) {		/*		 * Command Complete Interrupt Pending		 * RO only - clear by writing 1 to the Command Completion		 * Detect bit in Controller SERR-INT register		 */		serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);		serr_int &= ~SERR_INTR_RSVDZ_MASK;		shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);		wake_up_interruptible(&ctrl->queue);	}	if (!(intr_loc & ~CMD_INTR_PENDING))		goto out;	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {		/* To find out which slot has interrupt pending */		if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))			continue;		slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));		dbg("%s: Slot %x with intr, slot register = %x\n",		    __func__, hp_slot, slot_reg);		if (slot_reg & MRL_CHANGE_DETECTED)			shpchp_handle_switch_change(hp_slot, ctrl);		if (slot_reg & BUTTON_PRESS_DETECTED)			shpchp_handle_attention_button(hp_slot, ctrl);		if (slot_reg & PRSNT_CHANGE_DETECTED)			shpchp_handle_presence_change(hp_slot, ctrl);		if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))			shpchp_handle_power_fault(hp_slot, ctrl);		/* Clear all slot events */		slot_reg &= ~SLOT_REG_RSVDZ_MASK;		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);	} out:	if (!shpchp_poll_mode) {		/* Unmask Global Interrupt Mask */		serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);		serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);		shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);	}	return IRQ_HANDLED;}static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value){	int retval = 0;	struct controller *ctrl = slot->ctrl;	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);	u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);	u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);	if (pi == 2) {		if (slot_avail2 & SLOT_133MHZ_PCIX_533)			bus_speed = PCI_SPEED_133MHz_PCIX_533;		else if (slot_avail2 & SLOT_100MHZ_PCIX_533)			bus_speed = PCI_SPEED_100MHz_PCIX_533;		else if (slot_avail2 & SLOT_66MHZ_PCIX_533)			bus_speed = PCI_SPEED_66MHz_PCIX_533;		else if (slot_avail2 & SLOT_133MHZ_PCIX_266)			bus_speed = PCI_SPEED_133MHz_PCIX_266;		else if (slot_avail2 & SLOT_100MHZ_PCIX_266)			bus_speed = PCI_SPEED_100MHz_PCIX_266;		else if (slot_avail2 & SLOT_66MHZ_PCIX_266)			bus_speed = PCI_SPEED_66MHz_PCIX_266;	}	if (bus_speed == PCI_SPEED_UNKNOWN) {		if (slot_avail1 & SLOT_133MHZ_PCIX)			bus_speed = PCI_SPEED_133MHz_PCIX;		else if (slot_avail1 & SLOT_100MHZ_PCIX)			bus_speed = PCI_SPEED_100MHz_PCIX;		else if (slot_avail1 & SLOT_66MHZ_PCIX)			bus_speed = PCI_SPEED_66MHz_PCIX;		else if (slot_avail2 & SLOT_66MHZ)			bus_speed = PCI_SPEED_66MHz;		else if (slot_avail1 & SLOT_33MHZ)			bus_speed = PCI_SPEED_33MHz;		else			retval = -ENODEV;	}	*value = bus_speed;	dbg("Max bus speed = %d\n", bus_speed);	return retval;}static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value){	int retval = 0;	struct controller *ctrl = slot->ctrl;	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;	u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);	u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);	if ((pi == 1) && (speed_mode > 4)) {		*value = PCI_SPEED_UNKNOWN;		return -ENODEV;	}	switch (speed_mode) {	case 0x0:		*value = PCI_SPEED_33MHz;		break;	case 0x1:		*value = PCI_SPEED_66MHz;		break;	case 0x2:		*value = PCI_SPEED_66MHz_PCIX;		break;	case 0x3:		*value = PCI_SPEED_100MHz_PCIX;		break;	case 0x4:		*value = PCI_SPEED_133MHz_PCIX;		break;	case 0x5:		*value = PCI_SPEED_66MHz_PCIX_ECC;		break;	case 0x6:		*value = PCI_SPEED_100MHz_PCIX_ECC;		break;	case 0x7:		*value = PCI_SPEED_133MHz_PCIX_ECC;		break;	case 0x8:		*value = PCI_SPEED_66MHz_PCIX_266;		break;	case 0x9:		*value = PCI_SPEED_100MHz_PCIX_266;		break;	case 0xa:		*value = PCI_SPEED_133MHz_PCIX_266;		break;	case 0xb:		*value = PCI_SPEED_66MHz_PCIX_533;		break;	case 0xc:		*value = PCI_SPEED_100MHz_PCIX_533;		break;	case 0xd:		*value = PCI_SPEED_133MHz_PCIX_533;		break;	default:		*value = PCI_SPEED_UNKNOWN;		retval = -ENODEV;		break;	}	dbg("Current bus speed = %d\n", bus_speed);	return retval;}static struct hpc_ops shpchp_hpc_ops = {	.power_on_slot			= hpc_power_on_slot,	.slot_enable			= hpc_slot_enable,	.slot_disable			= hpc_slot_disable,	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	.set_attention_status	= hpc_set_attention_status,	.get_power_status		= hpc_get_power_status,	.get_attention_status	= hpc_get_attention_status,	.get_latch_status		= hpc_get_latch_status,	.get_adapter_status		= hpc_get_adapter_status,	.get_max_bus_speed		= hpc_get_max_bus_speed,	.get_cur_bus_speed		= hpc_get_cur_bus_speed,	.get_adapter_speed		= hpc_get_adapter_speed,	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,	.get_prog_int			= hpc_get_prog_int,	.query_power_fault		= hpc_query_power_fault,	.green_led_on			= hpc_set_green_led_on,	.green_led_off			= hpc_set_green_led_off,	.green_led_blink		= hpc_set_green_led_blink,	.release_ctlr			= hpc_release_ctlr,};int shpc_init(struct controller *ctrl, struct pci_dev *pdev){	int rc = -1, num_slots = 0;	u8 hp_slot;	u32 shpc_base_offset;	u32 tempdword, slot_reg, slot_config;	u8 i;	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==				PCI_DEVICE_ID_AMD_GOLAM_7450)) {		/* amd shpc driver doesn't use Base Offset; assume 0 */		ctrl->mmio_base = pci_resource_start(pdev, 0);		ctrl->mmio_size = pci_resource_len(pdev, 0);	} else {		ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);		if (!ctrl->cap_offset) {			err("%s : cap_offset == 0\n", __func__);			goto abort;		}		dbg("%s: cap_offset = %x\n", __func__, ctrl->cap_offset);		rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);		if (rc) {			err("%s: cannot read base_offset\n", __func__);			goto abort;		}		rc = shpc_indirect_read(ctrl, 3, &tempdword);		if (rc) {			err("%s: cannot read slot config\n", __func__);			goto abort;		}		num_slots = tempdword & SLOT_NUM;		dbg("%s: num_slots (indirect) %x\n", __func__, num_slots);		for (i = 0; i < 9 + num_slots; i++) {			rc = shpc_indirect_read(ctrl, i, &tempdword);			if (rc) {				err("%s: cannot read creg (index = %d)\n",				    __func__, i);				goto abort;			}			dbg("%s: offset %d: value %x\n", __func__,i,					tempdword);		}		ctrl->mmio_base =			pci_resource_start(pdev, 0) + shpc_base_offset;		ctrl->mmio_size = 0x24 + 0x4 * num_slots;	}	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,		pdev->subsystem_device);	rc = pci_enable_device(pdev);	if (rc) {		err("%s: pci_enable_device failed\n", __func__);		goto abort;	}	if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {		err("%s: cannot reserve MMIO region\n", __func__);		rc = -1;		goto abort;	}	ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);	if (!ctrl->creg) {		err("%s: cannot remap MMIO region %lx @ %lx\n", __func__,		    ctrl->mmio_size, ctrl->mmio_base);		release_mem_region(ctrl->mmio_base, ctrl->mmio_size);		rc = -1;		goto abort;	}	dbg("%s: ctrl->creg %p\n", __func__, ctrl->creg);	mutex_init(&ctrl->crit_sect);	mutex_init(&ctrl->cmd_lock);	/* Setup wait queue */	init_waitqueue_head(&ctrl->queue);	ctrl->hpc_ops = &shpchp_hpc_ops;	/* Return PCI Controller Info */	slot_config = shpc_readl(ctrl, SLOT_CONFIG);	ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;	ctrl->num_slots = slot_config & SLOT_NUM;	ctrl->first_slot = (slot_config & PSN) >> 16;	ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1;	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */	tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);	dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword);	tempdword |= (GLOBAL_INTR_MASK  | GLOBAL_SERR_MASK |		      COMMAND_INTR_MASK | ARBITER_SERR_MASK);	tempdword &= ~SERR_INTR_RSVDZ_MASK;	shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);	tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);	dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword);	/* Mask the MRL sensor SERR Mask of individual slot in	 * Slot SERR-INT Mask & clear all the existing event if any	 */	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {		slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));		dbg("%s: Default Logical Slot Register %d value %x\n", __func__,			hp_slot, slot_reg);		slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |			     BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |			     CON_PFAULT_INTR_MASK   | MRL_CHANGE_SERR_MASK |			     CON_PFAULT_SERR_MASK);		slot_reg &= ~SLOT_REG_RSVDZ_MASK;		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);	}	if (shpchp_poll_mode) {		/* Install interrupt polling timer. Start with 10 sec delay */		init_timer(&ctrl->poll_timer);		start_int_poll_timer(ctrl, 10);	} else {		/* Installs the interrupt handler */		rc = pci_enable_msi(pdev);		if (rc) {			info("Can't get msi for the hotplug controller\n");			info("Use INTx for the hotplug controller\n");		}		rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,				 MY_NAME, (void *)ctrl);		dbg("%s: request_irq %d for hpc%d (returns %d)\n",		    __func__, ctrl->pci_dev->irq,		    atomic_read(&shpchp_num_controllers), rc);		if (rc) {			err("Can't get irq %d for the hotplug controller\n",			    ctrl->pci_dev->irq);			goto abort_iounmap;		}	}	dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__,			pdev->bus->number, PCI_SLOT(pdev->devfn),			PCI_FUNC(pdev->devfn), pdev->irq);	/*	 * If this is the first controller to be initialized,	 * initialize the shpchpd work queue	 */	if (atomic_add_return(1, &shpchp_num_controllers) == 1) {		shpchp_wq = create_singlethread_workqueue("shpchpd");		if (!shpchp_wq) {			rc = -ENOMEM;			goto abort_iounmap;		}	}	/*	 * Unmask all event interrupts of all slots	 */	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {		slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));		dbg("%s: Default Logical Slot Register %d value %x\n", __func__,			hp_slot, slot_reg);		slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |			      BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |			      CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK);		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);	}	if (!shpchp_poll_mode) {		/* Unmask all general input interrupts and SERR */		tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);		tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK |			       SERR_INTR_RSVDZ_MASK);		shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);		tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);		dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword);	}	return 0;	/* We end up here for the many possible ways to fail this API.  */abort_iounmap:	iounmap(ctrl->creg);abort:	return rc;}

⌨️ 快捷键说明

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