diff --git a/patches.rpmify/makefile-after_link.patch b/0001-kbuild-AFTER_LINK.patch similarity index 62% rename from patches.rpmify/makefile-after_link.patch rename to 0001-kbuild-AFTER_LINK.patch index 70dd619..224316b 100644 --- a/patches.rpmify/makefile-after_link.patch +++ b/0001-kbuild-AFTER_LINK.patch @@ -1,4 +1,4 @@ -From 649d991ca7737dd227f2a1ca4f30247daf6a7b4b Mon Sep 17 00:00:00 2001 +From ca7615cf7944d9b233b7cfad8f0465b4dfc87fba Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 6 Oct 2008 23:03:03 -0700 Subject: [PATCH] kbuild: AFTER_LINK @@ -11,20 +11,16 @@ Upstream-status: ?? Signed-off-by: Roland McGrath --- - arch/arm64/kernel/vdso/Makefile | 3 ++- - arch/powerpc/kernel/vdso32/Makefile | 3 ++- - arch/powerpc/kernel/vdso64/Makefile | 3 ++- - arch/s390/kernel/vdso32/Makefile | 3 ++- - arch/s390/kernel/vdso64/Makefile | 3 ++- - arch/x86/entry/vdso/Makefile | 5 +++-- - scripts/link-vmlinux.sh | 4 ++++ - 7 files changed, 17 insertions(+), 7 deletions(-) + arch/arm64/kernel/vdso/Makefile | 3 ++- + arch/x86/entry/vdso/Makefile | 5 +++-- + scripts/link-vmlinux.sh | 4 ++++ + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile -index 62c84f7..f44236a 100644 +index b215c712d897..e18cd2a3ea53 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile -@@ -54,7 +54,8 @@ $(obj-vdso): %.o: %.S FORCE +@@ -55,7 +55,8 @@ $(obj-vdso): %.o: %.S FORCE # Actual build commands quiet_cmd_vdsold = VDSOL $@ @@ -35,26 +31,26 @@ index 62c84f7..f44236a 100644 cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile -index d540966..eeb47b6 100644 +index 141d415a8c80..771cc7e399dc 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -167,8 +167,9 @@ $(obj)/vdso32.so.dbg: FORCE \ quiet_cmd_vdso = VDSO $@ - cmd_vdso = $(CC) -nostdlib -o $@ \ + cmd_vdso = $(LD) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ -- -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ +- -T $(filter %.lds,$^) $(filter %.o,$^) && \ - sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' -+ -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) \ ++ -T $(filter %.lds,$^) $(filter %.o,$^) \ + $(if $(AFTER_LINK),; $(AFTER_LINK)) && \ + sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' - VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=both) \ - $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS) + VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \ + $(call ld-option, --build-id) -Bsymbolic diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index f742c65..526eee4 100755 +index c8cf45362bd6..ee9c4d8e1ddf 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh -@@ -111,6 +111,10 @@ vmlinux_link() +@@ -112,6 +112,10 @@ vmlinux_link() -lutil -lrt -lpthread rm -f linux fi @@ -66,5 +62,5 @@ index f742c65..526eee4 100755 -- -2.7.4 +2.17.1 diff --git a/patches.xen/xen-netfront-detach-crash.patch b/0002-xen-netfront-detach-crash.patch similarity index 69% rename from patches.xen/xen-netfront-detach-crash.patch rename to 0002-xen-netfront-detach-crash.patch index 6492702..81838be 100644 --- a/patches.xen/xen-netfront-detach-crash.patch +++ b/0002-xen-netfront-detach-crash.patch @@ -1,3 +1,9 @@ +From 702adf2c9c1536d5cb10b4be1340ba52654a05b5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= + +Date: Thu, 6 Sep 2018 15:09:44 +0200 +Subject: [PATCH] xen-netfront-detach-crash + When it get to free_page(queue->grant_tx_page[i]), the use counter on this page is already 0, which cause a crash. Not sure if this is the proper fix (according to git log this may introduce some memory leak), but at least it @@ -5,12 +11,15 @@ prevent the crash. Details in this thread: http://xen.markmail.org/thread/pw5edbtqienjx4q5 +--- + drivers/net/xen-netfront.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index f821a97..a5efbb0 100644 +index f17f602e6171..61298526aee3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c -@@ -1065,9 +1069,10 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue) +@@ -1140,9 +1140,10 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue) skb = queue->tx_skbs[i].skb; get_page(queue->grant_tx_page[i]); @@ -24,3 +33,6 @@ index f821a97..a5efbb0 100644 queue->grant_tx_page[i] = NULL; queue->grant_tx_ref[i] = GRANT_INVALID_REF; add_id_to_freelist(&queue->tx_skb_freelist, queue->tx_skbs, i); +-- +2.17.1 + diff --git a/patches.xen/0001-mce-hide-EBUSY-initialization-error-on-Xen.patch b/0003-mce-hide-EBUSY-initialization-error-on-Xen.patch similarity index 86% rename from patches.xen/0001-mce-hide-EBUSY-initialization-error-on-Xen.patch rename to 0003-mce-hide-EBUSY-initialization-error-on-Xen.patch index b2160f6..d1d52e3 100644 --- a/patches.xen/0001-mce-hide-EBUSY-initialization-error-on-Xen.patch +++ b/0003-mce-hide-EBUSY-initialization-error-on-Xen.patch @@ -1,4 +1,4 @@ -From 26df8496fdb73e9ae2bdf9d1684484196260a8f3 Mon Sep 17 00:00:00 2001 +From 2d71f4d315dfcaaa9e4c1e3693e391f9d2b0a8b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Tue, 5 Jan 2016 02:44:04 +0100 @@ -6,8 +6,6 @@ Subject: [PATCH] mce: hide EBUSY initialization error on Xen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Organization: Invisible Things Lab -Cc: Marek Marczykowski-Górecki In case of Xen, the device is already registered by xen mcelog (in xen_late_init_mcelog), so fail here is expected. Note that @@ -41,12 +39,12 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 9 insertions(+) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c -index c5b0d56..69b0b4b 100644 +index 953b3ce92dcc..e0bb9b52d8d1 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c -@@ -53,6 +53,10 @@ +@@ -52,6 +52,10 @@ + #include #include - #include +#ifdef CONFIG_XEN_MCE_LOG +#include @@ -55,7 +53,7 @@ index c5b0d56..69b0b4b 100644 #include "mce-internal.h" static DEFINE_MUTEX(mce_log_mutex); -@@ -2355,6 +2359,11 @@ static __init int mcheck_init_device(void) +@@ -2395,6 +2399,11 @@ static __init int mcheck_init_device(void) free_cpumask_var(mce_device_initialized); err_out: @@ -68,5 +66,5 @@ index c5b0d56..69b0b4b 100644 return err; -- -2.1.0 +2.17.1 diff --git a/0004-Log-error-code-of-EVTCHNOP_bind_pirq-failure.patch b/0004-Log-error-code-of-EVTCHNOP_bind_pirq-failure.patch new file mode 100644 index 0000000..356abaf --- /dev/null +++ b/0004-Log-error-code-of-EVTCHNOP_bind_pirq-failure.patch @@ -0,0 +1,27 @@ +From 84160fa4557bf07017e35180d53abe4ea6ef7b14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= + +Date: Sat, 30 Jan 2016 01:53:26 +0100 +Subject: [PATCH] Log error code of EVTCHNOP_bind_pirq failure + +Ease debugging of PCI passthrough problems. +--- + drivers/xen/events/events_base.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c +index e6c1934734b7..0458fcefa4b9 100644 +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -521,7 +521,7 @@ static unsigned int __startup_pirq(unsigned int irq) + BIND_PIRQ__WILL_SHARE : 0; + rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq); + if (rc != 0) { +- pr_warn("Failed to obtain physical IRQ %d\n", irq); ++ pr_warn("Failed to obtain physical IRQ %d (error %d)\n", irq, rc); + return 0; + } + evtchn = bind_pirq.port; +-- +2.17.1 + diff --git a/patches.xen/pvops-blkfront-removable-flag.patch b/0005-pvops-respect-removable-xenstore-flag-for-block-devi.patch similarity index 50% rename from patches.xen/pvops-blkfront-removable-flag.patch rename to 0005-pvops-respect-removable-xenstore-flag-for-block-devi.patch index ada0eae..c1b890e 100644 --- a/patches.xen/pvops-blkfront-removable-flag.patch +++ b/0005-pvops-respect-removable-xenstore-flag-for-block-devi.patch @@ -1,8 +1,19 @@ +From 6bec01bac2a0b1b8d7639de2c7fd646363f57d2d Mon Sep 17 00:00:00 2001 +From: Marek Marczykowski +Date: Mon, 11 Jun 2012 22:49:31 +0200 +Subject: [PATCH] pvops: respect 'removable' xenstore flag for block devices + +Especially this is needed by pmount to allow mount qvm-block attached devices +by normal user. +--- + drivers/block/xen-blkfront.c | 7 +++++++ + 1 file changed, 7 insertions(+) + diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c -index 4e86393..34493d7 100644 +index 429d20131c7e..2541d8c38336 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c -@@ -2317,6 +2317,7 @@ static void blkfront_connect(struct blkfront_info *info) +@@ -2338,6 +2338,7 @@ static void blkfront_connect(struct blkfront_info *info) unsigned int binfo; char *envp[] = { "RESIZE=1", NULL }; int err, i; @@ -10,7 +21,7 @@ index 4e86393..34493d7 100644 switch (info->connected) { case BLKIF_STATE_CONNECTED: -@@ -2384,6 +2385,12 @@ static void blkfront_connect(struct blkfront_info *info) +@@ -2405,6 +2406,12 @@ static void blkfront_connect(struct blkfront_info *info) } } @@ -23,3 +34,6 @@ index 4e86393..34493d7 100644 err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size, physical_sector_size); if (err) { +-- +2.17.1 + diff --git a/0006-pvops-xen-blkfront-handle-FDEJECT-as-detach-request-.patch b/0006-pvops-xen-blkfront-handle-FDEJECT-as-detach-request-.patch new file mode 100644 index 0000000..2e7982a --- /dev/null +++ b/0006-pvops-xen-blkfront-handle-FDEJECT-as-detach-request-.patch @@ -0,0 +1,34 @@ +From 6b4db8c77bd178701b3f501135ab3be08cdc43ac Mon Sep 17 00:00:00 2001 +From: Marek Marczykowski +Date: Sun, 15 Jul 2012 19:57:47 +0200 +Subject: [PATCH] pvops/xen-blkfront: handle FDEJECT as detach request (#630) + +--- + drivers/block/xen-blkfront.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index 2541d8c38336..3f6df7d98265 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -511,6 +512,9 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, + return 0; + return -EINVAL; + } ++ case FDEJECT: ++ xenbus_switch_state(info->xbdev, XenbusStateClosing); ++ return 0; + + default: + /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", +-- +2.17.1 + diff --git a/patches.qubes/0001-block-add-no_part_scan-module-parameter.patch b/0007-block-add-no_part_scan-module-parameter.patch similarity index 83% rename from patches.qubes/0001-block-add-no_part_scan-module-parameter.patch rename to 0007-block-add-no_part_scan-module-parameter.patch index eb3cc61..dab7084 100644 --- a/patches.qubes/0001-block-add-no_part_scan-module-parameter.patch +++ b/0007-block-add-no_part_scan-module-parameter.patch @@ -1,4 +1,4 @@ -From 19cb7d4e4efe39ef6ec8b216a254d83a1257846c Mon Sep 17 00:00:00 2001 +From a3d0a8585e975d169a3994463745620c8d8becd0 Mon Sep 17 00:00:00 2001 From: Rusty Bird Date: Mon, 11 Jul 2016 13:05:38 +0000 Subject: [PATCH] block: add no_part_scan module parameter @@ -15,10 +15,10 @@ the /sys/module/block/parameters/no_part_scan file. 1 file changed, 12 insertions(+) diff --git a/block/genhd.c b/block/genhd.c -index 9f42526..85b71f5 100644 +index be5bab20b2ab..f4561f06e273 100644 --- a/block/genhd.c +++ b/block/genhd.c -@@ -628,6 +628,15 @@ +@@ -643,6 +643,15 @@ static void register_disk(struct device *parent, struct gendisk *disk) WARN_ON(err); } @@ -34,7 +34,7 @@ index 9f42526..85b71f5 100644 /** * __device_add_disk - add disk information to kernel list * @parent: parent device for the disk -@@ -645,6 +654,9 @@ +@@ -660,6 +669,9 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, dev_t devt; int retval; @@ -45,5 +45,5 @@ index 9f42526..85b71f5 100644 * be accompanied with EXT_DEVT flag. Make sure all * parameters make sense. -- -2.5.5 +2.17.1 diff --git a/patches.xen/xsa155-linux-0008-xen-Add-RING_COPY_RESPONSE.patch b/0008-xen-Add-RING_COPY_RESPONSE.patch similarity index 97% rename from patches.xen/xsa155-linux-0008-xen-Add-RING_COPY_RESPONSE.patch rename to 0008-xen-Add-RING_COPY_RESPONSE.patch index 252c67b..5904853 100644 --- a/patches.xen/xsa155-linux-0008-xen-Add-RING_COPY_RESPONSE.patch +++ b/0008-xen-Add-RING_COPY_RESPONSE.patch @@ -1,4 +1,4 @@ -From bf0b3f33476360b5d72f87d749409b0a2b1a57cb Mon Sep 17 00:00:00 2001 +From bb7d9fa8c1c8d2e90ea7cac04fb1fafe4965ad69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Tue, 15 Dec 2015 21:35:14 +0100 diff --git a/patches.xen/xsa155-linux44-0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch b/0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch similarity index 95% rename from patches.xen/xsa155-linux44-0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch rename to 0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch index 23d78f1..9737750 100644 --- a/patches.xen/xsa155-linux44-0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch +++ b/0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch @@ -1,4 +1,4 @@ -From c7c1661d1b265ea620939bb5da4958eb0fb1385b Mon Sep 17 00:00:00 2001 +From 2d7190695574d4a39597a65d3ba3858098f22da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 16 Dec 2015 05:09:55 +0100 @@ -18,10 +18,10 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index 9dd2ca62d84a..1b6c319d74f1 100644 +index 61298526aee3..08ea5004e86b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c -@@ -388,13 +388,13 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) +@@ -387,13 +387,13 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) rmb(); /* Ensure we see responses up to 'rp'. */ for (cons = queue->tx.rsp_cons; cons != prod; cons++) { @@ -154,7 +154,7 @@ index 9dd2ca62d84a..1b6c319d74f1 100644 if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; -@@ -912,7 +911,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, +@@ -916,7 +915,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, skb_frag_page(nfrag), @@ -163,7 +163,7 @@ index 9dd2ca62d84a..1b6c319d74f1 100644 skb_shinfo(nskb)->nr_frags = 0; kfree_skb(nskb); -@@ -1008,7 +1007,7 @@ static int xennet_poll(struct napi_struct *napi, int budget) +@@ -1012,7 +1011,7 @@ static int xennet_poll(struct napi_struct *napi, int budget) i = queue->rx.rsp_cons; work_done = 0; while ((i != rp) && (work_done < budget)) { diff --git a/patches.xen/xsa155-linux44-0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch b/0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch similarity index 91% rename from patches.xen/xsa155-linux44-0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch rename to 0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch index 026991a..3226ed9 100644 --- a/patches.xen/xsa155-linux44-0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch +++ b/0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch @@ -1,4 +1,4 @@ -From 11b753cc107f41aca56ba0698a1bd6b806cd6795 Mon Sep 17 00:00:00 2001 +From a72bc89ab6d6c7e171bd04357ea6954a9c62b43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 16 Dec 2015 05:19:37 +0100 @@ -20,10 +20,10 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index 1b6c319d74f1..026d39702217 100644 +index 08ea5004e86b..88578e5aeaaf 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c -@@ -459,7 +459,7 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, +@@ -458,7 +458,7 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, tx->flags = 0; info->tx = tx; diff --git a/patches.xen/xsa155-linux-0011-xen-netfront-add-range-check-for-Tx-response-id.patch b/0011-xen-netfront-add-range-check-for-Tx-response-id.patch similarity index 84% rename from patches.xen/xsa155-linux-0011-xen-netfront-add-range-check-for-Tx-response-id.patch rename to 0011-xen-netfront-add-range-check-for-Tx-response-id.patch index 1c6c0e5..a512214 100644 --- a/patches.xen/xsa155-linux-0011-xen-netfront-add-range-check-for-Tx-response-id.patch +++ b/0011-xen-netfront-add-range-check-for-Tx-response-id.patch @@ -1,4 +1,4 @@ -From f8bc4b3be49e47dcf005ce12ef25071fe16bd45b Mon Sep 17 00:00:00 2001 +From 91bac2da855a018b8ffd1bed9694e9c962340f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 16 Dec 2015 05:22:24 +0100 @@ -19,10 +19,10 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 1 insertion(+) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index 026d39702217..4150128ab893 100644 +index 88578e5aeaaf..69e1c3aebe71 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c -@@ -395,6 +395,7 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) +@@ -394,6 +394,7 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) continue; id = txrsp.id; diff --git a/patches.xen/xsa155-linux312-0012-xen-blkfront-make-local-copy-of-response-before-usin.patch b/0012-xen-blkfront-make-local-copy-of-response-before-usin.patch similarity index 91% rename from patches.xen/xsa155-linux312-0012-xen-blkfront-make-local-copy-of-response-before-usin.patch rename to 0012-xen-blkfront-make-local-copy-of-response-before-usin.patch index 343d5b6..42a8079 100644 --- a/patches.xen/xsa155-linux312-0012-xen-blkfront-make-local-copy-of-response-before-usin.patch +++ b/0012-xen-blkfront-make-local-copy-of-response-before-usin.patch @@ -1,4 +1,4 @@ -From 26baa3367516dac7e376e2595d187dd9887bf0e0 Mon Sep 17 00:00:00 2001 +From bfad51710e1523650c2cfbf9aff561bb8364d9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 16 Dec 2015 05:51:10 +0100 @@ -20,10 +20,10 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c -index b5cedccb5d7d..87781c076733 100644 +index 3f6df7d98265..e520bc6f6007 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c -@@ -1548,7 +1548,7 @@ static bool blkif_completion(unsigned long *id, +@@ -1551,7 +1551,7 @@ static bool blkif_completion(unsigned long *id, static irqreturn_t blkif_interrupt(int irq, void *dev_id) { struct request *req; @@ -32,7 +32,7 @@ index b5cedccb5d7d..87781c076733 100644 RING_IDX i, rp; unsigned long flags; struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id; -@@ -1565,8 +1565,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) +@@ -1568,8 +1568,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) for (i = rinfo->ring.rsp_cons; i != rp; i++) { unsigned long id; @@ -43,7 +43,7 @@ index b5cedccb5d7d..87781c076733 100644 /* * The backend has messed up and given us an id that we would * never have given to it (we stamp it up to BLK_RING_SIZE - -@@ -1574,39 +1574,39 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) +@@ -1577,39 +1577,39 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) */ if (id >= BLK_RING_SIZE(info)) { WARN(1, "%s: response to %s has incorrect id (%ld)\n", @@ -91,7 +91,7 @@ index b5cedccb5d7d..87781c076733 100644 blkif_req(req)->error = BLK_STS_NOTSUPP; info->feature_discard = 0; info->feature_secdiscard = 0; -@@ -1616,15 +1616,15 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) +@@ -1619,15 +1619,15 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) break; case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_WRITE_BARRIER: @@ -111,7 +111,7 @@ index b5cedccb5d7d..87781c076733 100644 blkif_req(req)->error = BLK_STS_NOTSUPP; } if (unlikely(blkif_req(req)->error)) { -@@ -1637,9 +1637,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) +@@ -1640,9 +1640,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) /* fall through */ case BLKIF_OP_READ: case BLKIF_OP_WRITE: diff --git a/patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch b/0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch similarity index 91% rename from patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch rename to 0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch index 69e35c6..fbcff25 100644 --- a/patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch +++ b/0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch @@ -1,4 +1,4 @@ -From 5c574ee1c388258969b2c66d46db20be16c3aeb3 Mon Sep 17 00:00:00 2001 +From 98231d38e75826534ef10b0ea06ecde796b89c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 16 Dec 2015 06:07:14 +0100 @@ -22,10 +22,10 @@ Signed-off-by: Marek Marczykowski-Górecki 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c -index 87781c076733..3da0f6be24c9 100644 +index e520bc6f6007..8132836e225b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c -@@ -524,19 +524,16 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, +@@ -527,19 +527,16 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo, struct request *req, @@ -47,7 +47,7 @@ index 87781c076733..3da0f6be24c9 100644 return id; } -@@ -544,23 +541,28 @@ static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo, +@@ -547,23 +544,28 @@ static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo, static int blkif_queue_discard_req(struct request *req, struct blkfront_ring_info *rinfo) { struct blkfront_info *info = rinfo->dev_info; @@ -84,7 +84,7 @@ index 87781c076733..3da0f6be24c9 100644 return 0; } -@@ -692,7 +694,7 @@ static void blkif_setup_extra_req(struct blkif_request *first, +@@ -695,7 +697,7 @@ static void blkif_setup_extra_req(struct blkif_request *first, static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *rinfo) { struct blkfront_info *info = rinfo->dev_info; @@ -93,7 +93,7 @@ index 87781c076733..3da0f6be24c9 100644 unsigned long id, extra_id = NO_ASSOCIATED_ID; bool require_extra_req = false; int i; -@@ -757,16 +759,16 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri +@@ -760,16 +762,16 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri * BLKIF_OP_WRITE */ BUG_ON(req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA); @@ -118,7 +118,7 @@ index 87781c076733..3da0f6be24c9 100644 BLKIF_OP_WRITE : BLKIF_OP_READ; if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) { /* -@@ -777,15 +779,15 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri +@@ -780,15 +782,15 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri * since it is guaranteed ordered WRT previous writes.) */ if (info->feature_flush && info->feature_fua) @@ -138,7 +138,7 @@ index 87781c076733..3da0f6be24c9 100644 if (unlikely(require_extra_req)) { extra_id = blkif_ring_get_request(rinfo, req, &extra_ring_req); -@@ -795,7 +797,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri +@@ -798,7 +800,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri */ rinfo->shadow[extra_id].num_sg = 0; @@ -147,7 +147,7 @@ index 87781c076733..3da0f6be24c9 100644 /* Link the 2 requests together */ rinfo->shadow[extra_id].associated_id = id; -@@ -803,12 +805,12 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri +@@ -806,12 +808,12 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri } } @@ -162,7 +162,7 @@ index 87781c076733..3da0f6be24c9 100644 for_each_sg(rinfo->shadow[id].sg, sg, num_sg, i) { BUG_ON(sg->offset + sg->length > PAGE_SIZE); -@@ -830,10 +832,20 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri +@@ -833,10 +835,20 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri if (setup.segments) kunmap_atomic(setup.segments); diff --git a/0014-xen-pcifront-pciback-Update-pciif.h-with-err-and-res.patch b/0014-xen-pcifront-pciback-Update-pciif.h-with-err-and-res.patch new file mode 100644 index 0000000..2d24b50 --- /dev/null +++ b/0014-xen-pcifront-pciback-Update-pciif.h-with-err-and-res.patch @@ -0,0 +1,75 @@ +From ca6107528e5b5c986b64297ae62f706b5b391b0c Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Wed, 1 Apr 2015 17:01:26 -0400 +Subject: [PATCH] xen/pcifront/pciback: Update pciif.h with ->err and ->result + values. + +The '->err' should contain only the XEN_PCI_ERR_* type values. +The '->result' may contain -EXX values or any other value +that the XEN_PCI_OP_* deems appropiate. + +As such update the header and also the implementations. + +Signed-off-by: Konrad Rzeszutek Wilk + +Details in this thread: +https://patchwork.kernel.org/patch/8258431/ +--- + drivers/pci/xen-pcifront.c | 2 +- + drivers/xen/xen-pciback/pciback_ops.c | 2 +- + include/xen/interface/io/pciif.h | 6 ++++-- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c +index eba6e33147a2..cc6dcb13f1a8 100644 +--- a/drivers/pci/xen-pcifront.c ++++ b/drivers/pci/xen-pcifront.c +@@ -298,7 +298,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, + } else { + pci_err(dev, "enable msix get err %x\n", err); + } +- return err; ++ return err ? -EINVAL : 0; + } + + static void pci_frontend_disable_msix(struct pci_dev *dev) +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index ea4a08b83fa0..2d63aa2946a3 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -268,7 +268,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, + if (dev_data) + dev_data->ack_intr = 0; + +- return result > 0 ? 0 : result; ++ return result >= 0 ? 0 : XEN_PCI_ERR_op_failed; + } + + static +diff --git a/include/xen/interface/io/pciif.h b/include/xen/interface/io/pciif.h +index d9922ae36eb5..c8b674fd2455 100644 +--- a/include/xen/interface/io/pciif.h ++++ b/include/xen/interface/io/pciif.h +@@ -70,7 +70,7 @@ struct xen_pci_op { + /* IN: what action to perform: XEN_PCI_OP_* */ + uint32_t cmd; + +- /* OUT: will contain an error number (if any) from errno.h */ ++ /* OUT: will contain an XEN_PCI_ERR_* number. */ + int32_t err; + + /* IN: which device to touch */ +@@ -82,7 +82,9 @@ struct xen_pci_op { + int32_t offset; + int32_t size; + +- /* IN/OUT: Contains the result after a READ or the value to WRITE */ ++ /* IN/OUT: Contains the result after a READ or the value to WRITE. ++ * If the err does not have XEN_PCI_ERR_success, depending on ++ * XEN_PCI_OP_* might have the errno value. */ + uint32_t value; + /* IN: Contains extra infor for this operation */ + uint32_t info; +-- +2.17.1 + diff --git a/patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch b/0015-xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch similarity index 81% rename from patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch rename to 0015-xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch index 597331d..9468186 100644 --- a/patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch +++ b/0015-xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch @@ -1,4 +1,4 @@ -From 292dcb5eb9ceedeb981eb926be566af8c99cbb26 Mon Sep 17 00:00:00 2001 +From 7cea4f1e3e43d8fc20e2605495d6ed24bfeeeb9b Mon Sep 17 00:00:00 2001 From: HW42 Date: Tue, 12 Sep 2017 00:49:02 +0200 Subject: [PATCH] xen-pciback: add attribute to allow MSI enable flag writes @@ -14,14 +14,16 @@ guest (or stubdom) can already generate MSIs through other ways, see [1]: https://invisiblethingslab.com/resources/2011/Software%20Attacks%20on%20Intel%20VT-d.pdf --- - drivers/xen/xen-pciback/conf_space_capability.c | 39 +++++++++++++++ - drivers/xen/xen-pciback/pci_stub.c | 65 +++++++++++++++++++++++++ - drivers/xen/xen-pciback/pciback.h | 1 + - 3 files changed, 105 insertions(+) + .../xen/xen-pciback/conf_space_capability.c | 39 +++++++++++ + drivers/xen/xen-pciback/pci_stub.c | 64 +++++++++++++++++++ + drivers/xen/xen-pciback/pciback.h | 1 + + 3 files changed, 104 insertions(+) +diff --git a/drivers/xen/xen-pciback/conf_space_capability.c b/drivers/xen/xen-pciback/conf_space_capability.c +index 73427d8e0116..a277ddc7f7b4 100644 --- a/drivers/xen/xen-pciback/conf_space_capability.c +++ b/drivers/xen/xen-pciback/conf_space_capability.c -@@ -190,6 +190,40 @@ static const struct config_field caplist +@@ -190,6 +190,40 @@ static const struct config_field caplist_pm[] = { {} }; @@ -62,7 +64,7 @@ guest (or stubdom) can already generate MSIs through other ways, see static struct xen_pcibk_config_capability xen_pcibk_config_capability_pm = { .capability = PCI_CAP_ID_PM, .fields = caplist_pm, -@@ -198,11 +232,16 @@ static struct xen_pcibk_config_capabilit +@@ -198,11 +232,16 @@ static struct xen_pcibk_config_capability xen_pcibk_config_capability_vpd = { .capability = PCI_CAP_ID_VPD, .fields = caplist_vpd, }; @@ -79,9 +81,11 @@ guest (or stubdom) can already generate MSIs through other ways, see return 0; } +diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c +index 59661db144e5..51a116f37b95 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c -@@ -303,6 +303,8 @@ void pcistub_put_pci_dev(struct pci_dev +@@ -303,6 +303,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev) xen_pcibk_config_reset_dev(dev); xen_pcibk_config_free_dyn_fields(dev); @@ -90,7 +94,7 @@ guest (or stubdom) can already generate MSIs through other ways, see xen_unregister_device_domain_owner(dev); spin_lock_irqsave(&found_psdev->lock, flags); -@@ -1430,6 +1432,63 @@ static ssize_t permissive_show(struct de +@@ -1430,6 +1432,63 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf) } static DRIVER_ATTR_RW(permissive); @@ -154,15 +158,15 @@ guest (or stubdom) can already generate MSIs through other ways, see static void pcistub_exit(void) { driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_new_slot); -@@ -1440,6 +1499,8 @@ static void pcistub_exit(void) +@@ -1439,6 +1498,8 @@ static void pcistub_exit(void) + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_quirks); driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_permissive); - driver_remove_file(&xen_pcibk_pci_driver.driver, -+ &driver_attr_allow_msi_enable); + driver_remove_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_allow_msi_enable); + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_irq_handlers); driver_remove_file(&xen_pcibk_pci_driver.driver, - &driver_attr_irq_handler_state); @@ -1529,6 +1590,9 @@ static int __init pcistub_init(void) if (!err) err = driver_create_file(&xen_pcibk_pci_driver.driver, @@ -173,6 +177,8 @@ guest (or stubdom) can already generate MSIs through other ways, see if (!err) err = driver_create_file(&xen_pcibk_pci_driver.driver, +diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h +index 263c059bff90..796f949c92be 100644 --- a/drivers/xen/xen-pciback/pciback.h +++ b/drivers/xen/xen-pciback/pciback.h @@ -45,6 +45,7 @@ struct xen_pcibk_dev_data { @@ -183,3 +189,6 @@ guest (or stubdom) can already generate MSIs through other ways, see unsigned int warned_on_write:1; unsigned int enable_intx:1; unsigned int isr_on:1; /* Whether the IRQ handler is installed. */ +-- +2.17.1 + diff --git a/patches.xen/irq-bind-debug-log.patch b/patches.xen/irq-bind-debug-log.patch deleted file mode 100644 index ad1910d..0000000 --- a/patches.xen/irq-bind-debug-log.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c -index 524c221..acb29f4 100644 ---- a/drivers/xen/events/events_base.c -+++ b/drivers/xen/events/events_base.c -@@ -519,7 +519,7 @@ static unsigned int __startup_pirq(unsigned int irq) - BIND_PIRQ__WILL_SHARE : 0; - rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq); - if (rc != 0) { -- pr_warn("Failed to obtain physical IRQ %d\n", irq); -+ pr_warn("Failed to obtain physical IRQ %d (error %d)\n", irq, rc); - return 0; - } - evtchn = bind_pirq.port; diff --git a/patches.xen/pci_op-cleanup.patch b/patches.xen/pci_op-cleanup.patch deleted file mode 100644 index 4628732..0000000 --- a/patches.xen/pci_op-cleanup.patch +++ /dev/null @@ -1,104 +0,0 @@ -From xen-devel-bounces@lists.xen.org Tue Feb 9 06:00:36 2016 -Date: Mon, 8 Feb 2016 23:59:27 -0500 -From: Konrad Rzeszutek Wilk -To: Marek =?iso-8859-1?Q?Marczykowski-G=F3recki?= - -Message-ID: <20160209045927.GC3853@localhost.localdomain> -References: - <20160127183005.GB3134@char.us.oracle.com> - - <1454323426.28781.73.camel@citrix.com> - <20160201145053.GA21826@char.us.oracle.com> - <20160203142230.GC24446@mail-itl> - <20160203152657.GE20732@char.us.oracle.com> - <20160208173917.GD24446@mail-itl> -MIME-Version: 1.0 -Content-Disposition: inline -In-Reply-To: <20160208173917.GD24446@mail-itl> -User-Agent: Mutt/1.5.24 (2015-08-30) -Cc: Tommi Airikka , Ian Campbell , - 810379@bugs.debian.org, xen-devel@lists.xen.org -Subject: Re: [Xen-devel] [BUG] pci-passthrough generates "xen:events: Failed - to obtain physical IRQ" for some devices - -I posted it at some point. It was that the MSI-X enable op stashes the -error value in op->value. But 'op->value' is an unsigned int so the -value ends up being 0xfffffe or such. And the other PV frontends only -check for !0 - and manufacture their own value (-EINVAL). - -Hence I want to update the pciff.h .. Oh here is the patch: -Oh man. A year?! - -Anyhow this can be posted as a cleanup patch seperately of the -bug-fixes. - -commit 393be47782bca7a24d3e365448d4d3d1a303abfe -Author: Konrad Rzeszutek Wilk -Date: Wed Apr 1 17:01:26 2015 -0400 - - xen/pcifront/pciback: Update pciif.h with ->err and ->result values. - - The '->err' should contain only the XEN_PCI_ERR_* type values. - The '->result' may contain -EXX values or any other value - that the XEN_PCI_OP_* deems appropiate. - - As such update the header and also the implementations. - - Signed-off-by: Konrad Rzeszutek Wilk - - Conflicts: - drivers/xen/xen-pciback/pciback_ops.c - - Conflicts: - drivers/xen/xen-pciback/pciback_ops.c - -diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c -index 8785014..d458e53 100644 ---- a/drivers/pci/xen-pcifront.c -+++ b/drivers/pci/xen-pcifront.c -@@ -298,7 +298,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, - } else { - pci_err(dev, "enable msix get err %x\n", err); - } -- return err; -+ return err ? -EINVAL : 0; - } - - static void pci_frontend_disable_msix(struct pci_dev *dev) -diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c -index ee2c891..573590b 100644 ---- a/drivers/xen/xen-pciback/pciback_ops.c -+++ b/drivers/xen/xen-pciback/pciback_ops.c -@@ -268,7 +268,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, - if (dev_data) - dev_data->ack_intr = 0; - -- return result > 0 ? 0 : result; -+ return result >= 0 ? 0 : XEN_PCI_ERR_op_failed; - } - - static -diff --git a/include/xen/interface/io/pciif.h b/include/xen/interface/io/pciif.h -index d9922ae..c8b674f 100644 ---- a/include/xen/interface/io/pciif.h -+++ b/include/xen/interface/io/pciif.h -@@ -70,7 +70,7 @@ struct xen_pci_op { - /* IN: what action to perform: XEN_PCI_OP_* */ - uint32_t cmd; - -- /* OUT: will contain an error number (if any) from errno.h */ -+ /* OUT: will contain an XEN_PCI_ERR_* number. */ - int32_t err; - - /* IN: which device to touch */ -@@ -82,7 +82,9 @@ struct xen_pci_op { - int32_t offset; - int32_t size; - -- /* IN/OUT: Contains the result after a READ or the value to WRITE */ -+ /* IN/OUT: Contains the result after a READ or the value to WRITE. -+ * If the err does not have XEN_PCI_ERR_success, depending on -+ * XEN_PCI_OP_* might have the errno value. */ - uint32_t value; - /* IN: Contains extra infor for this operation */ - uint32_t info; diff --git a/patches.xen/pvops-0100-usb-xen-pvusb-driver.patch b/patches.xen/pvops-0100-usb-xen-pvusb-driver.patch deleted file mode 100644 index 9df6cd9..0000000 --- a/patches.xen/pvops-0100-usb-xen-pvusb-driver.patch +++ /dev/null @@ -1,4255 +0,0 @@ -From 10b675fc21702ff5a9b94fc13e2b504ca09073fd Mon Sep 17 00:00:00 2001 -From: Nathanael Rensen -Date: Tue, 7 Feb 2012 13:50:24 +0800 -Subject: [PATCH] usb: xen pvusb driver - -Port the original Xen PV USB drivers developed by Noboru Iwamatsu - to the Linux pvops kernel. The backend driver -resides in dom0 with access to the physical USB device. The frontend driver -resides in a domU to provide paravirtualised access to physical USB devices. - -For usage, see http://wiki.xensource.com/xenwiki/XenUSBPassthrough. - -Signed-off-by: Nathanael Rensen . -Signed-off-by: Konrad Rzeszutek Wilk ---- - drivers/usb/host/Kconfig | 23 + - drivers/usb/host/Makefile | 2 + - drivers/usb/host/xen-usbback/Makefile | 3 + - drivers/usb/host/xen-usbback/common.h | 170 ++++ - drivers/usb/host/xen-usbback/usbback.c | 1272 +++++++++++++++++++++++ - drivers/usb/host/xen-usbback/usbdev.c | 319 ++++++ - drivers/usb/host/xen-usbback/xenbus.c | 482 +++++++++ - drivers/usb/host/xen-usbfront.c | 1739 ++++++++++++++++++++++++++++++++ - include/xen/interface/io/usbif.h | 150 +++ - 9 files changed, 4160 insertions(+), 0 deletions(-) - create mode 100644 drivers/usb/host/xen-usbback/Makefile - create mode 100644 drivers/usb/host/xen-usbback/common.h - create mode 100644 drivers/usb/host/xen-usbback/usbback.c - create mode 100644 drivers/usb/host/xen-usbback/usbdev.c - create mode 100644 drivers/usb/host/xen-usbback/xenbus.c - create mode 100644 drivers/usb/host/xen-usbfront.c - create mode 100644 include/xen/interface/io/usbif.h - -diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index f788eb8..cbb0961 100644 ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -745,3 +745,26 @@ - This option is of interest only to developers who need to validate - their USB hardware designs. It is not needed for normal use. If - unsure, say N. -+ -+config XEN_USBDEV_FRONTEND -+ tristate "Xen pvusb device frontend driver" -+ depends on XEN && USB -+ select XEN_XENBUS_FRONTEND -+ default m -+ help -+ The pvusb device frontend driver allows the kernel to -+ access usb devices exported exported by a virtual -+ machine containing a physical usb device driver. The -+ frontend driver is intended for unprivileged guest domains; -+ if you are compiling a kernel for a Xen guest, you almost -+ certainly want to enable this. -+ -+config XEN_USBDEV_BACKEND -+ tristate "PVUSB device backend driver" -+ depends on XEN_BACKEND && USB -+ default m -+ help -+ The pvusb backend driver allows the kernel to export its usb -+ devices to other guests via a high-performance shared-memory -+ interface. This requires the guest to have the pvusb frontend -+ available. -diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 0982bcc..d62fe38 100644 ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -40,6 +40,8 @@ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o - obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o - obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o - obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o -+obj-$(CONFIG_XEN_USBDEV_FRONTEND) += xen-usbfront.o -+obj-$(CONFIG_XEN_USBDEV_BACKEND) += xen-usbback/ - obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o - obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o - obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o -diff --git a/drivers/usb/host/xen-usbback/Makefile b/drivers/usb/host/xen-usbback/Makefile -new file mode 100644 -index 0000000..9f3628c ---- /dev/null -+++ b/drivers/usb/host/xen-usbback/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_XEN_USBDEV_BACKEND) := xen-usbback.o -+ -+xen-usbback-y := usbdev.o xenbus.o usbback.o -diff --git a/drivers/usb/host/xen-usbback/common.h b/drivers/usb/host/xen-usbback/common.h -new file mode 100644 -index 0000000..d9671ec ---- /dev/null -+++ b/drivers/usb/host/xen-usbback/common.h -@@ -0,0 +1,171 @@ -+/* -+ * This file is part of Xen USB backend driver. -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * or, by your choice, -+ * -+ * When distributed separately from the Linux kernel or incorporated into -+ * other software packages, subject to the following license: -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef __XEN_USBBACK__COMMON_H__ -+#define __XEN_USBBACK__COMMON_H__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRV_PFX "xen-usbback:" -+ -+struct xen_usbdev; -+ -+#ifndef BUS_ID_SIZE -+#define XEN_USB_BUS_ID_SIZE 20 -+#else -+#define XEN_USB_BUS_ID_SIZE BUS_ID_SIZE -+#endif -+ -+#define XEN_USB_DEV_ADDR_SIZE 128 -+ -+struct xen_usbif { -+ domid_t domid; -+ unsigned int handle; -+ int num_ports; -+ enum usb_spec_version usb_ver; -+ -+ struct list_head usbif_list; -+ -+ struct xenbus_device *xbdev; -+ -+ unsigned int irq; -+ -+ void *urb_sring; -+ void *conn_sring; -+ struct usbif_urb_back_ring urb_ring; -+ struct usbif_conn_back_ring conn_ring; -+ -+ spinlock_t urb_ring_lock; -+ spinlock_t conn_ring_lock; -+ atomic_t refcnt; -+ -+ struct xenbus_watch backend_watch; -+ -+ /* device address lookup table */ -+ struct xen_usbdev *addr_table[XEN_USB_DEV_ADDR_SIZE]; -+ spinlock_t addr_lock; -+ -+ /* connected device list */ -+ struct list_head dev_list; -+ spinlock_t dev_lock; -+ -+ /* request schedule */ -+ struct task_struct *xenusbd; -+ unsigned int waiting_reqs; -+ wait_queue_head_t waiting_to_free; -+ wait_queue_head_t wq; -+}; -+ -+struct xen_usbport { -+ struct list_head port_list; -+ -+ char phys_bus[XEN_USB_BUS_ID_SIZE]; -+ domid_t domid; -+ unsigned int handle; -+ int portnum; -+ unsigned is_connected:1; -+}; -+ -+struct xen_usbdev { -+ struct kref kref; -+ struct list_head dev_list; -+ -+ struct xen_usbport *port; -+ struct usb_device *udev; -+ struct xen_usbif *usbif; -+ int addr; -+ -+ struct list_head submitting_list; -+ spinlock_t submitting_lock; -+}; -+ -+#define usbif_get(_b) (atomic_inc(&(_b)->refcnt)) -+#define usbif_put(_b) \ -+ do { \ -+ if (atomic_dec_and_test(&(_b)->refcnt)) \ -+ wake_up(&(_b)->waiting_to_free); \ -+ } while (0) -+ -+int xen_usbif_xenbus_init(void); -+void xen_usbif_xenbus_exit(void); -+struct xen_usbif *xen_usbif_find(domid_t domid, unsigned int handle); -+ -+int xen_usbdev_init(void); -+void xen_usbdev_exit(void); -+ -+void xen_usbif_attach_device(struct xen_usbif *usbif, struct xen_usbdev *dev); -+void xen_usbif_detach_device(struct xen_usbif *usbif, struct xen_usbdev *dev); -+void xen_usbif_detach_device_without_lock(struct xen_usbif *usbif, -+ struct xen_usbdev *dev); -+void xen_usbif_hotplug_notify(struct xen_usbif *usbif, int portnum, int speed); -+struct xen_usbdev *xen_usbif_find_attached_device(struct xen_usbif *usbif, -+ int port); -+irqreturn_t xen_usbif_be_int(int irq, void *dev_id); -+int xen_usbif_schedule(void *arg); -+void xen_usbif_unlink_urbs(struct xen_usbdev *dev); -+ -+struct xen_usbport *xen_usbport_find_by_busid(const char *busid); -+struct xen_usbport *xen_usbport_find(const domid_t domid, -+ const unsigned int handle, const int portnum); -+int xen_usbport_add(const char *busid, const domid_t domid, -+ const unsigned int handle, const int portnum); -+int xen_usbport_remove(const domid_t domid, const unsigned int handle, -+ const int portnum); -+#endif /* __XEN_USBBACK__COMMON_H__ */ -diff --git a/drivers/usb/host/xen-usbback/usbback.c b/drivers/usb/host/xen-usbback/usbback.c -new file mode 100644 -index 0000000..df1afa9 ---- /dev/null -+++ b/drivers/usb/host/xen-usbback/usbback.c -@@ -0,0 +1,1272 @@ -+/* -+ * Xen USB backend driver -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * or, by your choice, -+ * -+ * When distributed separately from the Linux kernel or incorporated into -+ * other software packages, subject to the following license: -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include -+#include "common.h" -+ -+static int xen_usbif_reqs = USBIF_BACK_MAX_PENDING_REQS; -+module_param_named(reqs, xen_usbif_reqs, int, 0); -+MODULE_PARM_DESC(reqs, "Number of usbback requests to allocate"); -+ -+struct pending_req_segment { -+ uint16_t offset; -+ uint16_t length; -+}; -+ -+struct pending_req { -+ struct xen_usbif *usbif; -+ -+ uint16_t id; /* request id */ -+ -+ struct xen_usbdev *dev; -+ struct list_head urb_list; -+ -+ /* urb */ -+ struct urb *urb; -+ void *buffer; -+ dma_addr_t transfer_dma; -+ struct usb_ctrlrequest *setup; -+ dma_addr_t setup_dma; -+ -+ /* request segments */ -+ uint16_t nr_buffer_segs; -+ /* number of urb->transfer_buffer segments */ -+ uint16_t nr_extra_segs; -+ /* number of iso_frame_desc segments (ISO) */ -+ struct pending_req_segment *seg; -+ -+ struct list_head free_list; -+}; -+ -+#define USBBACK_INVALID_HANDLE (~0) -+ -+struct xen_usbbk { -+ struct pending_req *pending_reqs; -+ struct list_head pending_free; -+ spinlock_t pending_free_lock; -+ wait_queue_head_t pending_free_wq; -+ struct list_head urb_free; -+ spinlock_t urb_free_lock; -+ struct page **pending_pages; -+ grant_handle_t *pending_grant_handles; -+}; -+ -+static struct xen_usbbk *usbbk; -+ -+static inline int vaddr_pagenr(struct pending_req *req, int seg) -+{ -+ return (req - usbbk->pending_reqs) * -+ USBIF_MAX_SEGMENTS_PER_REQUEST + seg; -+} -+ -+#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)] -+ -+static inline unsigned long vaddr(struct pending_req *req, int seg) -+{ -+ unsigned long pfn = page_to_pfn(usbbk->pending_page(req, seg)); -+ return (unsigned long)pfn_to_kaddr(pfn); -+} -+ -+#define pending_handle(_req, _seg) \ -+ (usbbk->pending_grant_handles[vaddr_pagenr(_req, _seg)]) -+ -+static struct pending_req *alloc_req(void) -+{ -+ struct pending_req *req = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbbk->pending_free_lock, flags); -+ if (!list_empty(&usbbk->pending_free)) { -+ req = list_entry(usbbk->pending_free.next, struct pending_req, -+ free_list); -+ list_del(&req->free_list); -+ } -+ spin_unlock_irqrestore(&usbbk->pending_free_lock, flags); -+ return req; -+} -+ -+static void free_req(struct pending_req *req) -+{ -+ unsigned long flags; -+ int was_empty; -+ -+ spin_lock_irqsave(&usbbk->pending_free_lock, flags); -+ was_empty = list_empty(&usbbk->pending_free); -+ list_add(&req->free_list, &usbbk->pending_free); -+ spin_unlock_irqrestore(&usbbk->pending_free_lock, flags); -+ if (was_empty) -+ wake_up(&usbbk->pending_free_wq); -+} -+ -+static inline void add_req_to_submitting_list(struct xen_usbdev *dev, -+ struct pending_req *pending_req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->submitting_lock, flags); -+ list_add_tail(&pending_req->urb_list, &dev->submitting_list); -+ spin_unlock_irqrestore(&dev->submitting_lock, flags); -+} -+ -+static inline void remove_req_from_submitting_list(struct xen_usbdev *dev, -+ struct pending_req *pending_req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->submitting_lock, flags); -+ list_del_init(&pending_req->urb_list); -+ spin_unlock_irqrestore(&dev->submitting_lock, flags); -+} -+ -+void xen_usbif_unlink_urbs(struct xen_usbdev *dev) -+{ -+ struct pending_req *req, *tmp; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->submitting_lock, flags); -+ list_for_each_entry_safe(req, tmp, &dev->submitting_list, urb_list) { -+ usb_unlink_urb(req->urb); -+ } -+ spin_unlock_irqrestore(&dev->submitting_lock, flags); -+} -+ -+static void copy_buff_to_pages(void *buff, struct pending_req *pending_req, -+ int start, int nr_pages) -+{ -+ unsigned long copied = 0; -+ int i; -+ -+ for (i = start; i < start + nr_pages; i++) { -+ memcpy((void *) vaddr(pending_req, i) + -+ pending_req->seg[i].offset, -+ buff + copied, pending_req->seg[i].length); -+ copied += pending_req->seg[i].length; -+ } -+} -+ -+static void copy_pages_to_buff(void *buff, struct pending_req *pending_req, -+ int start, int nr_pages) -+{ -+ unsigned long copied = 0; -+ int i; -+ -+ for (i = start; i < start + nr_pages; i++) { -+ void *src = (void *) vaddr(pending_req, i) + -+ pending_req->seg[i].offset; -+ memcpy(buff + copied, src, pending_req->seg[i].length); -+ copied += pending_req->seg[i].length; -+ } -+} -+ -+static int usbbk_alloc_urb(struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ int ret; -+ -+ if (usb_pipeisoc(req->pipe)) -+ pending_req->urb = usb_alloc_urb(req->u.isoc.number_of_packets, -+ GFP_KERNEL); -+ else -+ pending_req->urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!pending_req->urb) { -+ pr_alert(DRV_PFX "can't alloc urb\n"); -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ if (req->buffer_length) { -+ pending_req->buffer = -+ usb_alloc_coherent(pending_req->dev->udev, -+ req->buffer_length, GFP_KERNEL, -+ &pending_req->transfer_dma); -+ if (!pending_req->buffer) { -+ pr_alert(DRV_PFX "can't alloc urb buffer\n"); -+ ret = -ENOMEM; -+ goto fail_free_urb; -+ } -+ } -+ -+ if (usb_pipecontrol(req->pipe)) { -+ pending_req->setup = usb_alloc_coherent(pending_req->dev->udev, -+ sizeof(struct usb_ctrlrequest), -+ GFP_KERNEL, &pending_req->setup_dma); -+ if (!pending_req->setup) { -+ pr_alert(DRV_PFX "can't alloc usb_ctrlrequest\n"); -+ ret = -ENOMEM; -+ goto fail_free_buffer; -+ } -+ } -+ -+ return 0; -+ -+fail_free_buffer: -+ if (req->buffer_length) -+ usb_free_coherent(pending_req->dev->udev, req->buffer_length, -+ pending_req->buffer, pending_req->transfer_dma); -+fail_free_urb: -+ usb_free_urb(pending_req->urb); -+fail: -+ return ret; -+} -+ -+static void usbbk_release_urb(struct urb *urb) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbbk->urb_free_lock, flags); -+ list_add(&urb->urb_list, &usbbk->urb_free); -+ spin_unlock_irqrestore(&usbbk->urb_free_lock, flags); -+} -+ -+static void usbbk_free_urb(struct urb *urb) -+{ -+ if (usb_pipecontrol(urb->pipe)) -+ usb_free_coherent(urb->dev, sizeof(struct usb_ctrlrequest), -+ urb->setup_packet, urb->setup_dma); -+ if (urb->transfer_buffer_length) -+ usb_free_coherent(urb->dev, urb->transfer_buffer_length, -+ urb->transfer_buffer, urb->transfer_dma); -+ barrier(); -+ usb_free_urb(urb); -+} -+ -+static void usbbk_free_urbs(void) -+{ -+ unsigned long flags; -+ struct list_head tmp_list; -+ -+ if (list_empty(&usbbk->urb_free)) -+ return; -+ -+ INIT_LIST_HEAD(&tmp_list); -+ -+ spin_lock_irqsave(&usbbk->urb_free_lock, flags); -+ list_splice_init(&usbbk->urb_free, &tmp_list); -+ spin_unlock_irqrestore(&usbbk->urb_free_lock, flags); -+ -+ while (!list_empty(&tmp_list)) { -+ struct urb *next_urb = -+ list_first_entry(&tmp_list, struct urb, urb_list); -+ list_del(&next_urb->urb_list); -+ usbbk_free_urb(next_urb); -+ } -+} -+ -+static void usbif_notify_work(struct xen_usbif *usbif) -+{ -+ usbif->waiting_reqs = 1; -+ wake_up(&usbif->wq); -+} -+ -+irqreturn_t xen_usbif_be_int(int irq, void *dev_id) -+{ -+ usbif_notify_work(dev_id); -+ return IRQ_HANDLED; -+} -+ -+static void xen_usbbk_unmap(struct pending_req *req) -+{ -+ struct gnttab_unmap_grant_ref unmap[USBIF_MAX_SEGMENTS_PER_REQUEST]; -+ unsigned int i, nr_segs, invcount = 0; -+ grant_handle_t handle; -+ int ret; -+ -+ nr_segs = req->nr_buffer_segs + req->nr_extra_segs; -+ -+ if (nr_segs == 0) -+ return; -+ -+ for (i = 0; i < nr_segs; i++) { -+ handle = pending_handle(req, i); -+ if (handle == USBBACK_INVALID_HANDLE) -+ continue; -+ gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), -+ GNTMAP_host_map, handle); -+ pending_handle(req, i) = USBBACK_INVALID_HANDLE; -+ invcount++; -+ } -+ -+ ret = HYPERVISOR_grant_table_op( -+ GNTTABOP_unmap_grant_ref, unmap, invcount); -+ BUG_ON(ret); -+ /* -+ * Note, we use invcount, not nr_segs, so we can't index -+ * using vaddr(req, i). -+ */ -+ for (i = 0; i < invcount; i++) { -+ ret = m2p_remove_override( -+ virt_to_page(unmap[i].host_addr), false); -+ if (ret) { -+ pr_alert(DRV_PFX "Failed to remove M2P override for " -+ "%lx\n", (unsigned long)unmap[i].host_addr); -+ continue; -+ } -+ } -+ -+ kfree(req->seg); -+} -+ -+static int xen_usbbk_map(struct xen_usbif *usbif, -+ struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ int i, ret; -+ unsigned int nr_segs; -+ uint32_t flags; -+ struct gnttab_map_grant_ref map[USBIF_MAX_SEGMENTS_PER_REQUEST]; -+ -+ nr_segs = pending_req->nr_buffer_segs + pending_req->nr_extra_segs; -+ -+ if (nr_segs == 0) -+ return 0; -+ -+ if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) { -+ pr_alert(DRV_PFX "Bad number of segments in request\n"); -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ pending_req->seg = kmalloc(sizeof(struct pending_req_segment) * -+ nr_segs, GFP_KERNEL); -+ if (!pending_req->seg) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ flags = GNTMAP_host_map; -+ if (usb_pipeout(req->pipe)) -+ flags |= GNTMAP_readonly; -+ for (i = 0; i < pending_req->nr_buffer_segs; i++) { -+ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags, -+ req->seg[i].gref, usbif->domid); -+ } -+ -+ flags = GNTMAP_host_map; -+ for (i = pending_req->nr_buffer_segs; i < nr_segs; i++) { -+ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags, -+ req->seg[i].gref, usbif->domid); -+ } -+ -+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nr_segs); -+ BUG_ON(ret); -+ -+ for (i = 0; i < nr_segs; i++) { -+ if (unlikely(map[i].status != 0)) { -+ pr_alert(DRV_PFX "invalid buffer " -+ "-- could not remap it (error %d)\n", -+ map[i].status); -+ map[i].handle = USBBACK_INVALID_HANDLE; -+ ret |= 1; -+ } -+ -+ pending_handle(pending_req, i) = map[i].handle; -+ -+ if (ret) -+ continue; -+ -+ ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), -+ usbbk->pending_page(pending_req, i), NULL); -+ if (ret) { -+ pr_alert(DRV_PFX "Failed to install M2P override for " -+ "%lx (ret: %d)\n", -+ (unsigned long)map[i].dev_bus_addr, ret); -+ /* We could switch over to GNTTABOP_copy */ -+ continue; -+ } -+ -+ pending_req->seg[i].offset = req->seg[i].offset; -+ pending_req->seg[i].length = req->seg[i].length; -+ -+ barrier(); -+ -+ if (pending_req->seg[i].offset >= PAGE_SIZE || -+ pending_req->seg[i].length > PAGE_SIZE || -+ pending_req->seg[i].offset + -+ pending_req->seg[i].length > PAGE_SIZE) -+ ret |= 1; -+ } -+ -+ if (ret) -+ goto fail_flush; -+ -+ return 0; -+ -+fail_flush: -+ xen_usbbk_unmap(pending_req); -+ ret = -ENOMEM; -+ -+fail: -+ return ret; -+} -+ -+static void usbbk_do_response(struct pending_req *pending_req, int32_t status, -+ int32_t actual_length, int32_t error_count, -+ uint16_t start_frame) -+{ -+ struct xen_usbif *usbif = pending_req->usbif; -+ struct usbif_urb_response *res; -+ unsigned long flags; -+ int notify; -+ -+ spin_lock_irqsave(&usbif->urb_ring_lock, flags); -+ res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); -+ res->id = pending_req->id; -+ res->status = status; -+ res->actual_length = actual_length; -+ res->error_count = error_count; -+ res->start_frame = start_frame; -+ usbif->urb_ring.rsp_prod_pvt++; -+ barrier(); -+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); -+ spin_unlock_irqrestore(&usbif->urb_ring_lock, flags); -+ -+ if (notify) -+ notify_remote_via_irq(usbif->irq); -+} -+ -+static void usbbk_urb_complete(struct urb *urb) -+{ -+ struct pending_req *pending_req = (struct pending_req *)urb->context; -+ -+ if (usb_pipein(urb->pipe) && urb->status == 0 && urb->actual_length > 0) -+ copy_buff_to_pages(pending_req->buffer, pending_req, 0, -+ pending_req->nr_buffer_segs); -+ -+ if (usb_pipeisoc(urb->pipe)) -+ copy_buff_to_pages(&urb->iso_frame_desc[0], pending_req, -+ pending_req->nr_buffer_segs, -+ pending_req->nr_extra_segs); -+ -+ barrier(); -+ -+ xen_usbbk_unmap(pending_req); -+ -+ usbbk_do_response(pending_req, urb->status, urb->actual_length, -+ urb->error_count, urb->start_frame); -+ -+ remove_req_from_submitting_list(pending_req->dev, pending_req); -+ -+ barrier(); -+ usbbk_release_urb(urb); -+ usbif_put(pending_req->usbif); -+ free_req(pending_req); -+} -+ -+static void usbbk_init_urb(struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ unsigned int pipe; -+ struct usb_device *udev = pending_req->dev->udev; -+ struct urb *urb = pending_req->urb; -+ -+ switch (usb_pipetype(req->pipe)) { -+ case PIPE_ISOCHRONOUS: -+ if (usb_pipein(req->pipe)) -+ pipe = usb_rcvisocpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ else -+ pipe = usb_sndisocpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ -+ urb->dev = udev; -+ urb->pipe = pipe; -+ urb->transfer_flags = req->transfer_flags; -+ urb->transfer_flags |= URB_ISO_ASAP; -+ urb->transfer_buffer = pending_req->buffer; -+ urb->transfer_buffer_length = req->buffer_length; -+ urb->complete = usbbk_urb_complete; -+ urb->context = pending_req; -+ urb->interval = req->u.isoc.interval; -+ urb->start_frame = req->u.isoc.start_frame; -+ urb->number_of_packets = req->u.isoc.number_of_packets; -+ -+ break; -+ case PIPE_INTERRUPT: -+ if (usb_pipein(req->pipe)) -+ pipe = usb_rcvintpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ else -+ pipe = usb_sndintpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ -+ usb_fill_int_urb(urb, udev, pipe, -+ pending_req->buffer, req->buffer_length, -+ usbbk_urb_complete, -+ pending_req, req->u.intr.interval); -+ /* -+ * high speed interrupt endpoints use a logarithmic encoding of -+ * the endpoint interval, and usb_fill_int_urb() initializes a -+ * interrupt urb with the encoded interval value. -+ * -+ * req->u.intr.interval is the interval value that already -+ * encoded in the frontend part, and the above -+ * usb_fill_int_urb() initializes the urb->interval with double -+ * encoded value. -+ * -+ * so, simply overwrite the urb->interval with original value. -+ */ -+ urb->interval = req->u.intr.interval; -+ urb->transfer_flags = req->transfer_flags; -+ -+ break; -+ case PIPE_CONTROL: -+ if (usb_pipein(req->pipe)) -+ pipe = usb_rcvctrlpipe(udev, 0); -+ else -+ pipe = usb_sndctrlpipe(udev, 0); -+ -+ usb_fill_control_urb(urb, udev, pipe, -+ (unsigned char *) pending_req->setup, -+ pending_req->buffer, req->buffer_length, -+ usbbk_urb_complete, pending_req); -+ memcpy(pending_req->setup, req->u.ctrl, 8); -+ urb->setup_dma = pending_req->setup_dma; -+ urb->transfer_flags = req->transfer_flags; -+ -+ break; -+ case PIPE_BULK: -+ if (usb_pipein(req->pipe)) -+ pipe = usb_rcvbulkpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ else -+ pipe = usb_sndbulkpipe(udev, -+ usb_pipeendpoint(req->pipe)); -+ -+ usb_fill_bulk_urb(urb, udev, pipe, pending_req->buffer, -+ req->buffer_length, usbbk_urb_complete, -+ pending_req); -+ urb->transfer_flags = req->transfer_flags; -+ -+ break; -+ default: -+ break; -+ } -+ -+ if (req->buffer_length) { -+ urb->transfer_dma = pending_req->transfer_dma; -+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ } -+} -+ -+struct set_interface_request { -+ struct pending_req *pending_req; -+ int interface; -+ int alternate; -+ struct work_struct work; -+}; -+ -+static void usbbk_set_interface_work(struct work_struct *arg) -+{ -+ struct set_interface_request *req -+ = container_of(arg, struct set_interface_request, work); -+ struct pending_req *pending_req = req->pending_req; -+ struct usb_device *udev = req->pending_req->dev->udev; -+ -+ int ret; -+ -+ usb_lock_device(udev); -+ ret = usb_set_interface(udev, req->interface, req->alternate); -+ usb_unlock_device(udev); -+ usb_put_dev(udev); -+ -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(pending_req->usbif); -+ free_req(pending_req); -+ kfree(req); -+} -+ -+static int usbbk_set_interface(struct pending_req *pending_req, int interface, -+ int alternate) -+{ -+ struct set_interface_request *req; -+ struct usb_device *udev = pending_req->dev->udev; -+ -+ req = kmalloc(sizeof(*req), GFP_KERNEL); -+ if (!req) -+ return -ENOMEM; -+ req->pending_req = pending_req; -+ req->interface = interface; -+ req->alternate = alternate; -+ INIT_WORK(&req->work, usbbk_set_interface_work); -+ usb_get_dev(udev); -+ schedule_work(&req->work); -+ return 0; -+} -+ -+struct clear_halt_request { -+ struct pending_req *pending_req; -+ int pipe; -+ struct work_struct work; -+}; -+ -+static void usbbk_clear_halt_work(struct work_struct *arg) -+{ -+ struct clear_halt_request *req = container_of(arg, -+ struct clear_halt_request, work); -+ struct pending_req *pending_req = req->pending_req; -+ struct usb_device *udev = req->pending_req->dev->udev; -+ int ret; -+ -+ usb_lock_device(udev); -+ ret = usb_clear_halt(req->pending_req->dev->udev, req->pipe); -+ usb_unlock_device(udev); -+ usb_put_dev(udev); -+ -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(pending_req->usbif); -+ free_req(pending_req); -+ kfree(req); -+} -+ -+static int usbbk_clear_halt(struct pending_req *pending_req, int pipe) -+{ -+ struct clear_halt_request *req; -+ struct usb_device *udev = pending_req->dev->udev; -+ -+ req = kmalloc(sizeof(*req), GFP_KERNEL); -+ if (!req) -+ return -ENOMEM; -+ req->pending_req = pending_req; -+ req->pipe = pipe; -+ INIT_WORK(&req->work, usbbk_clear_halt_work); -+ -+ usb_get_dev(udev); -+ schedule_work(&req->work); -+ return 0; -+} -+ -+#if 0 -+struct port_reset_request { -+ struct pending_req *pending_req; -+ struct work_struct work; -+}; -+ -+static void usbbk_port_reset_work(struct work_struct *arg) -+{ -+ struct port_reset_request *req = container_of(arg, -+ struct port_reset_request, work); -+ struct pending_req *pending_req = req->pending_req; -+ struct usb_device *udev = pending_req->dev->udev; -+ int ret, ret_lock; -+ -+ ret = ret_lock = usb_lock_device_for_reset(udev, NULL); -+ if (ret_lock >= 0) { -+ ret = usb_reset_device(udev); -+ if (ret_lock) -+ usb_unlock_device(udev); -+ } -+ usb_put_dev(udev); -+ -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(pending_req->usbif); -+ free_req(pending_req); -+ kfree(req); -+} -+ -+static int usbbk_port_reset(struct pending_req *pending_req) -+{ -+ struct port_reset_request *req; -+ struct usb_device *udev = pending_req->dev->udev; -+ -+ req = kmalloc(sizeof(*req), GFP_KERNEL); -+ if (!req) -+ return -ENOMEM; -+ -+ req->pending_req = pending_req; -+ INIT_WORK(&req->work, usbbk_port_reset_work); -+ -+ usb_get_dev(udev); -+ schedule_work(&req->work); -+ return 0; -+} -+#endif -+ -+static void usbbk_set_address(struct xen_usbif *usbif, struct xen_usbdev *dev, -+ int cur_addr, int new_addr) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbif->addr_lock, flags); -+ if (cur_addr) -+ usbif->addr_table[cur_addr] = NULL; -+ if (new_addr) -+ usbif->addr_table[new_addr] = dev; -+ dev->addr = new_addr; -+ spin_unlock_irqrestore(&usbif->addr_lock, flags); -+} -+ -+static void process_unlink_req(struct xen_usbif *usbif, -+ struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ struct pending_req *unlink_req = NULL; -+ int devnum; -+ int ret = 0; -+ unsigned long flags; -+ -+ devnum = usb_pipedevice(req->pipe); -+ if (unlikely(devnum == 0)) { -+ pending_req->dev = xen_usbif_find_attached_device(usbif, -+ usbif_pipeportnum(req->pipe)); -+ if (unlikely(!pending_req->dev)) { -+ ret = -ENODEV; -+ goto fail_response; -+ } -+ } else { -+ if (unlikely(!usbif->addr_table[devnum])) { -+ ret = -ENODEV; -+ goto fail_response; -+ } -+ pending_req->dev = usbif->addr_table[devnum]; -+ } -+ -+ spin_lock_irqsave(&pending_req->dev->submitting_lock, flags); -+ list_for_each_entry(unlink_req, &pending_req->dev->submitting_list, -+ urb_list) { -+ if (unlink_req->id == req->u.unlink.unlink_id) { -+ ret = usb_unlink_urb(unlink_req->urb); -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&pending_req->dev->submitting_lock, flags); -+ -+fail_response: -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(usbif); -+ free_req(pending_req); -+ return; -+} -+ -+static int check_and_submit_special_ctrlreq(struct xen_usbif *usbif, -+ struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ int devnum; -+ struct xen_usbdev *dev = NULL; -+ struct usb_ctrlrequest *ctrl = (struct usb_ctrlrequest *) req->u.ctrl; -+ int ret; -+ int done = 0; -+ -+ devnum = usb_pipedevice(req->pipe); -+ -+ /* -+ * When the device is first connected or reseted, USB device has no -+ * address. In this initial state, following requests are send to -+ * device address (#0), -+ * -+ * 1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is send, and -+ * OS knows what device is connected to. -+ * -+ * 2. SET_ADDRESS is send, and then, device has its address. -+ * -+ * In the next step, SET_CONFIGURATION is send to addressed device, and -+ * then, the device is finally ready to use. -+ */ -+ if (unlikely(devnum == 0)) { -+ dev = xen_usbif_find_attached_device(usbif, -+ usbif_pipeportnum(req->pipe)); -+ if (unlikely(!dev)) { -+ ret = -ENODEV; -+ goto fail_response; -+ } -+ -+ switch (ctrl->bRequest) { -+ case USB_REQ_GET_DESCRIPTOR: -+ /* -+ * GET_DESCRIPTOR request to device #0. -+ * through to normal urb transfer. -+ */ -+ pending_req->dev = dev; -+ return 0; -+ break; -+ case USB_REQ_SET_ADDRESS: -+ /* -+ * SET_ADDRESS request to device #0. -+ * add attached device to addr_table. -+ */ -+ { -+ __u16 addr = le16_to_cpu(ctrl->wValue); -+ usbbk_set_address(usbif, dev, 0, addr); -+ } -+ ret = 0; -+ goto fail_response; -+ break; -+ default: -+ ret = -EINVAL; -+ goto fail_response; -+ } -+ } else { -+ if (unlikely(!usbif->addr_table[devnum])) { -+ ret = -ENODEV; -+ goto fail_response; -+ } -+ pending_req->dev = usbif->addr_table[devnum]; -+ } -+ -+ /* -+ * Check special request -+ */ -+ switch (ctrl->bRequest) { -+ case USB_REQ_SET_ADDRESS: -+ /* -+ * SET_ADDRESS request to addressed device. -+ * change addr or remove from addr_table. -+ */ -+ { -+ __u16 addr = le16_to_cpu(ctrl->wValue); -+ usbbk_set_address(usbif, dev, devnum, addr); -+ } -+ ret = 0; -+ goto fail_response; -+ break; -+#if 0 -+ case USB_REQ_SET_CONFIGURATION: -+ /* -+ * linux 2.6.27 or later version only! -+ */ -+ if (ctrl->RequestType == USB_RECIP_DEVICE) { -+ __u16 config = le16_to_cpu(ctrl->wValue); -+ usb_driver_set_configuration(pending_req->dev->udev, -+ config); -+ done = 1; -+ } -+ break; -+#endif -+ case USB_REQ_SET_INTERFACE: -+ if (ctrl->bRequestType == USB_RECIP_INTERFACE) { -+ __u16 alt = le16_to_cpu(ctrl->wValue); -+ __u16 intf = le16_to_cpu(ctrl->wIndex); -+ usbbk_set_interface(pending_req, intf, alt); -+ done = 1; -+ } -+ break; -+ case USB_REQ_CLEAR_FEATURE: -+ if (ctrl->bRequestType == USB_RECIP_ENDPOINT -+ && ctrl->wValue == USB_ENDPOINT_HALT) { -+ int pipe; -+ int ep = le16_to_cpu(ctrl->wIndex) & 0x0f; -+ int dir = le16_to_cpu(ctrl->wIndex) & USB_DIR_IN; -+ if (dir) -+ pipe = usb_rcvctrlpipe(pending_req->dev->udev, -+ ep); -+ else -+ pipe = usb_sndctrlpipe(pending_req->dev->udev, -+ ep); -+ usbbk_clear_halt(pending_req, pipe); -+ done = 1; -+ } -+ break; -+#if 0 /* not tested yet */ -+ case USB_REQ_SET_FEATURE: -+ if (ctrl->bRequestType == USB_RT_PORT) { -+ __u16 feat = le16_to_cpu(ctrl->wValue); -+ if (feat == USB_PORT_FEAT_RESET) { -+ usbbk_port_reset(pending_req); -+ done = 1; -+ } -+ } -+ break; -+#endif -+ default: -+ break; -+ } -+ -+ return done; -+ -+fail_response: -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(usbif); -+ free_req(pending_req); -+ return 1; -+} -+ -+static void dispatch_request_to_pending_reqs(struct xen_usbif *usbif, -+ struct usbif_urb_request *req, -+ struct pending_req *pending_req) -+{ -+ int ret; -+ -+ pending_req->id = req->id; -+ pending_req->usbif = usbif; -+ -+ barrier(); -+ -+ usbif_get(usbif); -+ -+ /* unlink request */ -+ if (unlikely(usbif_pipeunlink(req->pipe))) { -+ process_unlink_req(usbif, req, pending_req); -+ return; -+ } -+ -+ if (usb_pipecontrol(req->pipe)) { -+ if (check_and_submit_special_ctrlreq(usbif, req, pending_req)) -+ return; -+ } else { -+ int devnum = usb_pipedevice(req->pipe); -+ if (unlikely(!usbif->addr_table[devnum])) { -+ ret = -ENODEV; -+ goto fail_response; -+ } -+ pending_req->dev = usbif->addr_table[devnum]; -+ } -+ -+ barrier(); -+ -+ ret = usbbk_alloc_urb(req, pending_req); -+ if (ret) { -+ ret = -ESHUTDOWN; -+ goto fail_response; -+ } -+ -+ add_req_to_submitting_list(pending_req->dev, pending_req); -+ -+ barrier(); -+ -+ usbbk_init_urb(req, pending_req); -+ -+ barrier(); -+ -+ pending_req->nr_buffer_segs = req->nr_buffer_segs; -+ if (usb_pipeisoc(req->pipe)) -+ pending_req->nr_extra_segs = req->u.isoc.nr_frame_desc_segs; -+ else -+ pending_req->nr_extra_segs = 0; -+ -+ barrier(); -+ -+ ret = xen_usbbk_map(usbif, req, pending_req); -+ if (ret) { -+ pr_alert(DRV_PFX "invalid buffer\n"); -+ ret = -ESHUTDOWN; -+ goto fail_free_urb; -+ } -+ -+ barrier(); -+ -+ if (usb_pipeout(req->pipe) && req->buffer_length) -+ copy_pages_to_buff(pending_req->buffer, pending_req, 0, -+ pending_req->nr_buffer_segs); -+ if (usb_pipeisoc(req->pipe)) { -+ copy_pages_to_buff(&pending_req->urb->iso_frame_desc[0], -+ pending_req, pending_req->nr_buffer_segs, -+ pending_req->nr_extra_segs); -+ } -+ -+ barrier(); -+ -+ ret = usb_submit_urb(pending_req->urb, GFP_KERNEL); -+ if (ret) { -+ pr_alert(DRV_PFX "failed submitting urb, error %d\n", ret); -+ ret = -ESHUTDOWN; -+ goto fail_flush_area; -+ } -+ return; -+ -+fail_flush_area: -+ xen_usbbk_unmap(pending_req); -+fail_free_urb: -+ remove_req_from_submitting_list(pending_req->dev, pending_req); -+ barrier(); -+ usbbk_release_urb(pending_req->urb); -+fail_response: -+ usbbk_do_response(pending_req, ret, 0, 0, 0); -+ usbif_put(usbif); -+ free_req(pending_req); -+} -+ -+static int usbbk_start_submit_urb(struct xen_usbif *usbif) -+{ -+ struct usbif_urb_back_ring *urb_ring = &usbif->urb_ring; -+ struct usbif_urb_request *req; -+ struct pending_req *pending_req; -+ RING_IDX rc, rp; -+ int more_to_do = 0; -+ -+ rc = urb_ring->req_cons; -+ rp = urb_ring->sring->req_prod; -+ rmb(); -+ -+ while (rc != rp) { -+ if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) { -+ pr_warn(DRV_PFX "RING_REQUEST_CONS_OVERFLOW\n"); -+ break; -+ } -+ -+ pending_req = alloc_req(); -+ if (NULL == pending_req) { -+ more_to_do = 1; -+ break; -+ } -+ -+ req = RING_GET_REQUEST(urb_ring, rc); -+ urb_ring->req_cons = ++rc; -+ -+ dispatch_request_to_pending_reqs(usbif, req, pending_req); -+ } -+ -+ RING_FINAL_CHECK_FOR_REQUESTS(&usbif->urb_ring, more_to_do); -+ -+ cond_resched(); -+ -+ return more_to_do; -+} -+ -+void xen_usbif_hotplug_notify(struct xen_usbif *usbif, int portnum, int speed) -+{ -+ struct usbif_conn_back_ring *ring = &usbif->conn_ring; -+ struct usbif_conn_request *req; -+ struct usbif_conn_response *res; -+ unsigned long flags; -+ u16 id; -+ int notify; -+ -+ spin_lock_irqsave(&usbif->conn_ring_lock, flags); -+ -+ req = RING_GET_REQUEST(ring, ring->req_cons); -+ id = req->id; -+ ring->req_cons++; -+ ring->sring->req_event = ring->req_cons + 1; -+ -+ res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); -+ res->id = id; -+ res->portnum = portnum; -+ res->speed = speed; -+ ring->rsp_prod_pvt++; -+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); -+ -+ spin_unlock_irqrestore(&usbif->conn_ring_lock, flags); -+ -+ if (notify) -+ notify_remote_via_irq(usbif->irq); -+} -+ -+int xen_usbif_schedule(void *arg) -+{ -+ struct xen_usbif *usbif = (struct xen_usbif *) arg; -+ -+ usbif_get(usbif); -+ -+ while (!kthread_should_stop()) { -+ wait_event_interruptible(usbif->wq, -+ usbif->waiting_reqs || kthread_should_stop()); -+ wait_event_interruptible(usbbk->pending_free_wq, -+ !list_empty(&usbbk->pending_free) || kthread_should_stop()); -+ usbif->waiting_reqs = 0; -+ smp_mb(); -+ -+ if (usbbk_start_submit_urb(usbif)) -+ usbif->waiting_reqs = 1; -+ -+ usbbk_free_urbs(); -+ } -+ -+ usbbk_free_urbs(); -+ usbif->xenusbd = NULL; -+ usbif_put(usbif); -+ -+ return 0; -+} -+ -+/* -+ * attach xen_usbdev device to usbif. -+ */ -+void xen_usbif_attach_device(struct xen_usbif *usbif, struct xen_usbdev *dev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbif->dev_lock, flags); -+ list_add(&dev->dev_list, &usbif->dev_list); -+ spin_unlock_irqrestore(&usbif->dev_lock, flags); -+ dev->usbif = usbif; -+} -+ -+/* -+ * detach usbdev device from usbif. -+ */ -+void xen_usbif_detach_device(struct xen_usbif *usbif, struct xen_usbdev *dev) -+{ -+ unsigned long flags; -+ -+ if (dev->addr) -+ usbbk_set_address(usbif, dev, dev->addr, 0); -+ spin_lock_irqsave(&usbif->dev_lock, flags); -+ list_del(&dev->dev_list); -+ spin_unlock_irqrestore(&usbif->dev_lock, flags); -+ dev->usbif = NULL; -+} -+ -+void xen_usbif_detach_device_without_lock(struct xen_usbif *usbif, -+ struct xen_usbdev *dev) -+{ -+ if (dev->addr) -+ usbbk_set_address(usbif, dev, dev->addr, 0); -+ list_del(&dev->dev_list); -+ dev->usbif = NULL; -+} -+ -+static int __init xen_usbif_init(void) -+{ -+ int i, mmap_pages; -+ int rc = 0; -+ -+ if (!xen_pv_domain()) -+ return -ENODEV; -+ -+ usbbk = kzalloc(sizeof(struct xen_usbbk), GFP_KERNEL); -+ if (!usbbk) { -+ pr_alert(DRV_PFX "%s: out of memory!\n", __func__); -+ return -ENOMEM; -+ } -+ -+ mmap_pages = xen_usbif_reqs * USBIF_MAX_SEGMENTS_PER_REQUEST; -+ usbbk->pending_reqs = -+ kzalloc(sizeof(usbbk->pending_reqs[0]) * xen_usbif_reqs, -+ GFP_KERNEL); -+ usbbk->pending_grant_handles = -+ kmalloc(sizeof(usbbk->pending_grant_handles[0]) * mmap_pages, -+ GFP_KERNEL); -+ usbbk->pending_pages = -+ kzalloc(sizeof(usbbk->pending_pages[0]) * mmap_pages, -+ GFP_KERNEL); -+ -+ if (!usbbk->pending_reqs || !usbbk->pending_grant_handles || -+ !usbbk->pending_pages) { -+ rc = -ENOMEM; -+ pr_alert(DRV_PFX "%s: out of memory\n", __func__); -+ goto failed_init; -+ } -+ -+ for (i = 0; i < mmap_pages; i++) { -+ usbbk->pending_grant_handles[i] = USBBACK_INVALID_HANDLE; -+ usbbk->pending_pages[i] = alloc_page(GFP_KERNEL); -+ if (usbbk->pending_pages[i] == NULL) { -+ rc = -ENOMEM; -+ pr_alert(DRV_PFX "%s: out of memory\n", __func__); -+ goto failed_init; -+ } -+ } -+ -+ INIT_LIST_HEAD(&usbbk->pending_free); -+ spin_lock_init(&usbbk->pending_free_lock); -+ init_waitqueue_head(&usbbk->pending_free_wq); -+ -+ INIT_LIST_HEAD(&usbbk->urb_free); -+ spin_lock_init(&usbbk->urb_free_lock); -+ -+ for (i = 0; i < xen_usbif_reqs; i++) -+ list_add_tail(&usbbk->pending_reqs[i].free_list, -+ &usbbk->pending_free); -+ -+ rc = xen_usbdev_init(); -+ if (rc) -+ goto failed_init; -+ -+ rc = xen_usbif_xenbus_init(); -+ if (rc) -+ goto usb_exit; -+ -+ return 0; -+ -+ usb_exit: -+ xen_usbdev_exit(); -+ failed_init: -+ kfree(usbbk->pending_reqs); -+ kfree(usbbk->pending_grant_handles); -+ if (usbbk->pending_pages) { -+ for (i = 0; i < mmap_pages; i++) { -+ if (usbbk->pending_pages[i]) -+ __free_page(usbbk->pending_pages[i]); -+ } -+ kfree(usbbk->pending_pages); -+ } -+ kfree(usbbk); -+ usbbk = NULL; -+ return rc; -+} -+ -+struct xen_usbdev *xen_usbif_find_attached_device(struct xen_usbif *usbif, -+ int portnum) -+{ -+ struct xen_usbdev *dev; -+ int found = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbif->dev_lock, flags); -+ list_for_each_entry(dev, &usbif->dev_list, dev_list) { -+ if (dev->port->portnum == portnum) { -+ found = 1; -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&usbif->dev_lock, flags); -+ -+ if (found) -+ return dev; -+ -+ return NULL; -+} -+ -+static void __exit xen_usbif_exit(void) -+{ -+ int i; -+ int mmap_pages = xen_usbif_reqs * USBIF_MAX_SEGMENTS_PER_REQUEST; -+ -+ xen_usbif_xenbus_exit(); -+ xen_usbdev_exit(); -+ kfree(usbbk->pending_reqs); -+ kfree(usbbk->pending_grant_handles); -+ for (i = 0; i < mmap_pages; i++) { -+ if (usbbk->pending_pages[i]) -+ __free_page(usbbk->pending_pages[i]); -+ } -+ kfree(usbbk->pending_pages); -+ usbbk = NULL; -+} -+ -+module_init(xen_usbif_init); -+module_exit(xen_usbif_exit); -+ -+MODULE_AUTHOR(""); -+MODULE_DESCRIPTION("Xen USB backend driver (xen_usbback)"); -+MODULE_LICENSE("Dual BSD/GPL"); -diff --git a/drivers/usb/host/xen-usbback/usbdev.c b/drivers/usb/host/xen-usbback/usbdev.c -new file mode 100644 -index 0000000..53a14b4 ---- /dev/null -+++ b/drivers/usb/host/xen-usbback/usbdev.c -@@ -0,0 +1,319 @@ -+/* -+ * USB stub device driver - grabbing and managing USB devices. -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * or, by your choice, -+ * -+ * When distributed separately from the Linux kernel or incorporated into -+ * other software packages, subject to the following license: -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include "common.h" -+ -+static LIST_HEAD(port_list); -+static DEFINE_SPINLOCK(port_list_lock); -+ -+struct xen_usbport *xen_usbport_find_by_busid(const char *busid) -+{ -+ struct xen_usbport *port; -+ int found = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port_list_lock, flags); -+ list_for_each_entry(port, &port_list, port_list) { -+ if (!(strncmp(port->phys_bus, busid, XEN_USB_BUS_ID_SIZE))) { -+ found = 1; -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&port_list_lock, flags); -+ -+ if (found) -+ return port; -+ -+ return NULL; -+} -+ -+struct xen_usbport *xen_usbport_find(const domid_t domid, -+ const unsigned int handle, const int portnum) -+{ -+ struct xen_usbport *port; -+ int found = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port_list_lock, flags); -+ list_for_each_entry(port, &port_list, port_list) { -+ if ((port->domid == domid) && -+ (port->handle == handle) && -+ (port->portnum == portnum)) { -+ found = 1; -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&port_list_lock, flags); -+ -+ if (found) -+ return port; -+ -+ return NULL; -+} -+ -+int xen_usbport_add(const char *busid, const domid_t domid, -+ const unsigned int handle, const int portnum) -+{ -+ struct xen_usbport *port; -+ unsigned long flags; -+ -+ port = kzalloc(sizeof(*port), GFP_KERNEL); -+ if (!port) -+ return -ENOMEM; -+ -+ port->domid = domid; -+ port->handle = handle; -+ port->portnum = portnum; -+ -+ strncpy(port->phys_bus, busid, XEN_USB_BUS_ID_SIZE); -+ -+ spin_lock_irqsave(&port_list_lock, flags); -+ list_add(&port->port_list, &port_list); -+ spin_unlock_irqrestore(&port_list_lock, flags); -+ -+ return 0; -+} -+ -+int xen_usbport_remove(const domid_t domid, const unsigned int handle, -+ const int portnum) -+{ -+ struct xen_usbport *port, *tmp; -+ int err = -ENOENT; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port_list_lock, flags); -+ list_for_each_entry_safe(port, tmp, &port_list, port_list) { -+ if (port->domid == domid && -+ port->handle == handle && -+ port->portnum == portnum) { -+ list_del(&port->port_list); -+ kfree(port); -+ -+ err = 0; -+ } -+ } -+ spin_unlock_irqrestore(&port_list_lock, flags); -+ -+ return err; -+} -+ -+static struct xen_usbdev *xen_usbdev_alloc(struct usb_device *udev, -+ struct xen_usbport *port) -+{ -+ struct xen_usbdev *dev; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) { -+ pr_alert(DRV_PFX "no memory for alloc xen_usbdev\n"); -+ return NULL; -+ } -+ kref_init(&dev->kref); -+ dev->udev = usb_get_dev(udev); -+ dev->port = port; -+ spin_lock_init(&dev->submitting_lock); -+ INIT_LIST_HEAD(&dev->submitting_list); -+ -+ return dev; -+} -+ -+static void usbdev_release(struct kref *kref) -+{ -+ struct xen_usbdev *dev; -+ -+ dev = container_of(kref, struct xen_usbdev, kref); -+ -+ usb_put_dev(dev->udev); -+ dev->udev = NULL; -+ dev->port = NULL; -+ kfree(dev); -+} -+ -+static inline void usbdev_get(struct xen_usbdev *dev) -+{ -+ kref_get(&dev->kref); -+} -+ -+static inline void usbdev_put(struct xen_usbdev *dev) -+{ -+ kref_put(&dev->kref, usbdev_release); -+} -+ -+static int usbdev_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *udev = interface_to_usbdev(intf); -+ const char *busid = dev_name(intf->dev.parent); -+ struct xen_usbport *port = NULL; -+ struct xen_usbdev *dev = NULL; -+ struct xen_usbif *usbif = NULL; -+ int retval = -ENODEV; -+ -+ /* hub currently not supported, so skip. */ -+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) -+ goto out; -+ -+ port = xen_usbport_find_by_busid(busid); -+ if (!port) -+ goto out; -+ -+ usbif = xen_usbif_find(port->domid, port->handle); -+ if (!usbif) -+ goto out; -+ -+ switch (udev->speed) { -+ case USB_SPEED_LOW: -+ case USB_SPEED_FULL: -+ break; -+ case USB_SPEED_HIGH: -+ if (usbif->usb_ver >= USB_VER_USB20) -+ break; -+ /* fall through */ -+ default: -+ goto out; -+ } -+ -+ dev = xen_usbif_find_attached_device(usbif, port->portnum); -+ if (!dev) { -+ /* new connection */ -+ dev = xen_usbdev_alloc(udev, port); -+ if (!dev) -+ return -ENOMEM; -+ xen_usbif_attach_device(usbif, dev); -+ xen_usbif_hotplug_notify(usbif, port->portnum, udev->speed); -+ } else { -+ /* maybe already called and connected by other intf */ -+ if (strncmp(dev->port->phys_bus, busid, XEN_USB_BUS_ID_SIZE)) -+ goto out; /* invalid call */ -+ } -+ -+ usbdev_get(dev); -+ usb_set_intfdata(intf, dev); -+ retval = 0; -+ -+out: -+ return retval; -+} -+ -+static void usbdev_disconnect(struct usb_interface *intf) -+{ -+ struct xen_usbdev *dev -+ = (struct xen_usbdev *) usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ -+ if (!dev) -+ return; -+ -+ if (dev->usbif) { -+ xen_usbif_hotplug_notify(dev->usbif, dev->port->portnum, 0); -+ xen_usbif_detach_device(dev->usbif, dev); -+ } -+ xen_usbif_unlink_urbs(dev); -+ usbdev_put(dev); -+} -+ -+static ssize_t usbdev_show_ports(struct device_driver *driver, char *buf) -+{ -+ struct xen_usbport *port; -+ size_t count = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port_list_lock, flags); -+ list_for_each_entry(port, &port_list, port_list) { -+ if (count >= PAGE_SIZE) -+ break; -+ count += scnprintf((char *)buf + count, PAGE_SIZE - count, -+ "%s:%d:%d:%d\n", -+ &port->phys_bus[0], -+ port->domid, -+ port->handle, -+ port->portnum); -+ } -+ spin_unlock_irqrestore(&port_list_lock, flags); -+ -+ return count; -+} -+ -+DRIVER_ATTR(port_ids, S_IRUSR, usbdev_show_ports, NULL); -+ -+/* table of devices that matches any usbdevice */ -+static const struct usb_device_id usbdev_table[] = { -+ { .driver_info = 1 }, /* wildcard, see usb_match_id() */ -+ { } /* Terminating entry */ -+}; -+MODULE_DEVICE_TABLE(usb, usbdev_table); -+ -+static struct usb_driver xen_usbdev_driver = { -+ .name = "usbback", -+ .probe = usbdev_probe, -+ .disconnect = usbdev_disconnect, -+ .id_table = usbdev_table, -+ .no_dynamic_id = 1, -+}; -+ -+int __init xen_usbdev_init(void) -+{ -+ int err; -+ -+ err = usb_register(&xen_usbdev_driver); -+ if (err < 0) { -+ pr_alert(DRV_PFX "usb_register failed (error %d)\n", -+ err); -+ goto out; -+ } -+ -+ err = driver_create_file(&xen_usbdev_driver.drvwrap.driver, -+ &driver_attr_port_ids); -+ if (err) -+ usb_deregister(&xen_usbdev_driver); -+ -+out: -+ return err; -+} -+ -+void xen_usbdev_exit(void) -+{ -+ driver_remove_file(&xen_usbdev_driver.drvwrap.driver, -+ &driver_attr_port_ids); -+ usb_deregister(&xen_usbdev_driver); -+} -diff --git a/drivers/usb/host/xen-usbback/xenbus.c b/drivers/usb/host/xen-usbback/xenbus.c -new file mode 100644 -index 0000000..5eae4ec ---- /dev/null -+++ b/drivers/usb/host/xen-usbback/xenbus.c -@@ -0,0 +1,482 @@ -+/* -+ * Xenbus interface for USB backend driver. -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * or, by your choice, -+ * -+ * When distributed separately from the Linux kernel or incorporated into -+ * other software packages, subject to the following license: -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include -+#include "common.h" -+ -+static LIST_HEAD(usbif_list); -+static DEFINE_SPINLOCK(usbif_list_lock); -+ -+struct xen_usbif *xen_usbif_find(domid_t domid, unsigned int handle) -+{ -+ struct xen_usbif *usbif; -+ int found = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbif_list_lock, flags); -+ list_for_each_entry(usbif, &usbif_list, usbif_list) { -+ if (usbif->domid == domid && usbif->handle == handle) { -+ found = 1; -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&usbif_list_lock, flags); -+ -+ if (found) -+ return usbif; -+ -+ return NULL; -+} -+ -+struct xen_usbif *xen_usbif_alloc(domid_t domid, unsigned int handle) -+{ -+ struct xen_usbif *usbif; -+ unsigned long flags; -+ int i; -+ -+ usbif = kzalloc(sizeof(struct xen_usbif), GFP_KERNEL); -+ if (!usbif) -+ return NULL; -+ -+ usbif->domid = domid; -+ usbif->handle = handle; -+ INIT_LIST_HEAD(&usbif->usbif_list); -+ spin_lock_init(&usbif->urb_ring_lock); -+ spin_lock_init(&usbif->conn_ring_lock); -+ atomic_set(&usbif->refcnt, 0); -+ init_waitqueue_head(&usbif->wq); -+ init_waitqueue_head(&usbif->waiting_to_free); -+ spin_lock_init(&usbif->dev_lock); -+ INIT_LIST_HEAD(&usbif->dev_list); -+ spin_lock_init(&usbif->addr_lock); -+ for (i = 0; i < XEN_USB_DEV_ADDR_SIZE; i++) -+ usbif->addr_table[i] = NULL; -+ -+ spin_lock_irqsave(&usbif_list_lock, flags); -+ list_add(&usbif->usbif_list, &usbif_list); -+ spin_unlock_irqrestore(&usbif_list_lock, flags); -+ -+ return usbif; -+} -+ -+static int xen_usbif_map(struct xen_usbif *usbif, unsigned long urb_ring_ref, -+ unsigned long conn_ring_ref, unsigned int evtchn) -+{ -+ int err = -ENOMEM; -+ -+ if (usbif->irq) -+ return 0; -+ -+ err = xenbus_map_ring_valloc(usbif->xbdev, urb_ring_ref, -+ &usbif->urb_sring); -+ if (err < 0) -+ return err; -+ -+ err = xenbus_map_ring_valloc(usbif->xbdev, conn_ring_ref, -+ &usbif->conn_sring); -+ if (err < 0) -+ goto fail_alloc; -+ -+ err = bind_interdomain_evtchn_to_irqhandler(usbif->domid, evtchn, -+ xen_usbif_be_int, 0, "usbif-backend", usbif); -+ if (err < 0) -+ goto fail_evtchn; -+ usbif->irq = err; -+ -+ BACK_RING_INIT(&usbif->urb_ring, -+ (struct usbif_urb_sring *)usbif->urb_sring, PAGE_SIZE); -+ BACK_RING_INIT(&usbif->conn_ring, -+ (struct usbif_conn_sring *)usbif->conn_sring, PAGE_SIZE); -+ -+ return 0; -+ -+fail_evtchn: -+ xenbus_unmap_ring_vfree(usbif->xbdev, usbif->conn_sring); -+fail_alloc: -+ xenbus_unmap_ring_vfree(usbif->xbdev, usbif->urb_sring); -+ -+ return err; -+} -+ -+static void xen_usbif_disconnect(struct xen_usbif *usbif) -+{ -+ struct xen_usbdev *dev, *tmp; -+ unsigned long flags; -+ -+ if (usbif->xenusbd) { -+ kthread_stop(usbif->xenusbd); -+ usbif->xenusbd = NULL; -+ } -+ -+ spin_lock_irqsave(&usbif->dev_lock, flags); -+ list_for_each_entry_safe(dev, tmp, &usbif->dev_list, dev_list) { -+ xen_usbif_unlink_urbs(dev); -+ xen_usbif_detach_device_without_lock(usbif, dev); -+ } -+ spin_unlock_irqrestore(&usbif->dev_lock, flags); -+ -+ wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0); -+ -+ if (usbif->irq) { -+ unbind_from_irqhandler(usbif->irq, usbif); -+ usbif->irq = 0; -+ } -+ -+ if (usbif->urb_ring.sring) { -+ xenbus_unmap_ring_vfree(usbif->xbdev, usbif->urb_sring); -+ usbif->urb_ring.sring = NULL; -+ xenbus_unmap_ring_vfree(usbif->xbdev, usbif->conn_sring); -+ usbif->conn_ring.sring = NULL; -+ } -+} -+ -+static void xen_usbif_free(struct xen_usbif *usbif) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usbif_list_lock, flags); -+ list_del(&usbif->usbif_list); -+ spin_unlock_irqrestore(&usbif_list_lock, flags); -+ kfree(usbif); -+} -+ -+static void usbbk_changed(struct xenbus_watch *watch, const char **vec, -+ unsigned int len) -+{ -+ struct xenbus_transaction xbt; -+ int err; -+ int i; -+ char node[8]; -+ char *busid; -+ struct xen_usbport *port = NULL; -+ -+ struct xen_usbif *usbif = container_of(watch, struct xen_usbif, -+ backend_watch); -+ struct xenbus_device *dev = usbif->xbdev; -+ -+again: -+ err = xenbus_transaction_start(&xbt); -+ if (err) { -+ xenbus_dev_fatal(dev, err, "starting transaction"); -+ return; -+ } -+ -+ for (i = 1; i <= usbif->num_ports; i++) { -+ sprintf(node, "port/%d", i); -+ busid = xenbus_read(xbt, dev->nodename, node, NULL); -+ if (IS_ERR(busid)) { -+ err = PTR_ERR(busid); -+ xenbus_dev_fatal(dev, err, "reading port/%d", i); -+ goto abort; -+ } -+ -+ /* -+ * remove port, if the port is not connected, -+ */ -+ if (strlen(busid) == 0) { -+ port = xen_usbport_find(usbif->domid, usbif->handle, i); -+ if (port) { -+ if (port->is_connected) -+ xenbus_dev_fatal(dev, err, -+ "can't remove port/%d, " -+ "unbind first", i); -+ else -+ xen_usbport_remove(usbif->domid, -+ usbif->handle, i); -+ } -+ continue; /* never configured, ignore */ -+ } -+ -+ /* -+ * add port, -+ * if the port is not configured and not used from other usbif. -+ */ -+ port = xen_usbport_find(usbif->domid, usbif->handle, i); -+ if (port) { -+ if ((strncmp(port->phys_bus, busid, -+ XEN_USB_BUS_ID_SIZE))) -+ xenbus_dev_fatal(dev, err, "can't add port/%d, " -+ "remove first", i); -+ else -+ continue; /* already configured, ignore */ -+ } else { -+ if (xen_usbport_find_by_busid(busid)) -+ xenbus_dev_fatal(dev, err, "can't add port/%d, " -+ "busid already used", i); -+ else -+ xen_usbport_add(busid, usbif->domid, -+ usbif->handle, i); -+ } -+ } -+ -+ err = xenbus_transaction_end(xbt, 0); -+ if (err == -EAGAIN) -+ goto again; -+ if (err) -+ xenbus_dev_fatal(dev, err, "completing transaction"); -+ -+ return; -+ -+abort: -+ xenbus_transaction_end(xbt, 1); -+ -+ return; -+} -+ -+static int usbbk_remove(struct xenbus_device *dev) -+{ -+ struct xen_usbif *usbif = dev_get_drvdata(&dev->dev); -+ int i; -+ -+ if (usbif->backend_watch.node) { -+ unregister_xenbus_watch(&usbif->backend_watch); -+ kfree(usbif->backend_watch.node); -+ usbif->backend_watch.node = NULL; -+ } -+ -+ if (usbif) { -+ /* remove all ports */ -+ for (i = 1; i <= usbif->num_ports; i++) -+ xen_usbport_remove(usbif->domid, usbif->handle, i); -+ xen_usbif_disconnect(usbif); -+ xen_usbif_free(usbif); -+ } -+ dev_set_drvdata(&dev->dev, NULL); -+ -+ return 0; -+} -+ -+static int usbbk_probe(struct xenbus_device *dev, -+ const struct xenbus_device_id *id) -+{ -+ struct xen_usbif *usbif; -+ unsigned long handle; -+ int num_ports; -+ int usb_ver; -+ int err; -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ if (kstrtoul(strrchr(dev->otherend, '/') + 1, 0, &handle)) -+ return -ENOENT; -+ -+ usbif = xen_usbif_alloc(dev->otherend_id, handle); -+ if (!usbif) { -+ xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface"); -+ return -ENOMEM; -+ } -+ usbif->xbdev = dev; -+ dev_set_drvdata(&dev->dev, usbif); -+ -+ err = xenbus_scanf(XBT_NIL, dev->nodename, "num-ports", -+ "%d", &num_ports); -+ if (err != 1) { -+ xenbus_dev_fatal(dev, err, "reading num-ports"); -+ goto fail; -+ } -+ if (num_ports < 1 || num_ports > USB_MAXCHILDREN) { -+ xenbus_dev_fatal(dev, err, "invalid num-ports"); -+ goto fail; -+ } -+ usbif->num_ports = num_ports; -+ -+ err = xenbus_scanf(XBT_NIL, dev->nodename, "usb-ver", "%d", &usb_ver); -+ if (err != 1) { -+ xenbus_dev_fatal(dev, err, "reading usb-ver"); -+ goto fail; -+ } -+ switch (usb_ver) { -+ case USB_VER_USB11: -+ case USB_VER_USB20: -+ usbif->usb_ver = usb_ver; -+ break; -+ default: -+ xenbus_dev_fatal(dev, err, "invalid usb-ver"); -+ goto fail; -+ } -+ -+ err = xenbus_switch_state(dev, XenbusStateInitWait); -+ if (err) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ usbbk_remove(dev); -+ return err; -+} -+ -+static int connect_rings(struct xen_usbif *usbif) -+{ -+ struct xenbus_device *dev = usbif->xbdev; -+ unsigned long urb_ring_ref; -+ unsigned long conn_ring_ref; -+ unsigned int evtchn; -+ int err; -+ -+ err = xenbus_gather(XBT_NIL, dev->otherend, -+ "urb-ring-ref", "%lu", &urb_ring_ref, -+ "conn-ring-ref", "%lu", &conn_ring_ref, -+ "event-channel", "%u", &evtchn, NULL); -+ if (err) { -+ xenbus_dev_fatal(dev, err, -+ "reading %s/ring-ref and event-channel", -+ dev->otherend); -+ return err; -+ } -+ -+ pr_info(DRV_PFX "urb-ring-ref %ld, conn-ring-ref %ld, " -+ "event-channel %d\n", urb_ring_ref, conn_ring_ref, evtchn); -+ -+ err = xen_usbif_map(usbif, urb_ring_ref, conn_ring_ref, evtchn); -+ if (err) { -+ xenbus_dev_fatal(dev, err, "mapping urb-ring-ref %lu " -+ "conn-ring-ref %lu port %u", -+ urb_ring_ref, conn_ring_ref, evtchn); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static int start_xenusbd(struct xen_usbif *usbif) -+{ -+ int err = 0; -+ char name[TASK_COMM_LEN]; -+ -+ snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, -+ usbif->handle); -+ usbif->xenusbd = kthread_run(xen_usbif_schedule, usbif, name); -+ if (IS_ERR(usbif->xenusbd)) { -+ err = PTR_ERR(usbif->xenusbd); -+ usbif->xenusbd = NULL; -+ xenbus_dev_error(usbif->xbdev, err, "start xenusbd"); -+ } -+ -+ return err; -+} -+ -+static void frontend_changed(struct xenbus_device *dev, -+ enum xenbus_state frontend_state) -+{ -+ struct xen_usbif *usbif = dev_get_drvdata(&dev->dev); -+ int err; -+ -+ switch (frontend_state) { -+ case XenbusStateReconfiguring: -+ case XenbusStateReconfigured: -+ break; -+ -+ case XenbusStateInitialising: -+ if (dev->state == XenbusStateClosed) { -+ pr_info(DRV_PFX "%s: %s: prepare for reconnect\n", -+ __func__, dev->nodename); -+ xenbus_switch_state(dev, XenbusStateInitWait); -+ } -+ break; -+ -+ case XenbusStateInitialised: -+ case XenbusStateConnected: -+ if (dev->state == XenbusStateConnected) -+ break; -+ -+ xen_usbif_disconnect(usbif); -+ -+ err = connect_rings(usbif); -+ if (err) -+ break; -+ err = start_xenusbd(usbif); -+ if (err) -+ break; -+ err = xenbus_watch_pathfmt(dev, &usbif->backend_watch, -+ usbbk_changed, "%s/%s", dev->nodename, "port"); -+ if (err) -+ break; -+ xenbus_switch_state(dev, XenbusStateConnected); -+ break; -+ -+ case XenbusStateClosing: -+ xenbus_switch_state(dev, XenbusStateClosing); -+ break; -+ -+ case XenbusStateClosed: -+ xen_usbif_disconnect(usbif); -+ xenbus_switch_state(dev, XenbusStateClosed); -+ if (xenbus_dev_is_online(dev)) -+ break; -+ /* fall through if not online */ -+ case XenbusStateUnknown: -+ device_unregister(&dev->dev); -+ break; -+ -+ default: -+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", -+ frontend_state); -+ break; -+ } -+} -+ -+ -+/* ** Driver Registration ** */ -+ -+static const struct xenbus_device_id usbback_ids[] = { -+ { "vusb" }, -+ { "" }, -+}; -+ -+static DEFINE_XENBUS_DRIVER(usbback, , -+ .probe = usbbk_probe, -+ .remove = usbbk_remove, -+ .otherend_changed = frontend_changed, -+); -+ -+int __init xen_usbif_xenbus_init(void) -+{ -+ return xenbus_register_backend(&usbback_driver); -+} -+ -+void __exit xen_usbif_xenbus_exit(void) -+{ -+ xenbus_unregister_driver(&usbback_driver); -+} -diff --git a/drivers/usb/host/xen-usbfront.c b/drivers/usb/host/xen-usbfront.c -new file mode 100644 -index 0000000..e632de3 ---- /dev/null -+++ b/drivers/usb/host/xen-usbfront.c -@@ -0,0 +1,1739 @@ -+/* -+ * xen-usbfront.c -+ * -+ * This file is part of Xen USB Virtual Host Controller driver. -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * or, by your choice, -+ * -+ * When distributed separately from the Linux kernel or incorporated into -+ * other software packages, subject to the following license: -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static inline struct usbfront_info *hcd_to_info(struct usb_hcd *hcd) -+{ -+ return (struct usbfront_info *) (hcd->hcd_priv); -+} -+ -+static inline struct usb_hcd *info_to_hcd(struct usbfront_info *info) -+{ -+ return container_of((void *) info, struct usb_hcd, hcd_priv); -+} -+ -+/* Private per-URB data */ -+struct urb_priv { -+ struct list_head list; -+ struct urb *urb; -+ int req_id; /* RING_REQUEST id for submitting */ -+ int unlink_req_id; /* RING_REQUEST id for unlinking */ -+ int status; -+ unsigned unlinked:1; /* dequeued marker */ -+}; -+ -+/* virtual roothub port status */ -+struct rhport_status { -+ u32 status; -+ unsigned resuming:1; /* in resuming */ -+ unsigned c_connection:1; /* connection changed */ -+ unsigned long timeout; -+}; -+ -+/* status of attached device */ -+struct vdevice_status { -+ int devnum; -+ enum usb_device_state status; -+ enum usb_device_speed speed; -+}; -+ -+/* RING request shadow */ -+struct usb_shadow { -+ struct usbif_urb_request req; -+ struct urb *urb; -+}; -+ -+/* statistics for tuning, monitoring, ... */ -+struct xenhcd_stats { -+ unsigned long ring_full; /* RING_FULL conditions */ -+ unsigned long complete; /* normal giveback urbs */ -+ unsigned long unlink; /* unlinked urbs */ -+}; -+ -+struct usbfront_info { -+ /* Virtual Host Controller has 4 urb queues */ -+ struct list_head pending_submit_list; -+ struct list_head pending_unlink_list; -+ struct list_head in_progress_list; -+ struct list_head giveback_waiting_list; -+ -+ spinlock_t lock; -+ -+ /* timer that kick pending and giveback waiting urbs */ -+ struct timer_list watchdog; -+ unsigned long actions; -+ -+ /* virtual root hub */ -+ int rh_numports; -+ struct rhport_status ports[USB_MAXCHILDREN]; -+ struct vdevice_status devices[USB_MAXCHILDREN]; -+ -+ /* Xen related staff */ -+ struct xenbus_device *xbdev; -+ int urb_ring_ref; -+ int conn_ring_ref; -+ struct usbif_urb_front_ring urb_ring; -+ struct usbif_conn_front_ring conn_ring; -+ -+ unsigned int evtchn, irq; /* event channel */ -+ struct usb_shadow shadow[USB_URB_RING_SIZE]; -+ unsigned long shadow_free; -+ -+ /* RING_RESPONSE thread */ -+ struct task_struct *kthread; -+ wait_queue_head_t wq; -+ unsigned int waiting_resp; -+ -+ /* xmit statistics */ -+#ifdef XENHCD_STATS -+ struct xenhcd_stats stats; -+#define COUNT(x) do { (x)++; } while (0) -+#else -+#define COUNT(x) do {} while (0) -+#endif -+}; -+ -+#define XENHCD_RING_JIFFIES (HZ/200) -+#define XENHCD_SCAN_JIFFIES 1 -+ -+enum xenhcd_timer_action { -+ TIMER_RING_WATCHDOG, -+ TIMER_SCAN_PENDING_URBS, -+}; -+ -+static inline void -+timer_action_done(struct usbfront_info *info, enum xenhcd_timer_action action) -+{ -+ clear_bit(action, &info->actions); -+} -+ -+static inline void -+timer_action(struct usbfront_info *info, enum xenhcd_timer_action action) -+{ -+ if (timer_pending(&info->watchdog) && -+ test_bit(TIMER_SCAN_PENDING_URBS, &info->actions)) -+ return; -+ -+ if (!test_and_set_bit(action, &info->actions)) { -+ unsigned long t; -+ -+ switch (action) { -+ case TIMER_RING_WATCHDOG: -+ t = XENHCD_RING_JIFFIES; -+ break; -+ default: -+ t = XENHCD_SCAN_JIFFIES; -+ break; -+ } -+ mod_timer(&info->watchdog, t + jiffies); -+ } -+} -+ -+struct kmem_cache *xenhcd_urbp_cachep; -+struct hc_driver xen_usb20_hc_driver; -+struct hc_driver xen_usb11_hc_driver; -+ -+static ssize_t show_statistics(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct usb_hcd *hcd; -+ struct usbfront_info *info; -+ unsigned long flags; -+ unsigned temp, size; -+ char *next; -+ -+ hcd = dev_get_drvdata(dev); -+ info = hcd_to_info(hcd); -+ next = buf; -+ size = PAGE_SIZE; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ temp = scnprintf(next, size, -+ "bus %s, device %s\n" -+ "%s\n" -+ "xenhcd, hcd state %d\n", -+ hcd->self.controller->bus->name, -+ dev_name(hcd->self.controller), -+ hcd->product_desc, -+ hcd->state); -+ size -= temp; -+ next += temp; -+ -+#ifdef XENHCD_STATS -+ temp = scnprintf(next, size, -+ "complete %ld unlink %ld ring_full %ld\n", -+ info->stats.complete, info->stats.unlink, -+ info->stats.ring_full); -+ size -= temp; -+ next += temp; -+#endif -+ -+ spin_unlock_irqrestore(&info->lock, flags); -+ -+ return PAGE_SIZE - size; -+} -+ -+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); -+ -+static inline void create_debug_file(struct usbfront_info *info) -+{ -+ struct device *dev = info_to_hcd(info)->self.controller; -+ if (device_create_file(dev, &dev_attr_statistics)) -+ printk(KERN_WARNING "statistics file not created for %s\n", -+ info_to_hcd(info)->self.bus_name); -+} -+ -+static inline void remove_debug_file(struct usbfront_info *info) -+{ -+ struct device *dev = info_to_hcd(info)->self.controller; -+ device_remove_file(dev, &dev_attr_statistics); -+} -+ -+/* -+ * set virtual port connection status -+ */ -+void set_connect_state(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ if (info->ports[port].status & USB_PORT_STAT_POWER) { -+ switch (info->devices[port].speed) { -+ case USB_SPEED_UNKNOWN: -+ info->ports[port].status &= -+ ~(USB_PORT_STAT_CONNECTION | -+ USB_PORT_STAT_ENABLE | -+ USB_PORT_STAT_LOW_SPEED | -+ USB_PORT_STAT_HIGH_SPEED | -+ USB_PORT_STAT_SUSPEND); -+ break; -+ case USB_SPEED_LOW: -+ info->ports[port].status |= USB_PORT_STAT_CONNECTION; -+ info->ports[port].status |= USB_PORT_STAT_LOW_SPEED; -+ break; -+ case USB_SPEED_FULL: -+ info->ports[port].status |= USB_PORT_STAT_CONNECTION; -+ break; -+ case USB_SPEED_HIGH: -+ info->ports[port].status |= USB_PORT_STAT_CONNECTION; -+ info->ports[port].status |= USB_PORT_STAT_HIGH_SPEED; -+ break; -+ default: /* error */ -+ return; -+ } -+ info->ports[port].status |= (USB_PORT_STAT_C_CONNECTION << 16); -+ } -+} -+ -+/* -+ * set virtual device connection status -+ */ -+void rhport_connect(struct usbfront_info *info, int portnum, -+ enum usb_device_speed speed) -+{ -+ int port; -+ -+ if (portnum < 1 || portnum > info->rh_numports) -+ return; /* invalid port number */ -+ -+ port = portnum - 1; -+ if (info->devices[port].speed != speed) { -+ switch (speed) { -+ case USB_SPEED_UNKNOWN: /* disconnect */ -+ info->devices[port].status = USB_STATE_NOTATTACHED; -+ break; -+ case USB_SPEED_LOW: -+ case USB_SPEED_FULL: -+ case USB_SPEED_HIGH: -+ info->devices[port].status = USB_STATE_ATTACHED; -+ break; -+ default: /* error */ -+ return; -+ } -+ info->devices[port].speed = speed; -+ info->ports[port].c_connection = 1; -+ -+ set_connect_state(info, portnum); -+ } -+} -+ -+/* -+ * SetPortFeature(PORT_SUSPENDED) -+ */ -+void rhport_suspend(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ info->ports[port].status |= USB_PORT_STAT_SUSPEND; -+ info->devices[port].status = USB_STATE_SUSPENDED; -+} -+ -+/* -+ * ClearPortFeature(PORT_SUSPENDED) -+ */ -+void rhport_resume(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ if (info->ports[port].status & USB_PORT_STAT_SUSPEND) { -+ info->ports[port].resuming = 1; -+ info->ports[port].timeout = jiffies + msecs_to_jiffies(20); -+ } -+} -+ -+/* -+ * SetPortFeature(PORT_POWER) -+ */ -+void rhport_power_on(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ if ((info->ports[port].status & USB_PORT_STAT_POWER) == 0) { -+ info->ports[port].status |= USB_PORT_STAT_POWER; -+ if (info->devices[port].status != USB_STATE_NOTATTACHED) -+ info->devices[port].status = USB_STATE_POWERED; -+ if (info->ports[port].c_connection) -+ set_connect_state(info, portnum); -+ } -+} -+ -+/* -+ * ClearPortFeature(PORT_POWER) -+ * SetConfiguration(non-zero) -+ * Power_Source_Off -+ * Over-current -+ */ -+void rhport_power_off(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ if (info->ports[port].status & USB_PORT_STAT_POWER) { -+ info->ports[port].status = 0; -+ if (info->devices[port].status != USB_STATE_NOTATTACHED) -+ info->devices[port].status = USB_STATE_ATTACHED; -+ } -+} -+ -+/* -+ * ClearPortFeature(PORT_ENABLE) -+ */ -+void rhport_disable(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ info->ports[port].status &= ~USB_PORT_STAT_ENABLE; -+ info->ports[port].status &= ~USB_PORT_STAT_SUSPEND; -+ info->ports[port].resuming = 0; -+ if (info->devices[port].status != USB_STATE_NOTATTACHED) -+ info->devices[port].status = USB_STATE_POWERED; -+} -+ -+/* -+ * SetPortFeature(PORT_RESET) -+ */ -+void rhport_reset(struct usbfront_info *info, int portnum) -+{ -+ int port; -+ -+ port = portnum - 1; -+ info->ports[port].status &= ~(USB_PORT_STAT_ENABLE -+ | USB_PORT_STAT_LOW_SPEED -+ | USB_PORT_STAT_HIGH_SPEED); -+ info->ports[port].status |= USB_PORT_STAT_RESET; -+ -+ if (info->devices[port].status != USB_STATE_NOTATTACHED) -+ info->devices[port].status = USB_STATE_ATTACHED; -+ -+ /* 10msec reset signaling */ -+ info->ports[port].timeout = jiffies + msecs_to_jiffies(10); -+} -+ -+#ifdef XENHCD_PM -+#ifdef CONFIG_PM -+static int xenhcd_bus_suspend(struct usb_hcd *hcd) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ int ret = 0; -+ int i, ports; -+ -+ ports = info->rh_numports; -+ -+ spin_lock_irq(&info->lock); -+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) -+ ret = -ESHUTDOWN; -+ else { -+ /* suspend any active ports*/ -+ for (i = 1; i <= ports; i++) -+ rhport_suspend(info, i); -+ } -+ spin_unlock_irq(&info->lock); -+ -+ del_timer_sync(&info->watchdog); -+ -+ return ret; -+} -+ -+static int xenhcd_bus_resume(struct usb_hcd *hcd) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ int ret = 0; -+ int i, ports; -+ -+ ports = info->rh_numports; -+ -+ spin_lock_irq(&info->lock); -+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) -+ ret = -ESHUTDOWN; -+ else { -+ /* resume any suspended ports*/ -+ for (i = 1; i <= ports; i++) -+ rhport_resume(info, i); -+ } -+ spin_unlock_irq(&info->lock); -+ -+ return ret; -+} -+#endif -+#endif -+ -+static void xenhcd_hub_descriptor(struct usbfront_info *info, -+ struct usb_hub_descriptor *desc) -+{ -+ u16 temp; -+ int ports = info->rh_numports; -+ -+ desc->bDescriptorType = 0x29; -+ desc->bPwrOn2PwrGood = 10; /* EHCI says 20ms max */ -+ desc->bHubContrCurrent = 0; -+ desc->bNbrPorts = ports; -+ -+ /* size of DeviceRemovable and PortPwrCtrlMask fields*/ -+ temp = 1 + (ports / 8); -+ desc->bDescLength = 7 + 2 * temp; -+ -+ /* bitmaps for DeviceRemovable and PortPwrCtrlMask */ -+ memset(&desc->u.hs.DeviceRemovable[0], 0, temp); -+ memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); -+ -+ /* per-port over current reporting and no power switching */ -+ temp = 0x000a; -+ desc->wHubCharacteristics = cpu_to_le16(temp); -+} -+ -+/* port status change mask for hub_status_data */ -+#define PORT_C_MASK \ -+ ((USB_PORT_STAT_C_CONNECTION \ -+ | USB_PORT_STAT_C_ENABLE \ -+ | USB_PORT_STAT_C_SUSPEND \ -+ | USB_PORT_STAT_C_OVERCURRENT \ -+ | USB_PORT_STAT_C_RESET) << 16) -+ -+/* -+ * See USB 2.0 Spec, 11.12.4 Hub and Port Status Change Bitmap. -+ * If port status changed, writes the bitmap to buf and return -+ * that length(number of bytes). -+ * If Nothing changed, return 0. -+ */ -+static int xenhcd_hub_status_data(struct usb_hcd *hcd, char *buf) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ -+ int ports; -+ int i; -+ int length; -+ -+ unsigned long flags; -+ int ret = 0; -+ -+ int changed = 0; -+ -+ if (!HC_IS_RUNNING(hcd->state)) -+ return 0; -+ -+ /* initialize the status to no-changes */ -+ ports = info->rh_numports; -+ length = 1 + (ports / 8); -+ for (i = 0; i < length; i++) { -+ buf[i] = 0; -+ ret++; -+ } -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ for (i = 0; i < ports; i++) { -+ /* check status for each port */ -+ if (info->ports[i].status & PORT_C_MASK) { -+ if (i < 7) -+ buf[0] |= 1 << (i + 1); -+ else if (i < 15) -+ buf[1] |= 1 << (i - 7); -+ else if (i < 23) -+ buf[2] |= 1 << (i - 15); -+ else -+ buf[3] |= 1 << (i - 23); -+ changed = 1; -+ } -+ } -+ -+ if (!changed) -+ ret = 0; -+ -+ spin_unlock_irqrestore(&info->lock, flags); -+ -+ return ret; -+} -+ -+static int xenhcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, -+ u16 wIndex, char *buf, u16 wLength) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ int ports = info->rh_numports; -+ unsigned long flags; -+ int ret = 0; -+ int i; -+ int changed = 0; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ switch (typeReq) { -+ case ClearHubFeature: -+ /* ignore this request */ -+ break; -+ case ClearPortFeature: -+ if (!wIndex || wIndex > ports) -+ goto error; -+ -+ switch (wValue) { -+ case USB_PORT_FEAT_SUSPEND: -+ rhport_resume(info, wIndex); -+ break; -+ case USB_PORT_FEAT_POWER: -+ rhport_power_off(info, wIndex); -+ break; -+ case USB_PORT_FEAT_ENABLE: -+ rhport_disable(info, wIndex); -+ break; -+ case USB_PORT_FEAT_C_CONNECTION: -+ info->ports[wIndex-1].c_connection = 0; -+ /* falling through */ -+ default: -+ info->ports[wIndex-1].status &= ~(1 << wValue); -+ break; -+ } -+ break; -+ case GetHubDescriptor: -+ xenhcd_hub_descriptor(info, (struct usb_hub_descriptor *) buf); -+ break; -+ case GetHubStatus: -+ /* always local power supply good and no over-current exists. */ -+ *(__le32 *)buf = cpu_to_le32(0); -+ break; -+ case GetPortStatus: -+ if (!wIndex || wIndex > ports) -+ goto error; -+ -+ wIndex--; -+ -+ /* resume completion */ -+ if (info->ports[wIndex].resuming && -+ time_after_eq(jiffies, info->ports[wIndex].timeout)) { -+ info->ports[wIndex].status |= -+ (USB_PORT_STAT_C_SUSPEND << 16); -+ info->ports[wIndex].status &= ~USB_PORT_STAT_SUSPEND; -+ } -+ -+ /* reset completion */ -+ if ((info->ports[wIndex].status & USB_PORT_STAT_RESET) != 0 && -+ time_after_eq(jiffies, info->ports[wIndex].timeout)) { -+ info->ports[wIndex].status |= -+ (USB_PORT_STAT_C_RESET << 16); -+ info->ports[wIndex].status &= ~USB_PORT_STAT_RESET; -+ -+ if (info->devices[wIndex].status != -+ USB_STATE_NOTATTACHED) { -+ info->ports[wIndex].status |= -+ USB_PORT_STAT_ENABLE; -+ info->devices[wIndex].status = -+ USB_STATE_DEFAULT; -+ } -+ -+ switch (info->devices[wIndex].speed) { -+ case USB_SPEED_LOW: -+ info->ports[wIndex].status |= -+ USB_PORT_STAT_LOW_SPEED; -+ break; -+ case USB_SPEED_HIGH: -+ info->ports[wIndex].status |= -+ USB_PORT_STAT_HIGH_SPEED; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ ((u16 *) buf)[0] = cpu_to_le16(info->ports[wIndex].status); -+ ((u16 *) buf)[1] = cpu_to_le16(info->ports[wIndex].status -+ >> 16); -+ break; -+ case SetHubFeature: -+ /* not supported */ -+ goto error; -+ case SetPortFeature: -+ if (!wIndex || wIndex > ports) -+ goto error; -+ -+ switch (wValue) { -+ case USB_PORT_FEAT_POWER: -+ rhport_power_on(info, wIndex); -+ break; -+ case USB_PORT_FEAT_RESET: -+ rhport_reset(info, wIndex); -+ break; -+ case USB_PORT_FEAT_SUSPEND: -+ rhport_suspend(info, wIndex); -+ break; -+ default: -+ if ((info->ports[wIndex-1].status & -+ USB_PORT_STAT_POWER) != 0) -+ info->ports[wIndex-1].status |= (1 << wValue); -+ } -+ break; -+ -+ default: -+error: -+ ret = -EPIPE; -+ } -+ spin_unlock_irqrestore(&info->lock, flags); -+ -+ /* check status for each port */ -+ for (i = 0; i < ports; i++) { -+ if (info->ports[i].status & PORT_C_MASK) -+ changed = 1; -+ } -+ if (changed) -+ usb_hcd_poll_rh_status(hcd); -+ -+ return ret; -+} -+ -+struct kmem_cache *xenhcd_urbp_cachep; -+ -+static struct urb_priv *alloc_urb_priv(struct urb *urb) -+{ -+ struct urb_priv *urbp; -+ -+ urbp = kmem_cache_zalloc(xenhcd_urbp_cachep, GFP_ATOMIC); -+ if (!urbp) -+ return NULL; -+ -+ urbp->urb = urb; -+ urb->hcpriv = urbp; -+ urbp->req_id = ~0; -+ urbp->unlink_req_id = ~0; -+ INIT_LIST_HEAD(&urbp->list); -+ -+ return urbp; -+} -+ -+static void free_urb_priv(struct urb_priv *urbp) -+{ -+ urbp->urb->hcpriv = NULL; -+ kmem_cache_free(xenhcd_urbp_cachep, urbp); -+} -+ -+static inline int get_id_from_freelist(struct usbfront_info *info) -+{ -+ unsigned long free; -+ free = info->shadow_free; -+ BUG_ON(free >= USB_URB_RING_SIZE); -+ info->shadow_free = info->shadow[free].req.id; -+ info->shadow[free].req.id = (unsigned int)0x0fff; /* debug */ -+ return free; -+} -+ -+static inline void add_id_to_freelist(struct usbfront_info *info, -+ unsigned long id) -+{ -+ info->shadow[id].req.id = info->shadow_free; -+ info->shadow[id].urb = NULL; -+ info->shadow_free = id; -+} -+ -+static inline int count_pages(void *addr, int length) -+{ -+ unsigned long start = (unsigned long) addr >> PAGE_SHIFT; -+ unsigned long end = (unsigned long) -+ (addr + length + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ return end - start; -+} -+ -+static inline void xenhcd_gnttab_map(struct usbfront_info *info, void *addr, -+ int length, grant_ref_t *gref_head, -+ struct usbif_request_segment *seg, -+ int nr_pages, int flags) -+{ -+ grant_ref_t ref; -+ unsigned long mfn; -+ unsigned int offset; -+ unsigned int len; -+ unsigned int bytes; -+ int i; -+ -+ len = length; -+ -+ for (i = 0; i < nr_pages; i++) { -+ BUG_ON(!len); -+ -+ mfn = virt_to_mfn(addr); -+ offset = offset_in_page(addr); -+ -+ bytes = PAGE_SIZE - offset; -+ if (bytes > len) -+ bytes = len; -+ -+ ref = gnttab_claim_grant_reference(gref_head); -+ BUG_ON(ref == -ENOSPC); -+ gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, -+ mfn, flags); -+ seg[i].gref = ref; -+ seg[i].offset = (uint16_t)offset; -+ seg[i].length = (uint16_t)bytes; -+ -+ addr += bytes; -+ len -= bytes; -+ } -+} -+ -+static int map_urb_for_request(struct usbfront_info *info, struct urb *urb, -+ struct usbif_urb_request *req) -+{ -+ grant_ref_t gref_head; -+ int nr_buff_pages = 0; -+ int nr_isodesc_pages = 0; -+ int ret = 0; -+ -+ if (urb->transfer_buffer_length) { -+ nr_buff_pages = count_pages(urb->transfer_buffer, -+ urb->transfer_buffer_length); -+ -+ if (usb_pipeisoc(urb->pipe)) -+ nr_isodesc_pages = count_pages(&urb->iso_frame_desc[0], -+ sizeof(struct usb_iso_packet_descriptor) * -+ urb->number_of_packets); -+ -+ if (nr_buff_pages + nr_isodesc_pages > -+ USBIF_MAX_SEGMENTS_PER_REQUEST) -+ return -E2BIG; -+ -+ ret = gnttab_alloc_grant_references( -+ USBIF_MAX_SEGMENTS_PER_REQUEST, &gref_head); -+ if (ret) { -+ printk(KERN_ERR "usbfront: " -+ "gnttab_alloc_grant_references() error\n"); -+ return -ENOMEM; -+ } -+ -+ xenhcd_gnttab_map(info, urb->transfer_buffer, -+ urb->transfer_buffer_length, &gref_head, -+ &req->seg[0], nr_buff_pages, -+ usb_pipein(urb->pipe) ? 0 : GTF_readonly); -+ -+ if (!usb_pipeisoc(urb->pipe)) -+ gnttab_free_grant_references(gref_head); -+ } -+ -+ req->pipe = usbif_setportnum_pipe(urb->pipe, urb->dev->portnum); -+ req->transfer_flags = urb->transfer_flags; -+ req->buffer_length = urb->transfer_buffer_length; -+ req->nr_buffer_segs = nr_buff_pages; -+ -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_ISOCHRONOUS: -+ req->u.isoc.interval = urb->interval; -+ req->u.isoc.start_frame = urb->start_frame; -+ req->u.isoc.number_of_packets = urb->number_of_packets; -+ req->u.isoc.nr_frame_desc_segs = nr_isodesc_pages; -+ /* urb->number_of_packets must be > 0 */ -+ if (unlikely(urb->number_of_packets <= 0)) -+ BUG(); -+ xenhcd_gnttab_map(info, &urb->iso_frame_desc[0], -+ sizeof(struct usb_iso_packet_descriptor) * -+ urb->number_of_packets, &gref_head, -+ &req->seg[nr_buff_pages], nr_isodesc_pages, 0); -+ gnttab_free_grant_references(gref_head); -+ break; -+ case PIPE_INTERRUPT: -+ req->u.intr.interval = urb->interval; -+ break; -+ case PIPE_CONTROL: -+ if (urb->setup_packet) -+ memcpy(req->u.ctrl, urb->setup_packet, 8); -+ break; -+ case PIPE_BULK: -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static void xenhcd_gnttab_done(struct usb_shadow *shadow) -+{ -+ int nr_segs = 0; -+ int i; -+ -+ nr_segs = shadow->req.nr_buffer_segs; -+ -+ if (usb_pipeisoc(shadow->req.pipe)) -+ nr_segs += shadow->req.u.isoc.nr_frame_desc_segs; -+ -+ for (i = 0; i < nr_segs; i++) -+ gnttab_end_foreign_access(shadow->req.seg[i].gref, 0, 0UL); -+ -+ shadow->req.nr_buffer_segs = 0; -+ shadow->req.u.isoc.nr_frame_desc_segs = 0; -+} -+ -+static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb, -+ int status) -+__releases(info->lock) -+__acquires(info->lock) -+{ -+ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; -+ -+ list_del_init(&urbp->list); -+ free_urb_priv(urbp); -+ switch (urb->status) { -+ case -ECONNRESET: -+ case -ENOENT: -+ COUNT(info->stats.unlink); -+ break; -+ case -EINPROGRESS: -+ urb->status = status; -+ /* falling through */ -+ default: -+ COUNT(info->stats.complete); -+ } -+ spin_unlock(&info->lock); -+ usb_hcd_giveback_urb(info_to_hcd(info), urb, -+ urbp->status <= 0 ? urbp->status : urb->status); -+ spin_lock(&info->lock); -+} -+ -+static inline int xenhcd_do_request(struct usbfront_info *info, -+ struct urb_priv *urbp) -+{ -+ struct usbif_urb_request *req; -+ struct urb *urb = urbp->urb; -+ uint16_t id; -+ int notify; -+ int ret = 0; -+ -+ req = RING_GET_REQUEST(&info->urb_ring, info->urb_ring.req_prod_pvt); -+ id = get_id_from_freelist(info); -+ req->id = id; -+ -+ if (unlikely(urbp->unlinked)) { -+ req->u.unlink.unlink_id = urbp->req_id; -+ req->pipe = usbif_setunlink_pipe(usbif_setportnum_pipe( -+ urb->pipe, urb->dev->portnum)); -+ urbp->unlink_req_id = id; -+ } else { -+ ret = map_urb_for_request(info, urb, req); -+ if (ret < 0) { -+ add_id_to_freelist(info, id); -+ return ret; -+ } -+ urbp->req_id = id; -+ } -+ -+ info->urb_ring.req_prod_pvt++; -+ info->shadow[id].urb = urb; -+ info->shadow[id].req = *req; -+ -+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify); -+ if (notify) -+ notify_remote_via_irq(info->irq); -+ -+ return ret; -+} -+ -+static void xenhcd_kick_pending_urbs(struct usbfront_info *info) -+{ -+ struct urb_priv *urbp; -+ int ret; -+ -+ while (!list_empty(&info->pending_submit_list)) { -+ if (RING_FULL(&info->urb_ring)) { -+ COUNT(info->stats.ring_full); -+ timer_action(info, TIMER_RING_WATCHDOG); -+ goto done; -+ } -+ -+ urbp = list_entry(info->pending_submit_list.next, -+ struct urb_priv, list); -+ ret = xenhcd_do_request(info, urbp); -+ if (ret == 0) -+ list_move_tail(&urbp->list, &info->in_progress_list); -+ else -+ xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN); -+ } -+ timer_action_done(info, TIMER_SCAN_PENDING_URBS); -+ -+done: -+ return; -+} -+ -+/* -+ * caller must lock info->lock -+ */ -+static void xenhcd_cancel_all_enqueued_urbs(struct usbfront_info *info) -+{ -+ struct urb_priv *urbp, *tmp; -+ -+ list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) { -+ if (!urbp->unlinked) { -+ xenhcd_gnttab_done(&info->shadow[urbp->req_id]); -+ barrier(); -+ if (urbp->urb->status == -EINPROGRESS)/* not dequeued */ -+ xenhcd_giveback_urb(info, urbp->urb, -+ -ESHUTDOWN); -+ else /* dequeued */ -+ xenhcd_giveback_urb(info, urbp->urb, -+ urbp->urb->status); -+ } -+ info->shadow[urbp->req_id].urb = NULL; -+ } -+ -+ list_for_each_entry_safe(urbp, tmp, &info->pending_submit_list, list) { -+ xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN); -+ } -+ -+ return; -+} -+ -+/* -+ * caller must lock info->lock -+ */ -+static void xenhcd_giveback_unlinked_urbs(struct usbfront_info *info) -+{ -+ struct urb_priv *urbp, *tmp; -+ -+ list_for_each_entry_safe(urbp, tmp, -+ &info->giveback_waiting_list, list) { -+ xenhcd_giveback_urb(info, urbp->urb, urbp->urb->status); -+ } -+} -+ -+static int xenhcd_submit_urb(struct usbfront_info *info, struct urb_priv *urbp) -+{ -+ int ret = 0; -+ -+ if (RING_FULL(&info->urb_ring)) { -+ list_add_tail(&urbp->list, &info->pending_submit_list); -+ COUNT(info->stats.ring_full); -+ timer_action(info, TIMER_RING_WATCHDOG); -+ goto done; -+ } -+ -+ if (!list_empty(&info->pending_submit_list)) { -+ list_add_tail(&urbp->list, &info->pending_submit_list); -+ timer_action(info, TIMER_SCAN_PENDING_URBS); -+ goto done; -+ } -+ -+ ret = xenhcd_do_request(info, urbp); -+ if (ret == 0) -+ list_add_tail(&urbp->list, &info->in_progress_list); -+ -+done: -+ return ret; -+} -+ -+static int xenhcd_unlink_urb(struct usbfront_info *info, struct urb_priv *urbp) -+{ -+ int ret = 0; -+ -+ /* already unlinked? */ -+ if (urbp->unlinked) -+ return -EBUSY; -+ -+ urbp->unlinked = 1; -+ -+ /* the urb is still in pending_submit queue */ -+ if (urbp->req_id == ~0) { -+ list_move_tail(&urbp->list, &info->giveback_waiting_list); -+ timer_action(info, TIMER_SCAN_PENDING_URBS); -+ goto done; -+ } -+ -+ /* send unlink request to backend */ -+ if (RING_FULL(&info->urb_ring)) { -+ list_move_tail(&urbp->list, &info->pending_unlink_list); -+ COUNT(info->stats.ring_full); -+ timer_action(info, TIMER_RING_WATCHDOG); -+ goto done; -+ } -+ -+ if (!list_empty(&info->pending_unlink_list)) { -+ list_move_tail(&urbp->list, &info->pending_unlink_list); -+ timer_action(info, TIMER_SCAN_PENDING_URBS); -+ goto done; -+ } -+ -+ ret = xenhcd_do_request(info, urbp); -+ if (ret == 0) -+ list_move_tail(&urbp->list, &info->in_progress_list); -+ -+done: -+ return ret; -+} -+ -+static int xenhcd_urb_request_done(struct usbfront_info *info) -+{ -+ struct usbif_urb_response *res; -+ struct urb *urb; -+ -+ RING_IDX i, rp; -+ uint16_t id; -+ int more_to_do = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ rp = info->urb_ring.sring->rsp_prod; -+ rmb(); /* ensure we see queued responses up to "rp" */ -+ -+ for (i = info->urb_ring.rsp_cons; i != rp; i++) { -+ res = RING_GET_RESPONSE(&info->urb_ring, i); -+ id = res->id; -+ -+ if (likely(usbif_pipesubmit(info->shadow[id].req.pipe))) { -+ xenhcd_gnttab_done(&info->shadow[id]); -+ urb = info->shadow[id].urb; -+ barrier(); -+ if (likely(urb)) { -+ urb->actual_length = res->actual_length; -+ urb->error_count = res->error_count; -+ urb->start_frame = res->start_frame; -+ barrier(); -+ xenhcd_giveback_urb(info, urb, res->status); -+ } -+ } -+ -+ add_id_to_freelist(info, id); -+ } -+ info->urb_ring.rsp_cons = i; -+ -+ if (i != info->urb_ring.req_prod_pvt) -+ RING_FINAL_CHECK_FOR_RESPONSES(&info->urb_ring, more_to_do); -+ else -+ info->urb_ring.sring->rsp_event = i + 1; -+ -+ spin_unlock_irqrestore(&info->lock, flags); -+ -+ cond_resched(); -+ -+ return more_to_do; -+} -+ -+static int xenhcd_conn_notify(struct usbfront_info *info) -+{ -+ struct usbif_conn_response *res; -+ struct usbif_conn_request *req; -+ RING_IDX rc, rp; -+ uint16_t id; -+ uint8_t portnum, speed; -+ int more_to_do = 0; -+ int notify; -+ int port_changed = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ rc = info->conn_ring.rsp_cons; -+ rp = info->conn_ring.sring->rsp_prod; -+ rmb(); /* ensure we see queued responses up to "rp" */ -+ -+ while (rc != rp) { -+ res = RING_GET_RESPONSE(&info->conn_ring, rc); -+ id = res->id; -+ portnum = res->portnum; -+ speed = res->speed; -+ info->conn_ring.rsp_cons = ++rc; -+ -+ rhport_connect(info, portnum, speed); -+ if (info->ports[portnum-1].c_connection) -+ port_changed = 1; -+ -+ barrier(); -+ -+ req = RING_GET_REQUEST(&info->conn_ring, -+ info->conn_ring.req_prod_pvt); -+ req->id = id; -+ info->conn_ring.req_prod_pvt++; -+ } -+ -+ if (rc != info->conn_ring.req_prod_pvt) -+ RING_FINAL_CHECK_FOR_RESPONSES(&info->conn_ring, more_to_do); -+ else -+ info->conn_ring.sring->rsp_event = rc + 1; -+ -+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify); -+ if (notify) -+ notify_remote_via_irq(info->irq); -+ -+ spin_unlock_irqrestore(&info->lock, flags); -+ -+ if (port_changed) -+ usb_hcd_poll_rh_status(info_to_hcd(info)); -+ -+ cond_resched(); -+ -+ return more_to_do; -+} -+ -+int xenhcd_schedule(void *arg) -+{ -+ struct usbfront_info *info = (struct usbfront_info *) arg; -+ -+ while (!kthread_should_stop()) { -+ wait_event_interruptible(info->wq, -+ info->waiting_resp || kthread_should_stop()); -+ info->waiting_resp = 0; -+ smp_mb(); -+ -+ if (xenhcd_urb_request_done(info)) -+ info->waiting_resp = 1; -+ -+ if (xenhcd_conn_notify(info)) -+ info->waiting_resp = 1; -+ } -+ -+ return 0; -+} -+ -+static void xenhcd_notify_work(struct usbfront_info *info) -+{ -+ info->waiting_resp = 1; -+ wake_up(&info->wq); -+} -+ -+irqreturn_t xenhcd_int(int irq, void *dev_id) -+{ -+ xenhcd_notify_work((struct usbfront_info *) dev_id); -+ return IRQ_HANDLED; -+} -+ -+static void xenhcd_watchdog(unsigned long param) -+{ -+ struct usbfront_info *info = (struct usbfront_info *) param; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ if (likely(HC_IS_RUNNING(info_to_hcd(info)->state))) { -+ timer_action_done(info, TIMER_RING_WATCHDOG); -+ xenhcd_giveback_unlinked_urbs(info); -+ xenhcd_kick_pending_urbs(info); -+ } -+ spin_unlock_irqrestore(&info->lock, flags); -+} -+ -+/* -+ * one-time HC init -+ */ -+static int xenhcd_setup(struct usb_hcd *hcd) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ -+ spin_lock_init(&info->lock); -+ INIT_LIST_HEAD(&info->pending_submit_list); -+ INIT_LIST_HEAD(&info->pending_unlink_list); -+ INIT_LIST_HEAD(&info->in_progress_list); -+ INIT_LIST_HEAD(&info->giveback_waiting_list); -+ init_timer(&info->watchdog); -+ info->watchdog.function = xenhcd_watchdog; -+ info->watchdog.data = (unsigned long) info; -+ return 0; -+} -+ -+/* -+ * start HC running -+ */ -+static int xenhcd_run(struct usb_hcd *hcd) -+{ -+ hcd->uses_new_polling = 1; -+ hcd->state = HC_STATE_RUNNING; -+ create_debug_file(hcd_to_info(hcd)); -+ return 0; -+} -+ -+/* -+ * stop running HC -+ */ -+static void xenhcd_stop(struct usb_hcd *hcd) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ -+ del_timer_sync(&info->watchdog); -+ remove_debug_file(info); -+ spin_lock_irq(&info->lock); -+ /* cancel all urbs */ -+ hcd->state = HC_STATE_HALT; -+ xenhcd_cancel_all_enqueued_urbs(info); -+ xenhcd_giveback_unlinked_urbs(info); -+ spin_unlock_irq(&info->lock); -+} -+ -+/* -+ * called as .urb_enqueue() -+ * non-error returns are promise to giveback the urb later -+ */ -+static int xenhcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, -+ gfp_t mem_flags) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ struct urb_priv *urbp; -+ unsigned long flags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ urbp = alloc_urb_priv(urb); -+ if (!urbp) { -+ ret = -ENOMEM; -+ goto done; -+ } -+ urbp->status = 1; -+ -+ ret = xenhcd_submit_urb(info, urbp); -+ if (ret != 0) -+ free_urb_priv(urbp); -+ -+done: -+ spin_unlock_irqrestore(&info->lock, flags); -+ return ret; -+} -+ -+/* -+ * called as .urb_dequeue() -+ */ -+static int xenhcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -+{ -+ struct usbfront_info *info = hcd_to_info(hcd); -+ struct urb_priv *urbp; -+ unsigned long flags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&info->lock, flags); -+ -+ urbp = urb->hcpriv; -+ if (!urbp) -+ goto done; -+ -+ urbp->status = status; -+ ret = xenhcd_unlink_urb(info, urbp); -+ -+done: -+ spin_unlock_irqrestore(&info->lock, flags); -+ return ret; -+} -+ -+/* -+ * called from usb_get_current_frame_number(), -+ * but, almost all drivers not use such function. -+ */ -+static int xenhcd_get_frame(struct usb_hcd *hcd) -+{ -+ /* it means error, but probably no problem :-) */ -+ return 0; -+} -+ -+static const char hcd_name[] = "xen_hcd"; -+ -+struct hc_driver xen_usb20_hc_driver = { -+ .description = hcd_name, -+ .product_desc = "Xen USB2.0 Virtual Host Controller", -+ .hcd_priv_size = sizeof(struct usbfront_info), -+ .flags = HCD_USB2, -+ -+ /* basic HC lifecycle operations */ -+ .reset = xenhcd_setup, -+ .start = xenhcd_run, -+ .stop = xenhcd_stop, -+ -+ /* managing urb I/O */ -+ .urb_enqueue = xenhcd_urb_enqueue, -+ .urb_dequeue = xenhcd_urb_dequeue, -+ .get_frame_number = xenhcd_get_frame, -+ -+ /* root hub operations */ -+ .hub_status_data = xenhcd_hub_status_data, -+ .hub_control = xenhcd_hub_control, -+#ifdef XENHCD_PM -+#ifdef CONFIG_PM -+ .bus_suspend = xenhcd_bus_suspend, -+ .bus_resume = xenhcd_bus_resume, -+#endif -+#endif -+}; -+ -+struct hc_driver xen_usb11_hc_driver = { -+ .description = hcd_name, -+ .product_desc = "Xen USB1.1 Virtual Host Controller", -+ .hcd_priv_size = sizeof(struct usbfront_info), -+ .flags = HCD_USB11, -+ -+ /* basic HC lifecycle operations */ -+ .reset = xenhcd_setup, -+ .start = xenhcd_run, -+ .stop = xenhcd_stop, -+ -+ /* managing urb I/O */ -+ .urb_enqueue = xenhcd_urb_enqueue, -+ .urb_dequeue = xenhcd_urb_dequeue, -+ .get_frame_number = xenhcd_get_frame, -+ -+ /* root hub operations */ -+ .hub_status_data = xenhcd_hub_status_data, -+ .hub_control = xenhcd_hub_control, -+#ifdef XENHCD_PM -+#ifdef CONFIG_PM -+ .bus_suspend = xenhcd_bus_suspend, -+ .bus_resume = xenhcd_bus_resume, -+#endif -+#endif -+}; -+ -+#define GRANT_INVALID_REF 0 -+ -+static void destroy_rings(struct usbfront_info *info) -+{ -+ if (info->irq) -+ unbind_from_irqhandler(info->irq, info); -+ info->evtchn = info->irq = 0; -+ -+ if (info->urb_ring_ref != GRANT_INVALID_REF) { -+ gnttab_end_foreign_access(info->urb_ring_ref, 0, -+ (unsigned long)info->urb_ring.sring); -+ info->urb_ring_ref = GRANT_INVALID_REF; -+ } -+ info->urb_ring.sring = NULL; -+ -+ if (info->conn_ring_ref != GRANT_INVALID_REF) { -+ gnttab_end_foreign_access(info->conn_ring_ref, 0, -+ (unsigned long)info->conn_ring.sring); -+ info->conn_ring_ref = GRANT_INVALID_REF; -+ } -+ info->conn_ring.sring = NULL; -+} -+ -+static int setup_rings(struct xenbus_device *dev, struct usbfront_info *info) -+{ -+ struct usbif_urb_sring *urb_sring; -+ struct usbif_conn_sring *conn_sring; -+ int err; -+ -+ info->urb_ring_ref = GRANT_INVALID_REF; -+ info->conn_ring_ref = GRANT_INVALID_REF; -+ -+ urb_sring = (struct usbif_urb_sring *) -+ get_zeroed_page(GFP_NOIO|__GFP_HIGH); -+ if (!urb_sring) { -+ xenbus_dev_fatal(dev, -ENOMEM, "allocating urb ring"); -+ return -ENOMEM; -+ } -+ SHARED_RING_INIT(urb_sring); -+ FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE); -+ -+ err = xenbus_grant_ring(dev, virt_to_mfn(info->urb_ring.sring)); -+ if (err < 0) { -+ free_page((unsigned long)urb_sring); -+ info->urb_ring.sring = NULL; -+ goto fail; -+ } -+ info->urb_ring_ref = err; -+ -+ conn_sring = (struct usbif_conn_sring *) -+ get_zeroed_page(GFP_NOIO|__GFP_HIGH); -+ if (!conn_sring) { -+ xenbus_dev_fatal(dev, -ENOMEM, "allocating conn ring"); -+ return -ENOMEM; -+ } -+ SHARED_RING_INIT(conn_sring); -+ FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE); -+ -+ err = xenbus_grant_ring(dev, virt_to_mfn(info->conn_ring.sring)); -+ if (err < 0) { -+ free_page((unsigned long)conn_sring); -+ info->conn_ring.sring = NULL; -+ goto fail; -+ } -+ info->conn_ring_ref = err; -+ -+ err = xenbus_alloc_evtchn(dev, &info->evtchn); -+ if (err) -+ goto fail; -+ -+ err = bind_evtchn_to_irqhandler(info->evtchn, xenhcd_int, 0, -+ "usbif", info); -+ if (err <= 0) { -+ xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler"); -+ goto fail; -+ } -+ info->irq = err; -+ -+ return 0; -+fail: -+ destroy_rings(info); -+ return err; -+} -+ -+static int talk_to_usbback(struct xenbus_device *dev, -+ struct usbfront_info *info) -+{ -+ const char *message; -+ struct xenbus_transaction xbt; -+ int err; -+ -+ err = setup_rings(dev, info); -+ if (err) -+ goto out; -+ -+again: -+ err = xenbus_transaction_start(&xbt); -+ if (err) { -+ xenbus_dev_fatal(dev, err, "starting transaction"); -+ goto destroy_ring; -+ } -+ -+ err = xenbus_printf(xbt, dev->nodename, "urb-ring-ref", -+ "%u", info->urb_ring_ref); -+ if (err) { -+ message = "writing urb-ring-ref"; -+ goto abort_transaction; -+ } -+ -+ err = xenbus_printf(xbt, dev->nodename, "conn-ring-ref", -+ "%u", info->conn_ring_ref); -+ if (err) { -+ message = "writing conn-ring-ref"; -+ goto abort_transaction; -+ } -+ -+ err = xenbus_printf(xbt, dev->nodename, "event-channel", -+ "%u", info->evtchn); -+ if (err) { -+ message = "writing event-channel"; -+ goto abort_transaction; -+ } -+ -+ err = xenbus_transaction_end(xbt, 0); -+ if (err) { -+ if (err == -EAGAIN) -+ goto again; -+ xenbus_dev_fatal(dev, err, "completing transaction"); -+ goto destroy_ring; -+ } -+ -+ return 0; -+ -+abort_transaction: -+ xenbus_transaction_end(xbt, 1); -+ xenbus_dev_fatal(dev, err, "%s", message); -+ -+destroy_ring: -+ destroy_rings(info); -+ -+out: -+ return err; -+} -+ -+static int connect(struct xenbus_device *dev) -+{ -+ struct usbfront_info *info = dev_get_drvdata(&dev->dev); -+ -+ struct usbif_conn_request *req; -+ int i, idx, err; -+ int notify; -+ char name[TASK_COMM_LEN]; -+ struct usb_hcd *hcd; -+ -+ hcd = info_to_hcd(info); -+ snprintf(name, TASK_COMM_LEN, "xenhcd.%d", hcd->self.busnum); -+ -+ err = talk_to_usbback(dev, info); -+ if (err) -+ return err; -+ -+ info->kthread = kthread_run(xenhcd_schedule, info, name); -+ if (IS_ERR(info->kthread)) { -+ err = PTR_ERR(info->kthread); -+ info->kthread = NULL; -+ xenbus_dev_fatal(dev, err, "Error creating thread"); -+ return err; -+ } -+ /* prepare ring for hotplug notification */ -+ for (idx = 0, i = 0; i < USB_CONN_RING_SIZE; i++) { -+ req = RING_GET_REQUEST(&info->conn_ring, idx); -+ req->id = idx; -+ idx++; -+ } -+ info->conn_ring.req_prod_pvt = idx; -+ -+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify); -+ if (notify) -+ notify_remote_via_irq(info->irq); -+ -+ return 0; -+} -+ -+static struct usb_hcd *create_hcd(struct xenbus_device *dev) -+{ -+ int i; -+ int err = 0; -+ int num_ports; -+ int usb_ver; -+ struct usb_hcd *hcd = NULL; -+ struct usbfront_info *info = NULL; -+ -+ err = xenbus_scanf(XBT_NIL, dev->otherend, "num-ports", -+ "%d", &num_ports); -+ if (err != 1) { -+ xenbus_dev_fatal(dev, err, "reading num-ports"); -+ return ERR_PTR(-EINVAL); -+ } -+ if (num_ports < 1 || num_ports > USB_MAXCHILDREN) { -+ xenbus_dev_fatal(dev, err, "invalid num-ports"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ err = xenbus_scanf(XBT_NIL, dev->otherend, "usb-ver", "%d", &usb_ver); -+ if (err != 1) { -+ xenbus_dev_fatal(dev, err, "reading usb-ver"); -+ return ERR_PTR(-EINVAL); -+ } -+ switch (usb_ver) { -+ case USB_VER_USB11: -+ hcd = usb_create_hcd(&xen_usb11_hc_driver, -+ &dev->dev, dev_name(&dev->dev)); -+ break; -+ case USB_VER_USB20: -+ hcd = usb_create_hcd(&xen_usb20_hc_driver, -+ &dev->dev, dev_name(&dev->dev)); -+ break; -+ default: -+ xenbus_dev_fatal(dev, err, "invalid usb-ver"); -+ return ERR_PTR(-EINVAL); -+ } -+ if (!hcd) { -+ xenbus_dev_fatal(dev, err, -+ "fail to allocate USB host controller"); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ info = hcd_to_info(hcd); -+ info->xbdev = dev; -+ info->rh_numports = num_ports; -+ -+ for (i = 0; i < USB_URB_RING_SIZE; i++) { -+ info->shadow[i].req.id = i + 1; -+ info->shadow[i].urb = NULL; -+ } -+ info->shadow[USB_URB_RING_SIZE-1].req.id = 0x0fff; -+ -+ return hcd; -+} -+ -+static int usbfront_probe(struct xenbus_device *dev, -+ const struct xenbus_device_id *id) -+{ -+ int err; -+ struct usb_hcd *hcd; -+ struct usbfront_info *info; -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ hcd = create_hcd(dev); -+ if (IS_ERR(hcd)) { -+ err = PTR_ERR(hcd); -+ xenbus_dev_fatal(dev, err, -+ "failed to create usb host controller"); -+ goto fail; -+ } -+ -+ info = hcd_to_info(hcd); -+ dev_set_drvdata(&dev->dev, info); -+ -+ err = usb_add_hcd(hcd, 0, 0); -+ if (err != 0) { -+ xenbus_dev_fatal(dev, err, "fail to add USB host controller"); -+ goto fail; -+ } -+ -+ init_waitqueue_head(&info->wq); -+ -+ return 0; -+ -+fail: -+ usb_put_hcd(hcd); -+ dev_set_drvdata(&dev->dev, NULL); -+ return err; -+} -+ -+static void usbfront_disconnect(struct xenbus_device *dev) -+{ -+ struct usbfront_info *info = dev_get_drvdata(&dev->dev); -+ struct usb_hcd *hcd = info_to_hcd(info); -+ -+ usb_remove_hcd(hcd); -+ if (info->kthread) { -+ kthread_stop(info->kthread); -+ info->kthread = NULL; -+ } -+ xenbus_frontend_closed(dev); -+} -+ -+static void usbback_changed(struct xenbus_device *dev, -+ enum xenbus_state backend_state) -+{ -+ switch (backend_state) { -+ case XenbusStateInitialising: -+ case XenbusStateInitialised: -+ case XenbusStateConnected: -+ case XenbusStateReconfiguring: -+ case XenbusStateReconfigured: -+ case XenbusStateUnknown: -+ case XenbusStateClosed: -+ break; -+ -+ case XenbusStateInitWait: -+ if (dev->state != XenbusStateInitialising) -+ break; -+ if (!connect(dev)) -+ xenbus_switch_state(dev, XenbusStateConnected); -+ break; -+ -+ case XenbusStateClosing: -+ usbfront_disconnect(dev); -+ break; -+ -+ default: -+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", -+ backend_state); -+ break; -+ } -+} -+ -+static int usbfront_remove(struct xenbus_device *dev) -+{ -+ struct usbfront_info *info = dev_get_drvdata(&dev->dev); -+ struct usb_hcd *hcd = info_to_hcd(info); -+ -+ destroy_rings(info); -+ usb_put_hcd(hcd); -+ -+ return 0; -+} -+ -+static const struct xenbus_device_id usbfront_ids[] = { -+ { "vusb" }, -+ { "" }, -+}; -+MODULE_ALIAS("xen:vusb"); -+ -+static DEFINE_XENBUS_DRIVER(usbfront, , -+ .probe = usbfront_probe, -+ .remove = usbfront_remove, -+ .otherend_changed = usbback_changed, -+); -+ -+static int __init usbfront_init(void) -+{ -+ if (!xen_domain()) -+ return -ENODEV; -+ -+ xenhcd_urbp_cachep = kmem_cache_create("xenhcd_urb_priv", -+ sizeof(struct urb_priv), 0, 0, NULL); -+ if (!xenhcd_urbp_cachep) { -+ printk(KERN_ERR "usbfront failed to create kmem cache\n"); -+ return -ENOMEM; -+ } -+ -+ return xenbus_register_frontend(&usbfront_driver); -+} -+ -+static void __exit usbfront_exit(void) -+{ -+ kmem_cache_destroy(xenhcd_urbp_cachep); -+ xenbus_unregister_driver(&usbfront_driver); -+} -+ -+module_init(usbfront_init); -+module_exit(usbfront_exit); -+ -+MODULE_AUTHOR(""); -+MODULE_DESCRIPTION("Xen USB Virtual Host Controller driver (usbfront)"); -+MODULE_LICENSE("Dual BSD/GPL"); -diff --git a/include/xen/interface/io/usbif.h b/include/xen/interface/io/usbif.h -new file mode 100644 -index 0000000..f3bb1b2 ---- /dev/null -+++ b/include/xen/interface/io/usbif.h -@@ -0,0 +1,150 @@ -+/* -+ * usbif.h -+ * -+ * USB I/O interface for Xen guest OSes. -+ * -+ * Copyright (C) 2009, FUJITSU LABORATORIES LTD. -+ * Author: Noboru Iwamatsu -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef __XEN_PUBLIC_IO_USBIF_H__ -+#define __XEN_PUBLIC_IO_USBIF_H__ -+ -+#include "ring.h" -+#include "../grant_table.h" -+ -+enum usb_spec_version { -+ USB_VER_UNKNOWN = 0, -+ USB_VER_USB11, -+ USB_VER_USB20, -+ USB_VER_USB30, /* not supported yet */ -+}; -+ -+/* -+ * USB pipe in usbif_request -+ * -+ * bits 0-5 are specific bits for virtual USB driver. -+ * bits 7-31 are standard urb pipe. -+ * -+ * - port number(NEW): bits 0-4 -+ * (USB_MAXCHILDREN is 31) -+ * -+ * - operation flag(NEW): bit 5 -+ * (0 = submit urb, -+ * 1 = unlink urb) -+ * -+ * - direction: bit 7 -+ * (0 = Host-to-Device [Out] -+ * 1 = Device-to-Host [In]) -+ * -+ * - device address: bits 8-14 -+ * -+ * - endpoint: bits 15-18 -+ * -+ * - pipe type: bits 30-31 -+ * (00 = isochronous, 01 = interrupt, -+ * 10 = control, 11 = bulk) -+ */ -+#define usbif_pipeportnum(pipe) ((pipe) & 0x1f) -+#define usbif_setportnum_pipe(pipe, portnum) \ -+ ((pipe)|(portnum)) -+ -+#define usbif_pipeunlink(pipe) ((pipe) & 0x20) -+#define usbif_pipesubmit(pipe) (!usbif_pipeunlink(pipe)) -+#define usbif_setunlink_pipe(pipe) ((pipe)|(0x20)) -+ -+#define USBIF_BACK_MAX_PENDING_REQS (128) -+#define USBIF_MAX_SEGMENTS_PER_REQUEST (16) -+ -+/* -+ * RING for transferring urbs. -+ */ -+struct usbif_request_segment { -+ grant_ref_t gref; -+ uint16_t offset; -+ uint16_t length; -+}; -+ -+struct usbif_urb_request { -+ uint16_t id; /* request id */ -+ uint16_t nr_buffer_segs; /* number of urb->transfer_buffer segments */ -+ -+ /* basic urb parameter */ -+ uint32_t pipe; -+ uint16_t transfer_flags; -+ uint16_t buffer_length; -+ union { -+ uint8_t ctrl[8]; /* setup_packet (Ctrl) */ -+ -+ struct { -+ uint16_t interval; /* maximum (1024*8) in usb core */ -+ uint16_t start_frame; /* start frame */ -+ uint16_t number_of_packets; /* number of ISO packet */ -+ uint16_t nr_frame_desc_segs; /* number of iso_frame_desc -+ segments */ -+ } isoc; -+ -+ struct { -+ uint16_t interval; /* maximum (1024*8) in usb core */ -+ uint16_t pad[3]; -+ } intr; -+ -+ struct { -+ uint16_t unlink_id; /* unlink request id */ -+ uint16_t pad[3]; -+ } unlink; -+ -+ } u; -+ -+ /* urb data segments */ -+ struct usbif_request_segment seg[USBIF_MAX_SEGMENTS_PER_REQUEST]; -+}; -+ -+struct usbif_urb_response { -+ uint16_t id; /* request id */ -+ uint16_t start_frame; /* start frame (ISO) */ -+ int32_t status; /* status (non-ISO) */ -+ int32_t actual_length; /* actual transfer length */ -+ int32_t error_count; /* number of ISO errors */ -+}; -+ -+DEFINE_RING_TYPES(usbif_urb, struct usbif_urb_request, -+ struct usbif_urb_response); -+#define USB_URB_RING_SIZE __CONST_RING_SIZE(usbif_urb, PAGE_SIZE) -+ -+/* -+ * RING for notifying connect/disconnect events to frontend -+ */ -+struct usbif_conn_request { -+ uint16_t id; -+}; -+ -+struct usbif_conn_response { -+ uint16_t id; /* request id */ -+ uint8_t portnum; /* port number */ -+ uint8_t speed; /* usb_device_speed */ -+}; -+ -+DEFINE_RING_TYPES(usbif_conn, struct usbif_conn_request, -+ struct usbif_conn_response); -+#define USB_CONN_RING_SIZE __CONST_RING_SIZE(usbif_conn, PAGE_SIZE) -+ -+#endif /* __XEN_PUBLIC_IO_USBIF_H__ */ diff --git a/patches.xen/pvops-blkfront-eject-support.patch b/patches.xen/pvops-blkfront-eject-support.patch deleted file mode 100644 index 1eeb80d..0000000 --- a/patches.xen/pvops-blkfront-eject-support.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- linux-3.4.1.orig/drivers/block/xen-blkfront.c 2012-06-01 09:18:44.000000000 +0200 -+++ linux-3.4.1/drivers/block/xen-blkfront.c 2012-07-15 15:54:31.350255623 +0200 -@@ -44,6 +44,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -241,6 +264,9 @@ - return 0; - return -EINVAL; - } -+ case FDEJECT: -+ xenbus_switch_state(info->xbdev, XenbusStateClosing); -+ return 0; - - default: - /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", diff --git a/patches.xen/xen-balloon-add-runtime-control-for-scrubbing-balloo.patch b/patches.xen/xen-balloon-add-runtime-control-for-scrubbing-balloo.patch deleted file mode 100644 index 6517cc9..0000000 --- a/patches.xen/xen-balloon-add-runtime-control-for-scrubbing-balloo.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 59e44d8c45afe91204e90229bef64a6d2c5ac103 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= - -Date: Thu, 6 Sep 2018 15:09:44 +0200 -Subject: [PATCH] xen/balloon: add runtime control for scrubbing ballooned out - pages - -Scrubbing pages on initial balloon down can take some time, especially -in nested virtualization case (nested EPT is slow). When HVM/PVH guest is -started with memory= significantly lower than maxmem=, all the extra -pages will be scrubbed before returning to Xen. But since most of them -weren't used at all at that point, Xen needs to populate them first -(from populate-on-demand pool). In nested virt case (Xen inside KVM) -this slows down the guest boot by 15-30s with just 1.5GB needed to be -returned to Xen. - -Add runtime parameter to enable/disable it, to allow initially disabling -scrubbing, then enable it back during boot (for example in initramfs). -Such usage relies on assumption that a) most pages ballooned out during -initial boot weren't used at all, and b) even if they were, very few -secrets are in the guest at that time (before any serious userspace -kicks in). -Convert CONFIG_XEN_SCRUB_PAGES to CONFIG_XEN_SCRUB_PAGES_DEFAULT (also -enabled by default), controlling default value for the new runtime -switch. - -Signed-off-by: Marek Marczykowski-Górecki - ---- - .../ABI/stable/sysfs-devices-system-xen_memory | 9 +++++++++ - Documentation/admin-guide/kernel-parameters.txt | 6 ++++++ - drivers/xen/Kconfig | 10 +++++++--- - drivers/xen/balloon.c | 9 ++++++--- - drivers/xen/xen-balloon.c | 2 ++ - include/xen/balloon.h | 1 + - 6 files changed, 31 insertions(+), 6 deletions(-) - -diff --git a/Documentation/ABI/stable/sysfs-devices-system-xen_memory b/Documentation/ABI/stable/sysfs-devices-system-xen_memory -index caa311d59ac1..6d83f95a8a8e 100644 ---- a/Documentation/ABI/stable/sysfs-devices-system-xen_memory -+++ b/Documentation/ABI/stable/sysfs-devices-system-xen_memory -@@ -75,3 +75,12 @@ Contact: Konrad Rzeszutek Wilk - Description: - Amount (in KiB) of low (or normal) memory in the - balloon. -+ -+What: /sys/devices/system/xen_memory/xen_memory0/scrub_pages -+Date: September 2018 -+KernelVersion: 4.20 -+Contact: xen-devel@lists.xenproject.org -+Description: -+ Control scrubbing pages before returning them to Xen for others domains -+ use. Can be set with xen_scrub_pages cmdline -+ parameter. Default value controlled with CONFIG_XEN_SCRUB_PAGES_DEFAULT. -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 1370b424a453..c62691ddd476 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -4921,6 +4921,12 @@ - Disables the PV optimizations forcing the HVM guest to - run as generic HVM guest with no PV drivers. - -+ xen_scrub_pages= [XEN] -+ Boolean option to control scrubbing pages before giving them back -+ to Xen, for use by other domains. Can be also changed at runtime -+ with /sys/devices/system/xen_memory/xen_memory0/scrub_pages. -+ Default value controlled with CONFIG_XEN_SCRUB_PAGES_DEFAULT. -+ - xirc2ps_cs= [NET,PCMCIA] - Format: - ,,,,,[,[,[,]]] -diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig -index e5d0c28372ea..2f0353290ce5 100644 ---- a/drivers/xen/Kconfig -+++ b/drivers/xen/Kconfig -@@ -79,15 +79,19 @@ config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT - This value is used to allocate enough space in internal - tables needed for physical memory administration. - --config XEN_SCRUB_PAGES -- bool "Scrub pages before returning them to system" -+config XEN_SCRUB_PAGES_DEFAULT -+ bool "Scrub pages before returning them to system by default" - depends on XEN_BALLOON - default y - help - Scrub pages before returning them to the system for reuse by - other domains. This makes sure that any confidential data - is not accidentally visible to other domains. Is it more -- secure, but slightly less efficient. -+ secure, but slightly less efficient. This can be controlled with -+ xen_scrub_pages=0 parameter and -+ /sys/devices/system/xen_memory/xen_memory0/scrub_pages. -+ This option only sets the default value. -+ - If in doubt, say yes. - - config XEN_DEV_EVTCHN -diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c -index 065f0b607373..a3e5dfa71796 100644 ---- a/drivers/xen/balloon.c -+++ b/drivers/xen/balloon.c -@@ -56,6 +56,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -74,6 +75,9 @@ - - static int xen_hotplug_unpopulated; - -+bool __read_mostly xen_scrub_pages = IS_ENABLED(CONFIG_XEN_SCRUB_PAGES_DEFAULT); -+core_param(xen_scrub_pages, xen_scrub_pages, bool, 0); -+ - #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - - static int zero; -@@ -159,9 +163,8 @@ static DECLARE_DELAYED_WORK(balloon_worker, balloon_process); - - static void scrub_page(struct page *page) - { --#ifdef CONFIG_XEN_SCRUB_PAGES -- clear_highpage(page); --#endif -+ if (xen_scrub_pages) -+ clear_highpage(page); - } - - /* balloon_append: add the given page to the balloon. */ -diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c -index b437fccd4e62..a3dd7c6ec371 100644 ---- a/drivers/xen/xen-balloon.c -+++ b/drivers/xen/xen-balloon.c -@@ -137,6 +137,7 @@ static DEVICE_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); - static DEVICE_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); - static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); - static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); -+static DEVICE_BOOL_ATTR(scrub_pages, 0644, xen_scrub_pages); - - static ssize_t show_target_kb(struct device *dev, struct device_attribute *attr, - char *buf) -@@ -203,6 +204,7 @@ static struct attribute *balloon_attrs[] = { - &dev_attr_max_schedule_delay.attr.attr, - &dev_attr_retry_count.attr.attr, - &dev_attr_max_retry_count.attr.attr, -+ &dev_attr_scrub_pages.attr.attr, - NULL - }; - -diff --git a/include/xen/balloon.h b/include/xen/balloon.h -index 61f410fd74e4..0ec832b9ff55 100644 ---- a/include/xen/balloon.h -+++ b/include/xen/balloon.h -@@ -21,6 +21,7 @@ struct balloon_stats { - }; - - extern struct balloon_stats balloon_stats; -+extern bool xen_scrub_pages; - - void balloon_set_new_target(unsigned long target); - --- -2.17.1 - diff --git a/patches.xen/xsa270.patch b/patches.xen/xsa270.patch deleted file mode 100644 index 93b0655..0000000 --- a/patches.xen/xsa270.patch +++ /dev/null @@ -1,49 +0,0 @@ -From: Jan Beulich -Subject: xen-netback: fix input validation in xenvif_set_hash_mapping() - -Both len and off are frontend specified values, so we need to make -sure there's no overflow when adding the two for the bounds check. We -also want to avoid undefined behavior and hence use off to index into -->hash.mapping[] only after bounds checking. This at the same time -allows to take care of not applying off twice for the bounds checking -against vif->num_queues. - -It is also insufficient to bounds check copy_op.len, as this is len -truncated to 16 bits. - -This is XSA-270. - -Signed-off-by: Jan Beulich -Reviewed-by: Paul Durrant -Tested-by: Paul Durrant - ---- a/drivers/net/xen-netback/hash.c -+++ b/drivers/net/xen-netback/hash.c -@@ -332,20 +332,22 @@ u32 xenvif_set_hash_mapping_size(struct - u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len, - u32 off) - { -- u32 *mapping = &vif->hash.mapping[off]; -+ u32 *mapping = vif->hash.mapping; - struct gnttab_copy copy_op = { - .source.u.ref = gref, - .source.domid = vif->domid, -- .dest.u.gmfn = virt_to_gfn(mapping), - .dest.domid = DOMID_SELF, -- .dest.offset = xen_offset_in_page(mapping), -- .len = len * sizeof(u32), -+ .len = len * sizeof(*mapping), - .flags = GNTCOPY_source_gref - }; - -- if ((off + len > vif->hash.size) || copy_op.len > XEN_PAGE_SIZE) -+ if ((off + len < off) || (off + len > vif->hash.size) || -+ len > XEN_PAGE_SIZE / sizeof(*mapping)) - return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; - -+ copy_op.dest.u.gmfn = virt_to_gfn(mapping + off); -+ copy_op.dest.offset = xen_offset_in_page(mapping + off); -+ - while (len-- != 0) - if (mapping[off++] >= vif->num_queues) - return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; diff --git a/series.conf b/series.conf index 5d98d94..6172b56 100644 --- a/series.conf +++ b/series.conf @@ -1,28 +1,23 @@ -patches.rpmify/makefile-after_link.patch - -patches.xen/xen-netfront-detach-crash.patch -patches.xen/0001-mce-hide-EBUSY-initialization-error-on-Xen.patch -patches.xen/irq-bind-debug-log.patch -patches.xen/xen-balloon-add-runtime-control-for-scrubbing-balloo.patch +0001-kbuild-AFTER_LINK.patch +0002-xen-netfront-detach-crash.patch +0003-mce-hide-EBUSY-initialization-error-on-Xen.patch +0004-Log-error-code-of-EVTCHNOP_bind_pirq-failure.patch # Additional features -#patches.xen/pvops-0100-usb-xen-pvusb-driver.patch -patches.xen/pvops-blkfront-removable-flag.patch -patches.xen/pvops-blkfront-eject-support.patch - -patches.qubes/0001-block-add-no_part_scan-module-parameter.patch +0005-pvops-respect-removable-xenstore-flag-for-block-devi.patch +0006-pvops-xen-blkfront-handle-FDEJECT-as-detach-request-.patch +0007-block-add-no_part_scan-module-parameter.patch # Security fixes -patches.xen/xsa155-linux-0008-xen-Add-RING_COPY_RESPONSE.patch -patches.xen/xsa155-linux44-0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch -patches.xen/xsa155-linux44-0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch -patches.xen/xsa155-linux-0011-xen-netfront-add-range-check-for-Tx-response-id.patch -patches.xen/xsa155-linux312-0012-xen-blkfront-make-local-copy-of-response-before-usin.patch -patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch -patches.xen/xsa270.patch +0008-xen-Add-RING_COPY_RESPONSE.patch +0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch +0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch +0011-xen-netfront-add-range-check-for-Tx-response-id.patch +0012-xen-blkfront-make-local-copy-of-response-before-usin.patch +0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch # MSI-X enabled device passthrough fix (#1734) -patches.xen/pci_op-cleanup.patch +0014-xen-pcifront-pciback-Update-pciif.h-with-err-and-res.patch # Fix for MSI support with stubdoms -patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch +0015-xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch diff --git a/version b/version index cf363a9..1fc0e81 100644 --- a/version +++ b/version @@ -1 +1 @@ -4.18.13 +4.19.1