mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
This commit is contained in:
commit
d2149b5423
@ -46,8 +46,9 @@ USB-specific:
|
||||
|
||||
-EMSGSIZE (a) endpoint maxpacket size is zero; it is not usable
|
||||
in the current interface altsetting.
|
||||
(b) ISO packet is biger than endpoint maxpacket
|
||||
(c) requested data transfer size is invalid (negative)
|
||||
(b) ISO packet is larger than the endpoint maxpacket.
|
||||
(c) requested data transfer length is invalid: negative
|
||||
or too large for the host controller.
|
||||
|
||||
-ENOSPC This request would overcommit the usb bandwidth reserved
|
||||
for periodic transfers (interrupt, isochronous).
|
||||
|
@ -432,7 +432,10 @@ int drm_addctx(struct inode *inode, struct file *filp,
|
||||
|
||||
if (ctx.handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_ctor)
|
||||
dev->driver->context_ctor(dev, ctx.handle);
|
||||
if (!dev->driver->context_ctor(dev, ctx.handle)) {
|
||||
DRM_DEBUG( "Running out of ctxs or memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST);
|
||||
|
@ -193,6 +193,7 @@ static const u8 W83792D_REG_LEVELS[3][4] = {
|
||||
0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */
|
||||
};
|
||||
|
||||
#define W83792D_REG_GPIO_EN 0x1A
|
||||
#define W83792D_REG_CONFIG 0x40
|
||||
#define W83792D_REG_VID_FANDIV 0x47
|
||||
#define W83792D_REG_CHIPID 0x49
|
||||
@ -257,7 +258,7 @@ DIV_TO_REG(long val)
|
||||
{
|
||||
int i;
|
||||
val = SENSORS_LIMIT(val, 1, 128) >> 1;
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (val == 0)
|
||||
break;
|
||||
val >>= 1;
|
||||
@ -1282,8 +1283,8 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
w83792d_init_client(new_client);
|
||||
|
||||
/* A few vars need to be filled upon startup */
|
||||
for (i = 1; i <= 7; i++) {
|
||||
data->fan_min[i - 1] = w83792d_read_value(new_client,
|
||||
for (i = 0; i < 7; i++) {
|
||||
data->fan_min[i] = w83792d_read_value(new_client,
|
||||
W83792D_REG_FAN_MIN[i]);
|
||||
}
|
||||
|
||||
@ -1306,9 +1307,19 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
/* Read GPIO enable register to check if pins for fan 4,5 are used as
|
||||
GPIO */
|
||||
val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN);
|
||||
if (!(val1 & 0x40))
|
||||
device_create_file_fan(new_client, 4);
|
||||
if (!(val1 & 0x20))
|
||||
device_create_file_fan(new_client, 5);
|
||||
|
||||
val1 = w83792d_read_value(new_client, W83792D_REG_PIN);
|
||||
if (val1 & 0x40)
|
||||
device_create_file_fan(new_client, 6);
|
||||
if (val1 & 0x04)
|
||||
device_create_file_fan(new_client, 7);
|
||||
|
||||
device_create_file_temp1(new_client); /* Temp1 */
|
||||
|
@ -787,6 +787,9 @@ static const struct usb_device_id cxacru_usb_ids[] = {
|
||||
{ /* V = Conexant P = ADSL modem (Hasbani project) */
|
||||
USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00
|
||||
},
|
||||
{ /* V = Conexant P = ADSL modem (Well PTI-800 */
|
||||
USB_DEVICE(0x0572, 0xcb02), .driver_info = (unsigned long) &cxacru_cb00
|
||||
},
|
||||
{ /* V = Conexant P = ADSL modem */
|
||||
USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
|
||||
},
|
||||
|
@ -219,6 +219,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
synchronize_irq(dev->irq);
|
||||
|
||||
/* FIXME until the generic PM interfaces change a lot more, this
|
||||
* can't use PCI D1 and D2 states. For example, the confusion
|
||||
@ -392,7 +393,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
|
||||
|
||||
dev->dev.power.power_state = PMSG_ON;
|
||||
|
||||
hcd->saw_irq = 0;
|
||||
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
|
||||
if (hcd->driver->resume) {
|
||||
retval = hcd->driver->resume(hcd);
|
||||
|
@ -1315,11 +1315,12 @@ static int hcd_unlink_urb (struct urb *urb, int status)
|
||||
* finish unlinking the initial failed usb_set_address()
|
||||
* or device descriptor fetch.
|
||||
*/
|
||||
if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) {
|
||||
if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
|
||||
&& hcd->self.root_hub != urb->dev) {
|
||||
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
|
||||
"Controller is probably using the wrong IRQ."
|
||||
"\n");
|
||||
hcd->saw_irq = 1;
|
||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
|
||||
struct usb_hcd *hcd = __hcd;
|
||||
int start = hcd->state;
|
||||
|
||||
if (start == HC_STATE_HALT)
|
||||
if (unlikely(start == HC_STATE_HALT ||
|
||||
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
|
||||
return IRQ_NONE;
|
||||
if (hcd->driver->irq (hcd, r) == IRQ_NONE)
|
||||
return IRQ_NONE;
|
||||
|
||||
hcd->saw_irq = 1;
|
||||
if (hcd->state == HC_STATE_HALT)
|
||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
|
||||
if (unlikely(hcd->state == HC_STATE_HALT))
|
||||
usb_hc_died (hcd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
|
||||
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* till now HC has been in an indeterminate state ... */
|
||||
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
|
||||
dev_err(hcd->self.controller, "can't reset\n");
|
||||
|
@ -72,7 +72,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
|
||||
* hardware info/state
|
||||
*/
|
||||
const struct hc_driver *driver; /* hw-specific hooks */
|
||||
unsigned saw_irq : 1;
|
||||
|
||||
/* Flags that need to be manipulated atomically */
|
||||
unsigned long flags;
|
||||
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
|
||||
#define HCD_FLAG_SAW_IRQ 0x00000002
|
||||
|
||||
unsigned can_wakeup:1; /* hw supports wakeup? */
|
||||
unsigned remote_wakeup:1;/* sw should use wakeup? */
|
||||
unsigned rh_registered:1;/* is root hub registered? */
|
||||
|
@ -121,8 +121,8 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called by khubd or root hub (re)init threads; leaves HC in halt state */
|
||||
static int ehci_pci_reset(struct usb_hcd *hcd)
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
@ -141,6 +141,11 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* NOTE: only the parts below this line are PCI-specific */
|
||||
|
||||
switch (pdev->vendor) {
|
||||
@ -154,7 +159,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
|
||||
/* AMD8111 EHCI doesn't work, according to AMD errata */
|
||||
if (pdev->device == 0x7463) {
|
||||
ehci_info(ehci, "ignoring AMD8111 (errata)\n");
|
||||
return -EIO;
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
@ -207,9 +213,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
|
||||
/* REVISIT: per-port wake capability (PCI 0x62) currently unused */
|
||||
|
||||
retval = ehci_pci_reinit(ehci, pdev);
|
||||
|
||||
/* finish init */
|
||||
return ehci_init(hcd);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -228,14 +233,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
|
||||
static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible, bail out if RH has been resumed. Use
|
||||
* the spinlock to properly synchronize with possible pending
|
||||
* RH suspend or resume activity.
|
||||
*
|
||||
* This is still racy as hcd->state is manipulated outside of
|
||||
* any locks =P But that will be a different fix.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
rc = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
writel (0, &ehci->regs->intr_enable);
|
||||
(void)readl(&ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
bail:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
// ... we'd only use it to handle clock skew
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
@ -251,6 +278,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* If CF is clear, we lost PCI Vaux power and need to restart. */
|
||||
if (readl(&ehci->regs->configured_flag) != FLAG_CF)
|
||||
goto restart;
|
||||
@ -319,7 +349,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_pci_reset,
|
||||
.reset = ehci_pci_setup,
|
||||
.start = ehci_run,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ehci_pci_suspend,
|
||||
|
@ -912,6 +912,7 @@ submit_async (
|
||||
int epnum;
|
||||
unsigned long flags;
|
||||
struct ehci_qh *qh = NULL;
|
||||
int rc = 0;
|
||||
|
||||
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
|
||||
epnum = ep->desc.bEndpointAddress;
|
||||
@ -926,21 +927,28 @@ submit_async (
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
|
||||
&ehci_to_hcd(ehci)->flags))) {
|
||||
rc = -ESHUTDOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
|
||||
if (unlikely(qh == NULL)) {
|
||||
rc = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Control/bulk operations through TTs don't need scheduling,
|
||||
* the HC and TT handle it when the TT has a buffer ready.
|
||||
*/
|
||||
if (likely (qh != NULL)) {
|
||||
if (likely (qh->qh_state == QH_STATE_IDLE))
|
||||
qh_link_async (ehci, qh_get (qh));
|
||||
}
|
||||
done:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
if (unlikely (qh == NULL)) {
|
||||
if (unlikely (qh == NULL))
|
||||
qtd_list_free (ehci, urb, qtd_list);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -602,6 +602,12 @@ static int intr_submit (
|
||||
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
|
||||
&ehci_to_hcd(ehci)->flags))) {
|
||||
status = -ESHUTDOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* get qh and force any scheduling errors */
|
||||
INIT_LIST_HEAD (&empty);
|
||||
qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
|
||||
@ -1456,6 +1462,10 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
|
||||
|
||||
/* schedule ... need to lock */
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
|
||||
&ehci_to_hcd(ehci)->flags)))
|
||||
status = -ESHUTDOWN;
|
||||
else
|
||||
status = iso_stream_schedule (ehci, urb, stream);
|
||||
if (likely (status == 0))
|
||||
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
|
||||
@ -1815,6 +1825,10 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
|
||||
|
||||
/* schedule ... need to lock */
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
|
||||
&ehci_to_hcd(ehci)->flags)))
|
||||
status = -ESHUTDOWN;
|
||||
else
|
||||
status = iso_stream_schedule (ehci, urb, stream);
|
||||
if (status == 0)
|
||||
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
|
||||
|
@ -115,7 +115,7 @@
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
// #define OHCI_VERBOSE_DEBUG /* not always helpful */
|
||||
#undef OHCI_VERBOSE_DEBUG /* not always helpful */
|
||||
|
||||
/* For initializing controller (mask in an HCFS mode too) */
|
||||
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
|
||||
@ -253,6 +253,10 @@ static int ohci_urb_enqueue (
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
|
||||
/* don't submit to a dead HC */
|
||||
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
|
||||
retval = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
if (!HC_IS_RUNNING(hcd->state)) {
|
||||
retval = -ENODEV;
|
||||
goto fail;
|
||||
|
@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
|
||||
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
|
||||
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
||||
case OHCI_USB_RESUME:
|
||||
@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
u32 temp, enables;
|
||||
int status = -EINPROGRESS;
|
||||
unsigned long flags;
|
||||
|
||||
if (time_before (jiffies, ohci->next_statechange))
|
||||
msleep(5);
|
||||
|
||||
spin_lock_irq (&ohci->lock);
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
|
||||
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
|
||||
|
||||
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
|
||||
@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
|
||||
ohci_dbg (ohci, "lost power\n");
|
||||
status = -EBUSY;
|
||||
}
|
||||
spin_unlock_irq (&ohci->lock);
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
if (status == -EBUSY) {
|
||||
(void) ohci_init (ohci);
|
||||
return ohci_restart (ohci);
|
||||
@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||
/* handle autosuspended root: finish resuming before
|
||||
* letting khubd or root hub timer see state changes.
|
||||
*/
|
||||
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
|
||||
|| !HC_IS_RUNNING(hcd->state)) {
|
||||
if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
|
||||
|| !HC_IS_RUNNING(hcd->state))) {
|
||||
can_suspend = 0;
|
||||
goto done;
|
||||
}
|
||||
@ -508,6 +521,9 @@ static int ohci_hub_control (
|
||||
u32 temp;
|
||||
int retval = 0;
|
||||
|
||||
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
switch (typeReq) {
|
||||
case ClearHubFeature:
|
||||
switch (wValue) {
|
||||
|
@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd)
|
||||
|
||||
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||
{
|
||||
/* root hub was already suspended */
|
||||
return 0;
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible, bail out if RH has been resumed. Use
|
||||
* the spinlock to properly synchronize with possible pending
|
||||
* RH suspend or resume activity.
|
||||
*
|
||||
* This is still racy as hcd->state is manipulated outside of
|
||||
* any locks =P But that will be a different fix.
|
||||
*/
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
rc = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
bail:
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int ohci_pci_resume (struct usb_hcd *hcd)
|
||||
{
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
@ -717,6 +717,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
* at the source, so we must turn off PIRQ.
|
||||
*/
|
||||
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
uhci->hc_inaccessible = 1;
|
||||
hcd->poll_rh = 0;
|
||||
|
||||
@ -733,6 +734,11 @@ static int uhci_resume(struct usb_hcd *hcd)
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
|
||||
|
||||
/* We aren't in D3 state anymore, we do that even if dead as I
|
||||
* really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0
|
||||
*/
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
|
||||
return 0;
|
||||
spin_lock_irq(&uhci->lock);
|
||||
|
@ -956,6 +956,7 @@ struct page *vmalloc_to_page(void *addr);
|
||||
unsigned long vmalloc_to_pfn(void *addr);
|
||||
int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
|
||||
unsigned long pfn, unsigned long size, pgprot_t);
|
||||
int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
|
||||
|
||||
struct page *follow_page(struct vm_area_struct *, unsigned long address,
|
||||
unsigned int foll_flags);
|
||||
|
36
mm/memory.c
36
mm/memory.c
@ -1172,7 +1172,7 @@ static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *pa
|
||||
spinlock_t *ptl;
|
||||
|
||||
retval = -EINVAL;
|
||||
if (PageAnon(page) || !PageReserved(page))
|
||||
if (PageAnon(page))
|
||||
goto out;
|
||||
retval = -ENOMEM;
|
||||
flush_dcache_page(page);
|
||||
@ -1196,6 +1196,35 @@ out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This allows drivers to insert individual pages they've allocated
|
||||
* into a user vma.
|
||||
*
|
||||
* The page has to be a nice clean _individual_ kernel allocation.
|
||||
* If you allocate a compound page, you need to have marked it as
|
||||
* such (__GFP_COMP), or manually just split the page up yourself
|
||||
* (which is mainly an issue of doing "set_page_count(page, 1)" for
|
||||
* each sub-page, and then freeing them one by one when you free
|
||||
* them rather than freeing it as a compound page).
|
||||
*
|
||||
* NOTE! Traditionally this was done with "remap_pfn_range()" which
|
||||
* took an arbitrary page protection parameter. This doesn't allow
|
||||
* that. Your vma protection will have to be set up correctly, which
|
||||
* means that if you want a shared writable mapping, you'd better
|
||||
* ask for a shared writable mapping!
|
||||
*
|
||||
* The page does not need to be reserved.
|
||||
*/
|
||||
int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page)
|
||||
{
|
||||
if (addr < vma->vm_start || addr >= vma->vm_end)
|
||||
return -EFAULT;
|
||||
if (!page_count(page))
|
||||
return -EINVAL;
|
||||
return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vm_insert_page);
|
||||
|
||||
/*
|
||||
* Somebody does a pfn remapping that doesn't actually work as a vma.
|
||||
*
|
||||
@ -1225,8 +1254,11 @@ static int incomplete_pfn_remap(struct vm_area_struct *vma,
|
||||
if (!pfn_valid(pfn))
|
||||
return -EINVAL;
|
||||
|
||||
retval = 0;
|
||||
page = pfn_to_page(pfn);
|
||||
if (!PageReserved(page))
|
||||
return -EINVAL;
|
||||
|
||||
retval = 0;
|
||||
while (start < end) {
|
||||
retval = insert_page(vma->vm_mm, start, page, prot);
|
||||
if (retval < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user