Shouldn't we use pci_alloc_consistent (or indirectly via pci_pool_alloc) instead of kmalloc?
-ch > -----Original Message----- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED]] On > Behalf Of Roland Dreier > Sent: Friday, June 07, 2002 4:57 PM > To: [EMAIL PROTECTED]; > [EMAIL PROTECTED] > Subject: [linux-usb-devel] USB on PPC440GP (cache incoherent) > Importance: High > > > I just got USB working on my PPC440GP (IBM Ebony eval board). > I'm using an Opti 82C861 OHCI controller, and so far I've > tried an Alcor SD card reader (mass storage) and a Belkin > usbnet device. My kernel is 2.4.19-pre10 from the > bk://ppc.bkbits.net/linuxppc_2_4_devel > BitKeeper tree. > > I had to make some changes to the USB driver to get this > working as there are still some places where structures on > the stack are being used for DMA. This causes problems on > processors like the 440GP, which are not cache coherent (you > can only invalidate a whole cache line, which can corrupt the > stack). I just changed all of these places to use kmalloc to > get memory instead. > > Note that this might not work perfectly on all > cache-incoherent processors, since kmalloc could potentially > allocate a chunk of memory that is smaller than the > processor's cache line size. However it is safe on the 440GP > since the 440GP's cache line size is 32 bytes. > > I've included a patch with my changes in this email. I'm > sending it to the linuxppc-embedded list in case someone else > is trying to do USB on a 440 or 405 or similar processor. > I'm also sending it to linux-usb-devel in the hope that these > changes make it into the mainline kernel. > > Best, > Roland > > # This is a BitKeeper generated patch for the following > project: # Project Name: Linux 2.4 for PowerPC development > tree # This patch format is intended for GNU patch command > version 2.5 or higher. # This patch includes the following deltas: > # ChangeSet 1.1077 -> 1.1078 > # drivers/usb/usb.c 1.19 -> 1.20 > # drivers/usb/hub.c 1.14 -> 1.15 > # drivers/usb/hub.h 1.7 -> 1.8 > # drivers/usb/storage/transport.c 1.10 -> 1.11 > # > # The following is the BitKeeper ChangeSet Log > # -------------------------------------------- > # 02/06/07 [EMAIL PROTECTED] 1.1078 > # Fix problems in USB when running on cache-incoherent cpus > like PPC440GP # (Don't do DMAs into memory allocated on > stack) # -------------------------------------------- > # > diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c > --- a/drivers/usb/hub.c Fri Jun 7 16:35:31 2002 > +++ b/drivers/usb/hub.c Fri Jun 7 16:35:31 2002 > @@ -155,7 +155,7 @@ > static int usb_hub_configure(struct usb_hub *hub, struct > usb_endpoint_descriptor *endpoint) { > struct usb_device *dev = hub->dev; > - struct usb_hub_status hubstatus; > + struct usb_hub_status *hubstatus; > char portstr[USB_MAXCHILDREN + 1]; > unsigned int pipe; > int i, maxp, ret; > @@ -258,27 +258,36 @@ > > dbg("port removable status: %s", portstr); > > - ret = usb_get_hub_status(dev, &hubstatus); > + hubstatus = kmalloc(sizeof *hubstatus, GFP_KERNEL); > + if (!hubstatus) { > + err("Unable to allocate hubstatus"); > + kfree(hub->descriptor); > + return -1; > + } > + ret = usb_get_hub_status(dev, hubstatus); > if (ret < 0) { > err("Unable to get hub status (err = %d)", ret); > + kfree(hubstatus); > kfree(hub->descriptor); > return -1; > } > > - le16_to_cpus(&hubstatus.wHubStatus); > + le16_to_cpus(&hubstatus->wHubStatus); > > dbg("local power source is %s", > - (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) > ? "lost (inactive)" : "good"); > + (hubstatus->wHubStatus & > HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" > +: "good"); > > dbg("%sover-current condition exists", > - (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) > ? "" : "no "); > + (hubstatus->wHubStatus & > HUB_STATUS_OVERCURRENT) ? "" : "no "); > + > + kfree(hubstatus); > > /* Start the interrupt endpoint */ > pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); > maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); > > - if (maxp > sizeof(hub->buffer)) > - maxp = sizeof(hub->buffer); > + if (maxp > USB_HUB_BUFFER_SIZE) > + maxp = USB_HUB_BUFFER_SIZE; > > hub->urb = usb_alloc_urb(0); > if (!hub->urb) { > @@ -357,6 +366,13 @@ > > memset(hub, 0, sizeof(*hub)); > > + hub->buffer = kmalloc(USB_HUB_BUFFER_SIZE, GFP_KERNEL); > + if (!hub->buffer) { > + err("couldn't kmalloc hub->buffer"); > + kfree(hub); > + return NULL; > + } > + > INIT_LIST_HEAD(&hub->event_list); > hub->dev = dev; > init_MUTEX(&hub->khubd_sem); > @@ -383,6 +399,7 @@ > > spin_unlock_irqrestore(&hub_event_lock, flags); > > + kfree(hub->buffer); > kfree(hub); > > return NULL; > @@ -417,6 +434,11 @@ > hub->descriptor = NULL; > } > > + if (hub->buffer) { > + kfree(hub->buffer); > + hub->buffer = NULL; > + } > + > /* Free the memory */ > kfree(hub); > } > @@ -782,7 +804,7 @@ > struct list_head *tmp; > struct usb_device *dev; > struct usb_hub *hub; > - struct usb_hub_status hubsts; > + struct usb_hub_status *hubsts; > u16 hubstatus; > u16 hubchange; > u16 portstatus; > @@ -872,22 +894,28 @@ > } /* end for i */ > > /* deal with hub status changes */ > - if (usb_get_hub_status(dev, &hubsts) < 0) > - err("get_hub_status failed"); > - else { > - hubstatus = le16_to_cpup(&hubsts.wHubStatus); > - hubchange = le16_to_cpup(&hubsts.wHubChange); > - if (hubchange & HUB_CHANGE_LOCAL_POWER) { > - dbg("hub power change"); > - usb_clear_hub_feature(dev, > C_HUB_LOCAL_POWER); > - } > - if (hubchange & HUB_CHANGE_OVERCURRENT) { > - dbg("hub overcurrent change"); > - wait_ms(500); /* Cool down */ > - usb_clear_hub_feature(dev, > C_HUB_OVER_CURRENT); > - usb_hub_power_on(hub); > - } > + hubsts = kmalloc(sizeof *hubsts, GFP_KERNEL); > + if (!hubsts) { > + err("couldn't allocate hubsts"); > + } else { > + if (usb_get_hub_status(dev, hubsts) < 0) > + err("get_hub_status failed"); > + else { > + hubstatus = > le16_to_cpup(&hubsts->wHubStatus); > + hubchange = > le16_to_cpup(&hubsts->wHubChange); > + if (hubchange & > HUB_CHANGE_LOCAL_POWER) { > + dbg("hub power change"); > + > usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); > + } > + if (hubchange & > HUB_CHANGE_OVERCURRENT) { > + dbg("hub overcurrent > change"); > + wait_ms(500); > /* Cool down */ > + > usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); > + usb_hub_power_on(hub); > + } > + } > } > + kfree(hubsts); > up(&hub->khubd_sem); > } /* end while (1) */ > > @@ -995,7 +1023,7 @@ > int usb_reset_device(struct usb_device *dev) > { > struct usb_device *parent = dev->parent; > - struct usb_device_descriptor descriptor; > + struct usb_device_descriptor *descriptor; > int i, ret, port = -1; > > if (!parent) { > @@ -1044,17 +1072,19 @@ > * If nothing changed, we reprogram the configuration and then > * the alternate settings. > */ > - ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor, > - sizeof(descriptor)); > + descriptor = kmalloc(sizeof *descriptor, GFP_KERNEL); > + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, > + sizeof *descriptor); > if (ret < 0) > return ret; > > - le16_to_cpus(&descriptor.bcdUSB); > - le16_to_cpus(&descriptor.idVendor); > - le16_to_cpus(&descriptor.idProduct); > - le16_to_cpus(&descriptor.bcdDevice); > + le16_to_cpus(&descriptor->bcdUSB); > + le16_to_cpus(&descriptor->idVendor); > + le16_to_cpus(&descriptor->idProduct); > + le16_to_cpus(&descriptor->bcdDevice); > > - if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) { > + if (memcmp(&dev->descriptor, descriptor, sizeof *descriptor)) { > + kfree(descriptor); > usb_destroy_configuration(dev); > > ret = usb_get_device_descriptor(dev); > @@ -1083,6 +1113,7 @@ > > return 1; > } > + kfree(descriptor); > > ret = usb_set_configuration(dev, > dev->actconfig->bConfigurationValue); > if (ret < 0) { > diff -Nru a/drivers/usb/hub.h b/drivers/usb/hub.h > --- a/drivers/usb/hub.h Fri Jun 7 16:35:31 2002 > +++ b/drivers/usb/hub.h Fri Jun 7 16:35:31 2002 > @@ -120,13 +120,15 @@ > > struct usb_device; > > +/* add 1 bit for hub status change and add 7 bits to round > up to byte > +boundary */ #define USB_HUB_BUFFER_SIZE ((USB_MAXCHILDREN + > 1 + 7) / 8) > + > struct usb_hub { > struct usb_device *dev; > > struct urb *urb; /* Interrupt polling pipe */ > > - char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 > bit for hub status change */ > - /* and add 7 bits to > round up to byte boundary */ > + char *buffer; > int error; > int nerrors; > > diff -Nru a/drivers/usb/storage/transport.c > b/drivers/usb/storage/transport.c > --- a/drivers/usb/storage/transport.c Fri Jun 7 16:35:31 2002 > +++ b/drivers/usb/storage/transport.c Fri Jun 7 16:35:31 2002 > @@ -723,7 +723,7 @@ > > /* use the new buffer we have */ > old_request_buffer = srb->request_buffer; > - srb->request_buffer = srb->sense_buffer; > + srb->request_buffer = kmalloc(18, > in_interrupt() ? GFP_ATOMIC : > +GFP_KERNEL); > > /* set the buffer length for transfer */ > old_request_bufflen = srb->request_bufflen; > @@ -733,8 +733,14 @@ > old_sg = srb->use_sg; > srb->use_sg = 0; > > - /* issue the auto-sense command */ > - temp_result = us->transport(us->srb, us); > + if (srb->request_buffer) { > + /* issue the auto-sense command */ > + temp_result = us->transport(us->srb, us); > + memcpy(srb->sense_buffer, > srb->request_buffer, 18); > + kfree(srb->request_buffer); > + } else { > + temp_result = USB_STOR_TRANSPORT_ERROR; > + } > > /* let's clean up right away */ > srb->request_buffer = old_request_buffer; > @@ -1041,9 +1047,12 @@ > int usb_stor_Bulk_max_lun(struct us_data *us) > { > unsigned char data; > + unsigned char *buffer; > int result; > int pipe; > > + buffer = kmalloc(sizeof data, GFP_KERNEL); > + > /* issue the command -- use usb_control_msg() because > * the state machine is not yet alive */ > pipe = usb_rcvctrlpipe(us->pusb_dev, 0); > @@ -1051,7 +1060,9 @@ > US_BULK_GET_MAX_LUN, > USB_DIR_IN | USB_TYPE_CLASS | > USB_RECIP_INTERFACE, > - 0, us->ifnum, &data, sizeof(data), HZ); > + 0, us->ifnum, buffer, > sizeof(data), HZ); > + data = *buffer; > + kfree(buffer); > > US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", > result, data); > @@ -1077,41 +1088,54 @@ > > int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { > - struct bulk_cb_wrap bcb; > - struct bulk_cs_wrap bcs; > + struct bulk_cb_wrap *bcb; > + struct bulk_cs_wrap *bcs; > int result; > int pipe; > int partial; > + int ret = USB_STOR_TRANSPORT_ERROR; > + > + bcb = kmalloc(sizeof *bcb, in_interrupt() ? > GFP_ATOMIC : GFP_KERNEL); > + if (!bcb) { > + return USB_STOR_TRANSPORT_ERROR; > + } > + bcs = kmalloc(sizeof *bcs, in_interrupt() ? > GFP_ATOMIC : GFP_KERNEL); > + if (!bcs) { > + kfree(bcb); > + return USB_STOR_TRANSPORT_ERROR; > + } > > /* set up the command wrapper */ > - bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); > - bcb.DataTransferLength = > cpu_to_le32(usb_stor_transfer_length(srb)); > - bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? > 1 << 7 : 0; > - bcb.Tag = srb->serial_number; > - bcb.Lun = srb->cmnd[1] >> 5; > + bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); > + bcb->DataTransferLength = > cpu_to_le32(usb_stor_transfer_length(srb)); > + bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? > 1 << 7 : 0; > + bcb->Tag = srb->serial_number; > + bcb->Lun = srb->cmnd[1] >> 5; > if (us->flags & US_FL_SCM_MULT_TARG) > - bcb.Lun |= srb->target << 4; > - bcb.Length = srb->cmd_len; > + bcb->Lun |= srb->target << 4; > + bcb->Length = srb->cmd_len; > > /* construct the pipe handle */ > pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); > > /* copy the command payload */ > - memset(bcb.CDB, 0, sizeof(bcb.CDB)); > - memcpy(bcb.CDB, srb->cmnd, bcb.Length); > + memset(bcb->CDB, 0, sizeof(bcb->CDB)); > + memcpy(bcb->CDB, srb->cmnd, bcb->Length); > > /* send it to out endpoint */ > US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L > %d F %d CL %d\n", > - le32_to_cpu(bcb.Signature), bcb.Tag, > - (bcb.Lun >> 4), (bcb.Lun & 0x0F), > - bcb.DataTransferLength, bcb.Flags, bcb.Length); > - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, > + le32_to_cpu(bcb->Signature), bcb->Tag, > + (bcb->Lun >> 4), (bcb->Lun & 0x0F), > + bcb->DataTransferLength, bcb->Flags, bcb->Length); > + result = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, > &partial); > US_DEBUGP("Bulk command transfer result=%d\n", result); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > > /* if we stall, we need to clear it before we go on */ > if (result == -EPIPE) { > @@ -1119,25 +1143,30 @@ > result = usb_stor_clear_halt(us, pipe); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > result = -EPIPE; > } else if (result) { > /* unknown error -- we've got a problem */ > - return USB_STOR_TRANSPORT_ERROR; > + ret = USB_STOR_TRANSPORT_ERROR; > + goto out; > } > > /* if the command transfered well, then we go to the > data stage */ > if (result == 0) { > /* send/receive data payload, if there is any */ > - if (bcb.DataTransferLength) { > + if (bcb->DataTransferLength) { > usb_stor_transfer(srb, us); > result = srb->result; > US_DEBUGP("Bulk data transfer result > 0x%x\n", result); > > /* if it was aborted, we need to > indicate that */ > - if (result == US_BULK_TRANSFER_ABORTED) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == US_BULK_TRANSFER_ABORTED) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > } > } > > @@ -1150,12 +1179,14 @@ > > /* get CSW for device status */ > US_DEBUGP("Attempting to get CSW...\n"); > - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, > + result = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, > &partial); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > > /* did the attempt to read the CSW fail? */ > if (result == -EPIPE) { > @@ -1163,17 +1194,21 @@ > result = usb_stor_clear_halt(us, pipe); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > > /* get the status again */ > US_DEBUGP("Attempting to get CSW (2nd try)...\n"); > - result = usb_stor_bulk_msg(us, &bcs, pipe, > + result = usb_stor_bulk_msg(us, bcs, pipe, > US_BULK_CS_WRAP_LEN, > &partial); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > > /* if it fails again, we need a reset and > return an error*/ > if (result == -EPIPE) { > @@ -1181,48 +1216,60 @@ > result = usb_stor_clear_halt(us, pipe); > > /* if the command was aborted, indicate that */ > - if (result == -ENOENT) > - return USB_STOR_TRANSPORT_ABORTED; > - return USB_STOR_TRANSPORT_ERROR; > + if (result == -ENOENT) { > + ret = USB_STOR_TRANSPORT_ABORTED; > + goto out; > + } > + ret = USB_STOR_TRANSPORT_ERROR; > + goto out; > } > } > > /* if we still have a failure at this point, we're in trouble */ > US_DEBUGP("Bulk status result = %d\n", result); > if (result) { > - return USB_STOR_TRANSPORT_ERROR; > + ret = USB_STOR_TRANSPORT_ERROR; > + goto out; > } > > /* check bulk status */ > US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", > - le32_to_cpu(bcs.Signature), bcs.Tag, > - bcs.Residue, bcs.Status); > - if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || > - bcs.Tag != bcb.Tag || > - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { > + le32_to_cpu(bcs->Signature), bcs->Tag, > + bcs->Residue, bcs->Status); > + if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) || > + bcs->Tag != bcb->Tag || > + bcs->Status > US_BULK_STAT_PHASE || partial != 13) { > US_DEBUGP("Bulk logical error\n"); > - return USB_STOR_TRANSPORT_ERROR; > + ret = USB_STOR_TRANSPORT_ERROR; > + goto out; > } > > /* based on the status code, we report good or bad */ > - switch (bcs.Status) { > + switch (bcs->Status) { > case US_BULK_STAT_OK: > /* command good -- note that data could > be short */ > - return USB_STOR_TRANSPORT_GOOD; > + ret = USB_STOR_TRANSPORT_GOOD; > + goto out; > > case US_BULK_STAT_FAIL: > /* command failed */ > - return USB_STOR_TRANSPORT_FAILED; > + ret = USB_STOR_TRANSPORT_FAILED; > + goto out; > > case US_BULK_STAT_PHASE: > /* phase error -- note that a transport > reset will be > * invoked by the invoke_transport() function > */ > - return USB_STOR_TRANSPORT_ERROR; > + ret = USB_STOR_TRANSPORT_ERROR; > + goto out; > } > > /* we should never get here, but if we do, we're in trouble */ > - return USB_STOR_TRANSPORT_ERROR; > + > + out: > + kfree(bcb); > + kfree(bcs); > + return ret; > } > > > /************************************************************* > ********** > diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c > --- a/drivers/usb/usb.c Fri Jun 7 16:35:31 2002 > +++ b/drivers/usb/usb.c Fri Jun 7 16:35:31 2002 > @@ -1787,16 +1787,23 @@ > { > int i = 5; > int result; > + void *tmp_buf; > > - memset(buf,0,size); // Make sure we parse really > received data > + tmp_buf = kmalloc(size, in_interrupt() ? GFP_ATOMIC > : GFP_KERNEL); > + if (!tmp_buf) { > + return -ENOMEM; > + } > + memset(tmp_buf,0,size); // Make sure we parse really > received data > > while (i--) { > if ((result = usb_control_msg(dev, > usb_rcvctrlpipe(dev, 0), > USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, > - (type << 8) + index, 0, buf, size, HZ * > GET_TIMEOUT)) > 0 || > + (type << 8) + index, 0, tmp_buf, size, > HZ * GET_TIMEOUT)) > 0 || > result == -EPIPE) > break; /* retry if the returned length > was 0; flaky device */ > } > + memcpy(buf, tmp_buf, size); > + kfree(tmp_buf); > return result; > } > > > _______________________________________________________________ > > Don't miss the 2002 Sprint PCS Application Developer's > Conference August 25-28 in Las Vegas - > http://devcon.sprintpcs.com/adp/index.cfm?> source=osdntextlink > > > _______________________________________________ > [EMAIL PROTECTED] > To unsubscribe, use the last form field at: > https://lists.sourceforge.net/lists/listinfo/l> inux-usb-devel > _______________________________________________________________ Don't miss the 2002 Sprint PCS Application Developer's Conference August 25-28 in Las Vegas - http://devcon.sprintpcs.com/adp/index.cfm?source=osdntextlink _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel