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

📄 sx8.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* response to a message we sent */		else if ((status & (1 << 31)) == 0) {			VPRINTK("handling msg response on index %u\n", idx);			carm_handle_resp(host, resp[idx].ret_handle, status);			resp[idx].status = cpu_to_le32(0xffffffff);		}		/* asynchronous events the hardware throws our way */		else if ((status & 0xff000000) == (1 << 31)) {			u8 *evt_type_ptr = (u8 *) &resp[idx];			u8 evt_type = *evt_type_ptr;			printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n",			       pci_name(host->pdev), (int) evt_type);			resp[idx].status = cpu_to_le32(0xffffffff);		}		idx = NEXT_RESP(idx);		work++;	}	VPRINTK("EXIT, work==%u\n", work);	host->resp_idx += work;}static irqreturn_t carm_interrupt(int irq, void *__host){	struct carm_host *host = __host;	void __iomem *mmio;	u32 mask;	int handled = 0;	unsigned long flags;	if (!host) {		VPRINTK("no host\n");		return IRQ_NONE;	}	spin_lock_irqsave(&host->lock, flags);	mmio = host->mmio;	/* reading should also clear interrupts */	mask = readl(mmio + CARM_INT_STAT);	if (mask == 0 || mask == 0xffffffff) {		VPRINTK("no work, mask == 0x%x\n", mask);		goto out;	}	if (mask & INT_ACK_MASK)		writel(mask, mmio + CARM_INT_STAT);	if (unlikely(host->state == HST_INVALID)) {		VPRINTK("not initialized yet, mask = 0x%x\n", mask);		goto out;	}	if (mask & CARM_HAVE_RESP) {		handled = 1;		carm_handle_responses(host);	}out:	spin_unlock_irqrestore(&host->lock, flags);	VPRINTK("EXIT\n");	return IRQ_RETVAL(handled);}static void carm_fsm_task (struct work_struct *work){	struct carm_host *host =		container_of(work, struct carm_host, fsm_task);	unsigned long flags;	unsigned int state;	int rc, i, next_dev;	int reschedule = 0;	int new_state = HST_INVALID;	spin_lock_irqsave(&host->lock, flags);	state = host->state;	spin_unlock_irqrestore(&host->lock, flags);	DPRINTK("ENTER, state == %s\n", state_name[state]);	switch (state) {	case HST_PROBE_START:		new_state = HST_ALLOC_BUF;		reschedule = 1;		break;	case HST_ALLOC_BUF:		rc = carm_send_special(host, carm_fill_alloc_buf);		if (rc) {			new_state = HST_ERROR;			reschedule = 1;		}		break;	case HST_SYNC_TIME:		rc = carm_send_special(host, carm_fill_sync_time);		if (rc) {			new_state = HST_ERROR;			reschedule = 1;		}		break;	case HST_GET_FW_VER:		rc = carm_send_special(host, carm_fill_get_fw_ver);		if (rc) {			new_state = HST_ERROR;			reschedule = 1;		}		break;	case HST_PORT_SCAN:		rc = carm_send_special(host, carm_fill_scan_channels);		if (rc) {			new_state = HST_ERROR;			reschedule = 1;		}		break;	case HST_DEV_SCAN_START:		host->cur_scan_dev = -1;		new_state = HST_DEV_SCAN;		reschedule = 1;		break;	case HST_DEV_SCAN:		next_dev = -1;		for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++)			if (host->dev_present & (1 << i)) {				next_dev = i;				break;			}		if (next_dev >= 0) {			host->cur_scan_dev = next_dev;			rc = carm_array_info(host, next_dev);			if (rc) {				new_state = HST_ERROR;				reschedule = 1;			}		} else {			new_state = HST_DEV_ACTIVATE;			reschedule = 1;		}		break;	case HST_DEV_ACTIVATE: {		int activated = 0;		for (i = 0; i < CARM_MAX_PORTS; i++)			if (host->dev_active & (1 << i)) {				struct carm_port *port = &host->port[i];				struct gendisk *disk = port->disk;				set_capacity(disk, port->capacity);				add_disk(disk);				activated++;			}		printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n",		       pci_name(host->pdev), activated);		new_state = HST_PROBE_FINISHED;		reschedule = 1;		break;	}	case HST_PROBE_FINISHED:		complete(&host->probe_comp);		break;	case HST_ERROR:		/* FIXME: TODO */		break;	default:		/* should never occur */		printk(KERN_ERR PFX "BUG: unknown state %d\n", state);		assert(0);		break;	}	if (new_state != HST_INVALID) {		spin_lock_irqsave(&host->lock, flags);		host->state = new_state;		spin_unlock_irqrestore(&host->lock, flags);	}	if (reschedule)		schedule_work(&host->fsm_task);}static int carm_init_wait(void __iomem *mmio, u32 bits, unsigned int test_bit){	unsigned int i;	for (i = 0; i < 50000; i++) {		u32 tmp = readl(mmio + CARM_LMUC);		udelay(100);		if (test_bit) {			if ((tmp & bits) == bits)				return 0;		} else {			if ((tmp & bits) == 0)				return 0;		}		cond_resched();	}	printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n",	       bits, test_bit ? "yes" : "no");	return -EBUSY;}static void carm_init_responses(struct carm_host *host){	void __iomem *mmio = host->mmio;	unsigned int i;	struct carm_response *resp = (struct carm_response *) host->shm;	for (i = 0; i < RMSG_Q_LEN; i++)		resp[i].status = cpu_to_le32(0xffffffff);	writel(0, mmio + CARM_RESP_IDX);}static int carm_init_host(struct carm_host *host){	void __iomem *mmio = host->mmio;	u32 tmp;	u8 tmp8;	int rc;	DPRINTK("ENTER\n");	writel(0, mmio + CARM_INT_MASK);	tmp8 = readb(mmio + CARM_INITC);	if (tmp8 & 0x01) {		tmp8 &= ~0x01;		writeb(tmp8, mmio + CARM_INITC);		readb(mmio + CARM_INITC);	/* flush */		DPRINTK("snooze...\n");		msleep(5000);	}	tmp = readl(mmio + CARM_HMUC);	if (tmp & CARM_CME) {		DPRINTK("CME bit present, waiting\n");		rc = carm_init_wait(mmio, CARM_CME, 1);		if (rc) {			DPRINTK("EXIT, carm_init_wait 1 failed\n");			return rc;		}	}	if (tmp & CARM_RME) {		DPRINTK("RME bit present, waiting\n");		rc = carm_init_wait(mmio, CARM_RME, 1);		if (rc) {			DPRINTK("EXIT, carm_init_wait 2 failed\n");			return rc;		}	}	tmp &= ~(CARM_RME | CARM_CME);	writel(tmp, mmio + CARM_HMUC);	readl(mmio + CARM_HMUC);	/* flush */	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0);	if (rc) {		DPRINTK("EXIT, carm_init_wait 3 failed\n");		return rc;	}	carm_init_buckets(mmio);	writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO);	writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI);	writel(RBUF_LEN, mmio + RBUF_BYTE_SZ);	tmp = readl(mmio + CARM_HMUC);	tmp |= (CARM_RME | CARM_CME | CARM_WZBC);	writel(tmp, mmio + CARM_HMUC);	readl(mmio + CARM_HMUC);	/* flush */	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1);	if (rc) {		DPRINTK("EXIT, carm_init_wait 4 failed\n");		return rc;	}	writel(0, mmio + CARM_HMPHA);	writel(INT_DEF_MASK, mmio + CARM_INT_MASK);	carm_init_responses(host);	/* start initialization, probing state machine */	spin_lock_irq(&host->lock);	assert(host->state == HST_INVALID);	host->state = HST_PROBE_START;	spin_unlock_irq(&host->lock);	schedule_work(&host->fsm_task);	DPRINTK("EXIT\n");	return 0;}static int carm_init_disks(struct carm_host *host){	unsigned int i;	int rc = 0;	for (i = 0; i < CARM_MAX_PORTS; i++) {		struct gendisk *disk;		struct request_queue *q;		struct carm_port *port;		port = &host->port[i];		port->host = host;		port->port_no = i;		disk = alloc_disk(CARM_MINORS_PER_MAJOR);		if (!disk) {			rc = -ENOMEM;			break;		}		port->disk = disk;		sprintf(disk->disk_name, DRV_NAME "/%u",			(unsigned int) (host->id * CARM_MAX_PORTS) + i);		disk->major = host->major;		disk->first_minor = i * CARM_MINORS_PER_MAJOR;		disk->fops = &carm_bd_ops;		disk->private_data = port;		q = blk_init_queue(carm_rq_fn, &host->lock);		if (!q) {			rc = -ENOMEM;			break;		}		disk->queue = q;		blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG);		blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG);		blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);		q->queuedata = port;	}	return rc;}static void carm_free_disks(struct carm_host *host){	unsigned int i;	for (i = 0; i < CARM_MAX_PORTS; i++) {		struct gendisk *disk = host->port[i].disk;		if (disk) {			struct request_queue *q = disk->queue;			if (disk->flags & GENHD_FL_UP)				del_gendisk(disk);			if (q)				blk_cleanup_queue(q);			put_disk(disk);		}	}}static int carm_init_shm(struct carm_host *host){	host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE,					 &host->shm_dma);	if (!host->shm)		return -ENOMEM;	host->msg_base = host->shm + RBUF_LEN;	host->msg_dma = host->shm_dma + RBUF_LEN;	memset(host->shm, 0xff, RBUF_LEN);	memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN);	return 0;}static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){	static unsigned int printed_version;	struct carm_host *host;	unsigned int pci_dac;	int rc;	struct request_queue *q;	unsigned int i;	if (!printed_version++)		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");	rc = pci_enable_device(pdev);	if (rc)		return rc;	rc = pci_request_regions(pdev, DRV_NAME);	if (rc)		goto err_out;#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */	rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);	if (!rc) {		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);		if (rc) {			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",				pci_name(pdev));			goto err_out_regions;		}		pci_dac = 1;	} else {#endif		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (rc) {			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",				pci_name(pdev));			goto err_out_regions;		}		pci_dac = 0;#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */	}#endif	host = kzalloc(sizeof(*host), GFP_KERNEL);	if (!host) {		printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",		       pci_name(pdev));		rc = -ENOMEM;		goto err_out_regions;	}	host->pdev = pdev;	host->flags = pci_dac ? FL_DAC : 0;	spin_lock_init(&host->lock);	INIT_WORK(&host->fsm_task, carm_fsm_task);	init_completion(&host->probe_comp);	for (i = 0; i < ARRAY_SIZE(host->req); i++)		host->req[i].tag = i;	host->mmio = ioremap(pci_resource_start(pdev, 0),			     pci_resource_len(pdev, 0));	if (!host->mmio) {		printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n",		       pci_name(pdev));		rc = -ENOMEM;		goto err_out_kfree;	}	rc = carm_init_shm(host);	if (rc) {		printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n",		       pci_name(pdev));		goto err_out_iounmap;	}	q = blk_init_queue(carm_oob_rq_fn, &host->lock);	if (!q) {		printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n",		       pci_name(pdev));		rc = -ENOMEM;		goto err_out_pci_free;	}	host->oob_q = q;	q->queuedata = host;	/*	 * Figure out which major to use: 160, 161, or dynamic	 */	if (!test_and_set_bit(0, &carm_major_alloc))		host->major = 160;	else if (!test_and_set_bit(1, &carm_major_alloc))		host->major = 161;	else		host->flags |= FL_DYN_MAJOR;	host->id = carm_host_id;	sprintf(host->name, DRV_NAME "%d", carm_host_id);	rc = register_blkdev(host->major, host->name);	if (rc < 0)		goto err_out_free_majors;	if (host->flags & FL_DYN_MAJOR)		host->major = rc;	rc = carm_init_disks(host);	if (rc)		goto err_out_blkdev_disks;	pci_set_master(pdev);	rc = request_irq(pdev->irq, carm_interrupt, IRQF_SHARED, DRV_NAME, host);	if (rc) {		printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n",		       pci_name(pdev));		goto err_out_blkdev_disks;	}	rc = carm_init_host(host);	if (rc)		goto err_out_free_irq;	DPRINTK("waiting for probe_comp\n");	wait_for_completion(&host->probe_comp);	printk(KERN_INFO "%s: pci %s, ports %d, io %llx, irq %u, major %d\n",	       host->name, pci_name(pdev), (int) CARM_MAX_PORTS,	       (unsigned long long)pci_resource_start(pdev, 0),		   pdev->irq, host->major);	carm_host_id++;	pci_set_drvdata(pdev, host);	return 0;err_out_free_irq:	free_irq(pdev->irq, host);err_out_blkdev_disks:	carm_free_disks(host);	unregister_blkdev(host->major, host->name);err_out_free_majors:	if (host->major == 160)		clear_bit(0, &carm_major_alloc);	else if (host->major == 161)		clear_bit(1, &carm_major_alloc);	blk_cleanup_queue(host->oob_q);err_out_pci_free:	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);err_out_iounmap:	iounmap(host->mmio);err_out_kfree:	kfree(host);err_out_regions:	pci_release_regions(pdev);err_out:	pci_disable_device(pdev);	return rc;}static void carm_remove_one (struct pci_dev *pdev){	struct carm_host *host = pci_get_drvdata(pdev);	if (!host) {		printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n",		       pci_name(pdev));		return;	}	free_irq(pdev->irq, host);	carm_free_disks(host);	unregister_blkdev(host->major, host->name);	if (host->major == 160)		clear_bit(0, &carm_major_alloc);	else if (host->major == 161)		clear_bit(1, &carm_major_alloc);	blk_cleanup_queue(host->oob_q);	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);	iounmap(host->mmio);	kfree(host);	pci_release_regions(pdev);	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);}static int __init carm_init(void){	return pci_register_driver(&carm_driver);}static void __exit carm_exit(void){	pci_unregister_driver(&carm_driver);}module_init(carm_init);module_exit(carm_exit);

⌨️ 快捷键说明

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