/* enable_suspend -- When enabled, the driver will respond to *USBsuspendrequestsbypoweringdowntheNET2280.Otherwise, *USBsuspendrequestswillbeignored.Thisisacceptablefor *self-powereddevices
*/ staticbool enable_suspend;
ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name ||
desc->bDescriptorType != USB_DT_ENDPOINT) {
pr_err("%s: failed at line=%d\n", __func__, __LINE__); return -EINVAL;
}
dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
ret = -ESHUTDOWN; goto print_err;
}
/* erratum 0119 workaround ties up an endpoint number */ if (usb_endpoint_num(desc) == EP_DONTUSE) {
ret = -EDOM; goto print_err;
}
if (dev->quirks & PLX_PCIE) { if (usb_endpoint_num(desc) >= 0x0c) {
ret = -EDOM; goto print_err;
}
ep->is_in = !!usb_endpoint_dir_in(desc); if (dev->enhanced_mode && ep->is_in && ep_key[ep->num]) {
ret = -EINVAL; goto print_err;
}
}
/* sanity check ep-e/ep-f since their fifos are small */
max = usb_endpoint_maxp(desc); if (ep->num > 4 && max > 64 && (dev->quirks & PLX_LEGACY)) {
ret = -ERANGE; goto print_err;
}
/* Make sure all the registers are written before ep_rsp*/
wmb();
/* for OUT transfers, block the rx fifo until a read is posted */ if (!ep->is_in)
writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); elseif (!(dev->quirks & PLX_2280)) { /* Added for 2282, Don't use nak packets on an in endpoint, *thiswasignoredon2280
*/
writel(BIT(CLEAR_NAK_OUT_PACKETS) |
BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
if (dev->quirks & PLX_PCIE)
ep_clear_seqnum(ep);
writel(tmp, &ep->cfg->ep_cfg);
/* load a packet into the fifo we use for usb IN transfers. *worksforallendpoints. * *NOTE:piowithep-a..ep-dcouldstuffmultiplepacketsintothefifo *atatime,butthiscodeissimplerbecauseitknowsitonlywrites *onepacket.ep-a..ep-dshouldusedmainstead.
*/ staticvoid write_fifo(struct net2280_ep *ep, struct usb_request *req)
{ struct net2280_ep_regs __iomem *regs = ep->regs;
u8 *buf;
u32 tmp; unsigned count, total;
/* INVARIANT: fifo is currently empty. (testable) */
if (req) {
buf = req->buf + req->actual;
prefetch(buf);
total = req->length - req->actual;
} else {
total = 0;
buf = NULL;
}
/* write just one packet at a time */
count = ep->ep.maxpacket; if (count > total) /* min() cannot be used on a bitfield */
count = total;
/* last fifo entry is "short" unless we wrote a full packet. *alsoexplicitlyvalidatelastwordin(periodic)transfers *whenmaxpacketisnotamultipleof4bytes.
*/ if (count || total < ep->ep.maxpacket) {
tmp = count ? get_unaligned((u32 *)buf) : count;
cpu_to_le32s(&tmp);
set_fifo_bytecount(ep, count & 0x03);
writel(tmp, ®s->ep_data);
}
/* pci writes may still be posted */
}
/* work around erratum 0106: PCI and USB race over the OUT fifo. *callerguaranteeschiprev0100,outendpointisNAKing,and *there'snorealdatainthefifo. * *NOTE:alsousedincaseswherethaterratumdoesn'tapply: *wherethehostwrote"toomuch"datatous.
*/ staticvoid out_flush(struct net2280_ep *ep)
{
u32 __iomem *statp;
u32 tmp;
/* fill out dma descriptor to match a given request */ staticvoid fill_dma_desc(struct net2280_ep *ep, struct net2280_request *req, int valid)
{ struct net2280_dma *td = req->td;
u32 dmacount = req->req.length;
/* don't let DMA continue after a short OUT packet, *sooverrunscan'taffectthenexttransfer. *incaseofoverrunsonmax-sizepackets,wecan't *stopthefifofromfillingbutwecanflushit.
*/ if (ep->is_in)
dmacount |= BIT(DMA_DIRECTION); if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) ||
!(ep->dev->quirks & PLX_2280))
dmacount |= BIT(END_OF_CHAIN);
/* on this path we "know" there's no dma active (yet) */
WARN_ON(readl(&dma->dmactl) & BIT(DMA_ENABLE));
writel(0, &ep->dma->dmactl);
/* previous OUT packet might have been short */ if (!ep->is_in && (readl(&ep->regs->ep_stat) &
BIT(NAK_OUT_PACKETS))) {
writel(BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT),
&ep->regs->ep_stat);
tmp = readl(&ep->regs->ep_avail); if (tmp) {
writel(readl(&dma->dmastat), &dma->dmastat);
/* transfer all/some fifo data */
writel(req->req.dma, &dma->dmaaddr);
tmp = min(tmp, req->req.length);
if (req->req.status == -EINPROGRESS)
req->req.status = status; else
status = req->req.status;
dev = ep->dev; if (ep->dma)
usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
if (status && status != -ESHUTDOWN)
ep_vdbg(dev, "complete %s req %p stat %d len %u/%u\n",
ep->ep.name, &req->req, status,
req->req.actual, req->req.length);
/* we always require a cpu-view buffer, so that we can *alwaysusepio(asfallbackorwhatever).
*/
ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || (!ep->desc && ep->num != 0)) {
pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); return -EINVAL;
}
req = container_of(_req, struct net2280_request, req); if (!_req || !_req->complete || !_req->buf ||
!list_empty(&req->queue)) {
ret = -EINVAL; goto print_err;
} if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) {
ret = -EDOM; goto print_err;
}
dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
ret = -ESHUTDOWN; goto print_err;
}
/* FIXME implement PIO fallback for ZLPs with DMA */ if (ep->dma && _req->length == 0) {
ret = -EOPNOTSUPP; goto print_err;
}
/* set up dma mapping in case the caller didn't */ if (ep->dma) {
ret = usb_gadget_map_request(&dev->gadget, _req,
ep->is_in); if (ret) goto print_err;
}
/* use DMA if the endpoint supports it, else pio */ if (ep->dma)
start_dma(ep, req); else { /* maybe there's no control data, just status ack */ if (ep->num == 0 && _req->length == 0) {
allow_status(ep);
done(ep, req, 0);
ep_vdbg(dev, "%s status ack\n", ep->ep.name); goto done;
}
/* PIO ... stuff the fifo, or unblock it. */ if (ep->is_in)
write_fifo(ep, _req); else {
u32 s;
/* OUT FIFO might have packet(s) buffered */
s = readl(&ep->regs->ep_stat); if ((s & BIT(FIFO_EMPTY)) == 0) { /* note: _req->short_not_ok is *ignoredheresincePIO_always_ *stopsqueueadvancehere,and *_req->statusdoesn'tchangefor *shortreads(only_req->actual)
*/ if (read_fifo(ep, req) &&
ep->num == 0) {
done(ep, req, 0);
allow_status(ep); /* don't queue it */
req = NULL;
} elseif (read_fifo(ep, req) &&
ep->num != 0) {
done(ep, req, 0);
req = NULL;
} else
s = readl(&ep->regs->ep_stat);
}
/* don't NAK, let the fifo fill */ if (req && (s & BIT(NAK_OUT_PACKETS)))
writel(BIT(CLEAR_NAK_OUT_PACKETS),
&ep->regs->ep_rsp);
}
}
} elseif (ep->dma) { int valid = 1;
if (ep->is_in) { int expect;
/* preventing magic zlps is per-engine state, not *per-transfer;irqlogicmustrecoverhiccups.
*/
expect = likely(req->req.zero ||
(req->req.length % ep->ep.maxpacket)); if (expect != ep->in_fifo_validate)
valid = 0;
}
queue_dma(ep, req, valid);
} /* else the irq handler advances the queue. */
ep->responded = 1; if (req)
list_add_tail(&req->queue, &ep->queue);
done:
spin_unlock_irqrestore(&dev->lock, flags);
staticint scan_dma_completions(struct net2280_ep *ep)
{ int num_completed = 0;
/* only look at descriptors that were "naturally" retired, *sofifoandlistheadstatewon'tmatter
*/ while (!list_empty(&ep->queue)) { struct net2280_request *req;
u32 req_dma_count;
req = list_entry(ep->queue.next, struct net2280_request, queue); if (!req->valid) break;
rmb();
req_dma_count = le32_to_cpup(&req->td->dmacount); if ((req_dma_count & BIT(VALID_BIT)) != 0) break;
if (req)
done(ep, req, -ECONNRESET);
ep->stopped = stopped;
if (ep->dma) { /* turn off dma on inactive queues */ if (list_empty(&ep->queue))
stop_dma(ep->dma); elseif (!ep->stopped) { /* resume current request, or start new one */ if (req)
writel(dmactl, &ep->dma->dmactl); else
start_dma(ep, list_entry(ep->queue.next, struct net2280_request, queue));
}
}
if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */
ep = gadget_find_ep_by_name(_gadget, "ep-e"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
ep = gadget_find_ep_by_name(_gadget, "ep-f"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
}
/* USB3380: Only first four endpoints have DMA channels. Allocate *slowerinterruptendpointsfromPIOhwendpoints,toallowbulk/isoc *endpointsuseDMAhwendpoints.
*/ if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
usb_endpoint_dir_in(desc)) {
ep = gadget_find_ep_by_name(_gadget, "ep2in"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
ep = gadget_find_ep_by_name(_gadget, "ep4in"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
} elseif (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
!usb_endpoint_dir_in(desc)) {
ep = gadget_find_ep_by_name(_gadget, "ep1out"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
ep = gadget_find_ep_by_name(_gadget, "ep3out"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
} elseif (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK &&
usb_endpoint_dir_in(desc)) {
ep = gadget_find_ep_by_name(_gadget, "ep1in"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
ep = gadget_find_ep_by_name(_gadget, "ep3in"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
} elseif (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK &&
!usb_endpoint_dir_in(desc)) {
ep = gadget_find_ep_by_name(_gadget, "ep2out"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
ep = gadget_find_ep_by_name(_gadget, "ep4out"); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
}
/* USB3380: use same address for usb and hardware endpoints */
snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
usb_endpoint_dir_in(desc) ? "in" : "out");
ep = gadget_find_ep_by_name(_gadget, name); if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) return ep;
/* FIXME move these into procfs, and use seq_file. *Sysfs_still_doesn'tbehaveforarbitrarilysizedfiles, *andalsodoesn'thelpproductsusingthiswith2.4kernels.
*/
dev = dev_get_drvdata(_dev);
next = buf;
size = PAGE_SIZE;
spin_lock_irqsave(&dev->lock, flags);
for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep[i]; struct net2280_request *req; int t;
if (i != 0) { conststruct usb_endpoint_descriptor *d;
d = ep->desc; if (!d) continue;
t = d->bEndpointAddress;
t = scnprintf(next, size, "\n%s (ep%d%s-%s) max %04x %s fifo %d\n",
ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
(t & USB_DIR_IN) ? "in" : "out",
type_string(d->bmAttributes),
usb_endpoint_maxp(d),
ep->dma ? "dma" : "pio", ep->fifo_size
);
} else/* ep0 should only have one transfer queued */
t = scnprintf(next, size, "ep0 max 64 pio %s\n",
ep->is_in ? "in" : "out"); if (t <= 0 || t > size) goto done;
size -= t;
next += t;
if (list_empty(&ep->queue)) {
t = scnprintf(next, size, "\t(nothing queued)\n"); if (t <= 0 || t > size) goto done;
size -= t;
next += t; continue;
}
list_for_each_entry(req, &ep->queue, queue) { if (ep->dma && req->td_dma == readl(&ep->dma->dmadesc))
t = scnprintf(next, size, "\treq %p len %d/%d " "buf %p (dmacount %08x)\n",
&req->req, req->req.actual,
req->req.length, req->req.buf,
readl(&ep->dma->dmacount)); else
t = scnprintf(next, size, "\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf); if (t <= 0 || t > size) goto done;
size -= t;
next += t;
/*Implemented for development and debug.
* Can be refined/tuned later.*/ for (ep_sel = 0; ep_sel <= 21; ep_sel++) { /* Select an endpoint for subsequent operations: */
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
writel(((tmp_reg & ~0x1f) | ep_sel),
&dev->plregs->pl_ep_ctrl);
/* Set FSM to focus on the first Control Read: *-Tip:Connectionspeedisknownuponthefirst
* setup request.*/
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
set_idx_reg(dev->regs, SCRATCH, scratch);
/* we want to prevent lowlevel/insecure access from the USB host, *buterratum0119meansthisenablebitisignored
*/ for (tmp = 0; tmp < 5; tmp++)
writel(EP_DONTUSE, &dev->dep[tmp].dep_cfg);
}
/* Link layer set up */ if (dev->bug7734_patched) {
tmp = readl(&dev->usb_ext->usbctl2) &
~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
writel(tmp, &dev->usb_ext->usbctl2);
}
/* Hardware Defect and Workaround */
val = readl(&dev->llregs->ll_lfps_5);
val &= ~(0xf << TIMER_LFPS_6US);
val |= 0x5 << TIMER_LFPS_6US;
writel(val, &dev->llregs->ll_lfps_5);
val = readl(&dev->llregs->ll_lfps_6);
val &= ~(0xffff << TIMER_LFPS_80US);
val |= 0x0100 << TIMER_LFPS_80US;
writel(val, &dev->llregs->ll_lfps_6);
/* *AA_ABErrata.Issue4.WorkaroundforSuperSpeedUSB *HotResetExitHandshakemayFailinSpecificCaseusing *DefaultRegisterSettings.WorkaroundforEnumerationtest.
*/
val = readl(&dev->llregs->ll_tsn_counters_2);
val &= ~(0x1f << HOT_TX_NORESET_TS2);
val |= 0x10 << HOT_TX_NORESET_TS2;
writel(val, &dev->llregs->ll_tsn_counters_2);
val = readl(&dev->llregs->ll_tsn_counters_3);
val &= ~(0x1f << HOT_RX_RESET_TS2);
val |= 0x3 << HOT_RX_RESET_TS2;
writel(val, &dev->llregs->ll_tsn_counters_3);
/* enable irqs so we can see ep0 and general operation */
writel(BIT(SETUP_PACKET_INTERRUPT_ENABLE) |
BIT(ENDPOINT_0_INTERRUPT_ENABLE),
&dev->regs->pciirqenb0);
writel(BIT(PCI_INTERRUPT_ENABLE) |
BIT(PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) |
BIT(PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) |
BIT(PCI_RETRY_ABORT_INTERRUPT_ENABLE) |
BIT(VBUS_INTERRUPT_ENABLE) |
BIT(ROOT_PORT_RESET_INTERRUPT_ENABLE) |
BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE),
&dev->regs->pciirqenb1);
/* don't leave any writes posted */
(void) readl(&dev->usb->usbctl);
}
staticvoid ep0_start_338x(struct net2280 *dev)
{
if (dev->bug7734_patched)
writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
BIT(SET_EP_HIDE_STATUS_PHASE),
&dev->epregs[0].ep_rsp);
/* enable irqs so we can see ep0 and general operation */
writel(BIT(SETUP_PACKET_INTERRUPT_ENABLE) |
BIT(ENDPOINT_0_INTERRUPT_ENABLE),
&dev->regs->pciirqenb0);
writel(BIT(PCI_INTERRUPT_ENABLE) |
BIT(ROOT_PORT_RESET_INTERRUPT_ENABLE) |
BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) |
BIT(VBUS_INTERRUPT_ENABLE),
&dev->regs->pciirqenb1);
/* don't leave any writes posted */
(void)readl(&dev->usb->usbctl);
}
/* when a driver is successfully registered, it will receive *controlrequestsincludingset_configuration(),whichenables *non-controlrequests.thenusbtrafficfollowsuntila *disconnectisreported.thenahostmayconnectagain,or *thedrivermightgetunbound.
*/ staticint net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver)
{ struct net2280 *dev; int retval; unsigned i;
/* insist on high speed support from the driver, since *(dev->usb->xcvrdiag&FORCE_FULL_SPEED_MODE) *"mustnotbeusedinnormaloperation"
*/ if (!driver || driver->max_speed < USB_SPEED_HIGH ||
!driver->setup) return -EINVAL;
dev = container_of(_gadget, struct net2280, gadget);
for (i = 0; i < dev->n_ep; i++)
dev->ep[i].irqs = 0;
/* hook up the driver ... */
dev->driver = driver;
retval = device_create_file(&dev->pdev->dev, &dev_attr_function); if (retval) goto err_unbind;
retval = device_create_file(&dev->pdev->dev, &dev_attr_queues); if (retval) goto err_func;
/* enable host detection and ep0; and we're ready *forset_configurationaswellaseventualdisconnect.
*/
net2280_led_active(dev, 1);
if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
defect7374_enable_data_eps_zero(dev);
staticvoid stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
{ int i;
/* don't disconnect if it's not connected */ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
driver = NULL;
/* stop hardware; prevent new request submissions; *andkillanyoutstandingrequests.
*/
usb_reset(dev); for (i = 0; i < dev->n_ep; i++)
nuke(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */ if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
if (!ep->is_in || (ep->dev->quirks & PLX_2280))
writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat); else /* Added for 2282 */
writel(t, &ep->regs->ep_stat);
/* for ep0, monitor token irqs to catch data stage length errors *andtosynchronizeonstatus. * *also,todeferreportingofprotocolstalls...here'swhere *dataorstatusfirstappears,handlingstallshereshouldnever *causetroubleonthehostside.. * *controlrequestscouldbeslightlyfasterwithouttokensynchfor *status,butstatuscanjamupthatway.
*/ if (unlikely(ep->num == 0)) { if (ep->is_in) { /* status; stop NAKing */ if (t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) {
ep->stopped = 1;
set_halt(ep);
} if (!req)
allow_status(ep);
mode = 2; /* reply to extra IN data tokens with a zlp */
} elseif (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) {
ep->stopped = 1;
set_halt(ep);
mode = 2;
} elseif (ep->responded &&
!req && !ep->stopped)
write_fifo(ep, NULL);
}
} else { /* status; stop NAKing */ if (t & BIT(DATA_IN_TOKEN_INTERRUPT)) { if (ep->dev->protocol_stall) {
ep->stopped = 1;
set_halt(ep);
}
mode = 2; /* an extra OUT token is an error */
} elseif (((t & BIT(DATA_OUT_PING_TOKEN_INTERRUPT)) &&
req &&
req->req.actual == req->req.length) ||
(ep->responded && !req)) {
ep->dev->protocol_stall = 1;
set_halt(ep);
ep->stopped = 1; if (req)
done(ep, req, -EOVERFLOW);
req = NULL;
}
}
}
if (unlikely(!req)) return;
/* manual DMA queue advance after short OUT */ if (likely(ep->dma)) { if (t & BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)) { struct net2280_request *stuck_req = NULL; int stopped = ep->stopped; int num_completed; int stuck = 0;
u32 count;
/* TRANSFERRED works around OUT_DONE erratum 0112. *weexpect(N<=maxpacket)bytes;hostwroteM. *iff(M<N)wewon'teverseeaDMAinterrupt.
*/
ep->stopped = 1; for (count = 0; ; t = readl(&ep->regs->ep_stat)) {
/* any preceding dma transfers must finish. *dmahandles(M>=N),mayemptythequeue
*/
num_completed = scan_dma_completions(ep); if (unlikely(list_empty(&ep->queue) ||
ep->out_overflow)) {
req = NULL; break;
}
req = list_entry(ep->queue.next, struct net2280_request, queue);
/* here either (M < N), a "real" short rx; *or(M==N)andthequeuedidn'tempty
*/ if (likely(t & BIT(FIFO_EMPTY))) {
count = readl(&ep->dma->dmacount);
count &= DMA_BYTE_COUNT_MASK; if (readl(&ep->dma->dmadesc)
!= req->td_dma)
req = NULL; break;
}
/* data packet(s) received (in the fifo, OUT) */
} elseif (t & BIT(DATA_PACKET_RECEIVED_INTERRUPT)) { if (read_fifo(ep, req) && ep->num != 0)
mode = 2;
len = req->req.length - req->req.actual; if (len > ep->ep.maxpacket)
len = ep->ep.maxpacket;
req->req.actual += len;
/* if we wrote it all, we're usually done */ /* send zlps until the status stage */ if ((req->req.actual == req->req.length) &&
(!req->req.zero || len != ep->ep.maxpacket) && ep->num)
mode = 2;
/* there was nothing to do ... */
} elseif (mode == 1) return;
/* done */ if (mode == 2) { /* stream endpoints often resubmit/unlink in completion */
done(ep, req, 0);
/* maybe advance queue to next request */ if (ep->num == 0) { /* NOTE: net2280 could let gadget driver start the *statusstagelater.sincenotallcontrollerslet *themcontrolthat,theapidoesn't(yet)allowit.
*/ if (!ep->stopped)
allow_status(ep);
req = NULL;
} else { if (!list_empty(&ep->queue) && !ep->stopped)
req = list_entry(ep->queue.next, struct net2280_request, queue); else
req = NULL; if (req && !ep->is_in)
stop_out_naking(ep);
}
}
/* is there a buffer for the next packet? *forbeststreamingperformance,makesurethereisone.
*/ if (req && !ep->stopped) {
/* load IN fifo with next packet (may be zlp) */ if (t & BIT(DATA_PACKET_TRANSMITTED_INTERRUPT))
write_fifo(ep, &req->req);
}
}
if (!((fsmvalue == DEFECT7374_FSM_WAITING_FOR_CONTROL_READ) &&
(r.bRequestType & USB_DIR_IN))) return;
/* This is the first Control Read for this connection: */ if (!(readl(&dev->usb->usbstat) & BIT(SUPER_SPEED_MODE))) { /* *ConnectionisNOTSS: *-ConnectionmustbeFSorHS. *-ThisFSMstateshouldallowworkaroundsoftwareto *runafterthenextUSBconnection.
*/
scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
dev->bug7734_patched = 1; goto restore_data_eps;
}
/* Connection is SS: */ for (ack_wait_timeout = 0;
ack_wait_timeout < DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS;
ack_wait_timeout++) {
val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
val |= ep_pl[ep->num];
writel(val, &dev->plregs->pl_ep_ctrl);
val |= BIT(SEQUENCE_NUMBER_RESET);
writel(val, &dev->plregs->pl_ep_ctrl);
/* most of these don't need individual acks */
stat &= ~BIT(INTA_ASSERTED); if (!stat) return; /* ep_dbg(dev, "irqstat0 %04x\n", stat); */
/* starting a control request? */ if (unlikely(stat & BIT(SETUP_PACKET_INTERRUPT))) { union {
u32 raw[2]; struct usb_ctrlrequest r;
} u; int tmp; struct net2280_request *req;
if (disconnect || reset) {
stop_activity(dev, dev->driver);
ep0_start(dev); if (dev->async_callbacks) {
spin_unlock(&dev->lock); if (reset)
usb_gadget_udc_reset(&dev->gadget, dev->driver); else
(dev->driver->disconnect)(&dev->gadget);
spin_lock(&dev->lock);
} return;
}
}
stat &= ~tmp;
/* vBUS can bounce ... one of many reasons to ignore the *notionofhotplugeventsonbusconnect/disconnect!
*/ if (!stat) return;
}
/* NOTE: chip stays in PCI D0 state for now, but it could *enterD1tosavemorepower
*/
tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT); if (stat & tmp) {
writel(tmp, &dev->regs->irqstat1);
spin_unlock(&dev->lock); if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget); if (!enable_suspend)
stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT);
} else { if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget); /* at high speed, note erratum 0133 */
}
spin_lock(&dev->lock);
stat &= ~tmp;
}
/* clear any other status/irqs */ if (stat)
writel(stat, &dev->regs->irqstat1);
/* some status we can just ignore */ if (dev->quirks & PLX_2280)
stat &= ~(BIT(CONTROL_STATUS_INTERRUPT) |
BIT(SUSPEND_REQUEST_INTERRUPT) |
BIT(RESUME_INTERRUPT) |
BIT(SOF_INTERRUPT)); else
stat &= ~(BIT(CONTROL_STATUS_INTERRUPT) |
BIT(RESUME_INTERRUPT) |
BIT(SOF_DOWN_INTERRUPT) |
BIT(SOF_INTERRUPT));
if (!stat) return; /* ep_dbg(dev, "irqstat1 %08x\n", stat);*/
/* DMA status, for ep-{a,b,c,d} */
scratch = stat & DMA_INTERRUPTS;
stat &= ~DMA_INTERRUPTS;
scratch >>= 9; for (num = 0; scratch; num++) { struct net2280_dma_regs __iomem *dma;
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
ep_dbg(ep->dev, "%s no xact done? %08x\n",
ep->ep.name, tmp); continue;
}
stop_dma(ep->dma);
/* OUT transfers terminate when the data from the *hostisinourmemory.Processwhatever'sdone. *Onthispath,weknowtransfer'slastpacketwasn't *lessthanreq->length.NAK_OUT_PACKETSmaybeset, *ortheFIFOmayalreadybeholdingnewpackets. * *INtransferscanlingerintheFIFOforavery *longtime...weignorethatfornow,accounting *precisely(likePIOdoes)needsper-packetirqs
*/
scan_dma_completions(ep);
/* disable dma on inactive queues; else maybe restart */ if (!list_empty(&ep->queue)) {
tmp = readl(&dma->dmactl);
restart_dma(ep);
}
ep->irqs++;
}
/* NOTE: there are other PCI errors we might usefully notice. *iftheyappearveryoften,here'swheretotryrecovering.
*/ if (stat & PCI_ERROR_INTERRUPTS) {
ep_err(dev, "pci dma error; stat %08x\n", stat);
stat &= ~PCI_ERROR_INTERRUPTS; /* these are fatal errors, but "maybe" they won't *happenagain...
*/
stop_activity(dev, dev->driver);
ep0_start(dev);
stat = 0;
}
if (stat)
ep_dbg(dev, "unhandled irqstat1 %08x\n", stat);
}
/* then clean up the resources we allocated during probe() */ if (dev->requests) { int i; for (i = 1; i < 5; i++) { if (!dev->ep[i].dummy) continue;
dma_pool_free(dev->requests, dev->ep[i].dummy,
dev->ep[i].td_dma);
}
dma_pool_destroy(dev->requests);
} if (dev->got_irq)
free_irq(pdev->irq, dev); if (dev->quirks & PLX_PCIE)
pci_disable_msi(pdev); if (dev->regs) {
net2280_led_shutdown(dev);
iounmap(dev->regs);
} if (dev->region)
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0)); if (dev->enabled)
pci_disable_device(pdev);
device_remove_file(&pdev->dev, &dev_attr_registers);
/* DMA setup */ /* NOTE: we know only the 32 LSBs of dma addresses may be nonzero */
dev->requests = dma_pool_create("requests", &pdev->dev, sizeof(struct net2280_dma), 0/* no alignment requirements */, 0/* or page-crossing issues */); if (!dev->requests) {
ep_dbg(dev, "can't get request pool\n");
retval = -ENOMEM; goto done;
} for (i = 1; i < 5; i++) { struct net2280_dma *td;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.78Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.