17e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/*
27e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Wireless Host Controller (WHC) periodic schedule management.
37e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
47e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
57e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
67e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * This program is free software; you can redistribute it and/or
77e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * modify it under the terms of the GNU General Public License version
87e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * 2 as published by the Free Software Foundation.
97e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
107e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * This program is distributed in the hope that it will be useful,
117e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * but WITHOUT ANY WARRANTY; without even the implied warranty of
127e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * GNU General Public License for more details.
147e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
157e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * You should have received a copy of the GNU General Public License
167e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * along with this program.  If not, see <http://www.gnu.org/licenses/>.
177e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
187e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include <linux/kernel.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
207e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include <linux/dma-mapping.h>
217e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include <linux/uwb/umc.h>
227e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include <linux/usb.h>
237e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
247e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include "../../wusbcore/wusbhc.h"
257e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
267e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel#include "whcd.h"
277e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
287e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic void update_pzl_pointers(struct whc *whc, int period, u64 addr)
297e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
307e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	switch (period) {
317e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	case 0:
327e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[0], addr);
337e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[2], addr);
347e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[4], addr);
357e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[6], addr);
367e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[8], addr);
377e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[10], addr);
387e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[12], addr);
397e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[14], addr);
407e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		break;
417e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	case 1:
427e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[1], addr);
437e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[5], addr);
447e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[9], addr);
457e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[13], addr);
467e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		break;
477e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	case 2:
487e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[3], addr);
497e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[11], addr);
507e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		break;
517e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	case 3:
527e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[7], addr);
537e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		break;
547e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	case 4:
557e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc_qset_set_link_ptr(&whc->pz_list[15], addr);
567e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		break;
577e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
587e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
597e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
607e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/*
617e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Return the 'period' to use for this qset.  The minimum interval for
627e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * the endpoint is used so whatever urbs are submitted the device is
637e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * polled often enough.
647e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
657e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic int qset_get_period(struct whc *whc, struct whc_qset *qset)
667e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
677e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	uint8_t bInterval = qset->ep->desc.bInterval;
687e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
697e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (bInterval < 6)
707e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		bInterval = 6;
717e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (bInterval > 10)
727e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		bInterval = 10;
737e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	return bInterval - 6;
747e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
757e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
767e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
777e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
787e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int period;
797e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
807e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	period = qset_get_period(whc, qset);
817e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
827e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset_clear(whc, qset);
837e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	list_move(&qset->list_node, &whc->periodic_list[period]);
847e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset->in_sw_list = true;
857e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
867e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
877e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
887e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
897e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	list_move(&qset->list_node, &whc->periodic_removed_list);
907e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset->in_hw_list = false;
917e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset->in_sw_list = false;
927e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
937e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
947e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
957e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_process_qset - process any recently inactivated or halted qTDs
967e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * in a qset.
977e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
987e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * After inactive qTDs are removed, new qTDs can be added if the
997e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * urb queue still contains URBs.
1007e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
1017e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Returns the schedule updates required.
1027e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
1037e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
1047e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
1057e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	enum whc_update update = 0;
1067e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	uint32_t status = 0;
1077e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1087e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	while (qset->ntds) {
1097e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		struct whc_qtd *td;
1107e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		int t;
1117e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1127e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		t = qset->td_start;
1137e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		td = &qset->qtd[qset->td_start];
1147e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		status = le32_to_cpu(td->status);
1157e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1167e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		/*
1177e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		 * Nothing to do with a still active qTD.
1187e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		 */
1197e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		if (status & QTD_STS_ACTIVE)
1207e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			break;
1217e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1227e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		if (status & QTD_STS_HALTED) {
1237e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			/* Ug, an error. */
1247e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			process_halted_qtd(whc, qset, td);
1251f01ca4e0c1d4126eb663f8ea0bab03836099770David Vrabel			/* A halted qTD always triggers an update
1261f01ca4e0c1d4126eb663f8ea0bab03836099770David Vrabel			   because the qset was either removed or
1271f01ca4e0c1d4126eb663f8ea0bab03836099770David Vrabel			   reactivated. */
1281f01ca4e0c1d4126eb663f8ea0bab03836099770David Vrabel			update |= WHC_UPDATE_UPDATED;
1297e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			goto done;
1307e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		}
1317e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1327e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		/* Mmm, a completed qTD. */
1337e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		process_inactive_qtd(whc, qset, td);
1347e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
1357e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1367f0406db5fe4dd3ad3cbd53830239a87d68156fdDavid Vrabel	if (!qset->remove)
1377f0406db5fe4dd3ad3cbd53830239a87d68156fdDavid Vrabel		update |= qset_add_qtds(whc, qset);
1387e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1397e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabeldone:
1407e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	/*
1417e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	 * If there are no qTDs in this qset, remove it from the PZL.
1427e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	 */
1437e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (qset->remove && qset->ntds == 0) {
1447e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		pzl_qset_remove(whc, qset);
1457e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		update |= WHC_UPDATE_REMOVED;
1467e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
1477e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1487e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	return update;
1497e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
1507e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1517e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
1527e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_start - start the periodic schedule
1537e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
1547e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
1557e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * The PZL must be valid (e.g., all entries in the list should have
1567e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * the T bit set).
1577e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
1587e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid pzl_start(struct whc *whc)
1597e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
1607e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
1617e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1627e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
1637e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
1647e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		      WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
1657e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		      1000, "start PZL");
1667e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
1677e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
1687e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
1697e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_stop - stop the periodic schedule
1707e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
1717e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
1727e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid pzl_stop(struct whc *whc)
1737e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
1747e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
1757e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
1767e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		      WUSBSTS_PERIODIC_SCHED, 0,
1777e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		      1000, "stop PZL");
1787e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
1797e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
18056968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel/**
18156968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * pzl_update - request a PZL update and wait for the hardware to be synced
18256968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * @whc: the WHCI HC
18356968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * @wusbcmd: WUSBCMD value to start the update.
18456968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel *
18556968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
18656968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * update must be skipped as the hardware may not respond to update
18756968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel * requests.
18856968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel */
1897e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid pzl_update(struct whc *whc, uint32_t wusbcmd)
1907e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
19156968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel	struct wusbhc *wusbhc = &whc->wusbhc;
192a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel	long t;
19356968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel
19456968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel	mutex_lock(&wusbhc->mutex);
19556968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel	if (wusbhc->active) {
19656968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel		whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
197a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel		t = wait_event_timeout(
198a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel			whc->periodic_list_wq,
199a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel			(le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
200a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel			msecs_to_jiffies(1000));
201a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel		if (t == 0)
202a5e6ced58d423cb09c4fc0087dcfdb0b5deb5e1cDavid Vrabel			whc_hw_error(whc, "PZL update timeout");
20356968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel	}
20456968d0c1a920eb165c06318f5c458724e1df0afDavid Vrabel	mutex_unlock(&wusbhc->mutex);
2057e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
2067e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2077e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelstatic void update_pzl_hw_view(struct whc *whc)
2087e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
2097e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_qset *qset, *t;
2107e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int period;
2117e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	u64 tmp_qh = 0;
2127e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2137e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	for (period = 0; period < 5; period++) {
2147e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
2157e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
2167e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			tmp_qh = qset->qset_dma;
2177e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			qset->in_hw_list = true;
2187e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		}
2197e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		update_pzl_pointers(whc, period, tmp_qh);
2207e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
2217e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
2227e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2237e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
2247e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * scan_periodic_work - scan the PZL for qsets to process.
2257e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
2267e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Process each qset in the PZL in turn and then signal the WHC that
2277e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * the PZL has been updated.
2287e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
2297e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Then start, stop or update the periodic schedule as required.
2307e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
2317e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid scan_periodic_work(struct work_struct *work)
2327e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
2337e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc *whc = container_of(work, struct whc, periodic_work);
2347e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_qset *qset, *t;
2357e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	enum whc_update update = 0;
2367e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int period;
2377e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2387e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_lock_irq(&whc->lock);
2397e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2407e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	for (period = 4; period >= 0; period--) {
2417e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
2427e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			if (!qset->in_hw_list)
2437e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel				update |= WHC_UPDATE_ADDED;
2447e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			update |= pzl_process_qset(whc, qset);
2457e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		}
2467e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
2477e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2487e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
2497e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		update_pzl_hw_view(whc);
2507e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2517e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_unlock_irq(&whc->lock);
2527e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2537e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (update) {
2547e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
2557e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		if (update & WHC_UPDATE_REMOVED)
2567e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
2577e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		pzl_update(whc, wusbcmd);
2587e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
2597e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2607e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	/*
2617e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	 * Now that the PZL is updated, complete the removal of any
2627e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	 * removed qsets.
263831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel	 *
264831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel	 * If the qset was to be reset, do so and reinsert it into the
265831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel	 * PZL if it has pending transfers.
2667e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	 */
267a3c1239eb59c0a907f8be5587d42e950f44543f8David Vrabel	spin_lock_irq(&whc->lock);
2687e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2697e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
2707e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		qset_remove_complete(whc, qset);
271831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel		if (qset->reset) {
272831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel			qset_reset(whc, qset);
273831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel			if (!list_empty(&qset->stds)) {
274831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel				qset_insert_in_sw_list(whc, qset);
275831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel				queue_work(whc->workqueue, &whc->periodic_work);
276831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel			}
277831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel		}
2787e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
2797e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
280a3c1239eb59c0a907f8be5587d42e950f44543f8David Vrabel	spin_unlock_irq(&whc->lock);
2817e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
2827e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2837e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
2847e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
2857e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
2867e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @urb: the URB to enqueue
2877e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @mem_flags: flags for any memory allocations
2887e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
2897e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * The qset for the endpoint is obtained and the urb queued on to it.
2907e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
2917e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * Work is scheduled to update the hardware's view of the PZL.
2927e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
2937e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelint pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
2947e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
2957e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_qset *qset;
2967e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int err;
2977e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	unsigned long flags;
2987e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
2997e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_lock_irqsave(&whc->lock, flags);
3007e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
301f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel	err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
302f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel	if (err < 0) {
303f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel		spin_unlock_irqrestore(&whc->lock, flags);
304f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel		return err;
305f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel	}
306f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel
3077e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset = get_qset(whc, urb, GFP_ATOMIC);
3087e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (qset == NULL)
3097e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		err = -ENOMEM;
3107e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	else
3117e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
3127e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (!err) {
313831baa4915de465357b25c471bbb9b36472024dfDavid Vrabel		if (!qset->in_sw_list && !qset->remove)
3147e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			qset_insert_in_sw_list(whc, qset);
315f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel	} else
316f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel		usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
3177e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3187e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_unlock_irqrestore(&whc->lock, flags);
3197e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3207e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (!err)
3217e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		queue_work(whc->workqueue, &whc->periodic_work);
3227e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
323f720af91ec2c67e9a1abbd935570f4b4e1f0dd54David Vrabel	return err;
3247e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
3257e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3267e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
3277e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_urb_dequeue - remove an URB (qset) from the periodic list
3287e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
3297e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @urb: the URB to dequeue
3307e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @status: the current status of the URB
3317e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
3327e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * URBs that do yet have qTDs can simply be removed from the software
3337e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * queue, otherwise the qset must be removed so the qTDs can be safely
3347e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * removed.
3357e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
3367e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelint pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
3377e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
3387e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_urb *wurb = urb->hcpriv;
3397e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_qset *qset = wurb->qset;
3407e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	struct whc_std *std, *t;
341171b37ee95865c052a88d52a05895c3c584f4871David Vrabel	bool has_qtd = false;
3427e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int ret;
3437e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	unsigned long flags;
3447e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3457e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_lock_irqsave(&whc->lock, flags);
3467e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3477e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
3487e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (ret < 0)
3497e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		goto out;
3507e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3517e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	list_for_each_entry_safe(std, t, &qset->stds, list_node) {
352171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		if (std->urb == urb) {
353171b37ee95865c052a88d52a05895c3c584f4871David Vrabel			if (std->qtd)
354171b37ee95865c052a88d52a05895c3c584f4871David Vrabel				has_qtd = true;
3557e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			qset_free_std(whc, std);
356171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		} else
3577e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel			std->qtd = NULL; /* so this std is re-added when the qset is */
3587e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	}
3597e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
360171b37ee95865c052a88d52a05895c3c584f4871David Vrabel	if (has_qtd) {
361171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		pzl_qset_remove(whc, qset);
362171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		update_pzl_hw_view(whc);
363171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		wurb->status = status;
364171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		wurb->is_async = false;
365171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		queue_work(whc->workqueue, &wurb->dequeue_work);
366171b37ee95865c052a88d52a05895c3c584f4871David Vrabel	} else
367171b37ee95865c052a88d52a05895c3c584f4871David Vrabel		qset_remove_urb(whc, qset, urb, status);
3687e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelout:
3697e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	spin_unlock_irqrestore(&whc->lock, flags);
3707e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3717e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	return ret;
3727e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
3737e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3747e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
3757e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_qset_delete - delete a qset from the PZL
3767e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
3777e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
3787e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
3797e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset->remove = 1;
3807e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	queue_work(whc->workqueue, &whc->periodic_work);
3817e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	qset_delete(whc, qset);
3827e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
3837e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3847e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
3857e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_init - initialize the periodic zone list
3867e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
3877e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
3887e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelint pzl_init(struct whc *whc)
3897e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
3907e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	int i;
3917e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3927e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
3937e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel					  &whc->pz_list_dma, GFP_KERNEL);
3947e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (whc->pz_list == NULL)
3957e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		return -ENOMEM;
3967e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
3977e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	/* Set T bit on all elements in PZL. */
3987e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	for (i = 0; i < 16; i++)
3997e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
4007e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
4017e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
4027e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
4037e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	return 0;
4047e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
4057e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel
4067e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel/**
4077e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * pzl_clean_up - free PZL resources
4087e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * @whc: the WHCI host controller
4097e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel *
4107e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel * The PZL is stopped and empty.
4117e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel */
4127e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabelvoid pzl_clean_up(struct whc *whc)
4137e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel{
4147e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel	if (whc->pz_list)
4157e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel		dma_free_coherent(&whc->umc->dev,  sizeof(u64) * 16, whc->pz_list,
4167e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel				  whc->pz_list_dma);
4177e6133aa42920ea87ad9791a0fb2b95d1a23b8f9David Vrabel}
418