VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip) { PDEV *ppdev = pRc->ppdev; BYTE *pjBase = ppdev->pjBase; CHECK_FIFO_FREE(pjBase, pRc->cFifo, 4); CP_WRITE(pjBase, DWG_CYTOP, ((pClip->top + pRc->hwBufferYBias) * ppdev->cxMemory) + ppdev->ulYDstOrg); CP_WRITE(pjBase, DWG_CXLEFT, pClip->left); CP_WRITE(pjBase, DWG_CXRIGHT, pClip->right - 1); CP_WRITE(pjBase, DWG_CYBOT, ((pClip->bottom + pRc->hwBufferYBias - 1) * ppdev->cxMemory) + ppdev->ulYDstOrg); }
/* * Get device PROM values from CP * * This function will issue a GET_PROM command to the CP in order to * initiate the DMA transfer of the CP's PROM structure to the host. * This will be called after CP initialization has completed. * There is (currently) no retry if this fails. * * Called at interrupt level. * * Arguments: * fup pointer to device unit structure * * Returns: * none * */ static void fore_get_prom(Fore_unit *fup) { H_cmd_queue *hcp; Cmd_queue *cqp; /* * Queue command at end of command queue */ hcp = fup->fu_cmd_tail; if ((*hcp->hcq_status) & QSTAT_FREE) { /* * Queue entry available, so set our view of things up */ hcp->hcq_code = CMD_GET_PROM; hcp->hcq_arg = NULL; fup->fu_cmd_tail = hcp->hcq_next; /* * Now set the CP-resident queue entry - the CP will grab * the command when the op-code is set. */ cqp = hcp->hcq_cpelem; (*hcp->hcq_status) = QSTAT_PENDING; fup->fu_promd = DMA_GET_ADDR(fup->fu_prom, sizeof(Fore_prom), FORE_PROM_ALIGN, 0); if (fup->fu_promd == NULL) { fup->fu_stats->st_drv.drv_cm_nodma++; return; } cqp->cmdq_prom.prom_buffer = (CP_dma) CP_WRITE(fup->fu_promd); cqp->cmdq_prom.prom_cmd = CP_WRITE(CMD_GET_PROM | CMD_INTR_REQ); } else { /* * Command queue full */ fup->fu_stats->st_drv.drv_cm_full++; } return; }
/* * Supply Strategy 1 Large Buffers to CP * * May be called in interrupt state. * Must be called with interrupts locked out. * * Arguments: * fup pointer to device unit structure * * Returns: * none */ static void fore_buf_supply_1l(Fore_unit *fup) { H_buf_queue *hbp; Buf_queue *cqp; Buf_descr *bdp; Buf_handle *bhp; KBuffer *m; int nvcc, nbuf, i; /* * Figure out how many buffers we should be giving to the CP. * We're basing this calculation on the current number of open * VCCs thru this device, with certain minimum and maximum values * enforced. This will then allow us to figure out how many more * buffers we need to supply to the CP. This will be rounded up * to fill a supply queue entry. */ nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC); nbuf = nvcc * 4 * RECV_MAX_SEGS; nbuf = MIN(nbuf, BUF1_LG_CPPOOL); nbuf -= fup->fu_buf1l_cnt; nbuf = roundup(nbuf, BUF1_LG_ENTSIZE); /* * OK, now supply the buffers to the CP */ while (nbuf > 0) { /* * Acquire a supply queue entry */ hbp = fup->fu_buf1l_tail; if (!((*hbp->hbq_status) & QSTAT_FREE)) break; bdp = hbp->hbq_descr; /* * Get a buffer for each descriptor in the queue entry */ for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) { caddr_t cp; /* * Get a cluster buffer */ KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA); if (m == NULL) { break; } KB_HEADSET(m, BUF1_LG_DOFF); /* * Point to buffer handle structure */ bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF); bhp->bh_type = BHT_S1_LARGE; /* * Setup buffer descriptor */ bdp->bsd_handle = bhp; KB_DATASTART(m, cp, caddr_t); bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR( cp, BUF1_LG_SIZE, BUF_DATA_ALIGN, 0); if (bdp->bsd_buffer == 0) { /* * Unable to assign dma address - free up * this descriptor's buffer */ fup->fu_stats->st_drv.drv_bf_segdma++; KB_FREEALL(m); break; } /* * All set, so queue buffer (handle) */ ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); } /* * If we we're not able to fill all the descriptors for * an entry, free up what's been partially built */ if (i != BUF1_LG_ENTSIZE) { caddr_t cp; /* * Clean up each used descriptor */ for (bdp = hbp->hbq_descr; i; i--, bdp++) { bhp = bdp->bsd_handle; DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF); KB_DATASTART(m, cp, caddr_t); DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0); KB_FREEALL(m); } break; } /* * Finally, we've got an entry ready for the CP. * So claim the host queue entry and setup the CP-resident * queue entry. The CP will (potentially) grab the supplied * buffers when the descriptor pointer is set. */ fup->fu_buf1l_tail = hbp->hbq_next; (*hbp->hbq_status) = QSTAT_PENDING; cqp = hbp->hbq_cpelem; cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma); /* * Update counters, etc for supplied buffers */ fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE; nbuf -= BUF1_LG_ENTSIZE; } return; }
/* * Buffer Supply Queues Initialization * * Allocate and initialize the host-resident buffer supply queue structures * and then initialize the CP-resident queue structures. * * Called at interrupt level. * * Arguments: * fup pointer to device unit structure * * Returns: * none */ void fore_buf_initialize(Fore_unit *fup) { Aali *aap = fup->fu_aali; Buf_queue *cqp; H_buf_queue *hbp; Buf_descr *bdp; Buf_descr *bdp_dma; Q_status *qsp; Q_status *qsp_dma; int i; /* * Initialize Strategy 1 Small Queues */ /* * Point to CP-resident buffer supply queue */ cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1s_q)); /* * Point to host-resident buffer supply queue structures */ hbp = fup->fu_buf1s_q; qsp = fup->fu_buf1s_stat; qsp_dma = fup->fu_buf1s_statd; bdp = fup->fu_buf1s_desc; bdp_dma = fup->fu_buf1s_descd; /* * Loop thru all queue entries and do whatever needs doing */ for (i = 0; i < BUF1_SM_QUELEN; i++) { /* * Set queue status word to free */ *qsp = QSTAT_FREE; /* * Set up host queue entry and link into ring */ hbp->hbq_cpelem = cqp; hbp->hbq_status = qsp; hbp->hbq_descr = bdp; hbp->hbq_descr_dma = bdp_dma; if (i == (BUF1_SM_QUELEN - 1)) hbp->hbq_next = fup->fu_buf1s_q; else hbp->hbq_next = hbp + 1; /* * Now let the CP into the game */ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); /* * Bump all queue pointers */ hbp++; qsp++; qsp_dma++; bdp += BUF1_SM_ENTSIZE; bdp_dma += BUF1_SM_ENTSIZE; cqp++; } /* * Initialize queue pointers */ fup->fu_buf1s_head = fup->fu_buf1s_tail = fup->fu_buf1s_q; /* * Initialize Strategy 1 Large Queues */ /* * Point to CP-resident buffer supply queue */ cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1l_q)); /* * Point to host-resident buffer supply queue structures */ hbp = fup->fu_buf1l_q; qsp = fup->fu_buf1l_stat; qsp_dma = fup->fu_buf1l_statd; bdp = fup->fu_buf1l_desc; bdp_dma = fup->fu_buf1l_descd; /* * Loop thru all queue entries and do whatever needs doing */ for (i = 0; i < BUF1_LG_QUELEN; i++) { /* * Set queue status word to free */ *qsp = QSTAT_FREE; /* * Set up host queue entry and link into ring */ hbp->hbq_cpelem = cqp; hbp->hbq_status = qsp; hbp->hbq_descr = bdp; hbp->hbq_descr_dma = bdp_dma; if (i == (BUF1_LG_QUELEN - 1)) hbp->hbq_next = fup->fu_buf1l_q; else hbp->hbq_next = hbp + 1; /* * Now let the CP into the game */ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); /* * Bump all queue pointers */ hbp++; qsp++; qsp_dma++; bdp += BUF1_LG_ENTSIZE; bdp_dma += BUF1_LG_ENTSIZE; cqp++; } /* * Initialize queue pointers */ fup->fu_buf1l_head = fup->fu_buf1l_tail = fup->fu_buf1l_q; return; }
/* * Begin CP Initialization * * This function will poll for the successful downloading and starting of * the CP microcode program. After the microcode is running, we will allocate * any needed kernel memory (must do it in non-interrupt mode), build the CP * queue configurations and issue an Initialize command to the CP. * * Arguments: * fup pointer to device unit structure * * Returns: * none */ void fore_initialize(void *xfup) { Fore_unit *fup = xfup; Aali *aap; Init_parms *inp; caddr_t errmsg; u_long vers; /* * Must wait until firmware has been downloaded and is running */ if (CP_READ(fup->fu_mon->mon_bstat) != BOOT_RUNNING) { /* * Try again later */ callout_reset(&fup->fu_init_timer, hz, fore_initialize, fup); return; } /* * Allocate queues and whatever else is needed */ if (fore_xmit_allocate(fup)) { errmsg = "transmit queue allocation"; goto failed; } if (fore_recv_allocate(fup)) { errmsg = "receive queue allocation"; goto failed; } if (fore_buf_allocate(fup)) { errmsg = "buffer supply queue allocation"; goto failed; } if (fore_cmd_allocate(fup)) { errmsg = "command queue allocation"; goto failed; } /* * CP microcode is downloaded - locate shared memory interface */ aap = (Aali *)(fup->fu_ram + CP_READ(fup->fu_mon->mon_appl)); fup->fu_aali = aap; /* * Pick out any interesting info from the microcode */ vers = CP_READ(aap->aali_ucode_ver); if (vers < FORE_MIN_UCODE) { errmsg = "unsupported microcode version"; goto failed; } ksnprintf(fup->fu_config.ac_firm_vers, sizeof(fup->fu_config.ac_firm_vers), "%ld.%ld.%ld", (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff); #ifdef notdef /* * Turn on CP debugging */ aap->aali_hostlog = 1; #endif /* * Build the initialization block */ inp = &aap->aali_init; inp->init_numvcc = CP_WRITE(FORE_MAX_VCC); inp->init_cmd_elem = CP_WRITE(CMD_QUELEN); inp->init_xmit_elem = CP_WRITE(XMIT_QUELEN); inp->init_recv_elem = CP_WRITE(RECV_QUELEN); inp->init_recv_ext = CP_WRITE(RECV_EXTRA_SEGS); inp->init_xmit_ext = CP_WRITE(XMIT_EXTRA_SEGS); inp->init_buf1s.bfs_quelen = CP_WRITE(BUF1_SM_QUELEN); inp->init_buf1s.bfs_bufsize = CP_WRITE(BUF1_SM_SIZE); inp->init_buf1s.bfs_cppool = CP_WRITE(BUF1_SM_CPPOOL); inp->init_buf1s.bfs_entsize = CP_WRITE(BUF1_SM_ENTSIZE); inp->init_buf1l.bfs_quelen = CP_WRITE(BUF1_LG_QUELEN); inp->init_buf1l.bfs_bufsize = CP_WRITE(BUF1_LG_SIZE); inp->init_buf1l.bfs_cppool = CP_WRITE(BUF1_LG_CPPOOL); inp->init_buf1l.bfs_entsize = CP_WRITE(BUF1_LG_ENTSIZE); inp->init_buf2s.bfs_quelen = CP_WRITE(0); inp->init_buf2s.bfs_bufsize = CP_WRITE(0); inp->init_buf2s.bfs_cppool = CP_WRITE(0); inp->init_buf2s.bfs_entsize = CP_WRITE(0); inp->init_buf2l.bfs_quelen = CP_WRITE(0); inp->init_buf2l.bfs_bufsize = CP_WRITE(0); inp->init_buf2l.bfs_cppool = CP_WRITE(0); inp->init_buf2l.bfs_entsize = CP_WRITE(0); /* * Enable device interrupts */ aap->aali_intr_ena = CP_WRITE(1); /* * Issue the Initialize command to the CP and wait for * the CP to interrupt to signal completion */ inp->init_status = CP_WRITE(QSTAT_PENDING); inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ); return; failed: /* * Initialization failure */ fore_interface_free(fup); log(LOG_ERR, "fore initialization failed: intf=%s%d, err=%s\n", fup->fu_pif.pif_name, fup->fu_pif.pif_unit, errmsg); return; }
/* * Get device statistics from CP * * This function will issue a GET_STATS command to the CP in order to * initiate the DMA transfer of the CP's statistics structure to the host. * We will then sleep pending command completion. This must only be called * from the ioctl system call handler. * * Called from a critical section. * * Arguments: * fup pointer to device unit structure * * Returns: * 0 stats retrieval successful * errno stats retrieval failed - reason indicated * */ int fore_get_stats(Fore_unit *fup) { H_cmd_queue *hcp; Cmd_queue *cqp; int sst; ATM_DEBUG1("fore_get_stats: fup=%p\n", fup); /* * Make sure device has been initialized */ if ((fup->fu_flags & CUF_INITED) == 0) { return (EIO); } /* * If someone has already initiated a stats request, we'll * just wait for that one to complete */ crit_enter(); if (fup->fu_flags & FUF_STATCMD) { sst = tsleep((caddr_t)&fup->fu_stats, PCATCH, "fore", 0); crit_exit(); return (sst ? sst : fup->fu_stats_ret); } /* * Limit stats gathering to once a second or so */ if (time_second == fup->fu_stats_time) { crit_exit(); return (0); } else fup->fu_stats_time = time_second; /* * Queue command at end of command queue */ hcp = fup->fu_cmd_tail; if ((*hcp->hcq_status) & QSTAT_FREE) { void *dma; /* * Queue entry available, so set our view of things up */ hcp->hcq_code = CMD_GET_STATS; hcp->hcq_arg = NULL; fup->fu_cmd_tail = hcp->hcq_next; /* * Now set the CP-resident queue entry - the CP will grab * the command when the op-code is set. */ cqp = hcp->hcq_cpelem; (*hcp->hcq_status) = QSTAT_PENDING; dma = DMA_GET_ADDR(fup->fu_stats, sizeof(Fore_cp_stats), FORE_STATS_ALIGN, 0); if (dma == NULL) { fup->fu_stats->st_drv.drv_cm_nodma++; crit_exit(); return (EIO); } fup->fu_statsd = dma; cqp->cmdq_stats.stats_buffer = (CP_dma) CP_WRITE(dma); fup->fu_flags |= FUF_STATCMD; cqp->cmdq_stats.stats_cmd = CP_WRITE(CMD_GET_STATS | CMD_INTR_REQ); /* * Now wait for command to finish */ sst = tsleep((caddr_t)&fup->fu_stats, PCATCH, "fore", 0); crit_exit(); return (sst ? sst : fup->fu_stats_ret); } else { /* * Command queue full */ fup->fu_stats->st_drv.drv_cm_full++; crit_exit(); return (EIO); } }