LCOV - code coverage report
Current view: top level - drivers/usb/host - ohci-dbg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 2 100.0 %
Date: 2017-01-25 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  * OHCI HCD (Host Controller Driver) for USB.
       3             :  *
       4             :  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
       5             :  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
       6             :  *
       7             :  * This file is licenced under the GPL.
       8             :  */
       9             : 
      10             : /*-------------------------------------------------------------------------*/
      11             : 
      12             : #ifdef DEBUG
      13             : 
      14             : #define edstring(ed_type) ({ char *temp; \
      15             :         switch (ed_type) { \
      16             :         case PIPE_CONTROL:      temp = "ctrl"; break; \
      17             :         case PIPE_BULK:         temp = "bulk"; break; \
      18             :         case PIPE_INTERRUPT:    temp = "intr"; break; \
      19             :         default:                temp = "isoc"; break; \
      20             :         }; temp;})
      21             : #define pipestring(pipe) edstring(usb_pipetype(pipe))
      22             : 
      23             : /* debug| print the main components of an URB
      24             :  * small: 0) header + data packets 1) just header
      25             :  */
      26             : static void __maybe_unused
      27             : urb_print(struct urb * urb, char * str, int small, int status)
      28             : {
      29             :         unsigned int pipe= urb->pipe;
      30             : 
      31             :         if (!urb->dev || !urb->dev->bus) {
      32             :                 dbg("%s URB: no dev", str);
      33             :                 return;
      34             :         }
      35             : 
      36             : #ifndef OHCI_VERBOSE_DEBUG
      37             :         if (status != 0)
      38             : #endif
      39             :         dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
      40             :                     str,
      41             :                     urb,
      42             :                     usb_pipedevice (pipe),
      43             :                     usb_pipeendpoint (pipe),
      44             :                     usb_pipeout (pipe)? "out" : "in",
      45             :                     pipestring (pipe),
      46             :                     urb->transfer_flags,
      47             :                     urb->actual_length,
      48             :                     urb->transfer_buffer_length,
      49             :                     status);
      50             : 
      51             : #ifdef  OHCI_VERBOSE_DEBUG
      52             :         if (!small) {
      53             :                 int i, len;
      54             : 
      55             :                 if (usb_pipecontrol (pipe)) {
      56             :                         printk (KERN_DEBUG __FILE__ ": setup(8):");
      57             :                         for (i = 0; i < 8 ; i++)
      58             :                                 printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
      59             :                         printk ("\n");
      60             :                 }
      61             :                 if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
      62             :                         printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
      63             :                                 urb->actual_length,
      64             :                                 urb->transfer_buffer_length);
      65             :                         len = usb_pipeout (pipe)?
      66             :                                                 urb->transfer_buffer_length: urb->actual_length;
      67             :                         for (i = 0; i < 16 && i < len; i++)
      68             :                                 printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
      69             :                         printk ("%s stat:%d\n", i < len? "...": "", status);
      70             :                 }
      71             :         }
      72             : #endif
      73             : }
      74             : 
      75             : #define ohci_dbg_sw(ohci, next, size, format, arg...) \
      76             :         do { \
      77             :         if (next != NULL) { \
      78             :                 unsigned s_len; \
      79             :                 s_len = scnprintf (*next, *size, format, ## arg ); \
      80             :                 *size -= s_len; *next += s_len; \
      81             :         } else \
      82             :                 ohci_dbg(ohci,format, ## arg ); \
      83             :         } while (0);
      84             : 
      85             : 
      86             : static void ohci_dump_intr_mask (
      87             :         struct ohci_hcd *ohci,
      88             :         char *label,
      89             :         u32 mask,
      90             :         char **next,
      91             :         unsigned *size)
      92             : {
      93             :         ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",
      94             :                 label,
      95             :                 mask,
      96             :                 (mask & OHCI_INTR_MIE) ? " MIE" : "",
      97             :                 (mask & OHCI_INTR_OC) ? " OC" : "",
      98             :                 (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
      99             :                 (mask & OHCI_INTR_FNO) ? " FNO" : "",
     100             :                 (mask & OHCI_INTR_UE) ? " UE" : "",
     101             :                 (mask & OHCI_INTR_RD) ? " RD" : "",
     102             :                 (mask & OHCI_INTR_SF) ? " SF" : "",
     103             :                 (mask & OHCI_INTR_WDH) ? " WDH" : "",
     104             :                 (mask & OHCI_INTR_SO) ? " SO" : ""
     105             :                 );
     106             : }
     107             : 
     108             : static void maybe_print_eds (
     109             :         struct ohci_hcd *ohci,
     110             :         char *label,
     111             :         u32 value,
     112             :         char **next,
     113             :         unsigned *size)
     114             : {
     115             :         if (value)
     116             :                 ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);
     117             : }
     118             : 
     119             : static char *hcfs2string (int state)
     120             : {
     121             :         switch (state) {
     122             :                 case OHCI_USB_RESET:    return "reset";
     123             :                 case OHCI_USB_RESUME:   return "resume";
     124             :                 case OHCI_USB_OPER:     return "operational";
     125             :                 case OHCI_USB_SUSPEND:  return "suspend";
     126             :         }
     127             :         return "?";
     128             : }
     129             : 
     130             : // dump control and status registers
     131             : static void
     132             : ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
     133             : {
     134             :         struct ohci_regs __iomem *regs = controller->regs;
     135             :         u32                     temp;
     136             : 
     137             :         temp = ohci_readl (controller, &regs->revision) & 0xff;
     138             :         ohci_dbg_sw (controller, next, size,
     139             :                 "OHCI %d.%d, %s legacy support registers\n",
     140             :                 0x03 & (temp >> 4), (temp & 0x0f),
     141             :                 (temp & 0x0100) ? "with" : "NO");
     142             : 
     143             :         temp = ohci_readl (controller, &regs->control);
     144             :         ohci_dbg_sw (controller, next, size,
     145             :                 "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
     146             :                 temp,
     147             :                 (temp & OHCI_CTRL_RWE) ? " RWE" : "",
     148             :                 (temp & OHCI_CTRL_RWC) ? " RWC" : "",
     149             :                 (temp & OHCI_CTRL_IR) ? " IR" : "",
     150             :                 hcfs2string (temp & OHCI_CTRL_HCFS),
     151             :                 (temp & OHCI_CTRL_BLE) ? " BLE" : "",
     152             :                 (temp & OHCI_CTRL_CLE) ? " CLE" : "",
     153             :                 (temp & OHCI_CTRL_IE) ? " IE" : "",
     154             :                 (temp & OHCI_CTRL_PLE) ? " PLE" : "",
     155             :                 temp & OHCI_CTRL_CBSR
     156             :                 );
     157             : 
     158             :         temp = ohci_readl (controller, &regs->cmdstatus);
     159             :         ohci_dbg_sw (controller, next, size,
     160             :                 "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,
     161             :                 (temp & OHCI_SOC) >> 16,
     162             :                 (temp & OHCI_OCR) ? " OCR" : "",
     163             :                 (temp & OHCI_BLF) ? " BLF" : "",
     164             :                 (temp & OHCI_CLF) ? " CLF" : "",
     165             :                 (temp & OHCI_HCR) ? " HCR" : ""
     166             :                 );
     167             : 
     168             :         ohci_dump_intr_mask (controller, "intrstatus",
     169             :                         ohci_readl (controller, &regs->intrstatus),
     170             :                         next, size);
     171             :         ohci_dump_intr_mask (controller, "intrenable",
     172             :                         ohci_readl (controller, &regs->intrenable),
     173             :                         next, size);
     174             :         // intrdisable always same as intrenable
     175             : 
     176             :         maybe_print_eds (controller, "ed_periodcurrent",
     177             :                         ohci_readl (controller, &regs->ed_periodcurrent),
     178             :                         next, size);
     179             : 
     180             :         maybe_print_eds (controller, "ed_controlhead",
     181             :                         ohci_readl (controller, &regs->ed_controlhead),
     182             :                         next, size);
     183             :         maybe_print_eds (controller, "ed_controlcurrent",
     184             :                         ohci_readl (controller, &regs->ed_controlcurrent),
     185             :                         next, size);
     186             : 
     187             :         maybe_print_eds (controller, "ed_bulkhead",
     188             :                         ohci_readl (controller, &regs->ed_bulkhead),
     189             :                         next, size);
     190             :         maybe_print_eds (controller, "ed_bulkcurrent",
     191             :                         ohci_readl (controller, &regs->ed_bulkcurrent),
     192             :                         next, size);
     193             : 
     194             :         maybe_print_eds (controller, "donehead",
     195             :                         ohci_readl (controller, &regs->donehead), next, size);
     196             : }
     197             : 
     198             : #define dbg_port_sw(hc,num,value,next,size) \
     199             :         ohci_dbg_sw (hc, next, size, \
     200             :                 "roothub.portstatus [%d] " \
     201             :                 "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
     202             :                 num, temp, \
     203             :                 (temp & RH_PS_PRSC) ? " PRSC" : "", \
     204             :                 (temp & RH_PS_OCIC) ? " OCIC" : "", \
     205             :                 (temp & RH_PS_PSSC) ? " PSSC" : "", \
     206             :                 (temp & RH_PS_PESC) ? " PESC" : "", \
     207             :                 (temp & RH_PS_CSC) ? " CSC" : "", \
     208             :                 \
     209             :                 (temp & RH_PS_LSDA) ? " LSDA" : "", \
     210             :                 (temp & RH_PS_PPS) ? " PPS" : "", \
     211             :                 (temp & RH_PS_PRS) ? " PRS" : "", \
     212             :                 (temp & RH_PS_POCI) ? " POCI" : "", \
     213             :                 (temp & RH_PS_PSS) ? " PSS" : "", \
     214             :                 \
     215             :                 (temp & RH_PS_PES) ? " PES" : "", \
     216             :                 (temp & RH_PS_CCS) ? " CCS" : "" \
     217             :                 );
     218             : 
     219             : 
     220             : static void
     221             : ohci_dump_roothub (
     222             :         struct ohci_hcd *controller,
     223             :         int verbose,
     224             :         char **next,
     225             :         unsigned *size)
     226             : {
     227             :         u32                     temp, i;
     228             : 
     229             :         temp = roothub_a (controller);
     230             :         if (temp == ~(u32)0)
     231             :                 return;
     232             : 
     233             :         if (verbose) {
     234             :                 ohci_dbg_sw (controller, next, size,
     235             :                         "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
     236             :                         ((temp & RH_A_POTPGT) >> 24) & 0xff,
     237             :                         (temp & RH_A_NOCP) ? " NOCP" : "",
     238             :                         (temp & RH_A_OCPM) ? " OCPM" : "",
     239             :                         (temp & RH_A_DT) ? " DT" : "",
     240             :                         (temp & RH_A_NPS) ? " NPS" : "",
     241             :                         (temp & RH_A_PSM) ? " PSM" : "",
     242             :                         (temp & RH_A_NDP), controller->num_ports
     243             :                         );
     244             :                 temp = roothub_b (controller);
     245             :                 ohci_dbg_sw (controller, next, size,
     246             :                         "roothub.b %08x PPCM=%04x DR=%04x\n",
     247             :                         temp,
     248             :                         (temp & RH_B_PPCM) >> 16,
     249             :                         (temp & RH_B_DR)
     250             :                         );
     251             :                 temp = roothub_status (controller);
     252             :                 ohci_dbg_sw (controller, next, size,
     253             :                         "roothub.status %08x%s%s%s%s%s%s\n",
     254             :                         temp,
     255             :                         (temp & RH_HS_CRWE) ? " CRWE" : "",
     256             :                         (temp & RH_HS_OCIC) ? " OCIC" : "",
     257             :                         (temp & RH_HS_LPSC) ? " LPSC" : "",
     258             :                         (temp & RH_HS_DRWE) ? " DRWE" : "",
     259             :                         (temp & RH_HS_OCI) ? " OCI" : "",
     260             :                         (temp & RH_HS_LPS) ? " LPS" : ""
     261             :                         );
     262             :         }
     263             : 
     264             :         for (i = 0; i < controller->num_ports; i++) {
     265             :                 temp = roothub_portstatus (controller, i);
     266             :                 dbg_port_sw (controller, i, temp, next, size);
     267             :         }
     268             : }
     269             : 
     270             : static void ohci_dump (struct ohci_hcd *controller, int verbose)
     271             : {
     272             :         ohci_dbg (controller, "OHCI controller state\n");
     273             : 
     274             :         // dumps some of the state we know about
     275             :         ohci_dump_status (controller, NULL, NULL);
     276             :         if (controller->hcca)
     277             :                 ohci_dbg (controller,
     278             :                         "hcca frame #%04x\n", ohci_frame_no(controller));
     279             :         ohci_dump_roothub (controller, 1, NULL, NULL);
     280             : }
     281             : 
     282             : static const char data0 [] = "DATA0";
     283             : static const char data1 [] = "DATA1";
     284             : 
     285             : static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
     286             :                 const struct td *td)
     287             : {
     288             :         u32     tmp = hc32_to_cpup (ohci, &td->hwINFO);
     289             : 
     290             :         ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x\n",
     291             :                 label, td,
     292             :                 (tmp & TD_DONE) ? " (DONE)" : "",
     293             :                 td->urb, td->index,
     294             :                 hc32_to_cpup (ohci, &td->hwNextTD));
     295             :         if ((tmp & TD_ISO) == 0) {
     296             :                 const char      *toggle, *pid;
     297             :                 u32     cbp, be;
     298             : 
     299             :                 switch (tmp & TD_T) {
     300             :                 case TD_T_DATA0: toggle = data0; break;
     301             :                 case TD_T_DATA1: toggle = data1; break;
     302             :                 case TD_T_TOGGLE: toggle = "(CARRY)"; break;
     303             :                 default: toggle = "(?)"; break;
     304             :                 }
     305             :                 switch (tmp & TD_DP) {
     306             :                 case TD_DP_SETUP: pid = "SETUP"; break;
     307             :                 case TD_DP_IN: pid = "IN"; break;
     308             :                 case TD_DP_OUT: pid = "OUT"; break;
     309             :                 default: pid = "(bad pid)"; break;
     310             :                 }
     311             :                 ohci_dbg (ohci, "     info %08x CC=%x %s DI=%d %s %s\n", tmp,
     312             :                         TD_CC_GET(tmp), /* EC, */ toggle,
     313             :                         (tmp & TD_DI) >> 21, pid,
     314             :                         (tmp & TD_R) ? "R" : "");
     315             :                 cbp = hc32_to_cpup (ohci, &td->hwCBP);
     316             :                 be = hc32_to_cpup (ohci, &td->hwBE);
     317             :                 ohci_dbg (ohci, "     cbp %08x be %08x (len %d)\n", cbp, be,
     318             :                         cbp ? (be + 1 - cbp) : 0);
     319             :         } else {
     320             :                 unsigned        i;
     321             :                 ohci_dbg (ohci, "  info %08x CC=%x FC=%d DI=%d SF=%04x\n", tmp,
     322             :                         TD_CC_GET(tmp),
     323             :                         (tmp >> 24) & 0x07,
     324             :                         (tmp & TD_DI) >> 21,
     325             :                         tmp & 0x0000ffff);
     326             :                 ohci_dbg (ohci, "  bp0 %08x be %08x\n",
     327             :                         hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
     328             :                         hc32_to_cpup (ohci, &td->hwBE));
     329             :                 for (i = 0; i < MAXPSW; i++) {
     330             :                         u16     psw = ohci_hwPSW (ohci, td, i);
     331             :                         int     cc = (psw >> 12) & 0x0f;
     332             :                         ohci_dbg (ohci, "    psw [%d] = %2x, CC=%x %s=%d\n", i,
     333             :                                 psw, cc,
     334             :                                 (cc >= 0x0e) ? "OFFSET" : "SIZE",
     335             :                                 psw & 0x0fff);
     336             :                 }
     337             :         }
     338             : }
     339             : 
     340             : /* caller MUST own hcd spinlock if verbose is set! */
     341             : static void __maybe_unused
     342             : ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
     343             :                 const struct ed *ed, int verbose)
     344             : {
     345             :         u32     tmp = hc32_to_cpu (ohci, ed->hwINFO);
     346             :         char    *type = "";
     347             : 
     348             :         ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n",
     349             :                 label,
     350             :                 ed, ed->state, edstring (ed->type),
     351             :                 hc32_to_cpup (ohci, &ed->hwNextED));
     352             :         switch (tmp & (ED_IN|ED_OUT)) {
     353             :         case ED_OUT: type = "-OUT"; break;
     354             :         case ED_IN: type = "-IN"; break;
     355             :         /* else from TDs ... control */
     356             :         }
     357             :         ohci_dbg (ohci,
     358             :                 "  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp,
     359             :                 0x03ff & (tmp >> 16),
     360             :                 (tmp & ED_DEQUEUE) ? " DQ" : "",
     361             :                 (tmp & ED_ISO) ? " ISO" : "",
     362             :                 (tmp & ED_SKIP) ? " SKIP" : "",
     363             :                 (tmp & ED_LOWSPEED) ? " LOW" : "",
     364             :                 0x000f & (tmp >> 7),
     365             :                 type,
     366             :                 0x007f & tmp);
     367             :         tmp = hc32_to_cpup (ohci, &ed->hwHeadP);
     368             :         ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s\n",
     369             :                 tmp,
     370             :                 (tmp & ED_C) ? data1 : data0,
     371             :                 (tmp & ED_H) ? " HALT" : "",
     372             :                 hc32_to_cpup (ohci, &ed->hwTailP),
     373             :                 verbose ? "" : " (not listing)");
     374             :         if (verbose) {
     375             :                 struct list_head        *tmp;
     376             : 
     377             :                 /* use ed->td_list because HC concurrently modifies
     378             :                  * hwNextTD as it accumulates ed_donelist.
     379             :                  */
     380             :                 list_for_each (tmp, &ed->td_list) {
     381             :                         struct td               *td;
     382             :                         td = list_entry (tmp, struct td, td_list);
     383             :                         ohci_dump_td (ohci, "  ->", td);
     384             :                 }
     385             :         }
     386             : }
     387             : 
     388             : #else
     389             : static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}
     390             : 
     391           7 : #undef OHCI_VERBOSE_DEBUG
     392             : 
     393             : #endif /* DEBUG */
     394             : 
     395             : /*-------------------------------------------------------------------------*/
     396             : 
     397             : #ifdef STUB_DEBUG_FILES
     398             : 
     399             : static inline void create_debug_files (struct ohci_hcd *bus) { }
     400             : static inline void remove_debug_files (struct ohci_hcd *bus) { }
     401           7 : 
     402             : #else
     403             : 
     404             : static int debug_async_open(struct inode *, struct file *);
     405             : static int debug_periodic_open(struct inode *, struct file *);
     406             : static int debug_registers_open(struct inode *, struct file *);
     407             : static int debug_async_open(struct inode *, struct file *);
     408             : static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
     409             : static int debug_close(struct inode *, struct file *);
     410             : 
     411             : static const struct file_operations debug_async_fops = {
     412             :         .owner          = THIS_MODULE,
     413             :         .open           = debug_async_open,
     414             :         .read           = debug_output,
     415             :         .release        = debug_close,
     416             : };
     417             : static const struct file_operations debug_periodic_fops = {
     418             :         .owner          = THIS_MODULE,
     419             :         .open           = debug_periodic_open,
     420             :         .read           = debug_output,
     421             :         .release        = debug_close,
     422             : };
     423             : static const struct file_operations debug_registers_fops = {
     424             :         .owner          = THIS_MODULE,
     425             :         .open           = debug_registers_open,
     426             :         .read           = debug_output,
     427             :         .release        = debug_close,
     428             : };
     429             : 
     430             : static struct dentry *ohci_debug_root;
     431             : 
     432             : struct debug_buffer {
     433             :         ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
     434             :         struct ohci_hcd *ohci;
     435             :         struct mutex mutex;     /* protect filling of buffer */
     436             :         size_t count;           /* number of characters filled into buffer */
     437             :         char *page;
     438             : };
     439             : 
     440             : static ssize_t
     441             : show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
     442             : {
     443             :         unsigned                temp, size = count;
     444             : 
     445             :         if (!ed)
     446             :                 return 0;
     447             : 
     448             :         /* print first --> last */
     449             :         while (ed->ed_prev)
     450             :                 ed = ed->ed_prev;
     451             : 
     452             :         /* dump a snapshot of the bulk or control schedule */
     453             :         while (ed) {
     454             :                 u32             info = hc32_to_cpu (ohci, ed->hwINFO);
     455             :                 u32             headp = hc32_to_cpu (ohci, ed->hwHeadP);
     456             :                 struct list_head *entry;
     457             :                 struct td       *td;
     458             : 
     459             :                 temp = scnprintf (buf, size,
     460             :                         "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
     461             :                         ed,
     462             :                         (info & ED_LOWSPEED) ? 'l' : 'f',
     463             :                         info & 0x7f,
     464             :                         (info >> 7) & 0xf,
     465             :                         (info & ED_IN) ? "in" : "out",
     466             :                         0x03ff & (info >> 16),
     467             :                         info,
     468             :                         (info & ED_SKIP) ? " s" : "",
     469             :                         (headp & ED_H) ? " H" : "",
     470             :                         (headp & ED_C) ? data1 : data0);
     471             :                 size -= temp;
     472             :                 buf += temp;
     473             : 
     474             :                 list_for_each (entry, &ed->td_list) {
     475             :                         u32             cbp, be;
     476             : 
     477             :                         td = list_entry (entry, struct td, td_list);
     478             :                         info = hc32_to_cpup (ohci, &td->hwINFO);
     479             :                         cbp = hc32_to_cpup (ohci, &td->hwCBP);
     480             :                         be = hc32_to_cpup (ohci, &td->hwBE);
     481             :                         temp = scnprintf (buf, size,
     482             :                                         "\n\ttd %p %s %d cc=%x urb %p (%08x)",
     483             :                                         td,
     484             :                                         ({ char *pid;
     485             :                                         switch (info & TD_DP) {
     486             :                                         case TD_DP_SETUP: pid = "setup"; break;
     487             :                                         case TD_DP_IN: pid = "in"; break;
     488             :                                         case TD_DP_OUT: pid = "out"; break;
     489             :                                         default: pid = "(?)"; break;
     490             :                                          } pid;}),
     491             :                                         cbp ? (be + 1 - cbp) : 0,
     492             :                                         TD_CC_GET (info), td->urb, info);
     493             :                         size -= temp;
     494             :                         buf += temp;
     495             :                 }
     496             : 
     497             :                 temp = scnprintf (buf, size, "\n");
     498             :                 size -= temp;
     499             :                 buf += temp;
     500             : 
     501             :                 ed = ed->ed_next;
     502             :         }
     503             :         return count - size;
     504             : }
     505             : 
     506             : static ssize_t fill_async_buffer(struct debug_buffer *buf)
     507             : {
     508             :         struct ohci_hcd         *ohci;
     509             :         size_t                  temp;
     510             :         unsigned long           flags;
     511             : 
     512             :         ohci = buf->ohci;
     513             : 
     514             :         /* display control and bulk lists together, for simplicity */
     515             :         spin_lock_irqsave (&ohci->lock, flags);
     516             :         temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
     517             :         temp += show_list(ohci, buf->page + temp, buf->count - temp,
     518             :                           ohci->ed_bulktail);
     519             :         spin_unlock_irqrestore (&ohci->lock, flags);
     520             : 
     521             :         return temp;
     522             : }
     523             : 
     524             : #define DBG_SCHED_LIMIT 64
     525             : 
     526             : static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
     527             : {
     528             :         struct ohci_hcd         *ohci;
     529             :         struct ed               **seen, *ed;
     530             :         unsigned long           flags;
     531             :         unsigned                temp, size, seen_count;
     532             :         char                    *next;
     533             :         unsigned                i;
     534             : 
     535             :         if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
     536             :                 return 0;
     537             :         seen_count = 0;
     538             : 
     539             :         ohci = buf->ohci;
     540             :         next = buf->page;
     541             :         size = PAGE_SIZE;
     542             : 
     543             :         temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
     544             :         size -= temp;
     545             :         next += temp;
     546             : 
     547             :         /* dump a snapshot of the periodic schedule (and load) */
     548             :         spin_lock_irqsave (&ohci->lock, flags);
     549             :         for (i = 0; i < NUM_INTS; i++) {
     550             :                 if (!(ed = ohci->periodic [i]))
     551             :                         continue;
     552             : 
     553             :                 temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
     554             :                 size -= temp;
     555             :                 next += temp;
     556             : 
     557             :                 do {
     558             :                         temp = scnprintf (next, size, " ed%d/%p",
     559             :                                 ed->interval, ed);
     560             :                         size -= temp;
     561             :                         next += temp;
     562             :                         for (temp = 0; temp < seen_count; temp++) {
     563             :                                 if (seen [temp] == ed)
     564             :                                         break;
     565             :                         }
     566             : 
     567             :                         /* show more info the first time around */
     568             :                         if (temp == seen_count) {
     569             :                                 u32     info = hc32_to_cpu (ohci, ed->hwINFO);
     570             :                                 struct list_head        *entry;
     571             :                                 unsigned                qlen = 0;
     572             : 
     573             :                                 /* qlen measured here in TDs, not urbs */
     574             :                                 list_for_each (entry, &ed->td_list)
     575             :                                         qlen++;
     576             : 
     577             :                                 temp = scnprintf (next, size,
     578             :                                         " (%cs dev%d ep%d%s-%s qlen %u"
     579             :                                         " max %d %08x%s%s)",
     580             :                                         (info & ED_LOWSPEED) ? 'l' : 'f',
     581             :                                         info & 0x7f,
     582             :                                         (info >> 7) & 0xf,
     583             :                                         (info & ED_IN) ? "in" : "out",
     584             :                                         (info & ED_ISO) ? "iso" : "int",
     585             :                                         qlen,
     586             :                                         0x03ff & (info >> 16),
     587             :                                         info,
     588             :                                         (info & ED_SKIP) ? " K" : "",
     589             :                                         (ed->hwHeadP &
     590             :                                                 cpu_to_hc32(ohci, ED_H)) ?
     591             :                                                         " H" : "");
     592             :                                 size -= temp;
     593             :                                 next += temp;
     594             : 
     595             :                                 if (seen_count < DBG_SCHED_LIMIT)
     596             :                                         seen [seen_count++] = ed;
     597             : 
     598             :                                 ed = ed->ed_next;
     599             : 
     600             :                         } else {
     601             :                                 /* we've seen it and what's after */
     602             :                                 temp = 0;
     603             :                                 ed = NULL;
     604             :                         }
     605             : 
     606             :                 } while (ed);
     607             : 
     608             :                 temp = scnprintf (next, size, "\n");
     609             :                 size -= temp;
     610             :                 next += temp;
     611             :         }
     612             :         spin_unlock_irqrestore (&ohci->lock, flags);
     613             :         kfree (seen);
     614             : 
     615             :         return PAGE_SIZE - size;
     616             : }
     617             : #undef DBG_SCHED_LIMIT
     618             : 
     619             : static ssize_t fill_registers_buffer(struct debug_buffer *buf)
     620             : {
     621             :         struct usb_hcd          *hcd;
     622             :         struct ohci_hcd         *ohci;
     623             :         struct ohci_regs __iomem *regs;
     624             :         unsigned long           flags;
     625             :         unsigned                temp, size;
     626             :         char                    *next;
     627             :         u32                     rdata;
     628             : 
     629             :         ohci = buf->ohci;
     630             :         hcd = ohci_to_hcd(ohci);
     631             :         regs = ohci->regs;
     632             :         next = buf->page;
     633             :         size = PAGE_SIZE;
     634             : 
     635             :         spin_lock_irqsave (&ohci->lock, flags);
     636             : 
     637             :         /* dump driver info, then registers in spec order */
     638             : 
     639             :         ohci_dbg_sw (ohci, &next, &size,
     640             :                 "bus %s, device %s\n"
     641             :                 "%s\n"
     642             :                 "%s\n",
     643             :                 hcd->self.controller->bus->name,
     644             :                 dev_name(hcd->self.controller),
     645             :                 hcd->product_desc,
     646             :                 hcd_name);
     647             : 
     648             :         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
     649             :                 size -= scnprintf (next, size,
     650             :                         "SUSPENDED (no register access)\n");
     651             :                 goto done;
     652             :         }
     653             : 
     654             :         ohci_dump_status(ohci, &next, &size);
     655             : 
     656             :         /* hcca */
     657             :         if (ohci->hcca)
     658             :                 ohci_dbg_sw (ohci, &next, &size,
     659             :                         "hcca frame 0x%04x\n", ohci_frame_no(ohci));
     660             : 
     661             :         /* other registers mostly affect frame timings */
     662             :         rdata = ohci_readl (ohci, &regs->fminterval);
     663             :         temp = scnprintf (next, size,
     664             :                         "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
     665             :                         rdata, (rdata >> 31) ? "FIT " : "",
     666             :                         (rdata >> 16) & 0xefff, rdata & 0xffff);
     667             :         size -= temp;
     668             :         next += temp;
     669             : 
     670             :         rdata = ohci_readl (ohci, &regs->fmremaining);
     671             :         temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
     672             :                         rdata, (rdata >> 31) ? "FRT " : "",
     673             :                         rdata & 0x3fff);
     674             :         size -= temp;
     675             :         next += temp;
     676             : 
     677             :         rdata = ohci_readl (ohci, &regs->periodicstart);
     678             :         temp = scnprintf (next, size, "periodicstart 0x%04x\n",
     679             :                         rdata & 0x3fff);
     680             :         size -= temp;
     681             :         next += temp;
     682             : 
     683             :         rdata = ohci_readl (ohci, &regs->lsthresh);
     684             :         temp = scnprintf (next, size, "lsthresh 0x%04x\n",
     685             :                         rdata & 0x3fff);
     686             :         size -= temp;
     687             :         next += temp;
     688             : 
     689             :         temp = scnprintf (next, size, "hub poll timer %s\n",
     690             :                         ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
     691             :         size -= temp;
     692             :         next += temp;
     693             : 
     694             :         /* roothub */
     695             :         ohci_dump_roothub (ohci, 1, &next, &size);
     696             : 
     697             : done:
     698             :         spin_unlock_irqrestore (&ohci->lock, flags);
     699             : 
     700             :         return PAGE_SIZE - size;
     701             : }
     702             : 
     703             : static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
     704             :                                 ssize_t (*fill_func)(struct debug_buffer *))
     705             : {
     706             :         struct debug_buffer *buf;
     707             : 
     708             :         buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
     709             : 
     710             :         if (buf) {
     711             :                 buf->ohci = ohci;
     712             :                 buf->fill_func = fill_func;
     713             :                 mutex_init(&buf->mutex);
     714             :         }
     715             : 
     716             :         return buf;
     717             : }
     718             : 
     719             : static int fill_buffer(struct debug_buffer *buf)
     720             : {
     721             :         int ret = 0;
     722             : 
     723             :         if (!buf->page)
     724             :                 buf->page = (char *)get_zeroed_page(GFP_KERNEL);
     725             : 
     726             :         if (!buf->page) {
     727             :                 ret = -ENOMEM;
     728             :                 goto out;
     729             :         }
     730             : 
     731             :         ret = buf->fill_func(buf);
     732             : 
     733             :         if (ret >= 0) {
     734             :                 buf->count = ret;
     735             :                 ret = 0;
     736             :         }
     737             : 
     738             : out:
     739             :         return ret;
     740             : }
     741             : 
     742             : static ssize_t debug_output(struct file *file, char __user *user_buf,
     743             :                         size_t len, loff_t *offset)
     744             : {
     745             :         struct debug_buffer *buf = file->private_data;
     746             :         int ret = 0;
     747             : 
     748             :         mutex_lock(&buf->mutex);
     749             :         if (buf->count == 0) {
     750             :                 ret = fill_buffer(buf);
     751             :                 if (ret != 0) {
     752             :                         mutex_unlock(&buf->mutex);
     753             :                         goto out;
     754             :                 }
     755             :         }
     756             :         mutex_unlock(&buf->mutex);
     757             : 
     758             :         ret = simple_read_from_buffer(user_buf, len, offset,
     759             :                                       buf->page, buf->count);
     760             : 
     761             : out:
     762             :         return ret;
     763             : 
     764             : }
     765             : 
     766             : static int debug_close(struct inode *inode, struct file *file)
     767             : {
     768             :         struct debug_buffer *buf = file->private_data;
     769             : 
     770             :         if (buf) {
     771             :                 if (buf->page)
     772             :                         free_page((unsigned long)buf->page);
     773             :                 kfree(buf);
     774             :         }
     775             : 
     776             :         return 0;
     777             : }
     778             : static int debug_async_open(struct inode *inode, struct file *file)
     779             : {
     780             :         file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
     781             : 
     782             :         return file->private_data ? 0 : -ENOMEM;
     783             : }
     784             : 
     785             : static int debug_periodic_open(struct inode *inode, struct file *file)
     786             : {
     787             :         file->private_data = alloc_buffer(inode->i_private,
     788             :                                           fill_periodic_buffer);
     789             : 
     790             :         return file->private_data ? 0 : -ENOMEM;
     791             : }
     792             : 
     793             : static int debug_registers_open(struct inode *inode, struct file *file)
     794             : {
     795             :         file->private_data = alloc_buffer(inode->i_private,
     796             :                                           fill_registers_buffer);
     797             : 
     798             :         return file->private_data ? 0 : -ENOMEM;
     799             : }
     800             : static inline void create_debug_files (struct ohci_hcd *ohci)
     801             : {
     802             :         struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
     803             : 
     804             :         ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
     805             :         if (!ohci->debug_dir)
     806             :                 goto dir_error;
     807             : 
     808             :         ohci->debug_async = debugfs_create_file("async", S_IRUGO,
     809             :                                                 ohci->debug_dir, ohci,
     810             :                                                 &debug_async_fops);
     811             :         if (!ohci->debug_async)
     812             :                 goto async_error;
     813             : 
     814             :         ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
     815             :                                                    ohci->debug_dir, ohci,
     816             :                                                    &debug_periodic_fops);
     817             :         if (!ohci->debug_periodic)
     818             :                 goto periodic_error;
     819             : 
     820             :         ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
     821             :                                                     ohci->debug_dir, ohci,
     822             :                                                     &debug_registers_fops);
     823             :         if (!ohci->debug_registers)
     824             :                 goto registers_error;
     825             : 
     826             :         ohci_dbg (ohci, "created debug files\n");
     827             :         return;
     828             : 
     829             : registers_error:
     830             :         debugfs_remove(ohci->debug_periodic);
     831             : periodic_error:
     832             :         debugfs_remove(ohci->debug_async);
     833             : async_error:
     834             :         debugfs_remove(ohci->debug_dir);
     835             : dir_error:
     836             :         ohci->debug_periodic = NULL;
     837             :         ohci->debug_async = NULL;
     838             :         ohci->debug_dir = NULL;
     839             : }
     840             : 
     841             : static inline void remove_debug_files (struct ohci_hcd *ohci)
     842             : {
     843             :         debugfs_remove(ohci->debug_registers);
     844             :         debugfs_remove(ohci->debug_periodic);
     845             :         debugfs_remove(ohci->debug_async);
     846             :         debugfs_remove(ohci->debug_dir);
     847             : }
     848             : 
     849             : #endif
     850             : 
     851             : /*-------------------------------------------------------------------------*/
     852             : 

Generated by: LCOV version 1.10