From: Linus Torvalds Date: Fri, 23 Nov 2007 20:32:38 +0000 (-0500) Subject: Import 2.3.51pre2 X-Git-Tag: 2.3.51pre2 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=520b32fa9ecfa3312cf899679d7a0e019af32846;p=history.git Import 2.3.51pre2 --- diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 3d403b93cf63..99e2587565ad 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -590,11 +590,11 @@ static void apm_cpu_idle(void) continue; if (hlt_counter) continue; - asm volatile("cli" : : : "memory"); + __cli(); if (!current->need_resched) - asm volatile("sti ; hlt" : : : "memory"); + safe_halt(); else - asm volatile("sti" : : : "memory"); + __sti(); continue; } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index a043b4cfe0a2..3ba1d8257f63 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -75,11 +75,11 @@ void enable_hlt(void) static void default_idle(void) { if (current_cpu_data.hlt_works_ok && !hlt_counter) { - asm volatile("cli" : : : "memory"); + __cli(); if (!current->need_resched) - asm volatile("sti ; hlt" : : : "memory"); + safe_halt(); else - asm volatile("sti" : : : "memory"); + __sti(); } } diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index f766605bcde9..2ef50f2851ea 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -105,8 +105,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id) * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. * Some drives can be jumpered to use 15 heads instead of 16. + * Some drives can be jumpered to use 4092 cyls instead of 16383. */ - if (id->cyls == 16383 && id->sectors == 63 && + if ((id->cyls == 16383 + || (id->cyls == 4092 && id->cur_cyls == 16383)) && + id->sectors == 63 && (id->heads == 15 || id->heads == 16) && id->lba_capacity >= 16383*63*id->heads) return 1; diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c index 0f24b0ac3ac3..6ebf20fe1133 100644 --- a/drivers/block/ide-geometry.c +++ b/drivers/block/ide-geometry.c @@ -2,6 +2,8 @@ * linux/drivers/block/ide-geometry.c */ #include + +#ifdef CONFIG_BLK_DEV_IDE #include #include @@ -60,15 +62,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) /* Extract drive geometry from CMOS+BIOS if not already setup */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; -#if 0 - if ((cmos_disks & (0xf0 >> (unit*4))) && - !drive->present && !drive->nobios) { - drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = *(BIOS+2); - drive->sect = drive->bios_sect = *(BIOS+14); - drive->ctl = *(BIOS+8); - } -#else + if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { unsigned short cyl = *(unsigned short *)BIOS; @@ -83,7 +77,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit, cyl, head, sect); } } -#endif + BIOS += 16; } #endif @@ -98,13 +92,15 @@ static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) { static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *headp = dm_head_vals; - unsigned long total, tracks; + unsigned long total; /* * The specs say: take geometry as obtained from Identify, * compute total capacity C*H*S from that, and truncate to * 1024*255*63. Now take S=63, H the first in the sequence * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total. + * [Please tell aeb@cwi.nl in case this computes a + * geometry different from what OnTrack uses.] */ total = DRIVER(drive)->capacity(drive); @@ -116,32 +112,10 @@ ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) { return; } -#if 0 while (63 * headp[0] * 1024 < total && headp[1] != 0) headp++; *h = headp[0]; *c = total / (63 * headp[0]); -#else - /* The code below differs in two aspects: - (i) It will not produce geometries like C/H/S = 1024/64/63 - because of the `>='. This follows OnTracks text (which - claims that 512 <= C <= 1023), but not OnTracks code. - (ii) It starts dividing by 63, so that a rounding down occurs. - For example, with C=11159, H=10, S=37 we find total=4128830 - and DM would make C=512, H=128, S=63, but we make 1024/64/63 - if `>=' is replaced by `>'. - The reason we use this code is mainly that we have done so for - a long time without getting complaints. - */ - - tracks = total / 63; - while (*c >= 1024) { - *h = *headp; - *c = tracks / *h; - if (*++headp == 0) - break; - } -#endif } /* @@ -237,3 +211,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg) drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } +#endif /* CONFIG_BLK_DEV_IDE */ diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index debba3207c19..753597e9cf19 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -51,7 +51,7 @@ * be updated someday soon to use this mechanism. * * Feel free to develop and distribute fancy GUI configuration - * utilities for you favorite PCI chipsets. I'll be working on + * utilities for your favorite PCI chipsets. I'll be working on * one for the Promise 20246 someday soon. -ml * */ @@ -798,7 +798,7 @@ void proc_ide_create(void) create_proc_ide_interfaces(); - create_proc_read_entry("drivers",0,proc_ide_root, + create_proc_read_entry("drivers", 0, proc_ide_root, proc_ide_read_drivers, NULL); #ifdef CONFIG_BLK_DEV_AEC6210 @@ -823,11 +823,11 @@ void proc_ide_create(void) #endif /* CONFIG_BLK_DEV_CS5530 */ #ifdef CONFIG_BLK_DEV_HPT34X if ((hpt34x_display_info) && (hpt34x_proc)) - create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info); + create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info); #endif /* CONFIG_BLK_DEV_HPT34X */ #ifdef CONFIG_BLK_DEV_HPT366 if ((hpt366_display_info) && (hpt366_proc)) - create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info); + create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info); #endif /* CONFIG_BLK_DEV_HPT366 */ #ifdef CONFIG_BLK_DEV_PDC202XX if ((pdc202xx_display_info) && (pdc202xx_proc)) diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 06a616592c51..08c92ace9d02 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -186,8 +186,10 @@ u16 el3_isapnp_phys_addr[8][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; -#endif +#endif /* CONFIG_ISAPNP */ +#if defined(CONFIG_ISAPNP) || defined(MODULE) static int nopnp = 0; +#endif int el3_probe(struct net_device *dev) { @@ -195,8 +197,10 @@ int el3_probe(struct net_device *dev) int ioaddr, irq, if_port; u16 phys_addr[3]; static int current_tag = 0; - static int pnp_cards = 0; int mca_slot = -1; +#ifdef CONFIG_ISAPNP + static int pnp_cards = 0; +#endif /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ddfed868e8c5..0b3aeff4bc63 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -558,7 +558,9 @@ int __init ppp_init(void) { int err; #ifndef MODULE +#ifdef CONFIG_PPP_DEFLATE extern struct compressor ppp_deflate, ppp_deflate_draft; +#endif extern int ppp_async_init(void); extern int ppp_sync_init(void); #endif diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index ec4cad49199e..bf6fe6571d19 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -54,18 +54,21 @@ MODULE_PARM(debug, "i"); static kmem_cache_t *uhci_td_cachep; static kmem_cache_t *uhci_qh_cachep; +static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static LIST_HEAD(uhci_list); static int rh_submit_urb(urb_t *urb); static int rh_unlink_urb(urb_t *urb); static int uhci_get_current_frame_number(struct usb_device *dev); -static void uhci_stop_hc_schedule(struct uhci *uhci); -static void uhci_start_hc_schedule(struct uhci *uhci); +static int uhci_unlink_generic(urb_t *urb); static int uhci_unlink_urb(urb_t *urb); #define min(a,b) (((a)<(b))?(a):(b)) +/* If a transfer is still active after this much time, turn off FSBR */ +#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ + /* * Only the USB core should call uhci_alloc_dev and uhci_free_dev */ @@ -78,7 +81,7 @@ static int uhci_free_dev(struct usb_device *dev) { urb_t *u; struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; - struct list_head *tmp, *head = &uhci->urb_list; + struct list_head *tmp, *next, *head = &uhci->urb_list; unsigned long flags; /* Walk through the entire URB list and forcefully remove any */ @@ -88,38 +91,18 @@ static int uhci_free_dev(struct usb_device *dev) while (tmp != head) { u = list_entry(tmp, urb_t, urb_list); + next = tmp->next; + if (u->dev == dev) uhci_unlink_urb(u); + + tmp = next; } nested_unlock(&uhci->urblist_lock, flags); return 0; } -/* - * UHCI interrupt list operations.. - */ -static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td) -{ - unsigned long flags; - - nested_lock(&uhci->irqlist_lock, flags); - list_add(&td->irq_list, &uhci->interrupt_list); - nested_unlock(&uhci->irqlist_lock, flags); -} - -static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td) -{ - unsigned long flags; - - nested_lock(&uhci->irqlist_lock, flags); - if (td->irq_list.next != &td->irq_list) { - list_del(&td->irq_list); - INIT_LIST_HEAD(&td->irq_list); - } - nested_unlock(&uhci->irqlist_lock, flags); -} - static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb) { unsigned long flags; @@ -141,6 +124,54 @@ static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb) nested_unlock(&uhci->urblist_lock, flags); } +static struct uhci_td *uhci_alloc_td(struct usb_device *dev) +{ + struct uhci_td *td; + + td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + if (!td) + return NULL; + + td->link = UHCI_PTR_TERM; + td->buffer = 0; + + td->frameptr = NULL; + td->nexttd = td->prevtd = NULL; + td->list.next = td->list.prev = NULL; + td->dev = dev; + + usb_inc_dev_use(dev); + + return td; +} + +static void inline uhci_fill_td(struct uhci_td *td, __u32 status, + __u32 info, __u32 buffer) +{ + td->status = status; + td->info = info; + td->buffer = buffer; +} + +static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + + /* Fix the linked list pointers */ + td->nexttd = skeltd->nexttd; + td->prevtd = skeltd; + if (skeltd->nexttd) + skeltd->nexttd->prevtd = td; + skeltd->nexttd = td; + + td->link = skeltd->link; + skeltd->link = virt_to_bus(td); + + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + /* * We insert Isochronous transfers directly into the frame list at the * beginning @@ -157,6 +188,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns framenum %= UHCI_NUMFRAMES; spin_lock_irqsave(&uhci->framelist_lock, flags); + td->frameptr = &uhci->fl->frame[framenum]; td->link = uhci->fl->frame[framenum]; if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { @@ -166,6 +198,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns nexttd->frameptr = NULL; } uhci->fl->frame[framenum] = virt_to_bus(td); + spin_unlock_irqrestore(&uhci->framelist_lock, flags); } @@ -173,6 +206,10 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td) { unsigned long flags; + /* If it's not inserted, don't remove it */ + if (!td->frameptr && !td->prevtd && !td->nexttd) + return; + spin_lock_irqsave(&uhci->framelist_lock, flags); if (td->frameptr) { *(td->frameptr) = td->link; @@ -195,77 +232,41 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td) spin_unlock_irqrestore(&uhci->framelist_lock, flags); } -static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td) -{ - unsigned long flags; - - spin_lock_irqsave(&uhci->framelist_lock, flags); - - /* Fix the linked list pointers */ - td->nexttd = skeltd->nexttd; - td->prevtd = skeltd; - if (skeltd->nexttd) - skeltd->nexttd->prevtd = td; - skeltd->nexttd = td; - - td->link = skeltd->link; - skeltd->link = virt_to_bus(td); - - spin_unlock_irqrestore(&uhci->framelist_lock, flags); -} - /* * Inserts a td into qh list at the top. */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin) +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth) { - struct uhci_td *td, *prevtd; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td, *prevtd = NULL; - if (!begin) /* Nothing to do */ + if (!urbp) return; - /* Grab the first TD and add it to the QH */ - td = begin; - qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH; + td = urbp->list.begin; + if (!td) + return; + + /* Add the first TD to the QH element pointer */ + qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH); - /* Go through the rest of the TD's, link them together */ prevtd = td; - td = td->next; - while (td) { - prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; + + /* Then link the rest of the TD's */ + for (td = td->list.next; td; td = td->list.next) { + prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH); prevtd = td; - td = td->next; } prevtd->link = UHCI_PTR_TERM; } -static struct uhci_td *uhci_alloc_td(struct usb_device *dev) -{ - struct uhci_td *td; - - td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); - if (!td) - return NULL; - - td->link = UHCI_PTR_TERM; - td->buffer = 0; - - td->frameptr = NULL; - td->nexttd = td->prevtd = NULL; - td->next = NULL; - td->dev = dev; - INIT_LIST_HEAD(&td->irq_list); - INIT_LIST_HEAD(&td->list); - - usb_inc_dev_use(dev); - - return td; -} - static void uhci_free_td(struct uhci_td *td) { + if (td->list.next || td->list.prev) + dbg("td is still in URB list!"); + kmem_cache_free(uhci_td_cachep, td); if (td->dev) @@ -286,7 +287,7 @@ static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev) qh->dev = dev; qh->prevqh = qh->nextqh = NULL; - INIT_LIST_HEAD(&qh->list); + INIT_LIST_HEAD(&qh->remove_list); usb_inc_dev_use(dev); @@ -333,14 +334,31 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh) qh->nextqh->prevqh = qh->prevqh; qh->prevqh = qh->nextqh = NULL; spin_unlock_irqrestore(&uhci->framelist_lock, flags); + + spin_lock_irqsave(&uhci->qh_remove_lock, flags); + list_add(&qh->remove_list, &uhci->qh_remove_list); + spin_unlock_irqrestore(&uhci->qh_remove_lock, flags); } -static void inline uhci_fill_td(struct uhci_td *td, __u32 status, - __u32 info, __u32 buffer) +struct urb_priv *uhci_alloc_urb_priv(struct urb *urb) { - td->status = status; - td->info = info; - td->buffer = buffer; + struct urb_priv *urbp; + + urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + if (!urbp) + return NULL; + + memset((void *)urbp, 0, sizeof(*urbp)); + + urbp->list.begin = urbp->list.end = NULL; + + urb->hcpriv = urbp; + + urbp->inserttime = jiffies; + + usb_inc_dev_use(urb->dev); + + return urbp; } static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td) @@ -349,35 +367,110 @@ static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td) td->urb = urb; - if (urbp->end) - urbp->end->next = td; + if (!urbp->list.begin) + urbp->list.begin = td; + + if (urbp->list.end) { + urbp->list.end->list.next = td; + td->list.prev = urbp->list.end; + } + urbp->list.end = td; +} + +static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + + if (!urbp->list.begin && !urbp->list.end) + return; + + if (td->list.prev) + td->list.prev->list.next = td->list.next; + else + urbp->list.begin = td->list.next; + + if (td->list.next) + td->list.next->list.prev = td->list.prev; + else + urbp->list.end = td->list.prev; + + td->list.next = td->list.prev = NULL; + td->urb = NULL; +} + +static void uhci_destroy_urb_priv(urb_t *urb) +{ + struct urb_priv *urbp; + struct uhci *uhci; + struct uhci_td *td, *nexttd; + unsigned long flags; + + spin_lock_irqsave(&urb->lock, flags); + + urbp = (struct urb_priv *)urb->hcpriv; + if (!urbp) + return; + + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) + return; + + uhci = urb->dev->bus->hcpriv; + + td = urbp->list.begin; + while (td) { + nexttd = td->list.next; + + uhci_remove_td_from_urb(urb, td); + + uhci_remove_td(uhci, td); + + uhci_free_td(td); + + td = nexttd; + } + + urb->hcpriv = NULL; + kmem_cache_free(uhci_up_cachep, urbp); - urbp->end = td; + spin_unlock_irqrestore(&urb->lock, flags); - if (!urbp->begin) - urbp->begin = td; + usb_dec_dev_use(urb->dev); } -void uhci_inc_fsbr(struct uhci *uhci) +static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb) { unsigned long flags; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + + if (!urbp) + return; spin_lock_irqsave(&uhci->framelist_lock, flags); - if (!uhci->fsbr++) - uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; + if (!urbp->fsbr) { + urbp->fsbr = 1; + if (!uhci->fsbr++) + uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; + } spin_unlock_irqrestore(&uhci->framelist_lock, flags); } -void uhci_dec_fsbr(struct uhci *uhci) +static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb) { unsigned long flags; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + + if (!urbp) + return; spin_lock_irqsave(&uhci->framelist_lock, flags); - if (!--uhci->fsbr) - uhci->skel_term_qh.link = UHCI_PTR_TERM; + if (urbp->fsbr) { + urbp->fsbr = 0; + if (!--uhci->fsbr) + uhci->skel_term_td.link = UHCI_PTR_TERM; + } spin_unlock_irqrestore(&uhci->framelist_lock, flags); } @@ -419,14 +512,14 @@ static int uhci_map_status(int status, int dir_out) */ static int uhci_submit_control(urb_t *urb) { + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct uhci_td *td; struct uhci_qh *qh; unsigned long destination, status; - struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; unsigned char *data = urb->transfer_buffer; - struct urb_priv *urbp; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -434,14 +527,6 @@ static int uhci_submit_control(urb_t *urb) /* 3 errors */ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); - urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (!urbp) - return -ENOMEM; - - urbp->begin = urbp->end = NULL; - - urb->hcpriv = urbp; - /* * Build the TD for the control request */ @@ -465,18 +550,16 @@ static int uhci_submit_control(urb_t *urb) /* * Build the DATA TD's */ - td = uhci_alloc_td(urb->dev); - if (!td) { - /* FIXME: Free the TD's */ - return -ENOMEM; - } - while (len > 0) { int pktsze = len; if (pktsze > maxsze) pktsze = maxsze; + td = uhci_alloc_td(urb->dev); + if (!td) + return -ENOMEM; + /* Alternate Data0/1 (start with Data1) */ destination ^= 1 << TD_TOKEN_TOGGLE; @@ -486,16 +569,16 @@ static int uhci_submit_control(urb_t *urb) data += pktsze; len -= pktsze; - - td = uhci_alloc_td(urb->dev); - if (!td) - /* FIXME: Free all of the previously allocated td's */ - return -ENOMEM; } /* * Build the final TD for control status - * + */ + td = uhci_alloc_td(urb->dev); + if (!td) + return -ENOMEM; + + /* * It's IN if the pipe is an output pipe or we're not expecting * data back. */ @@ -513,20 +596,19 @@ static int uhci_submit_control(urb_t *urb) uhci_fill_td(td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21), 0); - uhci_add_irq_list(uhci, td); - qh = uhci_alloc_qh(urb->dev); - if (!qh) { - /* FIXME: Free all of the TD's */ + if (!qh) return -ENOMEM; - } - uhci_insert_tds_in_qh(qh, urbp->begin); - if (!(urb->pipe & TD_CTRL_LS)) { - uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh); - uhci_inc_fsbr(uhci); - } else + /* Low speed or small transfers gets a different queue and treatment */ + if (urb->pipe & TD_CTRL_LS) { + uhci_insert_tds_in_qh(qh, urb, 0); uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh); + } else { + uhci_insert_tds_in_qh(qh, urb, 1); + uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh); + uhci_inc_fsbr(uhci, urb); + } urbp->qh = qh; @@ -537,66 +619,22 @@ static int uhci_submit_control(urb_t *urb) return -EINPROGRESS; } -/* This is also the uhci_unlink_bulk function */ -static int uhci_unlink_control(urb_t *urb) +static int uhci_result_control(urb_t *urb) { struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; - struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - int notfinished; + unsigned int status; if (!urbp) return -EINVAL; - notfinished = (urb->status == -EINPROGRESS); - - if (notfinished) - uhci_stop_hc_schedule(uhci); - - if (!(urb->pipe & TD_CTRL_LS)) - uhci_dec_fsbr(uhci); - - uhci_remove_qh(uhci, urbp->qh); - uhci_free_qh(urbp->qh); - - /* Go through the rest of the TD's, deleting them, then scheduling */ - /* their deletion */ - td = urbp->begin; - while (td) { - struct uhci_td *next = td->next; - - if (td->status & TD_CTRL_IOC) - uhci_remove_irq_list(uhci, td); - - uhci_free_td(td); - - td = next; - } - - if (notfinished) - uhci_start_hc_schedule(uhci); - - kfree(urbp); - urb->hcpriv = NULL; - - uhci_remove_urb_list(uhci, urb); - - return 0; -} - -static int uhci_result_control(urb_t *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - unsigned int status; - - td = urbp->begin; - if (!td) /* Nothing to do */ + td = urbp->list.begin; + if (!td) return -EINVAL; /* The first TD is the SETUP phase, check the status, but skip */ /* the count */ - status = uhci_status_bits(td->status); + status = uhci_status_bits(td->status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; @@ -605,9 +643,10 @@ static int uhci_result_control(urb_t *urb) urb->actual_length = 0; + td = td->list.next; + /* The rest of the TD's (but the last) are data */ - td = td->next; - while (td && td->next) { + while (td && td->list.next) { status = uhci_status_bits(td->status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; @@ -617,13 +656,14 @@ static int uhci_result_control(urb_t *urb) /* If SPD is set then we received a short packet */ /* There will be no status phase at the end */ /* FIXME: Re-setup the queue to run the STATUS phase? */ - if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) + if ((td->status & TD_CTRL_SPD) && + (uhci_actual_length(td->status) < uhci_expected_length(td->info))) return 0; if (status) goto td_error; - td = td->next; + td = td->list.next; } /* Control status phase */ @@ -648,18 +688,16 @@ static int uhci_result_control(urb_t *urb) td_error: /* Some debugging code */ if (debug) { - dbg("uhci_result_control() failed with status %x", - status); + dbg("uhci_result_control() failed with status %x", status); /* Print the chain for debugging purposes */ uhci_show_queue(urbp->qh); } - if (status & TD_CTRL_STALLED) { + if (status & TD_CTRL_STALLED) /* endpoint has stalled - mark it halted */ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - } return uhci_map_status(status, uhci_packetout(td->info)); } @@ -672,7 +710,6 @@ static int uhci_submit_interrupt(urb_t *urb) struct uhci_td *td; unsigned long destination, status; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - struct urb_priv *urbp; if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) return -EINVAL; @@ -680,16 +717,7 @@ static int uhci_submit_interrupt(urb_t *urb) /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | - TD_CTRL_IOC; - - urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (!urbp) - return -ENOMEM; - - urbp->begin = urbp->end = NULL; - - urb->hcpriv = urbp; + status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC; td = uhci_alloc_td(urb->dev); if (!td) @@ -698,72 +726,70 @@ static int uhci_submit_interrupt(urb_t *urb) destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); destination |= ((urb->transfer_buffer_length - 1) << 21); + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination, virt_to_bus(urb->transfer_buffer)); - uhci_add_irq_list(uhci, td); - uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td); uhci_add_urb_list(uhci, urb); - usb_inc_dev_use(urb->dev); - return -EINPROGRESS; } -static int uhci_unlink_interrupt(urb_t *urb) +static int uhci_result_interrupt(urb_t *urb) { struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; - struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - int notfinished; + unsigned int status; if (!urbp) return -EINVAL; - notfinished = (urb->status == -EINPROGRESS); + urb->actual_length = 0; - if (notfinished) - uhci_stop_hc_schedule(uhci); + for (td = urbp->list.begin; td; td = td->list.next) { + status = uhci_status_bits(td->status); + if (status & TD_CTRL_ACTIVE) + return -EINPROGRESS; - td = urbp->begin; - uhci_remove_td(uhci, td); - if (td->status & TD_CTRL_IOC) - uhci_remove_irq_list(uhci, td); - uhci_free_td(td); + urb->actual_length += uhci_actual_length(td->status); - if (notfinished) - uhci_start_hc_schedule(uhci); + /* If SPD is set then we received a short packet */ + if ((td->status & TD_CTRL_SPD) && + (uhci_actual_length(td->status) < uhci_expected_length(td->info))) { + usb_settoggle(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info), + uhci_toggle(td->info) ^ 1); - kfree(urbp); - urb->hcpriv = NULL; + return 0; + } - uhci_remove_urb_list(uhci, urb); + if (status) + goto td_error; + } return 0; -} - -static int uhci_result_interrupt(urb_t *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - int status; - - if (!urbp) - return -EINVAL; - td = urbp->begin; - if (!td) - return -EINVAL; +td_error: + /* Some debugging code */ + if (debug) { + dbg("uhci_result_interrupt/bulk() failed with status %x", + status); - status = uhci_status_bits(td->status); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; + /* Print the chain for debugging purposes */ + if (urbp->qh) + uhci_show_queue(urbp->qh); + else + uhci_show_td(td); + } - if (!status) - urb->actual_length = uhci_actual_length(td->status); + if (status & TD_CTRL_STALLED) + /* endpoint has stalled - mark it halted */ + usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info)); return uhci_map_status(status, uhci_packetout(td->info)); } @@ -773,12 +799,17 @@ static void uhci_reset_interrupt(urb_t *urb) struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - td = urbp->begin; + if (!urbp) + return; + + td = urbp->list.begin; + if (!td) + return; - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; td->info &= ~(1 << TD_TOKEN_TOGGLE); td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); urb->status = -EINPROGRESS; } @@ -795,27 +826,23 @@ static int uhci_submit_bulk(urb_t *urb) int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; unsigned char *data = urb->transfer_buffer; - struct urb_priv *urbp; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; if (len < 0) return -EINVAL; + /* Can't have low speed bulk transfers */ + if (urb->pipe & TD_CTRL_LS) + return -EINVAL; + /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); /* 3 errors */ - status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); + status = TD_CTRL_ACTIVE | (3 << 27); if (!(urb->transfer_flags & USB_DISABLE_SPD)) status |= TD_CTRL_SPD; - urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (!urbp) - return -ENOMEM; - - urbp->begin = urbp->end = NULL; - - urb->hcpriv = urbp; - /* * Build the DATA TD's */ @@ -826,10 +853,8 @@ static int uhci_submit_bulk(urb_t *urb) pktsze = maxsze; td = uhci_alloc_td(urb->dev); - if (!td) { - /* FIXME: Free the TD's */ + if (!td) return -ENOMEM; - } uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) | @@ -840,86 +865,31 @@ static int uhci_submit_bulk(urb_t *urb) data += pktsze; len -= maxsze; - if (len <= 0) { + if (len <= 0) td->status |= TD_CTRL_IOC; - uhci_add_irq_list(uhci, td); - } usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); } qh = uhci_alloc_qh(urb->dev); - if (!qh) { - /* FIXME: Free all of the TD's */ + if (!qh) return -ENOMEM; - } - uhci_insert_tds_in_qh(qh, urbp->begin); + + uhci_insert_tds_in_qh(qh, urb, 1); uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh); urbp->qh = qh; uhci_add_urb_list(uhci, urb); - usb_inc_dev_use(urb->dev); - - uhci_inc_fsbr(uhci); + uhci_inc_fsbr(uhci, urb); return -EINPROGRESS; } -/* We can use the control unlink since they're identical */ -#define uhci_unlink_bulk uhci_unlink_control - -static int uhci_result_bulk(urb_t *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - unsigned int status; - - urb->actual_length = 0; - - /* The rest of the TD's (but the last) are data */ - for (td = urbp->begin; td; td = td->next) { - status = uhci_status_bits(td->status); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - urb->actual_length += uhci_actual_length(td->status); - - /* If SPD is set then we received a short packet */ - if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) { - usb_settoggle(urb->dev, uhci_endpoint(td->info), - uhci_packetout(td->info), - uhci_toggle(td->info) ^ 1); - - return 0; - } - - if (status) - goto td_error; - } - - return 0; - -td_error: - /* Some debugging code */ - if (debug) { - dbg("uhci_result_bulk() failed with status %x", - status); - - /* Print the chain for debugging purposes */ - uhci_show_queue(urbp->qh); - } - - if (status & TD_CTRL_STALLED) { - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), - uhci_packetout(td->info)); - } - - return uhci_map_status(status, uhci_packetout(td->info)); -} +/* We can use the result interrupt since they're identical */ +#define uhci_result_bulk uhci_result_interrupt /* * Isochronous transfers @@ -929,6 +899,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int urb_t *u, *last_urb = NULL; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct list_head *tmp, *head = &uhci->urb_list; + int ret = 0; unsigned long flags; nested_lock(&uhci->urblist_lock, flags); @@ -945,14 +916,16 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int } tmp = tmp->next; } - nested_unlock(&uhci->urblist_lock, flags); if (last_urb) { *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023; - return 0; + ret = 0; } else - return -1; // no previous urb found + ret = -1; /* no previous urb found */ + + nested_unlock(&uhci->urblist_lock, flags); + return ret; } static int isochronous_find_start(urb_t *urb) @@ -985,7 +958,6 @@ static int uhci_submit_isochronous(urb_t *urb) { struct uhci_td *td; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - struct urb_priv *urbp; int i, ret, framenum; int status, destination; @@ -996,85 +968,30 @@ static int uhci_submit_isochronous(urb_t *urb) if (ret) return ret; - urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (!urbp) - return -ENOMEM; - - urbp->begin = urbp->end = NULL; - - urb->hcpriv = urbp; - framenum = urb->start_frame; for (i = 0; i < urb->number_of_packets; i++, framenum++) { if (!urb->iso_frame_desc[i].length) continue; td = uhci_alloc_td(urb->dev); - if (!td) { - /* FIXME: Free the TD's */ + if (!td) return -ENOMEM; - } uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21), virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset)); - if (i + 1 >= urb->number_of_packets) { + if (i + 1 >= urb->number_of_packets) td->status |= TD_CTRL_IOC; - uhci_add_irq_list(uhci, td); - } uhci_insert_td_frame_list(uhci, td, framenum); } uhci_add_urb_list(uhci, urb); - usb_inc_dev_use(urb->dev); - return -EINPROGRESS; } -static int uhci_unlink_isochronous(urb_t *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; - int notfinished; - - if (!urbp) - return -EINVAL; - - notfinished = (urb->status == -EINPROGRESS); - - if (notfinished) - uhci_stop_hc_schedule(uhci); - - /* Go through the rest of the TD's, deleting them, then scheduling */ - /* their deletion */ - td = urbp->begin; - while (td) { - struct uhci_td *next = td->next; - - uhci_remove_td(uhci, td); - - if (td->status & TD_CTRL_IOC) - uhci_remove_irq_list(uhci, td); - uhci_free_td(td); - - td = next; - } - - if (notfinished) - uhci_start_hc_schedule(uhci); - - kfree(urbp); - urb->hcpriv = NULL; - - uhci_remove_urb_list(uhci, urb); - - return 0; -} - static int uhci_result_isochronous(urb_t *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -1082,19 +999,17 @@ static int uhci_result_isochronous(urb_t *urb) int status; int i, ret = 0; - td = urbp->end; - if (!td) /* Nothing to do */ + if (!urbp) return -EINVAL; - status = uhci_status_bits(td->status); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - urb->actual_length = 0; - for (i = 0, td = urbp->begin; td; i++, td = td->next) { + for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) { int actlength; + if (td->status & TD_CTRL_ACTIVE) + return -EINPROGRESS; + actlength = uhci_actual_length(td->status); urb->iso_frame_desc[i].actual_length = actlength; urb->actual_length += actlength; @@ -1114,17 +1029,26 @@ static int uhci_submit_urb(urb_t *urb) { int ret = -EINVAL; struct uhci *uhci; + unsigned long flags; if (!urb) return -EINVAL; - if (!urb->dev || !urb->dev->bus) + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) return -ENODEV; uhci = (struct uhci *)urb->dev->bus->hcpriv; + /* Short circuit the virtual root hub */ if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) - return rh_submit_urb(urb); /* Virtual root hub */ + return rh_submit_urb(urb); + + spin_lock_irqsave(&urb->lock, flags); + + if (!uhci_alloc_urb_priv(urb)) { + spin_unlock_irqrestore(&urb->lock, flags); + return -ENOMEM; + } switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1142,20 +1066,30 @@ static int uhci_submit_urb(urb_t *urb) } urb->status = ret; + + spin_unlock_irqrestore(&urb->lock, flags); + if (ret == -EINPROGRESS) - return 0; + ret = 0; + else + uhci_unlink_generic(urb); return ret; } /* * Return the result of a transfer + * + * Must be called with urblist_lock acquired */ static void uhci_transfer_result(urb_t *urb) { urb_t *turb; int proceed = 0, is_ring = 0; int ret = -EINVAL; + unsigned long flags; + + spin_lock_irqsave(&urb->lock, flags); switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1173,12 +1107,17 @@ static void uhci_transfer_result(urb_t *urb) } urb->status = ret; - if (urb->status == -EINPROGRESS) + + spin_unlock_irqrestore(&urb->lock, flags); + + if (ret == -EINPROGRESS) return; switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: - uhci_unlink_control(urb); + case PIPE_BULK: + case PIPE_ISOCHRONOUS: + uhci_unlink_generic(urb); break; case PIPE_INTERRUPT: /* Interrupts are an exception */ @@ -1186,14 +1125,8 @@ static void uhci_transfer_result(urb_t *urb) if (urb->interval) uhci_reset_interrupt(urb); else - uhci_unlink_interrupt(urb); - return; - case PIPE_BULK: - uhci_unlink_bulk(urb); - break; - case PIPE_ISOCHRONOUS: - uhci_unlink_isochronous(urb); - break; + uhci_unlink_generic(urb); + return; /* <-- Note the return */ } if (urb->next) { @@ -1231,10 +1164,32 @@ static void uhci_transfer_result(urb_t *urb) } } +static int uhci_unlink_generic(urb_t *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + + if (!urbp) + return -EINVAL; + + uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + + uhci_remove_urb_list(uhci, urb); + + if (urbp->qh) + /* The interrupt loop will reclaim the QH's */ + uhci_remove_qh(uhci, urbp->qh); + + uhci_destroy_urb_priv(urb); + + return 0; +} + static int uhci_unlink_urb(urb_t *urb) { struct uhci *uhci; int ret = 0; + unsigned long flags; if (!urb) return -EINVAL; @@ -1244,40 +1199,34 @@ static int uhci_unlink_urb(urb_t *urb) uhci = (struct uhci *)urb->dev->bus->hcpriv; + /* Short circuit the virtual root hub */ if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) return rh_unlink_urb(urb); if (urb->status == -EINPROGRESS) { - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - ret = uhci_unlink_control(urb); - break; - case PIPE_INTERRUPT: - ret = uhci_unlink_interrupt(urb); - break; - case PIPE_BULK: - ret = uhci_unlink_bulk(urb); - break; - case PIPE_ISOCHRONOUS: - ret = uhci_unlink_isochronous(urb); - break; - } + uhci_unlink_generic(urb); - if (urb->complete) - urb->complete(urb); + if (urb->transfer_flags & USB_ASYNC_UNLINK) { + spin_lock_irqsave(&uhci->urb_remove_lock, flags); + list_add(&urb->urb_list, &uhci->urb_remove_list); + spin_unlock_irqrestore(&uhci->urb_remove_lock, flags); -#ifndef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE - if (in_interrupt()) { /* wait at least 1 frame */ - int errorcount = 10; + urb->status = -ECONNABORTED; + } else { + if (in_interrupt()) { /* wait at least 1 frame */ + static int errorcount = 10; - if (errorcount--) - dbg("uhci_unlink_urb called from interrupt for urb %p", urb); - udelay(1000); - } else - schedule_timeout(1+1*HZ/1000); -#endif + if (errorcount--) + dbg("uhci_unlink_urb called from interrupt for urb %p", urb); + udelay(1000); + } else + schedule_timeout(1+1*HZ/1000); - urb->status = -ENOENT; + if (urb->complete) + urb->complete(urb); + + urb->status = -ENOENT; + } } return ret; @@ -1412,9 +1361,12 @@ static int rh_init_int_timer(urb_t *urb); static void rh_int_timer_do(unsigned long ptr) { - int len; - urb_t *urb = (urb_t *)ptr; + urb_t *urb = (urb_t *)ptr, *u; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct list_head *tmp, *head = &uhci->urb_list; + struct urb_priv *urbp; + int len; + unsigned long flags; if (uhci->rh.send) { len = rh_send_irq(urb); @@ -1425,6 +1377,21 @@ static void rh_int_timer_do(unsigned long ptr) } } + nested_lock(&uhci->urblist_lock, flags); + tmp = head->next; + while (tmp != head) { + u = list_entry(tmp, urb_t, urb_list); + + urbp = (struct urb_priv *)u->hcpriv; + if (urbp) { + if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT)) + uhci_dec_fsbr(uhci, u); + } + + tmp = tmp->next; + } + nested_unlock(&uhci->urblist_lock, flags); + rh_init_int_timer(urb); } @@ -1645,6 +1612,27 @@ static int rh_unlink_urb(urb_t *urb) } /*-------------------------------------------------------------------*/ +void uhci_free_pending_qhs(struct uhci *uhci) +{ + struct list_head *tmp, *head; + unsigned long flags; + + /* Free any pending QH's */ + spin_lock_irqsave(&uhci->qh_remove_lock, flags); + head = &uhci->qh_remove_list; + tmp = head->next; + while (tmp != head) { + struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list); + + tmp = tmp->next; + + list_del(&qh->remove_list); + + uhci_free_qh(qh); + } + spin_unlock_irqrestore(&uhci->qh_remove_lock, flags); +} + static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) { struct uhci *uhci = __uhci; @@ -1652,7 +1640,6 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) unsigned short status; unsigned long flags; struct list_head *tmp, *head; - urb_t *urb; /* * Read the interrupt status, and write it back to clear the @@ -1676,55 +1663,36 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) } } - /* Walk the list of pending TD's to see which ones completed.. */ - nested_lock(&uhci->irqlist_lock, flags); - head = &uhci->interrupt_list; + uhci_free_pending_qhs(uhci); + + spin_lock(&uhci->urb_remove_lock); + head = &uhci->urb_remove_list; tmp = head->next; while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); - - urb = td->urb; + struct urb *urb = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; - /* Checks the status and does all of the magic necessary */ - uhci_transfer_result(urb); - } - nested_unlock(&uhci->irqlist_lock, flags); -} - -static void uhci_stop_hc_schedule(struct uhci *uhci) -{ -#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE - unsigned int cmdreg, timeout = 1000; - - cmdreg = inw(uhci->io_addr + USBCMD); - outw(cmdreg & ~USBCMD_RS, uhci->io_addr + USBCMD); + list_del(&urb->urb_list); - while (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) { - if (!--timeout) { - printk(KERN_ERR "uhci: stop_hc_schedule failed, HC still running\n"); - break; - } + if (urb->complete) + urb->complete(urb); } -#endif -} + spin_unlock(&uhci->urb_remove_lock); -static void uhci_start_hc_schedule(struct uhci *uhci) -{ -#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE - unsigned int cmdreg, timeout = 1000; + /* Walk the list of pending TD's to see which ones completed */ + nested_lock(&uhci->urblist_lock, flags); + head = &uhci->urb_list; + tmp = head->next; + while (tmp != head) { + struct urb *urb = list_entry(tmp, struct urb, urb_list); - cmdreg = inw(uhci->io_addr + USBCMD); - outw(cmdreg | USBCMD_RS, uhci->io_addr + USBCMD); + tmp = tmp->next; - while (inw(uhci->io_addr + USBSTS) & USBSTS_HCH) { - if (!--timeout) { - printk(KERN_ERR "uhci: start_hc_schedule failed, HC still halted\n"); - break; - } + /* Checks the status and does all of the magic necessary */ + uhci_transfer_result(urb); } -#endif + nested_unlock(&uhci->urblist_lock, flags); } static void reset_hc(struct uhci *uhci) @@ -1780,7 +1748,7 @@ static void start_hc(struct uhci *uhci) * of the queues. We don't do that here, because * we'll create the actual TD entries on demand. * - The first queue is the "interrupt queue". - * - The second queue is the "control queue". + * - The second queue is the "control queue", split into low and high speed * - The third queue is "bulk data". */ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) @@ -1799,14 +1767,16 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) uhci->io_addr = io_addr; uhci->io_size = io_size; - INIT_LIST_HEAD(&uhci->interrupt_list); - INIT_LIST_HEAD(&uhci->urb_list); + spin_lock_init(&uhci->qh_remove_lock); + INIT_LIST_HEAD(&uhci->qh_remove_list); + + spin_lock_init(&uhci->urb_remove_lock); + INIT_LIST_HEAD(&uhci->urb_remove_list); - spin_lock_init(&uhci->framelist_lock); nested_init(&uhci->urblist_lock); - nested_init(&uhci->irqlist_lock); + INIT_LIST_HEAD(&uhci->urb_list); - uhci->fsbr = 0; + spin_lock_init(&uhci->framelist_lock); /* We need exactly one page (per UHCI specs), how convenient */ /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */ @@ -1870,8 +1840,12 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH; uhci->skel_bulk_qh.element = UHCI_PTR_TERM; + /* This dummy TD is to work around a bug in Intel PIIX controllers */ + uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); + uhci->skel_term_td.link = UHCI_PTR_TERM; + uhci->skel_term_qh.link = UHCI_PTR_TERM; - uhci->skel_term_qh.element = UHCI_PTR_TERM; + uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td); /* * Fill the frame list: make all entries point to @@ -2022,23 +1996,24 @@ static int found_uhci(struct pci_dev *dev) dev->resource[i].end - dev->resource[i].start + 1; /* IO address? */ - if (!(dev->resource[i].flags & 1)) + if (!(dev->resource[i].flags & IORESOURCE_IO)) continue; /* Is it already in use? */ if (check_region(io_addr, io_size)) break; - /* disable legacy emulation */ - pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); - - pci_enable_device(dev); - if (!dev->irq) { err("found UHCI device with no IRQ assigned. check BIOS settings!"); continue; } + /* disable legacy emulation */ + pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + + if (pci_enable_device(dev) < 0) + continue; + return setup_uhci(dev, dev->irq, io_addr, io_size); } @@ -2081,6 +2056,12 @@ int uhci_init(void) if (!uhci_qh_cachep) goto qh_failed; + uhci_up_cachep = kmem_cache_create("uhci_urb_priv", + sizeof(struct urb_priv), 0, 0, NULL, NULL); + + if (!uhci_up_cachep) + goto up_failed; + retval = -ENODEV; dev = NULL; for (;;) { @@ -2105,6 +2086,10 @@ int uhci_init(void) return 0; init_failed: + if (kmem_cache_destroy(uhci_up_cachep)) + printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); + +up_failed: if (kmem_cache_destroy(uhci_qh_cachep)) printk(KERN_INFO "uhci: not all QH's were freed\n"); @@ -2118,13 +2103,13 @@ td_failed: void uhci_cleanup(void) { - struct list_head *next, *tmp, *head = &uhci_list; + struct list_head *tmp, *head = &uhci_list; tmp = head->next; while (tmp != head) { struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list); - next = tmp->next; + tmp = tmp->next; list_del(&uhci->uhci_list); INIT_LIST_HEAD(&uhci->uhci_list); @@ -2137,11 +2122,14 @@ void uhci_cleanup(void) reset_hc(uhci); release_region(uhci->io_addr, uhci->io_size); - release_uhci(uhci); + uhci_free_pending_qhs(uhci); - tmp = next; + release_uhci(uhci); } + if (kmem_cache_destroy(uhci_up_cachep)) + printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); + if (kmem_cache_destroy(uhci_qh_cachep)) printk(KERN_INFO "uhci: not all QH's were freed\n"); diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h index 88891ea895d8..e7b5a7aac917 100644 --- a/drivers/usb/uhci.h +++ b/drivers/usb/uhci.h @@ -106,11 +106,12 @@ struct uhci_qh { __u32 element; /* Queue element pointer */ /* Software fields */ - struct uhci_qh *prevqh, *nextqh; /* Previous and next TD in queue */ + /* Can't use list_head since we want a specific order */ + struct uhci_qh *prevqh, *nextqh; struct usb_device *dev; /* The owning device */ - struct list_head list; + struct list_head remove_list; } __attribute__((aligned(16))); struct uhci_framelist { @@ -184,10 +185,10 @@ struct uhci_td { struct usb_device *dev; struct urb *urb; /* URB this TD belongs to */ - struct uhci_td *next; /* List of chained TD's for an URB */ - - struct list_head irq_list; /* Active interrupt list.. */ - struct list_head list; + /* We can't use list_head since we need a specific order */ + struct ut_list { + struct uhci_td *prev, *next; + } list; } __attribute__((aligned(16))); /* @@ -233,7 +234,7 @@ struct uhci_td { * labels (below) are only signficant to the root hub's QH's */ -#define UHCI_NUM_SKELTD 9 +#define UHCI_NUM_SKELTD 10 #define skel_int1_td skeltd[0] #define skel_int2_td skeltd[1] #define skel_int4_td skeltd[2] @@ -243,6 +244,7 @@ struct uhci_td { #define skel_int64_td skeltd[6] #define skel_int128_td skeltd[7] #define skel_int256_td skeltd[8] +#define skel_term_td skeltd[9] /* To work around PIIX UHCI bug */ #define UHCI_NUM_SKELQH 4 #define skel_ls_control_qh skelqh[0] @@ -306,6 +308,7 @@ struct virt_root_hub { * a subset of what the full implementation needs. */ struct uhci { + /* Grabbed from PCI */ int irq; unsigned int io_addr; unsigned int io_size; @@ -317,25 +320,32 @@ struct uhci { struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */ struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ + spinlock_t framelist_lock; struct uhci_framelist *fl; /* Frame list */ + int fsbr; /* Full speed bandwidth reclamation */ + + spinlock_t qh_remove_lock; + struct list_head qh_remove_list; - struct s_nested_lock irqlist_lock; - struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ + spinlock_t urb_remove_lock; + struct list_head urb_remove_list; struct s_nested_lock urblist_lock; struct list_head urb_list; - spinlock_t framelist_lock; - - int fsbr; /* Full speed bandwidth reclamation */ - struct virt_root_hub rh; /* private data of the virtual root hub */ }; struct urb_priv { struct uhci_qh *qh; /* QH for this URB */ - struct uhci_td *begin; - struct uhci_td *end; + + int fsbr; + + unsigned long inserttime; /* In jiffies */ + + struct up_list { + struct uhci_td *begin, *end; + } list; }; /* ------------------------------------------------------------------------- diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 9bc13642063e..bc6a842e574f 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -1675,20 +1675,24 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) static int hc_start_ohci (struct pci_dev * dev) { - u32 cmd; + unsigned long mem_base; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - unsigned long mem_base = dev->resource[0].start; + mem_base = dev->resource[0].start; + if (pci_enable_device(dev) < 0) + return -ENODEV; #else - unsigned long mem_base = dev->base_address[0]; + u16 cmd; + + mem_base = dev->base_address[0]; if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV; mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Some Mac firmware will switch memory response off */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); #endif - /* Some Mac firmware will switch memory response off */ - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY); - pci_write_config_dword(dev, PCI_COMMAND, cmd); - pci_set_master (dev); mem_base = (unsigned long) ioremap_nocache (mem_base, 4096); diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index 1b72efd92621..51b58ea72a24 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -2408,7 +2408,7 @@ _static int __init start_uhci (struct pci_dev *dev) unsigned int io_addr = dev->resource[i].start; unsigned int io_size = dev->resource[i].end - dev->resource[i].start + 1; - if (!(dev->resource[i].flags & 1)) + if (!(dev->resource[i].flags & IORESOURCE_IO)) continue; #else unsigned int io_addr = dev->base_address[i]; @@ -2464,7 +2464,8 @@ int __init uhci_init (void) continue; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8) - pci_enable_device (dev); + if (pci_enable_device (dev) < 0) + continue; #endif if(!dev->irq) { diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 6b9eba17a5d2..4197650b4e23 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -475,30 +475,34 @@ void usb_inc_dev_use(struct usb_device *dev) * New USB Core Functions * -------------------------------------------------------------------------------------*/ -urb_t* usb_alloc_urb(int iso_packets) +urb_t *usb_alloc_urb(int iso_packets) { urb_t *urb; - urb=(urb_t*)kmalloc(sizeof(urb_t) + iso_packets*sizeof(iso_packet_descriptor_t), + + urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (!urb) - { + if (!urb) { err("alloc_urb: kmalloc failed"); - return 0; + return NULL; } - memset(urb,0,sizeof(urb_t)); + + memset(urb, 0, sizeof(*urb)); + + spin_lock_init(&urb->lock); + return urb; } /*-------------------------------------------------------------------*/ void usb_free_urb(urb_t* urb) { - if(urb) + if (urb) kfree(urb); } /*-------------------------------------------------------------------*/ int usb_submit_urb(urb_t *urb) { - if(urb && urb->dev) + if (urb && urb->dev) return urb->dev->bus->op->submit_urb(urb); else return -1; @@ -507,7 +511,7 @@ int usb_submit_urb(urb_t *urb) /*-------------------------------------------------------------------*/ int usb_unlink_urb(urb_t *urb) { - if(urb && urb->dev) + if (urb && urb->dev) return urb->dev->bus->op->unlink_urb(urb); else return -1; @@ -537,10 +541,10 @@ static void usb_api_blocking_completion(urb_t *urb) *-------------------------------------------------------------------*/ static void usb_api_async_completion(urb_t *urb) { - api_wrapper_data *awd=(api_wrapper_data*)urb->context; + api_wrapper_data *awd = (api_wrapper_data *)urb->context; if (awd->handler) - awd->handler(urb->status,urb->transfer_buffer,urb->actual_length,awd->stuff); + awd->handler(urb->status, urb->transfer_buffer, urb->actual_length, awd->stuff); } /*-------------------------------------------------------------------* @@ -555,13 +559,13 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length) api_wrapper_data awd; int status; - awd.wakeup=&wqh; - awd.handler=0; + awd.wakeup = &wqh; + awd.handler = 0; init_waitqueue_head(&wqh); current->state = TASK_INTERRUPTIBLE; add_wait_queue(&wqh, &wait); - urb->context=&awd; - status=usb_submit_urb(urb); + urb->context = &awd; + status = usb_submit_urb(urb); if (status) { // something went wrong usb_free_urb(urb); @@ -581,13 +585,12 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length) // timeout printk("usb_control/bulk_msg: timeout\n"); usb_unlink_urb(urb); // remove urb safely - status=-ETIMEDOUT; - } - else - status=urb->status; + status = -ETIMEDOUT; + } else + status = urb->status; if (actual_length) - *actual_length=urb->actual_length; + *actual_length = urb->actual_length; usb_free_urb(urb); return status; @@ -602,20 +605,21 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, int retv; int length; - urb=usb_alloc_urb(0); + urb = usb_alloc_urb(0); if (!urb) return -ENOMEM; FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, /* build urb */ (usb_complete_t)usb_api_blocking_completion,0); - retv=usb_start_wait_urb(urb,timeout, &length); + retv = usb_start_wait_urb(urb, timeout, &length); if (retv < 0) return retv; else return length; } + /*-------------------------------------------------------------------*/ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout) @@ -623,7 +627,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL); int ret; - if(!dr) + if (!dr) return -ENOMEM; dr->requesttype = requesttype; @@ -634,7 +638,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u //dbg("usb_control_msg"); - ret=usb_internal_control_msg(dev, pipe, dr, data, size, timeout); + ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); kfree(dr); diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index d1381c10743c..69f0189aa4a6 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -364,17 +364,16 @@ struct usb_driver { */ typedef int (*usb_device_irq)(int, void *, int, void *); -/* -------------------------------------------------------------------------------------* - * New USB Structures * - * -------------------------------------------------------------------------------------*/ +/* --------------------------------------------------------------------------* + * New USB Structures * + * --------------------------------------------------------------------------*/ +#define USB_DISABLE_SPD 1 +#define USB_ISO_ASAP 2 +#define USB_URB_EARLY_COMPLETE 4 +#define USB_ASYNC_UNLINK 8 -#define USB_DISABLE_SPD 1 -#define USB_ISO_ASAP 2 -#define USB_URB_EARLY_COMPLETE 4 - -typedef struct -{ +typedef struct { unsigned int offset; unsigned int length; // expected length unsigned int actual_length; @@ -386,9 +385,10 @@ typedef void (*usb_complete_t)(struct urb *); typedef struct urb { + spinlock_t lock; // lock for the URB void *hcpriv; // private data for host controller struct list_head urb_list; // list pointer to all active urbs - struct urb* next; // pointer to next URB + struct urb *next; // pointer to next URB struct usb_device *dev; // pointer to associated USB device unsigned int pipe; // pipe information int status; // returned status @@ -396,7 +396,7 @@ typedef struct urb void *transfer_buffer; // associated data buffer int transfer_buffer_length; // data buffer length int actual_length; // actual data buffer length - unsigned char* setup_packet; // setup packet (control only) + unsigned char *setup_packet; // setup packet (control only) // int start_frame; // start frame (iso/irq only) int number_of_packets; // number of packets in this request (iso/irq only) @@ -411,6 +411,7 @@ typedef struct urb #define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \ do {\ + spin_lock_init(&(a)->lock);\ (a)->dev=aa;\ (a)->pipe=b;\ (a)->setup_packet=c;\ @@ -422,6 +423,7 @@ typedef struct urb #define FILL_BULK_URB(a,aa,b,c,d,e,f) \ do {\ + spin_lock_init(&(a)->lock);\ (a)->dev=aa;\ (a)->pipe=b;\ (a)->transfer_buffer=c;\ @@ -432,6 +434,7 @@ typedef struct urb #define FILL_INT_URB(a,aa,b,c,d,e,f,g) \ do {\ + spin_lock_init(&(a)->lock);\ (a)->dev=aa;\ (a)->pipe=b;\ (a)->transfer_buffer=c;\ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index ac0ff6e1e539..36f2c8855d62 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -279,6 +279,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define __cli() __asm__ __volatile__("cli": : :"memory") #define __sti() __asm__ __volatile__("sti": : :"memory") +/* used in the idle loop; sti takes one instruction cycle to complete */ +#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") diff --git a/include/linux/fb.h b/include/linux/fb.h index 4a345df690b6..43bf69f866e5 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -295,6 +295,7 @@ struct fb_info { struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ struct fb_monspecs monspecs; /* Current Monitor specs */ + struct fb_cmap cmap; /* Current cmap */ struct fb_ops *fbops; char *screen_base; /* Virtual address */ struct display *disp; /* initial display variable */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ebe4d6865ce8..5435fd57d2cf 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1056,6 +1056,9 @@ #define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 + #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_DEVICE_ID_SYMPHONY_101 0x0001 diff --git a/ipc/shm.c b/ipc/shm.c index 21d4257b5931..a36abec5ad94 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -216,6 +216,7 @@ void __init shm_init (void) #endif zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, 1); shm_unlock(zero_id); + INIT_LIST_HEAD(&zshmid_kernel.zero_list); zdent = d_alloc_root(get_empty_inode()); return; } @@ -1531,10 +1532,9 @@ done: #define VMA_TO_SHP(vma) ((vma)->vm_file->private_data) -static LIST_HEAD(zmap_list); static spinlock_t zmap_list_lock = SPIN_LOCK_UNLOCKED; static unsigned long zswap_idx = 0; /* next to swap */ -static struct shmid_kernel *zswap_shp = (struct shmid_kernel *)&zmap_list; +static struct shmid_kernel *zswap_shp = &zshmid_kernel; static int zshm_rss; static struct vm_operations_struct shmzero_vm_ops = { @@ -1607,7 +1607,7 @@ int map_zero_setup(struct vm_area_struct *vma) vma->vm_ops = &shmzero_vm_ops; shmzero_open(vma); spin_lock(&zmap_list_lock); - list_add(&shp->zero_list, &zmap_list); + list_add(&shp->zero_list, &zshmid_kernel.zero_list); spin_unlock(&zmap_list_lock); return 0; } @@ -1668,8 +1668,8 @@ static void zmap_unuse(swp_entry_t entry, struct page *page) spin_lock(&zmap_list_lock); shm_lock(zero_id); - for (shp = list_entry(zmap_list.next, struct shmid_kernel, zero_list); - shp != (struct shmid_kernel *)&zmap_list; + for (shp = list_entry(zshmid_kernel.zero_list.next, struct shmid_kernel, + zero_list); shp != &zshmid_kernel; shp = list_entry(shp->zero_list.next, struct shmid_kernel, zero_list)) { if (shm_unuse_core(shp, entry, page)) @@ -1697,10 +1697,10 @@ next: spin_lock(&zmap_list_lock); shm_lock(zero_id); - if (zmap_list.next == 0) + if (zshmid_kernel.zero_list.next == 0) goto failed; next_id: - if (zswap_shp == (struct shmid_kernel *)&zmap_list) { + if (zswap_shp == &zshmid_kernel) { if (loop) { failed: shm_unlock(zero_id); @@ -1708,8 +1708,8 @@ failed: __swap_free(swap_entry, 2); return; } - zswap_shp = list_entry(zmap_list.next, struct shmid_kernel, - zero_list); + zswap_shp = list_entry(zshmid_kernel.zero_list.next, + struct shmid_kernel, zero_list); zswap_idx = 0; loop = 1; }