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

📄 ohci1394.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
static void initialize_dma_trm_ctx(struct dma_trm_ctx *d){	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	/* Stop the context */	ohci1394_stop_context(ohci, d->ctrlClear, NULL);        d->prg_ind = 0;	d->sent_ind = 0;	d->free_prgs = d->num_desc;        d->branchAddrPtr = NULL;	d->fifo_first = NULL;	d->fifo_last = NULL;	d->pending_first = NULL;	d->pending_last = NULL;	DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx);}/* Count the number of available iso contexts */static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg){	int i,ctx=0;	u32 tmp;	reg_write(ohci, reg, 0xffffffff);	tmp = reg_read(ohci, reg);		DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp);	/* Count the number of contexts */	for(i=0; i<32; i++) {	    	if(tmp & 1) ctx++;		tmp >>= 1;	}	return ctx;}static void ohci_init_config_rom(struct ti_ohci *ohci);/* Global initialization */static int ohci_initialize(struct hpsb_host *host){	struct ti_ohci *ohci=host->hostdata;	int retval, i;	quadlet_t buf;	spin_lock_init(&ohci->phy_reg_lock);	spin_lock_init(&ohci->event_lock);  	/* Soft reset */	if ((retval = ohci_soft_reset(ohci)) < 0)		return retval;	/* Put some defaults to these undefined bus options */	buf = reg_read(ohci, OHCI1394_BusOptions);	buf |=  0x60000000; /* Enable CMC and ISC */	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */	buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */	reg_write(ohci, OHCI1394_BusOptions, buf);	/* Set Link Power Status (LPS) */	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);	/* After enabling LPS, we need to wait for the connection	 * between phy and link to be established.  This should be	 * signaled by the LPS bit becoming 1, but this happens	 * immediately.  There seems to be no consistent way to wait	 * for this, but 50ms seems to be enough. */	mdelay(50);	/* Set the bus number */	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);	/* Enable posted writes */	reg_write(ohci, OHCI1394_HCControlSet, 0x00040000);	/* Clear link control register */	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);  	/* Enable cycle timer and cycle master */	reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);	/* Clear interrupt registers */	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);	/* Set up self-id dma buffer */	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);	/* enable self-id dma */	reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);	/* Set the Config ROM mapping register */	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);	/* Initialize the Config ROM */	ohci_init_config_rom(ohci);	/* Now get our max packet size */	ohci->max_packet_size = 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);	/* Don't accept phy packets into AR request context */ 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);	/* Initialize IR dma */	ohci->nb_iso_rcv_ctx = 		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);	DBGMSG(ohci->id, "%d iso receive contexts available",	       ohci->nb_iso_rcv_ctx);	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,			  0xffffffff);		reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);		reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);	}	/* Set bufferFill, isochHeader, multichannel for IR context */	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);				/* Set the context match register to match on all tags */	reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000);	/* Clear the interrupt mask */	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);	/* Initialize IT dma */	ohci->nb_iso_xmit_ctx = 		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);	DBGMSG(ohci->id, "%d iso transmit contexts available",	       ohci->nb_iso_xmit_ctx);	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,			  0xffffffff);		reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);	}		/* Clear the interrupt mask */	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);	/* Clear the multi channel mask high and low registers */	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);	/* Initialize AR dma */	initialize_dma_rcv_ctx(ohci->ar_req_context, 0);	initialize_dma_rcv_ctx(ohci->ar_resp_context, 0);	/* Initialize AT dma */	initialize_dma_trm_ctx(ohci->at_req_context);	initialize_dma_trm_ctx(ohci->at_resp_context);	/* Initialize IR dma */	initialize_dma_rcv_ctx(ohci->ir_context, 1);        /* Initialize IT dma */        initialize_dma_trm_ctx(ohci->it_context);	/* Set up isoRecvIntMask to generate interrupts for context 0	   (thanks to Michael Greger for seeing that I forgot this) */	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);	/* Set up isoXmitIntMask to generate interrupts for context 0 */	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001);	/* 	 * Accept AT requests from all nodes. This probably 	 * will have to be controlled from the subsystem	 * on a per node basis.	 */	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);	/* Specify AT retries */	reg_write(ohci, OHCI1394_ATRetries, 		  OHCI1394_MAX_AT_REQ_RETRIES |		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));	/* We don't want hardware swapping */	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);	/* Enable interrupts */	reg_write(ohci, OHCI1394_IntMaskSet, 		  OHCI1394_masterIntEnable | 		  OHCI1394_busReset | 		  OHCI1394_selfIDComplete |		  OHCI1394_RSPkt |		  OHCI1394_RQPkt |		  OHCI1394_respTxComplete |		  OHCI1394_reqTxComplete |		  OHCI1394_isochRx |		  OHCI1394_isochTx |		  OHCI1394_unrecoverableError		);	/* Enable link */	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);	buf = reg_read(ohci, OHCI1394_Version);	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  MMIO=[%lx-%lx]"	      "  Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,	      pci_resource_start(ohci->dev, 0),	      pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),	      ohci->max_packet_size);	return 1;}static void ohci_remove(struct hpsb_host *host){	struct ti_ohci *ohci;	if (host != NULL) {		ohci = host->hostdata;		remove_card(ohci);	}}/*  * Insert a packet in the AT DMA fifo and generate the DMA prg * FIXME: rewrite the program in order to accept packets crossing *        page boundaries. *        check also that a single dma descriptor doesn't cross a  *        page boundary. */static void insert_packet(struct ti_ohci *ohci,			  struct dma_trm_ctx *d, struct hpsb_packet *packet){	u32 cycleTimer;	int idx = d->prg_ind;	DBGMSG(ohci->id, "Inserting packet for node %d, tlabel=%d, tcode=0x%x, speed=%d",			packet->node_id, packet->tlabel, packet->tcode, packet->speed_code);	d->prg_cpu[idx]->begin.address = 0;	d->prg_cpu[idx]->begin.branchAddress = 0;	if (d->ctx==1) {		/* 		 * For response packets, we need to put a timeout value in		 * the 16 lower bits of the status... let's try 1 sec timeout 		 */ 		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);		d->prg_cpu[idx]->begin.status = cpu_to_le32(			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | 			((cycleTimer&0x01fff000)>>12));		DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",		       cycleTimer, d->prg_cpu[idx]->begin.status);	} else 		d->prg_cpu[idx]->begin.status = 0;        if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {                if (packet->type == hpsb_raw) {			d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);                        d->prg_cpu[idx]->data[1] = packet->header[0];                        d->prg_cpu[idx]->data[2] = packet->header[1];                } else {                        d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |                                (packet->header[0] & 0xFFFF);                        d->prg_cpu[idx]->data[1] =                                (packet->header[1] & 0xFFFF) |                                 (packet->header[0] & 0xFFFF0000);                        d->prg_cpu[idx]->data[2] = packet->header[2];                        d->prg_cpu[idx]->data[3] = packet->header[3];			packet_swab(d->prg_cpu[idx]->data, packet->tcode,					packet->header_size>>2);                }                if (packet->data_size) { /* block transmit */                        d->prg_cpu[idx]->begin.control =                                cpu_to_le32(DMA_CTL_OUTPUT_MORE |					    DMA_CTL_IMMEDIATE | 0x10);                        d->prg_cpu[idx]->end.control =                                cpu_to_le32(DMA_CTL_OUTPUT_LAST |					    DMA_CTL_IRQ | 					    DMA_CTL_BRANCH |					    packet->data_size);                        /*                          * Check that the packet data buffer                         * does not cross a page boundary.                         */                        if (cross_bound((unsigned long)packet->data,                                         packet->data_size)>0) {                                /* FIXME: do something about it */                                PRINT(KERN_ERR, ohci->id, __FUNCTION__                                      ": packet data addr: %p size %Zd bytes "                                      "cross page boundary",                                       packet->data, packet->data_size);                        }                        d->prg_cpu[idx]->end.address = cpu_to_le32(                                pci_map_single(ohci->dev, packet->data,                                               packet->data_size,                                               PCI_DMA_TODEVICE));			OHCI_DMA_ALLOC("single, block transmit packet");                        d->prg_cpu[idx]->end.branchAddress = 0;                        d->prg_cpu[idx]->end.status = 0;                        if (d->branchAddrPtr)                                 *(d->branchAddrPtr) =					cpu_to_le32(d->prg_bus[idx] | 0x3);                        d->branchAddrPtr =                                &(d->prg_cpu[idx]->end.branchAddress);                } else { /* quadlet transmit */                        if (packet->type == hpsb_raw)                                d->prg_cpu[idx]->begin.control = 					cpu_to_le32(DMA_CTL_OUTPUT_LAST |						    DMA_CTL_IMMEDIATE |						    DMA_CTL_IRQ | 						    DMA_CTL_BRANCH |						    (packet->header_size + 4));                        else                                d->prg_cpu[idx]->begin.control =					cpu_to_le32(DMA_CTL_OUTPUT_LAST |						    DMA_CTL_IMMEDIATE |						    DMA_CTL_IRQ | 						    DMA_CTL_BRANCH |						    packet->header_size);                        if (d->branchAddrPtr)                                 *(d->branchAddrPtr) =					cpu_to_le32(d->prg_bus[idx] | 0x2);                        d->branchAddrPtr =                                &(d->prg_cpu[idx]->begin.branchAddress);                }        } else { /* iso packet */                d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |                        (packet->header[0] & 0xFFFF);                d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;		packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2);                  d->prg_cpu[idx]->begin.control = 			cpu_to_le32(DMA_CTL_OUTPUT_MORE | 				    DMA_CTL_IMMEDIATE | 0x8);                d->prg_cpu[idx]->end.control = 			cpu_to_le32(DMA_CTL_OUTPUT_LAST |				    DMA_CTL_UPDATE |				    DMA_CTL_IRQ |				    DMA_CTL_BRANCH |				    packet->data_size);                d->prg_cpu[idx]->end.address = cpu_to_le32(				pci_map_single(ohci->dev, packet->data,				packet->data_size, PCI_DMA_TODEVICE));		OHCI_DMA_ALLOC("single, iso transmit packet");                d->prg_cpu[idx]->end.branchAddress = 0;                d->prg_cpu[idx]->end.status = 0;                DBGMSG(ohci->id, "Iso xmit context info: header[%08x %08x]\n"                       "                       begin=%08x %08x %08x %08x\n"                       "                             %08x %08x %08x %08x\n"                       "                       end  =%08x %08x %08x %08x",                       d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],                       d->prg_cpu[idx]->begin.control,                       d->prg_cpu[idx]->begin.address,                       d->prg_cpu[idx]->begin.branchAddress,                       d->prg_cpu[idx]->begin.status,                       d->prg_cpu[idx]->data[0],                       d->prg_cpu[idx]->data[1],                       d->prg_cpu[idx]->data[2],                       d->prg_cpu[idx]->data[3],                       d->prg_cpu[idx]->end.control,                       d->prg_cpu[idx]->end.address,                       d->prg_cpu[idx]->end.branchAddress,                       d->prg_cpu[idx]->end.status);                if (d->branchAddrPtr)   		        *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);                d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);        }	d->free_prgs--;	/* queue the packet in the appropriate context queue */	if (d->fifo_last) {		d->fifo_last->xnext = packet;		d->fifo_last = packet;	} else {		d->fifo_first = packet;		d->fifo_last = packet;	}	d->prg_ind = (d->prg_ind+1)%d->num_desc;}/* * This function fills the AT FIFO with the (eventual) pending packets * and runs or wakes up the AT DMA prg if necessary. * * The function MUST be called with the d->lock held. */ static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d){	int idx,z;	if (d->pending_first == NULL || d->free_prgs == 0) 		return 0;	idx = d->prg_ind;	z = (d->pending_first->data_size) ? 3 : 2;	/* insert the packets into the at dma fifo */	while (d->free_prgs>0 && d->pending_first) {		insert_packet(ohci, d, d->pending_first);		d->pending_first = d->pending_first->xnext;	}	if (d->pending_first == NULL) 		d->pending_last = NULL;	else		PRINT(KERN_INFO, ohci->id, 		      "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx);	/* Is the context running ? (should be unless it is 	   the first packet to be sent in this context) */	if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {		DBGMSG(ohci->id,"Starting transmit DMA ctx=%d",d->ctx);		reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z);		run_context(ohci, d->ctrlSet, NULL);	}	else {		/* Wake up the dma context if necessary */		if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {			DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx);			reg_write(ohci, d->ctrlSet, 0x1000);		}	}	return 1;}/* Transmission of an async packet */static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet){	struct ti_ohci *ohci = host->hostdata;	struct dma_trm_ctx *d;	unsigned char tcode;	unsigned long flags;	if (packet->data_size > ohci->max_packet_size) {		PRINT(KERN_ERR, ohci->id, 		      "Transmit packet size %Zd is too big",		      packet->data_size);		return 0;	}	packet->xnext = NULL;

⌨️ 快捷键说明

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